From 94883b5edc39d058bf9d6340b782f9d0dfb521c6 Mon Sep 17 00:00:00 2001 From: Simon Martens Date: Sun, 21 Sep 2025 15:50:46 +0200 Subject: [PATCH] =?UTF-8?q?Guge=20problem:=20no=20IDs=20for=20the=20Beitr?= =?UTF-8?q?=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templating/engine.go | 20 +- .../components/_inhaltsverzeichnis.gohtml | 4 +- .../components/_akteur_beitraege.gohtml | 10 + views/routes/components/_akteur_werke.gohtml | 202 ++++++++++++++++-- views/routes/components/_piece_summary.gohtml | 74 ++++--- views/routes/piece/body.gohtml | 5 +- xmlmodels/pieces.go | 89 ++++++-- 7 files changed, 328 insertions(+), 76 deletions(-) diff --git a/templating/engine.go b/templating/engine.go index d8f2cec..0b95297 100644 --- a/templating/engine.go +++ b/templating/engine.go @@ -69,10 +69,15 @@ func PageIcon(iconType string) template.HTML { } } -// GetPieceURL generates a piece view URL from year, issue number, and page -func GetPieceURL(year, issueNum, page int) string { - pieceID := fmt.Sprintf("%d-%03d-%03d", year, issueNum, page) - return "/beitrag/" + pieceID +// GetPieceURL generates a piece view URL from year, issue number, page, and optional piece ID +func GetPieceURL(year, issueNum, page int, pieceID ...string) string { + if len(pieceID) > 0 && pieceID[0] != "" && pieceID[0] != "0" { + // Use just the piece ID (no year/issue prefix in URL) + return "/beitrag/" + pieceID[0] + } + // Fallback to old format for backward compatibility + id := fmt.Sprintf("%d-%03d-%03d", year, issueNum, page) + return "/beitrag/" + id } // IssueContext formats an issue reference into a readable context string @@ -296,6 +301,13 @@ func (e *Engine) funcs() error { return result }) + e.AddFunc("split", func(s, delimiter string) []string { + if s == "" { + return []string{} + } + return strings.Split(s, delimiter) + }) + e.AddFunc("sortStrings", func(items interface{}) []string { v := reflect.ValueOf(items) if v.Kind() != reflect.Slice { diff --git a/views/routes/ausgabe/components/_inhaltsverzeichnis.gohtml b/views/routes/ausgabe/components/_inhaltsverzeichnis.gohtml index 5ec0bbf..6b4de6e 100644 --- a/views/routes/ausgabe/components/_inhaltsverzeichnis.gohtml +++ b/views/routes/ausgabe/components/_inhaltsverzeichnis.gohtml @@ -96,7 +96,7 @@ duration-200"> Ganzer Beitrag @@ -231,7 +231,7 @@ duration-200"> Ganzer Beitrag diff --git a/views/routes/components/_akteur_beitraege.gohtml b/views/routes/components/_akteur_beitraege.gohtml index c005bed..32942b8 100644 --- a/views/routes/components/_akteur_beitraege.gohtml +++ b/views/routes/components/_akteur_beitraege.gohtml @@ -66,6 +66,16 @@ {{- end -}} {{- end -}} + {{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}} + {{- $firstGroupItem := index $groupedItems 0 -}} + {{- if gt (len $firstGroupItem.Item.IssueRefs) 1 -}} + {{ " " }}
+ + + Ganzer Beitrag + +
+ {{- end -}} {{- end -}} diff --git a/views/routes/components/_akteur_werke.gohtml b/views/routes/components/_akteur_werke.gohtml index ac3d499..b431dbe 100644 --- a/views/routes/components/_akteur_werke.gohtml +++ b/views/routes/components/_akteur_werke.gohtml @@ -1,6 +1,17 @@ {{ $a := . }} {{ $works := LookupWorks $a }} -{{- if ne (len $works) 0 -}} +{{ $allPieces := LookupPieces $a }} + +{{- /* Filter pieces for work-related categories */ -}} +{{- $workPieces := slice -}} +{{- range $_, $p := $allPieces -}} + {{- $categoryFlags := GetCategoryFlags $p.Item -}} + {{- if or $categoryFlags.Rezension $categoryFlags.Auszug $categoryFlags.Theaterkritik $categoryFlags.Uebersetzung $categoryFlags.Kommentar $categoryFlags.Replik $categoryFlags.Anzeige $categoryFlags.Provinienz -}} + {{- $workPieces = append $workPieces $p -}} + {{- end -}} +{{- end -}} + +{{- if or (ne (len $works) 0) (ne (len $workPieces) 0) -}}

