+Mor almanach edit, finished

This commit is contained in:
Simon Martens
2026-01-09 13:04:18 +01:00
parent 69d8ec71b3
commit 5b75456439
7 changed files with 1691 additions and 1184 deletions

View File

@@ -45,6 +45,7 @@ func (p *AlmanachEditPage) Setup(router *router.Router[*core.RequestEvent], app
rg.BindFunc(middleware.IsAdminOrEditor())
rg.GET(URL_ALMANACH_EDIT, p.GET(engine, app))
rg.POST(URL_ALMANACH_EDIT+"save", p.POSTSave(engine, app))
rg.POST(URL_ALMANACH_EDIT+"delete", p.POSTDelete(engine, app))
return nil
}
@@ -201,6 +202,74 @@ func (p *AlmanachEditPage) POSTSave(engine *templating.Engine, app core.App) Han
}
}
func (p *AlmanachEditPage) POSTDelete(engine *templating.Engine, app core.App) HandleFunc {
return func(e *core.RequestEvent) error {
id := e.Request.PathValue("id")
req := templating.NewRequest(e)
payload := almanachDeletePayload{}
if err := e.BindBody(&payload); err != nil {
return e.JSON(http.StatusBadRequest, map[string]any{
"error": "Ungültige Formulardaten.",
})
}
if err := req.CheckCSRF(payload.CSRFToken); err != nil {
return e.JSON(http.StatusBadRequest, map[string]any{
"error": err.Error(),
})
}
entry, err := dbmodels.Entries_MusenalmID(app, id)
if err != nil {
return e.JSON(http.StatusNotFound, map[string]any{
"error": "Band wurde nicht gefunden.",
})
}
if payload.LastEdited != "" {
lastEdited, err := types.ParseDateTime(payload.LastEdited)
if err != nil {
return e.JSON(http.StatusBadRequest, map[string]any{
"error": "Ungültiger Bearbeitungszeitstempel.",
})
}
if !entry.Updated().Time().Equal(lastEdited.Time()) {
return e.JSON(http.StatusConflict, map[string]any{
"error": "Der Eintrag wurde inzwischen geändert. Bitte Seite neu laden.",
})
}
}
if err := app.RunInTransaction(func(tx core.App) error {
if err := deleteEntryRelations(tx, entry.Id); err != nil {
return err
}
if err := deleteEntryItems(tx, entry.Id); err != nil {
return err
}
if err := deleteEntryContents(tx, entry.Id); err != nil {
return err
}
record, err := tx.FindRecordById(dbmodels.ENTRIES_TABLE, entry.Id)
if err != nil {
return err
}
return tx.Delete(record)
}); err != nil {
app.Logger().Error("Failed to delete almanach entry", "entry_id", entry.Id, "error", err)
return e.JSON(http.StatusInternalServerError, map[string]any{
"error": "Löschen fehlgeschlagen.",
})
}
return e.JSON(http.StatusOK, map[string]any{
"success": true,
"redirect": "/suche/baende",
})
}
}
type almanachEditPayload struct {
CSRFToken string `json:"csrf_token"`
LastEdited string `json:"last_edited"`
@@ -217,6 +286,11 @@ type almanachEditPayload struct {
DeletedAgentRelationIDs []string `json:"deleted_agent_relation_ids"`
}
type almanachDeletePayload struct {
CSRFToken string `json:"csrf_token"`
LastEdited string `json:"last_edited"`
}
type almanachEntryPayload struct {
PreferredTitle string `json:"preferred_title"`
Title string `json:"title"`
@@ -292,24 +366,23 @@ func (payload *almanachEditPayload) Validate() error {
}
}
hasPreferred := false
preferredCount := 0
for _, relation := range payload.SeriesRelations {
if strings.TrimSpace(relation.Type) == preferredSeriesRelationType {
hasPreferred = true
break
preferredCount++
}
}
if !hasPreferred {
for _, relation := range payload.NewSeriesRelations {
if strings.TrimSpace(relation.Type) == preferredSeriesRelationType {
hasPreferred = true
break
}
for _, relation := range payload.NewSeriesRelations {
if strings.TrimSpace(relation.Type) == preferredSeriesRelationType {
preferredCount++
}
}
if !hasPreferred {
if preferredCount == 0 {
return fmt.Errorf("Mindestens ein bevorzugter Reihentitel muss verknüpft sein.")
}
if preferredCount > 1 {
return fmt.Errorf("Es darf nur ein bevorzugter Reihentitel gesetzt sein.")
}
// Check for duplicate series relations
seriesTargetIDs := make(map[string]bool)
@@ -604,3 +677,85 @@ func applyAgentRelations(tx core.App, entry *dbmodels.Entry, payload *almanachEd
return nil
}
func deleteEntryRelations(tx core.App, entryID string) error {
seriesRelations, err := dbmodels.REntriesSeries_Entry(tx, entryID)
if err != nil {
return err
}
seriesTable := dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.SERIES_TABLE)
for _, relation := range seriesRelations {
record, err := tx.FindRecordById(seriesTable, relation.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
agentRelations, err := dbmodels.REntriesAgents_Entry(tx, entryID)
if err != nil {
return err
}
agentTable := dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.AGENTS_TABLE)
for _, relation := range agentRelations {
record, err := tx.FindRecordById(agentTable, relation.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
return nil
}
func deleteEntryItems(tx core.App, entryID string) error {
items, err := dbmodels.Items_Entry(tx, entryID)
if err != nil {
return err
}
for _, item := range items {
record, err := tx.FindRecordById(dbmodels.ITEMS_TABLE, item.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
return nil
}
func deleteEntryContents(tx core.App, entryID string) error {
contents, err := dbmodels.Contents_Entry(tx, entryID)
if err != nil {
return err
}
relationsTable := dbmodels.RelationTableName(dbmodels.CONTENTS_TABLE, dbmodels.AGENTS_TABLE)
for _, content := range contents {
contentRelations, err := dbmodels.RContentsAgents_Content(tx, content.Id)
if err != nil {
return err
}
for _, relation := range contentRelations {
record, err := tx.FindRecordById(relationsTable, relation.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
record, err := tx.FindRecordById(dbmodels.CONTENTS_TABLE, content.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
return nil
}