Files
bamort/backend/maintenance/masterdata_handlers.go
Bardioc26 95f0fc0b7a editing and maintenance and user suggestions
* 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
2026-02-03 17:21:43 +01:00

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
}