@@ -117,39 +128,48 @@ {{- if eq (len $categories) 0 -}} {{- $categories = append $categories "Beitrag" -}} {{- end -}} - {{- $categoryName := "" -}} - {{- if eq (len $categories) 0 -}} - {{- $categoryName = "Beitrag" -}} - {{- else -}} - {{- $sortedCategories := sortStrings $categories -}} - {{- $categoryName = joinWithUnd $sortedCategories -}} - {{- end -}} - {{- $existing := index $groupedByCategory $categoryName -}} + {{- /* Get additional authors for this specific piece */ -}} + {{- $pieceAdditionalAuthorIDs := slice -}} + {{- range $agentref := $p.Item.AgentRefs -}} + {{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}} + {{- $pieceAdditionalAuthorIDs = append $pieceAdditionalAuthorIDs $agentref.Ref -}} + {{- end -}} + {{- end -}} + {{- $sortedAdditionalAuthorIDs := sortStrings $pieceAdditionalAuthorIDs -}} + + {{- /* Create grouping key with category + additional authors */ -}} + {{- $sortedCategories := sortStrings $categories -}} + {{- $categoryName := joinWithUnd $sortedCategories -}} + {{- $groupKey := printf "%s|%s" $categoryName (joinWithUnd $sortedAdditionalAuthorIDs) -}} + + {{- $existing := index $groupedByCategory $groupKey -}} {{- if $existing -}} - {{- $groupedByCategory = merge $groupedByCategory (dict $categoryName (append $existing $p)) -}} + {{- $groupedByCategory = merge $groupedByCategory (dict $groupKey (append $existing $p)) -}} {{- else -}} - {{- $groupedByCategory = merge $groupedByCategory (dict $categoryName (slice $p)) -}} + {{- $groupedByCategory = merge $groupedByCategory (dict $groupKey (slice $p)) -}} {{- end -}} {{- end -}} {{- /* Display each category group */ -}} - {{- range $categoryName, $categoryPieces := $groupedByCategory -}} + {{- range $groupKey, $categoryPieces := $groupedByCategory -}}
+ {{- /* Extract category and additional authors from group key */ -}} + {{- $keyParts := split $groupKey "|" -}} + {{- $categoryName := index $keyParts 0 -}} + {{ $categoryName }} - {{- /* Check for additional authors (non-current actor) */ -}} + {{- /* Get additional authors from first piece in group */ -}} + {{- $firstPiece := index $categoryPieces 0 -}} {{- $additionalAuthorIDs := slice -}} - {{- range $_, $p := $categoryPieces -}} - {{- range $agentref := $p.Item.AgentRefs -}} - {{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}} - {{- $additionalAuthorIDs = append $additionalAuthorIDs $agentref.Ref -}} - {{- end -}} + {{- range $agentref := $firstPiece.Item.AgentRefs -}} + {{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}} + {{- $additionalAuthorIDs = append $additionalAuthorIDs $agentref.Ref -}} {{- end -}} {{- end -}} - {{- $uniqueAuthorIDs := unique $additionalAuthorIDs -}} - {{- if $uniqueAuthorIDs -}} - {{ " " }}von {{ range $i, $authorID := $uniqueAuthorIDs }}{{- if gt $i 0 }} und {{ end }}{{- $agent := GetAgent $authorID -}}{{- if and $agent (gt (len $agent.Names) 0) -}}{{ index $agent.Names 0 }}{{- end -}}{{ end }} + {{- if $additionalAuthorIDs -}} + {{ " " }}von {{ range $i, $authorID := $additionalAuthorIDs }}{{- if gt $i 0 }} und {{ end }}{{- $agent := GetAgent $authorID -}}{{- if and $agent (gt (len $agent.Names) 0) -}}{{ index $agent.Names 0 }}{{- end -}}{{ end }} {{- end -}}{{ ":" }} {{- /* Show all citations for this category inline with commas */ -}} @@ -174,12 +194,152 @@ {{- end -}} {{- end -}} + {{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}} + {{- $firstPiece := index $categoryPieces 0 -}} + {{- if gt (len $firstPiece.Item.IssueRefs) 1 -}} + {{ " " }} + {{- end -}}
{{- end -}}

