extra learn_categories added to spell maintenance

This commit is contained in:
2026-02-27 11:59:16 +01:00
parent 6ac04b2ae1
commit 09d12d3d8c
7 changed files with 240 additions and 5 deletions
+1
View File
@@ -47,6 +47,7 @@ func RegisterRoutes(r *gin.RouterGroup) {
maintGrp.PUT("/spells/:id", UpdateMDSpell) maintGrp.PUT("/spells/:id", UpdateMDSpell)
maintGrp.PUT("/spells-enhanced/:id", UpdateEnhancedMDSpell) // New enhanced endpoint maintGrp.PUT("/spells-enhanced/:id", UpdateEnhancedMDSpell) // New enhanced endpoint
maintGrp.POST("/spells", AddSpell) maintGrp.POST("/spells", AddSpell)
maintGrp.POST("/spells-enhanced", CreateEnhancedMDSpell) // New enhanced endpoint
maintGrp.DELETE("/spells/:id", DeleteMDSpell) maintGrp.DELETE("/spells/:id", DeleteMDSpell)
maintGrp.PUT("/equipment/:id", UpdateMDEquipment) maintGrp.PUT("/equipment/:id", UpdateMDEquipment)
@@ -66,6 +66,15 @@ func UpdateSpellWithCategories(spellID uint, req SpellUpdateRequest) error {
}) })
} }
// CreateSpellWithCategories creates a new spell
func CreateSpellWithCategories(req SpellUpdateRequest) (*models.Spell, error) {
spell := req.Spell
if err := database.DB.Create(&spell).Error; err != nil {
return nil, err
}
return &spell, nil
}
// ===== Handler Functions ===== // ===== Handler Functions =====
// GetEnhancedMDSpells returns spells with enhanced information // GetEnhancedMDSpells returns spells with enhanced information
@@ -87,11 +96,18 @@ func GetEnhancedMDSpells(c *gin.Context) {
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve spell categories: "+err.Error()) respondWithError(c, http.StatusInternalServerError, "Failed to retrieve spell categories: "+err.Error())
return return
} }
// Get spell Learn_categories
learnCategories, err := spell.GetSpellLearnCategories()
if err != nil {
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve spell learn categories: "+err.Error())
return
}
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"spells": spells, "spells": spells,
"sources": sources, "sources": sources,
"categories": categories, "categories": categories,
"learnCategories": learnCategories,
}) })
} }
@@ -145,3 +161,27 @@ func UpdateEnhancedMDSpell(c *gin.Context) {
c.JSON(http.StatusOK, spell) c.JSON(http.StatusOK, spell)
} }
// CreateEnhancedMDSpell creates a new spell
func CreateEnhancedMDSpell(c *gin.Context) {
var req SpellUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
respondWithError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
return
}
spell, err := CreateSpellWithCategories(req)
if err != nil {
respondWithError(c, http.StatusInternalServerError, "Failed to create spell: "+err.Error())
return
}
// Return created spell with enhanced information
spellWithCats, err := GetSpellWithCategories(spell.ID)
if err != nil {
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve created spell")
return
}
c.JSON(http.StatusCreated, spellWithCats)
}
@@ -0,0 +1,153 @@
package gsmaster
import (
"bamort/database"
"bamort/models"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUpdateSpellWithLearningCategory(t *testing.T) {
// Set test environment
setupTestEnvironment(t)
database.SetupTestDB(true)
defer database.ResetTestDB()
// Create a test spell
spell := models.Spell{
Name: "Testzauber",
Category: "Wunder",
LearningCategory: "",
Stufe: 1,
GameSystem: "midgard",
}
err := database.DB.Create(&spell).Error
require.NoError(t, err, "Failed to create test spell")
// Test 1: Update learning_category
spell.LearningCategory = "Wundertat"
updateReq := SpellUpdateRequest{Spell: spell}
err = UpdateSpellWithCategories(spell.ID, updateReq)
assert.NoError(t, err, "Failed to update spell with learning_category")
// Verify update
var updated models.Spell
err = database.DB.First(&updated, spell.ID).Error
require.NoError(t, err)
assert.Equal(t, "Wundertat", updated.LearningCategory, "Learning category not updated correctly")
assert.Equal(t, "Wunder", updated.Category, "Category should remain unchanged")
// Test 2: Update both categories
updated.Category = "Verändern"
updated.LearningCategory = "Zauberlied"
updateReq2 := SpellUpdateRequest{Spell: updated}
err = UpdateSpellWithCategories(updated.ID, updateReq2)
assert.NoError(t, err, "Failed to update both categories")
// Verify both were updated
var final models.Spell
err = database.DB.First(&final, updated.ID).Error
require.NoError(t, err)
assert.Equal(t, "Verändern", final.Category, "Category not updated")
assert.Equal(t, "Zauberlied", final.LearningCategory, "Learning category not updated")
}
func TestCreateSpellWithLearningCategory(t *testing.T) {
setupTestEnvironment(t)
database.SetupTestDB(true)
defer database.ResetTestDB()
// Test: Create spell with learning_category
spell := models.Spell{
Name: "Neuer Zauber",
Category: "Beherrschen",
LearningCategory: "Runenstab",
Stufe: 2,
GameSystem: "midgard",
AP: "3",
}
err := database.DB.Create(&spell).Error
require.NoError(t, err, "Failed to create spell with learning_category")
// Verify creation
var created models.Spell
err = database.DB.Where("name = ?", "Neuer Zauber").First(&created).Error
require.NoError(t, err)
assert.Equal(t, "Beherrschen", created.Category)
assert.Equal(t, "Runenstab", created.LearningCategory)
assert.Equal(t, 2, created.Stufe)
}
func TestLearningCategoryDefaultEmpty(t *testing.T) {
setupTestEnvironment(t)
database.SetupTestDB(true)
defer database.ResetTestDB()
// Test: Create spell without learning_category
spell := models.Spell{
Name: "Zauber ohne LearningCategory",
Category: "Normal",
Stufe: 1,
GameSystem: "midgard",
}
err := database.DB.Create(&spell).Error
require.NoError(t, err)
// Verify learning_category is empty (not nil)
var created models.Spell
err = database.DB.First(&created, spell.ID).Error
require.NoError(t, err)
assert.Equal(t, "", created.LearningCategory, "Learning category should be empty string by default")
assert.Equal(t, "Normal", created.Category)
}
func TestCreateEnhancedMDSpellEndpoint(t *testing.T) {
setupTestEnvironment(t)
database.SetupTestDB(true)
defer database.ResetTestDB()
// Test: Create spell with learning_category via endpoint
spell := models.Spell{
Name: "Test Endpoint Zauber",
Category: "Erkennen",
LearningCategory: "Erkenntnismagie",
Stufe: 3,
GameSystem: "midgard",
AP: "2",
}
req := SpellUpdateRequest{Spell: spell}
created, err := CreateSpellWithCategories(req)
require.NoError(t, err, "Failed to create spell")
assert.NotZero(t, created.ID, "Created spell should have an ID")
assert.Equal(t, "Erkennen", created.Category)
assert.Equal(t, "Erkenntnismagie", created.LearningCategory)
assert.Equal(t, 3, created.Stufe)
}
func TestGetSpellLearningCategories(t *testing.T) {
setupTestEnvironment(t)
database.SetupTestDB(true)
defer database.ResetTestDB()
var spell models.Spell
learningCategories, err := spell.GetSpellLearnCategories()
require.NoError(t, err, "Failed to get spell learning categories")
assert.Contains(t, learningCategories, "Spruch", "Learning categories should include 'Spruch'")
assert.Contains(t, learningCategories, "Runenstab", "Learning categories should include 'Runenstab'")
assert.Contains(t, learningCategories, "Zauberlied", "Learning categories should include 'Zauberlied'")
assert.Contains(t, learningCategories, "Wundertat", "Learning categories should include 'Wundertat'")
assert.Contains(t, learningCategories, "Dweomer", "Learning categories should include 'Dweomer'")
assert.Contains(t, learningCategories, "Thaumatherapie", "Learning categories should include 'Thaumatherapie'")
assert.Contains(t, learningCategories, "Zaubersalz", "Learning categories should include 'Zaubersalz'")
assert.Contains(t, learningCategories, "Rune", "Learning categories should include 'Rune'")
assert.Contains(t, learningCategories, "Siegel", "Learning categories should include 'Siegel'")
}
+16
View File
@@ -438,6 +438,22 @@ func (object *Spell) GetSpellCategories() ([]string, error) {
return categories, nil return categories, nil
} }
func (object *Spell) GetSpellLearnCategories() ([]string, error) {
var categories []string
gs := GetGameSystem(object.GameSystemId, object.GameSystem)
result := database.DB.Model(&Spell{}).
Where("game_system = ? OR game_system_id = ?", gs.Name, gs.ID).
Distinct().
Pluck("learning_category", &categories)
if result.Error != nil {
return nil, result.Error
}
return categories, nil
}
func (object *Spell) ensureGameSystem() { func (object *Spell) ensureGameSystem() {
gs := GetGameSystem(object.GameSystemId, object.GameSystem) gs := GetGameSystem(object.GameSystemId, object.GameSystem)
object.GameSystemId = gs.ID object.GameSystemId = gs.ID
@@ -129,6 +129,7 @@
{{ $t('spell.category') }} {{ $t('spell.category') }}
<button @click="sortBy('category')">{{ sortField === 'category' ? (sortAsc ? '' : '') : '-' }}</button> <button @click="sortBy('category')">{{ sortField === 'category' ? (sortAsc ? '' : '') : '-' }}</button>
</th> </th>
<th class="cd-table-header">{{ $t('spell.learning_category') || 'Learning Category' }}</th>
<th class="cd-table-header"> <th class="cd-table-header">
{{ $t('spell.name') }} {{ $t('spell.name') }}
<button @click="sortBy('name')">{{ sortField === 'name' ? (sortAsc ? '' : '') : '-' }}</button> <button @click="sortBy('name')">{{ sortField === 'name' ? (sortAsc ? '' : '') : '-' }}</button>
@@ -150,7 +151,7 @@
<tbody> <tbody>
<tr v-if="creatingNew"> <tr v-if="creatingNew">
<td>New</td> <td>New</td>
<td colspan="14"> <td colspan="15">
<div class="edit-form"> <div class="edit-form">
<div class="edit-row"> <div class="edit-row">
<div class="edit-field"> <div class="edit-field">
@@ -165,6 +166,15 @@
</option> </option>
</select> </select>
</div> </div>
<div class="edit-field">
<label>{{ $t('spell.learning_category') || 'Learning Category' }}:</label>
<select v-model="newItem.learning_category" style="width:150px;">
<option value="">-</option>
<option v-for="category in availableLearnCategories" :key="category" :value="category">
{{ category }}
</option>
</select>
</div>
<div class="edit-field"> <div class="edit-field">
<label>{{ $t('spell.level') }}:</label> <label>{{ $t('spell.level') }}:</label>
<input v-model.number="newItem.level" type="number" style="width:60px;" /> <input v-model.number="newItem.level" type="number" style="width:60px;" />
@@ -248,6 +258,7 @@
<tr v-if="editingIndex !== index"> <tr v-if="editingIndex !== index">
<td>{{ dtaItem.id || '' }}</td> <td>{{ dtaItem.id || '' }}</td>
<td>{{ dtaItem.category|| '-' }}</td> <td>{{ dtaItem.category|| '-' }}</td>
<td>{{ dtaItem.learning_category || '-' }}</td>
<td>{{ dtaItem.name || '-' }}</td> <td>{{ dtaItem.name || '-' }}</td>
<td>{{ dtaItem.level || '0' }}</td> <td>{{ dtaItem.level || '0' }}</td>
<td>{{ dtaItem.ap || '0' }}</td> <td>{{ dtaItem.ap || '0' }}</td>
@@ -267,7 +278,7 @@
<!-- Edit Mode --> <!-- Edit Mode -->
<tr v-else> <tr v-else>
<td><input v-model="editedItem.id" style="width:20px;" disabled /></td> <td><input v-model="editedItem.id" style="width:20px;" disabled /></td>
<td colspan="14"> <td colspan="15">
<!-- Expanded edit form --> <!-- Expanded edit form -->
<div class="edit-form"> <div class="edit-form">
<div class="edit-row"> <div class="edit-row">
@@ -283,6 +294,15 @@
</option> </option>
</select> </select>
</div> </div>
<div class="edit-field">
<label>{{ $t('spell.learning_category') || 'Learning Category' }}:</label>
<select v-model="editedItem.learning_category" style="width:150px;">
<option value="">-</option>
<option v-for="category in availableLearnCategories" :key="category" :value="category">
{{ category }}
</option>
</select>
</div>
<div class="edit-field"> <div class="edit-field">
<label>{{ $t('spell.level') }}:</label> <label>{{ $t('spell.level') }}:</label>
<input v-model.number="editedItem.level" type="number" style="width:60px;" /> <input v-model.number="editedItem.level" type="number" style="width:60px;" />
@@ -519,6 +539,7 @@ export default {
filterQuelle: '', filterQuelle: '',
enhancedSpells: [], enhancedSpells: [],
availableSources: [], availableSources: [],
availableLearnCategories: [],
gameSystems: [], gameSystems: [],
selectedSystemId: null, selectedSystemId: null,
creatingNew: false, creatingNew: false,
@@ -663,6 +684,7 @@ export default {
const response = await API.get('/api/maintenance/spells-enhanced') const response = await API.get('/api/maintenance/spells-enhanced')
this.enhancedSpells = response.data.spells || [] this.enhancedSpells = response.data.spells || []
this.availableSources = response.data.sources || [] this.availableSources = response.data.sources || []
this.availableLearnCategories = response.data.learnCategories || []
// Also update mdata for compatibility // Also update mdata for compatibility
if (response.data.categories) { if (response.data.categories) {
this.mdata.spellcategories = response.data.categories this.mdata.spellcategories = response.data.categories
@@ -725,6 +747,7 @@ export default {
this.newItem = { this.newItem = {
name: '', name: '',
category: this.mdata.spellcategories?.[0] || '', category: this.mdata.spellcategories?.[0] || '',
learning_category: '',
level: 0, level: 0,
ap: '', ap: '',
zauberdauer: '', zauberdauer: '',
+1
View File
@@ -177,6 +177,7 @@ export default {
spell:{ spell:{
id:'ID', id:'ID',
category:'Kategorie', category:'Kategorie',
learning_category:'Lernkategorie',
name:'Name', name:'Name',
description:'Beschreibung', description:'Beschreibung',
level:'Stufe', level:'Stufe',
+1
View File
@@ -173,6 +173,7 @@ export default {
spell:{ spell:{
id:'ID', id:'ID',
category:'Category', category:'Category',
learning_category:'Learning Category',
name:'Name', name:'Name',
description:'Description', description:'Description',
level:'Level', level:'Level',