95f0fc0b7a
* every user has a right of a username and a display name and has the right to change it * System information page now shows information about database user count, char count, and database schema version * more maintenance lists * show the right values in columns and fields * move similar from inside of frontend component functions to utility js when used multiple times * display help on mouse over * add more than one believe to character * make char name editable with better char info in headline * GiT Gifttoleranz value not calculated correctly * Bump backend to 0.2.3, frontend to 0.2.2
357 lines
9.2 KiB
Go
357 lines
9.2 KiB
Go
package maintenance
|
|
|
|
import (
|
|
"bamort/database"
|
|
"bamort/models"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func GetGameSystems(c *gin.Context) {
|
|
var systems []models.GameSystem
|
|
if err := database.DB.Order("code ASC").Find(&systems).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve game systems")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"game_systems": systems})
|
|
}
|
|
|
|
type gameSystemUpdateRequest struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
IsActive *bool `json:"is_active"`
|
|
}
|
|
|
|
func UpdateGameSystem(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Invalid ID")
|
|
return
|
|
}
|
|
|
|
var gs models.GameSystem
|
|
if err := database.DB.First(&gs, uint(id)).Error; err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Game system not found")
|
|
return
|
|
}
|
|
|
|
var payload gameSystemUpdateRequest
|
|
if err := c.ShouldBindJSON(&payload); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
name := strings.TrimSpace(payload.Name)
|
|
if name != "" {
|
|
gs.Name = name
|
|
}
|
|
gs.Description = payload.Description
|
|
if payload.IsActive != nil {
|
|
gs.IsActive = *payload.IsActive
|
|
}
|
|
|
|
if err := database.DB.Save(&gs).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to update game system")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gs)
|
|
}
|
|
|
|
// --- Sources ---
|
|
|
|
type sourceUpdateRequest struct {
|
|
Name string `json:"name"`
|
|
FullName string `json:"full_name"`
|
|
Edition string `json:"edition"`
|
|
Publisher string `json:"publisher"`
|
|
PublishYear int `json:"publish_year"`
|
|
Description string `json:"description"`
|
|
IsCore *bool `json:"is_core"`
|
|
IsActive *bool `json:"is_active"`
|
|
}
|
|
|
|
func GetLitSources(c *gin.Context) {
|
|
gs := resolveGameSystemOrDefault(c)
|
|
if gs == nil {
|
|
return
|
|
}
|
|
|
|
var sources []models.Source
|
|
if err := database.DB.Where("game_system=? OR game_system_id=?", gs.Name, gs.ID).
|
|
Order("code ASC").
|
|
Find(&sources).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve sources")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"sources": sources})
|
|
}
|
|
|
|
func UpdateLitSource(c *gin.Context) {
|
|
gs := resolveGameSystemOrDefault(c)
|
|
if gs == nil {
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Invalid ID")
|
|
return
|
|
}
|
|
|
|
var src models.Source
|
|
if err := database.DB.First(&src, uint(id)).Error; err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Source not found")
|
|
return
|
|
}
|
|
|
|
var payload sourceUpdateRequest
|
|
if err := c.ShouldBindJSON(&payload); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
if name := strings.TrimSpace(payload.Name); name != "" {
|
|
src.Name = name
|
|
}
|
|
src.FullName = payload.FullName
|
|
src.Edition = payload.Edition
|
|
src.Publisher = payload.Publisher
|
|
src.PublishYear = payload.PublishYear
|
|
src.Description = payload.Description
|
|
if payload.IsCore != nil {
|
|
src.IsCore = *payload.IsCore
|
|
}
|
|
if payload.IsActive != nil {
|
|
src.IsActive = *payload.IsActive
|
|
}
|
|
src.GameSystem = gs.Name
|
|
src.GameSystemId = gs.ID
|
|
|
|
if err := database.DB.Save(&src).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to update source")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, src)
|
|
}
|
|
|
|
// --- Misc lookup ---
|
|
|
|
type miscUpdateRequest struct {
|
|
Key string `json:"key"`
|
|
Value string `json:"value"`
|
|
SourceID *uint `json:"source_id"`
|
|
PageNumber *int `json:"page_number"`
|
|
}
|
|
|
|
func GetMisc(c *gin.Context) {
|
|
gs := resolveGameSystemOrDefault(c)
|
|
if gs == nil {
|
|
return
|
|
}
|
|
|
|
keyFilter := strings.TrimSpace(c.Query("key"))
|
|
|
|
var items []models.MiscLookup
|
|
q := database.DB.Where("game_system=? OR game_system_id=?", gs.Name, gs.ID)
|
|
if keyFilter != "" {
|
|
q = q.Where("`key` = ?", keyFilter)
|
|
}
|
|
if err := q.Order("`key` ASC, value ASC").Find(&items).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve misc")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"misc": items})
|
|
}
|
|
|
|
func UpdateMisc(c *gin.Context) {
|
|
gs := resolveGameSystemOrDefault(c)
|
|
if gs == nil {
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Invalid ID")
|
|
return
|
|
}
|
|
|
|
var item models.MiscLookup
|
|
if err := database.DB.First(&item, uint(id)).Error; err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Misc entry not found")
|
|
return
|
|
}
|
|
|
|
var payload miscUpdateRequest
|
|
if err := c.ShouldBindJSON(&payload); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
if key := strings.TrimSpace(payload.Key); key != "" {
|
|
item.Key = key
|
|
}
|
|
if payload.Value != "" {
|
|
item.Value = payload.Value
|
|
}
|
|
if payload.SourceID != nil {
|
|
item.SourceID = *payload.SourceID
|
|
}
|
|
if payload.PageNumber != nil {
|
|
item.PageNumber = *payload.PageNumber
|
|
}
|
|
item.GameSystem = gs.Name
|
|
item.GameSystemId = gs.ID
|
|
|
|
if err := database.DB.Save(&item).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to update misc entry")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, item)
|
|
}
|
|
|
|
// --- Skill improvement cost2 ---
|
|
|
|
type skillImprovementUpdateRequest struct {
|
|
CurrentLevel *int `json:"current_level"`
|
|
TERequired *int `json:"te_required"`
|
|
CategoryID *uint `json:"category_id"`
|
|
DifficultyID *uint `json:"difficulty_id"`
|
|
}
|
|
|
|
func GetSkillImprovementCost2(c *gin.Context) {
|
|
var costs []models.SkillImprovementCost
|
|
if err := database.DB.Order("current_level ASC").Find(&costs).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve skill improvement costs")
|
|
return
|
|
}
|
|
|
|
categoryNames, difficultyNames, err := loadSkillMetadata(costs)
|
|
if err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve skill improvement costs")
|
|
return
|
|
}
|
|
|
|
responses := make([]skillImprovementCostResponse, len(costs))
|
|
for i, cost := range costs {
|
|
responses[i] = skillImprovementCostResponse{
|
|
SkillImprovementCost: cost,
|
|
CategoryName: categoryNames[cost.CategoryID],
|
|
DifficultyName: difficultyNames[cost.DifficultyID],
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"costs": responses})
|
|
}
|
|
|
|
func UpdateSkillImprovementCost2(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Invalid ID")
|
|
return
|
|
}
|
|
|
|
var cost models.SkillImprovementCost
|
|
if err := database.DB.First(&cost, uint(id)).Error; err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Skill improvement cost not found")
|
|
return
|
|
}
|
|
|
|
var payload skillImprovementUpdateRequest
|
|
if err := c.ShouldBindJSON(&payload); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
if payload.CurrentLevel != nil {
|
|
cost.CurrentLevel = *payload.CurrentLevel
|
|
}
|
|
if payload.TERequired != nil {
|
|
cost.TERequired = *payload.TERequired
|
|
}
|
|
if payload.CategoryID != nil {
|
|
cost.CategoryID = *payload.CategoryID
|
|
}
|
|
if payload.DifficultyID != nil {
|
|
cost.DifficultyID = *payload.DifficultyID
|
|
}
|
|
|
|
if err := database.DB.Save(&cost).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to update skill improvement cost")
|
|
return
|
|
}
|
|
|
|
categoryNames, difficultyNames, err := loadSkillMetadata([]models.SkillImprovementCost{cost})
|
|
if err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Failed to update skill improvement cost")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, skillImprovementCostResponse{
|
|
SkillImprovementCost: cost,
|
|
CategoryName: categoryNames[cost.CategoryID],
|
|
DifficultyName: difficultyNames[cost.DifficultyID],
|
|
})
|
|
}
|
|
|
|
type skillImprovementCostResponse struct {
|
|
models.SkillImprovementCost
|
|
CategoryName string `json:"category_name,omitempty"`
|
|
DifficultyName string `json:"difficulty_name,omitempty"`
|
|
}
|
|
|
|
func loadSkillMetadata(costs []models.SkillImprovementCost) (map[uint]string, map[uint]string, error) {
|
|
categoryNames := make(map[uint]string)
|
|
difficultyNames := make(map[uint]string)
|
|
|
|
if len(costs) == 0 {
|
|
return categoryNames, difficultyNames, nil
|
|
}
|
|
|
|
categoryIDs := make([]uint, 0)
|
|
difficultyIDs := make([]uint, 0)
|
|
seenCategories := make(map[uint]struct{})
|
|
seenDifficulties := make(map[uint]struct{})
|
|
|
|
for _, cost := range costs {
|
|
if _, ok := seenCategories[cost.CategoryID]; !ok {
|
|
seenCategories[cost.CategoryID] = struct{}{}
|
|
categoryIDs = append(categoryIDs, cost.CategoryID)
|
|
}
|
|
if _, ok := seenDifficulties[cost.DifficultyID]; !ok {
|
|
seenDifficulties[cost.DifficultyID] = struct{}{}
|
|
difficultyIDs = append(difficultyIDs, cost.DifficultyID)
|
|
}
|
|
}
|
|
|
|
if len(categoryIDs) > 0 {
|
|
var categories []models.SkillCategory
|
|
if err := database.DB.Where("id IN ?", categoryIDs).Find(&categories).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
for _, category := range categories {
|
|
categoryNames[category.ID] = category.Name
|
|
}
|
|
}
|
|
|
|
if len(difficultyIDs) > 0 {
|
|
var difficulties []models.SkillDifficulty
|
|
if err := database.DB.Where("id IN ?", difficultyIDs).Find(&difficulties).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
for _, difficulty := range difficulties {
|
|
difficultyNames[difficulty.ID] = difficulty.Name
|
|
}
|
|
}
|
|
|
|
return categoryNames, difficultyNames, nil
|
|
}
|