{{ end }}
{{ end }} + + {{- /* Process standalone work pieces that aren't linked to specific works */ -}} + {{- if ne (len $workPieces) 0 -}} + {{- /* Group standalone work pieces by category and additional authors */ -}} + {{- $standaloneGrouped := dict -}} + {{- range $_, $p := $workPieces -}} + {{- /* Skip pieces that are already covered by works above */ -}} + {{- $isPieceInWorks := false -}} + {{- range $_, $w := $works -}} + {{- $workPiecesCheck := LookupPieces $w.Item -}} + {{- range $_, $wp := $workPiecesCheck -}} + {{- if eq $wp.Item.ID $p.Item.ID -}} + {{- $isPieceInWorks = true -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if not $isPieceInWorks -}} + {{- /* Get categories for this piece */ -}} + {{- $categoryFlags := GetCategoryFlags $p.Item -}} + {{- $categories := slice -}} + {{- if $categoryFlags.Rezension -}} + {{- $categories = append $categories "Rezension" -}} + {{- end -}} + {{- if $categoryFlags.Auszug -}} + {{- $categories = append $categories "Auszug" -}} + {{- end -}} + {{- if $categoryFlags.Theaterkritik -}} + {{- $categories = append $categories "Theaterkritik" -}} + {{- end -}} + {{- if $categoryFlags.Uebersetzung -}} + {{- $categories = append $categories "Übersetzung" -}} + {{- end -}} + {{- if $categoryFlags.Kommentar -}} + {{- $categories = append $categories "Kommentar" -}} + {{- end -}} + {{- if $categoryFlags.Replik -}} + {{- $categories = append $categories "Replik" -}} + {{- end -}} + {{- if $categoryFlags.Anzeige -}} + {{- $categories = append $categories "Anzeige" -}} + {{- end -}} + {{- if $categoryFlags.Provinienz -}} + {{- $categories = append $categories "Provinienz" -}} + {{- end -}} + + {{- if ne (len $categories) 0 -}} + {{- /* Get additional authors for this specific piece */ -}} + {{- $pieceAdditionalAuthorIDs := slice -}} + {{- range $agentref := $p.Item.AgentRefs -}} + {{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}} + {{- $pieceAdditionalAuthorIDs = append $pieceAdditionalAuthorIDs $agentref.Ref -}} + {{- end -}} + {{- end -}} + {{- $sortedAdditionalAuthorIDs := sortStrings $pieceAdditionalAuthorIDs -}} + + {{- /* Create grouping key with category + additional authors */ -}} + {{- $sortedCategories := sortStrings $categories -}} + {{- $categoryName := joinWithUnd $sortedCategories -}} + {{- $groupKey := printf "%s|%s" $categoryName (joinWithUnd $sortedAdditionalAuthorIDs) -}} + + {{- $existing := index $standaloneGrouped $groupKey -}} + {{- if $existing -}} + {{- $standaloneGrouped = merge $standaloneGrouped (dict $groupKey (append $existing $p)) -}} + {{- else -}} + {{- $standaloneGrouped = merge $standaloneGrouped (dict $groupKey (slice $p)) -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- /* Display standalone work pieces */ -}} + {{- range $groupKey, $categoryPieces := $standaloneGrouped -}} +
+
+ + {{- /* Extract category and additional authors from group key */ -}} + {{- $keyParts := split $groupKey "|" -}} + {{- $categoryName := index $keyParts 0 -}} + + {{ $categoryName }} + {{- /* Get additional authors from first piece in group */ -}} + {{- $firstPiece := index $categoryPieces 0 -}} + {{- $additionalAuthorIDs := slice -}} + {{- range $agentref := $firstPiece.Item.AgentRefs -}} + {{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}} + {{- $additionalAuthorIDs = append $additionalAuthorIDs $agentref.Ref -}} + {{- end -}} + {{- end -}} + {{- if $additionalAuthorIDs -}} + {{ " " }}von {{ range $i, $authorID := $additionalAuthorIDs }}{{- if gt $i 0 }} und {{ end }}{{- $agent := GetAgent $authorID -}}{{- if and $agent (gt (len $agent.Names) 0) -}}{{ index $agent.Names 0 }}{{- end -}}{{ end }} + {{- end -}}{{ ":" }} + + {{- /* Show all citations for this category inline with commas */ -}} + {{ " " }}{{- range $pieceIndex, $p := $categoryPieces -}} + {{- range $issueIndex, $issue := $p.Item.IssueRefs -}} + {{- if or (gt $pieceIndex 0) (gt $issueIndex 0) }}, {{ end -}} + {{ $issueData := GetIssue (printf "%d-%d" $issue.When.Year $issue.Nr) }} + {{- $url := printf "/%s/%d" $issue.When $issue.Nr -}} + {{- if $issue.Von -}} + {{- if $issue.Beilage -}} + {{- $url = printf "%s#beilage-%d-page-%d" $url $issue.Beilage $issue.Von -}} + {{- else -}} + {{- $url = printf "%s/%d" $url $issue.Von -}} + {{- end -}} + {{- end -}} + + {{- if $issueData -}} + {{ $issueData.Datum.When.Day }}.{{ $issueData.Datum.When.Month }}.{{ $issueData.Datum.When.Year }}/{{ $issue.Nr }}, S. {{ $issue.Von }}{{- if and $issue.Bis (ne $issue.Von $issue.Bis) }}-{{ $issue.Bis }}{{ end }} + {{- else -}} + {{ $issue.When.Day }}.{{ $issue.When.Month }}.{{ $issue.When.Year }}/{{ $issue.Nr }}, S. {{ $issue.Von }}{{- if and $issue.Bis (ne $issue.Von $issue.Bis) }}-{{ $issue.Bis }}{{ end }} + {{- end -}} + + {{- end -}} + {{- end -}} + {{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}} + {{- $firstPiece := index $categoryPieces 0 -}} + {{- if gt (len $firstPiece.Item.IssueRefs) 1 -}} + {{ " " }} + {{- end -}} +
+
+ {{- end -}} + {{- end -}} + {{ end }} diff --git a/views/routes/components/_piece_summary.gohtml b/views/routes/components/_piece_summary.gohtml index f06fe88..5c7a616 100644 --- a/views/routes/components/_piece_summary.gohtml +++ b/views/routes/components/_piece_summary.gohtml @@ -140,61 +140,65 @@ {{- /* Generate piece descriptions */ -}} {{- if has $categories "Rezension" -}} - {{- $authorFound := false -}} + {{- /* Collect all additional authors (not current actor) */ -}} + {{- $additionalAuthors := slice -}} + {{- $currentAuthorFound := false -}} {{- range $agentref := $piece.AgentRefs -}} {{- if (or (eq $agentref.Category "") (eq $agentref.Category "autor")) -}} {{- $agent := GetAgent $agentref.Ref -}} {{- if and $agent (gt (len $agent.Names) 0) -}} {{- if ne $agentref.Ref $currentActorID -}} - {{ index $agent.Names 0 }}, + {{- $additionalAuthors = append $additionalAuthors $agent -}} + {{- else -}} + {{- $currentAuthorFound = true -}} {{- end -}} - {{ $categoryName }} von: - {{ if $workAuthorName }} - {{ $workAuthorName }}, - {{ end }} - {{ if $workTitle }} - {{ $workTitle }} - {{ else if $title }} - {{ $title }} - {{ else }} - [Werk unbekannt] - {{ end }} - {{- $authorFound = true -}} - {{- break -}} {{- end -}} {{- end -}} {{- end -}} - {{- if not $authorFound -}} - {{ $categoryName }} von: - {{ if $workAuthorName }} - {{ $workAuthorName }}, - {{ end }} - {{ if $workTitle }} - {{ $workTitle }} - {{ else if $title }} - {{ $title }} - {{ else }} - [Werk unbekannt] - {{ end }} - {{- end -}} + + {{- /* Display review with proper author attribution */ -}} + {{- if $additionalAuthors -}} + mit {{ range $i, $author := $additionalAuthors }}{{- if gt $i 0 }} und {{ end }}{{ index $author.Names 0 }}{{ end }}, {{ $categoryName }} von: + {{- else if $currentAuthorFound -}} + {{ $categoryName }} von: + {{- else -}} + {{ $categoryName }} von: + {{- end -}} + {{ if $workAuthorName }} + {{ $workAuthorName }}, + {{ end }} + {{ if $workTitle }} + {{ $workTitle }} + {{ else if $title }} + {{ $title }} + {{ else }} + [Werk unbekannt] + {{ end }} {{- else -}} - {{- $authorFound := false -}} + {{- /* Collect all additional authors (not current actor) */ -}} + {{- $additionalAuthors := slice -}} + {{- $currentAuthorFound := false -}} {{- range $agentref := $piece.AgentRefs -}} {{- if (or (eq $agentref.Category "") (eq $agentref.Category "autor")) -}} {{- $agent := GetAgent $agentref.Ref -}} {{- if and $agent (gt (len $agent.Names) 0) -}} {{- if ne $agentref.Ref $currentActorID -}} - {{ index $agent.Names 0 }}, + {{- $additionalAuthors = append $additionalAuthors $agent -}} + {{- else -}} + {{- $currentAuthorFound = true -}} {{- end -}} - {{ $categoryName }}{{ if $title }}: „{{ $title }}"{{ end }} - {{- $authorFound = true -}} - {{- break -}} {{- end -}} {{- end -}} {{- end -}} - {{- if not $authorFound -}} - {{ $categoryName }}{{ if $title }}: „{{ $title }}"{{ else if eq $categoryName "Beitrag" }} ohne Titel{{ end }} + + {{- /* Display with proper author attribution */ -}} + {{- if $additionalAuthors -}} + mit {{ range $i, $author := $additionalAuthors }}{{- if gt $i 0 }} und {{ end }}{{ index $author.Names 0 }}{{ end }}, {{ $categoryName }}{{ if $title }}: {{ $title }}{{ end }} + {{- else if $currentAuthorFound -}} + {{ $categoryName }}{{ if $title }}: {{ $title }}{{ end }} + {{- else -}} + {{ $categoryName }}{{ if $title }}: {{ $title }}{{ else if eq $categoryName "Beitrag" }} ohne Titel{{ end }} {{- end -}} {{- end -}} diff --git a/views/routes/piece/body.gohtml b/views/routes/piece/body.gohtml index 1b383ed..ca7f0d8 100644 --- a/views/routes/piece/body.gohtml +++ b/views/routes/piece/body.gohtml @@ -19,13 +19,14 @@ {{ else }} - +

