+person delete endpond, BUGFIX: some visual inconistencies

This commit is contained in:
Simon Martens
2026-01-11 09:27:57 +01:00
parent 4c2fcb991f
commit 5ac7042c8d
10 changed files with 241 additions and 86 deletions

View File

@@ -330,7 +330,7 @@ func (p *AlmanachEditPage) POSTDelete(engine *templating.Engine, app core.App) H
return e.JSON(http.StatusOK, map[string]any{
"success": true,
"redirect": "/suche/baende",
"redirect": "/reihen",
})
}
}

View File

@@ -43,6 +43,7 @@ func (p *PersonEditPage) Setup(router *router.Router[*core.RequestEvent], app co
rg.BindFunc(middleware.IsAdminOrEditor())
rg.GET(URL_PERSON_EDIT, p.GET(engine, app))
rg.POST(URL_PERSON_EDIT, p.POST(engine, app))
rg.POST(URL_PERSON_EDIT+"/delete", p.POSTDelete(engine, app))
return nil
}
@@ -247,6 +248,11 @@ type personEditForm struct {
Comment string `form:"edit_comment"`
}
type personDeletePayload struct {
CSRFToken string `json:"csrf_token"`
LastEdited string `json:"last_edited"`
}
func applyPersonForm(agent *dbmodels.Agent, formdata personEditForm, name string, status string, user *dbmodels.FixedUser) {
agent.SetName(name)
agent.SetPseudonyms(strings.TrimSpace(formdata.Pseudonyms))
@@ -341,3 +347,108 @@ func (p *PersonEditPage) POST(engine *templating.Engine, app core.App) HandleFun
return e.Redirect(http.StatusSeeOther, redirect)
}
}
func (p *PersonEditPage) POSTDelete(engine *templating.Engine, app core.App) HandleFunc {
return func(e *core.RequestEvent) error {
id := e.Request.PathValue("id")
req := templating.NewRequest(e)
payload := personDeletePayload{}
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(),
})
}
agent, err := dbmodels.Agents_ID(app, id)
if err != nil {
return e.JSON(http.StatusNotFound, map[string]any{
"error": "Person 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 !agent.Updated().Time().Equal(lastEdited.Time()) {
return e.JSON(http.StatusConflict, map[string]any{
"error": "Die Person wurde inzwischen geändert. Bitte Seite neu laden.",
})
}
}
if err := app.RunInTransaction(func(tx core.App) error {
if err := deleteAgentRelations(tx, agent.Id); err != nil {
return err
}
record, err := tx.FindRecordById(dbmodels.AGENTS_TABLE, agent.Id)
if err != nil {
return err
}
return tx.Delete(record)
}); err != nil {
app.Logger().Error("Failed to delete agent", "agent_id", agent.Id, "error", err)
return e.JSON(http.StatusInternalServerError, map[string]any{
"error": "Löschen fehlgeschlagen.",
})
}
// Delete from FTS5 index asynchronously
go func(appInstance core.App, agentID string) {
if err := dbmodels.DeleteFTS5Agent(appInstance, agentID); err != nil {
appInstance.Logger().Error("Failed to delete FTS5 agent", "agent_id", agentID, "error", err)
}
}(app, agent.Id)
return e.JSON(http.StatusOK, map[string]any{
"success": true,
"redirect": "/personen/",
})
}
}
func deleteAgentRelations(tx core.App, agentID string) error {
// Delete all REntriesAgents relations
entryRelations, err := dbmodels.REntriesAgents_Agent(tx, agentID)
if err != nil {
return err
}
entryTable := dbmodels.RelationTableName(dbmodels.ENTRIES_TABLE, dbmodels.AGENTS_TABLE)
for _, relation := range entryRelations {
record, err := tx.FindRecordById(entryTable, relation.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
// Delete all RContentsAgents relations
contentRelations, err := dbmodels.RContentsAgents_Agent(tx, agentID)
if err != nil {
return err
}
contentTable := dbmodels.RelationTableName(dbmodels.CONTENTS_TABLE, dbmodels.AGENTS_TABLE)
for _, relation := range contentRelations {
record, err := tx.FindRecordById(contentTable, relation.Id)
if err != nil {
continue
}
if err := tx.Delete(record); err != nil {
return err
}
}
return nil
}

View File

@@ -1,11 +1,22 @@
TODO danach:
- Input:
- MO Input:
- Titelauflage von/ hat TA
- Zeilenumbrüche in Reihen-Annotationen (EVTL. fix in TinyMCE)
- Status: Auopsiert, Erfasst etc.
- Status farbig
- Lösch-Links in Liste, Übersicht u.s.w. (? CSRF-Token fehlt)
- Löschen von Personen: werden relationen zu Inhalten mitgelöscht? optional inhalte löschen?
- Display von Status u. Bearbeitungsvermerk in Almanach-Ansicht für eingeloggte Nutzer
- ACHTUNG! FTS5-Tabellen müssen beim Speichern (und löschen) synchronisiert werden!
- Hilfe-Texte für Felder
- SO Status farbig
- SO Löschen von Personen: werden relationen zu Inhalten mitgelöscht? optional inhalte löschen?
- SO Display von Status u. Bearbeitungsvermerk in Almanach-Ansicht für eingeloggte Nutzer
- SO Hilfe-Texte für Felder
- MO Lösch-Links in Liste, Übersicht u.s.w. (? CSRF-Token fehlt)
Features:
- SO, DI Double detection für Ortsnamen, Personennamen, Reihentitel, Kurztitel
- NÄCHSTE WOCHE Datenbank-Hygiene
- DI Extra-DB für FTS5: ist eigentlich nichtTeil der Haupt-DB, sondern nur Suchindex
- Suchindex beim Start erstellen, anstatt dauerhaft zu speichern
BUGS:
- DI: Schriftgröße edit-Screen
- MO: doppelte Einträge Reihen-Liste
- S. Abendstunden

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@
</div>
<div class="container-normal mt-12 flex flex-col font-serif">
<div class="font-sans"><i class="ri-article-line"></i> Einzelbeitrag</div>
<div class="font-sans mb-1"><i class="ri-article-line"></i> Einzelbeitrag</div>
<h1 class="text-3xl font-bold">
{{ $model.result.Entry.PreferredTitle }},
{{ if $model.result.Content.Extent -}}
@@ -45,13 +45,13 @@
{{ $model.result.Content.MusenalmID }}
{{- end -}}
</h1>
<span class="">
<span class="mt-1">
{{- $arr := $model.result.Content.MusenalmType -}}
{{- if $arr -}}
{{- range $i, $p := $arr -}}
<span
class="inline-block align-middle bg-slate-200 px-2 font-sans text-sm py-0.5
rounded mx-1 mt-1.5 hover:text-slate-900 no-underline">
rounded not-first:ml-1 mr-1 mt-1.5 hover:text-slate-900 no-underline">
{{- $p -}}
</span>
{{- end -}}

View File

@@ -173,42 +173,43 @@
</button>
</div>
</div>
</form>
</div>
{{- if not $model.is_new -}}
<dialog data-role="edit-delete-dialog" class="fixed inset-0 m-auto rounded-md border border-slate-200 p-0 shadow-xl backdrop:bg-black/40">
<div class="p-5 w-[26rem]">
<div class="text-base font-bold text-gray-900">Ort löschen?</div>
<div class="text-sm font-bold text-gray-900 mt-1">{{ $place.Name }}</div>
<p class="text-sm text-gray-700 mt-2">
Der Ort wird gelöscht und aus allen verknüpften Bänden entfernt.
</p>
<div class="mt-3">
<div class="text-sm font-semibold text-gray-700">Betroffene Bände</div>
<div class="mt-2 max-h-40 overflow-auto pr-1">
{{- if $model.result.Entries -}}
<ul class="flex flex-col gap-2 pl-0 pr-0 m-0 list-none">
{{- range $entry := $model.result.Entries -}}
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0 text-sm text-gray-700">
<span>{{ $entry.PreferredTitle }}</span>
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
</li>
{{- end -}}
</ul>
{{- else -}}
<div class="italic text-gray-500">Keine Bände betroffen.</div>
{{- end -}}
{{- if not $model.is_new -}}
<dialog data-role="edit-delete-dialog" class="fixed inset-0 m-auto rounded-md border border-slate-200 p-0 shadow-xl backdrop:bg-black/40">
<div class="p-5 w-[22rem]">
<div class="text-base font-bold text-gray-900">Ort löschen?</div>
<div class="text-sm font-bold text-gray-900 mt-1">{{ $place.Name }}</div>
<p class="text-sm text-gray-700 mt-2">
Der Ort wird gelöscht und aus allen verknüpften Bänden entfernt.
</p>
<div class="mt-3">
<div class="text-sm font-semibold text-gray-700">Betroffene Bände</div>
<div class="mt-2 max-h-40 overflow-auto pr-1">
{{- if $model.result.Entries -}}
<ul class="flex flex-col gap-2 pl-0 pr-0 m-0 list-none">
{{- range $entry := $model.result.Entries -}}
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0 text-sm text-gray-700">
<span>{{ $entry.PreferredTitle }}</span>
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
</li>
{{- end -}}
</ul>
{{- else -}}
<div class="italic text-gray-500">Keine Bände betroffen.</div>
{{- end -}}
</div>
</div>
<div class="flex items-center justify-end gap-3 mt-4">
<button type="button" class="resetbutton w-auto px-3 py-1 text-sm" data-role="edit-delete-cancel">Abbrechen</button>
<button
type="button"
class="submitbutton w-auto bg-red-700 hover:bg-red-800 px-3 py-1 text-sm"
data-role="edit-delete-confirm">
Löschen
</button>
</div>
</div>
<div class="flex items-center justify-end gap-3 mt-4">
<button type="button" class="resetbutton w-auto px-3 py-1 text-sm" data-role="edit-delete-cancel">Abbrechen</button>
<button type="button" class="submitbutton w-auto bg-red-700 hover:bg-red-800 px-3 py-1
text-sm text-slate-50" data-role="edit-delete-confirm">
Löschen
</button>
</div>
</div>
</dialog>
{{- end -}}
</dialog>
{{- end -}}
</form>
</div>
</edit-page>

View File

@@ -30,7 +30,7 @@
</div>
<div class="container-normal font-serif mt-12">
<div class="flex inline-flex flex-inline gap-x-3">
<div class="flex inline-flex flex-inline gap-x-3 mb-1">
{{ if $model.result.Agent.CorporateBody }}
<div class="font-sans">
<i class="ri-team-line"></i>

View File

@@ -104,7 +104,10 @@
class="w-full dbform"
id="changepersonform"
method="POST"
action="{{ if $model.is_new }}/personen/new/{{ else }}/person/{{ $agent.Id }}/edit{{ end }}">
action="{{ if $model.is_new }}/personen/new/{{ else }}/person/{{ $agent.Id }}/edit{{ end }}"
{{- if not $model.is_new -}}
data-delete-endpoint="/person/{{ $agent.Id }}/edit/delete"
{{- end -}}>
<input type="hidden" name="csrf_token" value="{{ $model.csrf_token }}" />
<input type="hidden" name="last_edited" value="{{ if not $model.is_new }}{{ $agent.Updated }}{{ end }}" />
@@ -186,6 +189,13 @@
<i class="ri-loop-left-line"></i>
<span>Reset</span>
</a>
<button
type="button"
class="resetbutton w-40 flex items-center gap-2 justify-center bg-red-50 text-red-800 hover:bg-red-100 hover:text-red-900"
data-role="edit-delete">
<i class="ri-delete-bin-line"></i>
<span>Person löschen</span>
</button>
{{- end -}}
<button type="submit" class="submitbutton w-40 flex items-center gap-2 justify-center">
<i class="ri-save-line"></i>
@@ -193,6 +203,26 @@
</button>
</div>
</div>
{{- if not $model.is_new -}}
<dialog data-role="edit-delete-dialog" class="fixed inset-0 m-auto rounded-md border border-slate-200 p-0 shadow-xl backdrop:bg-black/40">
<div class="p-5 w-[22rem]">
<div class="text-base font-bold text-gray-900">Person löschen?</div>
<div class="text-sm font-bold text-gray-900 mt-1">{{ $agent.Name }}</div>
<p class="text-sm text-gray-700 mt-2">
Die Person wird dauerhaft gelöscht. Verknüpfungen zu Bänden und Beiträgen werden entfernt.
</p>
<div class="flex items-center justify-end gap-3 mt-4">
<button type="button" class="resetbutton w-auto px-3 py-1 text-sm" data-role="edit-delete-cancel">Abbrechen</button>
<button
type="button"
class="submitbutton w-auto bg-red-700 hover:bg-red-800 px-3 py-1 text-sm"
data-role="edit-delete-confirm">
Löschen
</button>
</div>
</div>
</dialog>
{{- end -}}
</form>
</div>
</edit-page>

View File

@@ -17,7 +17,7 @@
</div>
<div class="container-normal flex flex-col font-serif mt-12">
<div class="flex inline-flex flex-inline gap-x-3">
<div class="flex inline-flex flex-inline gap-x-3 mb-1">
<div class="font-sans">
{{/* <svg
class="w-[0.9rem] h-[0.9rem] relative bottom-[0.04rem] inline-block"

View File

@@ -174,41 +174,43 @@
</button>
</div>
</div>
</form>
</div>
{{- if not $model.is_new -}}
<dialog data-role="edit-delete-dialog" class="fixed inset-0 m-auto rounded-md border border-slate-200 p-0 shadow-xl backdrop:bg-black/40">
<div class="p-5 w-[26rem]">
<div class="text-base font-bold text-gray-900">Reihe löschen?</div>
<div class="text-sm font-bold text-gray-900 mt-1">{{ $series.Title }}</div>
<p class="text-sm text-gray-700 mt-2">
Alle Bände, Inhalte und Verknüpfungen der bevorzugten Reihentitel werden gelöscht.
</p>
<div class="mt-3">
<div class="text-sm font-semibold text-gray-700">Betroffene Bände</div>
<div class="mt-2 max-h-40 overflow-auto pr-1">
{{- if $model.result.PreferredEntries -}}
<ul class="flex flex-col gap-2 pl-0 pr-0 m-0 list-none">
{{- range $entry := $model.result.PreferredEntries -}}
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0 text-sm text-gray-700">
<span>{{ $entry.PreferredTitle }}</span>
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
</li>
{{- end -}}
</ul>
{{- else -}}
<div class="italic text-gray-500">Keine Bände betroffen.</div>
{{- end -}}
{{- if not $model.is_new -}}
<dialog data-role="edit-delete-dialog" class="fixed inset-0 m-auto rounded-md border border-slate-200 p-0 shadow-xl backdrop:bg-black/40">
<div class="p-5 w-[22rem]">
<div class="text-base font-bold text-gray-900">Reihe löschen?</div>
<div class="text-sm font-bold text-gray-900 mt-1">{{ $series.Title }}</div>
<p class="text-sm text-gray-700 mt-2">
Alle Bände, Inhalte und Verknüpfungen der bevorzugten Reihentitel werden gelöscht.
</p>
<div class="mt-3">
<div class="text-sm font-semibold text-gray-700">Betroffene Bände</div>
<div class="mt-2 max-h-40 overflow-auto pr-1">
{{- if $model.result.PreferredEntries -}}
<ul class="flex flex-col gap-2 pl-0 pr-0 m-0 list-none">
{{- range $entry := $model.result.PreferredEntries -}}
<li class="flex items-baseline justify-between gap-3 ml-0 pl-0 text-sm text-gray-700">
<span>{{ $entry.PreferredTitle }}</span>
<span class="text-xs text-gray-500">{{ $entry.Year }}</span>
</li>
{{- end -}}
</ul>
{{- else -}}
<div class="italic text-gray-500">Keine Bände betroffen.</div>
{{- end -}}
</div>
</div>
<div class="flex items-center justify-end gap-3 mt-4">
<button type="button" class="resetbutton w-auto px-3 py-1 text-sm" data-role="edit-delete-cancel">Abbrechen</button>
<button
type="button"
class="submitbutton w-auto bg-red-700 hover:bg-red-800 px-3 py-1 text-sm"
data-role="edit-delete-confirm">
Löschen
</button>
</div>
</div>
<div class="flex items-center justify-end gap-3 mt-4">
<button type="button" class="resetbutton w-auto px-3 py-1 text-sm" data-role="edit-delete-cancel">Abbrechen</button>
<button type="button" class="submitbutton w-auto bg-red-700 hover:bg-red-800 px-3
py-1 text-sm text-white" data-role="edit-delete-confirm">
Löschen
</button>
</div>
</div>
</dialog>
{{- end -}}
</dialog>
{{- end -}}
</form>
</div>
</edit-page>