Keine Bilder verfügbar

-

+

Für diesen Beitrag sind derzeit keine Seitenbilder verfügbar.

+
{{ end }} \ No newline at end of file diff --git a/xmlmodels/pieces.go b/xmlmodels/pieces.go index cd2c96c..256b9e3 100644 --- a/xmlmodels/pieces.go +++ b/xmlmodels/pieces.go @@ -1,13 +1,16 @@ package xmlmodels import ( + "crypto/sha256" + "encoding/hex" "encoding/json" "encoding/xml" + "fmt" + "sort" "strconv" "strings" "github.com/Theodor-Springmann-Stiftung/kgpz_web/providers/xmlprovider" - "github.com/google/uuid" ) const ( @@ -34,6 +37,69 @@ func (p Piece) String() string { return string(data) } +// generateContentBasedID creates a deterministic ID based on piece content +func (p Piece) generateContentBasedID() string { + var parts []string + + // Add title if available + if len(p.Title) > 0 && p.Title[0] != "" { + parts = append(parts, "title:"+strings.ToLower(strings.TrimSpace(p.Title[0]))) + } + + // Add incipit if available + if len(p.Incipit) > 0 && p.Incipit[0] != "" { + incipit := strings.ToLower(strings.TrimSpace(p.Incipit[0])) + // Limit incipit to first 50 characters to avoid overly long IDs + if len(incipit) > 50 { + incipit = incipit[:50] + } + parts = append(parts, "incipit:"+incipit) + } + + // Add author references + var authors []string + for _, agent := range p.AgentRefs { + if agent.Category == "" || agent.Category == "autor" { + authors = append(authors, agent.Ref) + } + } + sort.Strings(authors) // Ensure consistent ordering + if len(authors) > 0 { + parts = append(parts, "authors:"+strings.Join(authors, ",")) + } + + // Add categories + var categories []string + for _, cat := range p.CategoryRefs { + if cat.Category != "" { + categories = append(categories, cat.Category) + } + } + sort.Strings(categories) // Ensure consistent ordering + if len(categories) > 0 { + parts = append(parts, "categories:"+strings.Join(categories, ",")) + } + + // If we have no meaningful content, create a minimal hash from issue refs + if len(parts) == 0 { + // Use issue references as fallback content + for _, issue := range p.IssueRefs { + parts = append(parts, fmt.Sprintf("issue:%d-%d-%d-%d", issue.When.Year, issue.Nr, issue.Von, issue.Bis)) + } + // If still no content, use a generic identifier + if len(parts) == 0 { + parts = append(parts, "unknown-piece") + } + } + + // Create hash of combined content + content := strings.Join(parts, "|") + hash := sha256.Sum256([]byte(content)) + + // Return first 12 characters of hex hash for reasonable ID length + return hex.EncodeToString(hash[:])[:12] +} + func (p Piece) Categories() map[string]bool { cats := make(map[string]bool) for _, c := range p.CategoryRefs { @@ -70,24 +136,23 @@ func (p Piece) Categories() map[string]bool { } func (p Piece) Keys() []string { - if len(p.keys) > 0 { - return p.keys - } - + // Always regenerate keys to ensure we use the new content-based logic ret := make([]string, 0, 3) + + // Primary ID: Use existing ID if available, otherwise content-based ID + var primaryID string if p.ID != "" { - ret = append(ret, p.ID) + primaryID = p.ID + } else { + primaryID = p.generateContentBasedID() } + ret = append(ret, primaryID) - // TODO: sensible IDs - uid := uuid.New() - ret = append(ret, uid.String()) - + // Create issue-specific keys using the primary ID for lookup for _, i := range p.IssueRefs { - ret = append(ret, strconv.Itoa(i.When.Year)+"-"+strconv.Itoa(i.Nr)+"-"+uid.String()) + ret = append(ret, strconv.Itoa(i.When.Year)+"-"+strconv.Itoa(i.Nr)+"-"+primaryID) } - p.keys = ret return ret }