diff --git a/dbmodels/series.go b/dbmodels/series.go index 0420bdb..4524a59 100644 --- a/dbmodels/series.go +++ b/dbmodels/series.go @@ -1,6 +1,12 @@ package dbmodels -import "github.com/pocketbase/pocketbase/core" +import ( + "slices" + + "github.com/pocketbase/pocketbase/core" + "golang.org/x/text/collate" + "golang.org/x/text/language" +) var _ core.RecordProxy = (*Series)(nil) @@ -81,3 +87,10 @@ func (s *Series) Frequency() string { func (s *Series) SetFrequency(frequency string) { s.Set(SERIES_FREQUENCY_FIELD, frequency) } + +func SortSeriesByTitle(series []*Series) { + collator := collate.New(language.German) + slices.SortFunc(series, func(i, j *Series) int { + return collator.CompareString(i.Title(), j.Title()) + }) +} diff --git a/musenalm.go b/musenalm.go index a5b6d89..dc1dcef 100644 --- a/musenalm.go +++ b/musenalm.go @@ -9,6 +9,7 @@ import ( _ "github.com/Theodor-Springmann-Stiftung/musenalm/migrations" _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages" _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_index" + _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_reihen" "github.com/pocketbase/pocketbase/plugins/migratecmd" ) diff --git a/pagemodels/common.go b/pagemodels/common.go index ffd74c9..5e1b6d5 100644 --- a/pagemodels/common.go +++ b/pagemodels/common.go @@ -2,6 +2,10 @@ package pagemodels const PAGE_DB_PREFIX = "page_" -func GeneratePageTableName(pagename, tablename string) string { - return PAGE_DB_PREFIX + pagename + "_" + tablename +func GeneratePageTableName(pagename string, tablename ...string) string { + name := PAGE_DB_PREFIX + pagename + for _, t := range tablename { + name += "_" + t + } + return name } diff --git a/pagemodels/functions.go b/pagemodels/functions.go new file mode 100644 index 0000000..0eba0e0 --- /dev/null +++ b/pagemodels/functions.go @@ -0,0 +1,65 @@ +package pagemodels + +import ( + "github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels" + "github.com/pocketbase/pocketbase/core" +) + +func BasePageCollection(pagename string) *core.Collection { + c := core.NewBaseCollection(GeneratePageTableName(pagename)) + c.ListRule = dbmodels.PUBLIC_LIST_RULE + c.ViewRule = dbmodels.PUBLIC_VIEW_RULE + c.Fields = StandardPageFields() + return c +} + +func StandardPageFields() core.FieldsList { + ret := core.NewFieldsList( + RequiredTextField(F_TITLE), + EditorField(F_DESCRIPTION), + TextField(F_TAGS), + ) + return ret +} + +func RequiredTextField(name string) *core.TextField { + return &core.TextField{Name: name, Required: true, Presentable: true} +} + +func EditorField(name string) *core.EditorField { + return &core.EditorField{Name: name, Required: false, Presentable: false} +} + +func TextField(name string) *core.TextField { + return &core.TextField{Name: name, Required: false, Presentable: false} +} + +func ImageField(name string, multiselect bool) *core.FileField { + maxSelect := 1 + if multiselect { + maxSelect = 999 + } + return &core.FileField{ + Name: name, + Required: false, + MaxSize: 100 * 1024 * 1024, + MaxSelect: maxSelect, + MimeTypes: dbmodels.MUSENALM_MIME_TYPES, + Thumbs: []string{"0x300", "0x500", "0x1000", "300x0", "500x0", "1000x0"}, + } +} + +func RequiredImageField(name string, multiselect bool) *core.FileField { + maxSelect := 1 + if multiselect { + maxSelect = 999 + } + return &core.FileField{ + Name: name, + Required: true, + MaxSize: 100 * 1024 * 1024, + MaxSelect: maxSelect, + MimeTypes: dbmodels.MUSENALM_MIME_TYPES, + Thumbs: []string{"0x300", "0x500", "0x1000", "300x0", "500x0", "1000x0"}, + } +} diff --git a/pagemodels/index.go b/pagemodels/index.go index ed7f29e..382db57 100644 --- a/pagemodels/index.go +++ b/pagemodels/index.go @@ -5,21 +5,6 @@ import ( "github.com/pocketbase/pocketbase/tools/filesystem" ) -const ( - P_INDEX_NAME = "index" - T_INDEX_BILDER = "bilder" - T_INDEX_TEXTE = "texte" - - F_INDEX_BILDER_TITEL = "Titel" - F_INDEX_BILDER_BESCHREIBUNG = "Beschreibung" - F_INDEX_BILDER_BILD = "Bild" - F_INDEX_BILDER_VORSCHAU = "Vorschau" - - F_INDEX_TEXTE_TITEL = "Titel" - F_INDEX_TEXTE_ABS1 = "Abs1" - F_INDEX_TEXTE_ABS2 = "Abs2" -) - type IndexBilder struct { core.BaseRecordProxy } @@ -35,35 +20,35 @@ func NewIndexBilder(record *core.Record) *IndexBilder { } func (b *IndexBilder) Titel() string { - return b.GetString(F_INDEX_BILDER_TITEL) + return b.GetString(F_TITLE) } func (b *IndexBilder) SetTitel(titel string) { - b.Set(F_INDEX_BILDER_TITEL, titel) + b.Set(F_TITLE, titel) } func (b *IndexBilder) Beschreibung() string { - return b.GetString(F_INDEX_BILDER_BESCHREIBUNG) + return b.GetString(F_DESCRIPTION) } func (b *IndexBilder) SetBeschreibung(beschreibung string) { - b.Set(F_INDEX_BILDER_BESCHREIBUNG, beschreibung) + b.Set(F_DESCRIPTION, beschreibung) } func (b *IndexBilder) Bild() string { - return b.GetString(F_INDEX_BILDER_BILD) + return b.GetString(F_IMAGE) } func (b *IndexBilder) SetBild(bild *filesystem.File) { - b.Set(F_INDEX_BILDER_BILD, bild) + b.Set(F_IMAGE, bild) } func (b *IndexBilder) Vorschau() string { - return b.GetString(F_INDEX_BILDER_VORSCHAU) + return b.GetString(F_PREVIEW) } func (b *IndexBilder) SetVorschau(vorschau *filesystem.File) { - b.Set(F_INDEX_BILDER_VORSCHAU, vorschau) + b.Set(F_PREVIEW, vorschau) } type IndexTexte struct { @@ -71,7 +56,7 @@ type IndexTexte struct { } func (t *IndexTexte) TableName() string { - return GeneratePageTableName(P_INDEX_NAME, T_INDEX_TEXTE) + return GeneratePageTableName(P_INDEX_NAME) } func NewIndexTexte(record *core.Record) *IndexTexte { @@ -81,11 +66,11 @@ func NewIndexTexte(record *core.Record) *IndexTexte { } func (t *IndexTexte) Titel() string { - return t.GetString(F_INDEX_TEXTE_TITEL) + return t.GetString(F_TITLE) } func (t *IndexTexte) SetTitel(titel string) { - t.Set(F_INDEX_TEXTE_TITEL, titel) + t.Set(F_TITLE, titel) } func (t *IndexTexte) Abs1() string { diff --git a/pagemodels/pagedata.go b/pagemodels/pagedata.go new file mode 100644 index 0000000..679729f --- /dev/null +++ b/pagemodels/pagedata.go @@ -0,0 +1,20 @@ +package pagemodels + +const ( + P_INDEX_NAME = "index" + T_INDEX_BILDER = "bilder" + T_INDEX_TEXTE = "texte" + + P_REIHEN_NAME = "reihen" + + F_TITLE = "Titel" + F_DESCRIPTION = "Beschreibung" + F_IMAGE = "Bild" + F_PREVIEW = "Vorschau" + F_TEXT = "Text" + F_TAGS = "Stichworte" + + F_INDEX_TEXTE_ABS1 = "Abs1" + F_INDEX_TEXTE_ABS2 = "Abs2" + F_INDEX_GO_BUTTON = "GoButton" +) diff --git a/pagemodels/reihen.go b/pagemodels/reihen.go new file mode 100644 index 0000000..710dc84 --- /dev/null +++ b/pagemodels/reihen.go @@ -0,0 +1,60 @@ +package pagemodels + +import ( + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/tools/filesystem" +) + +type Reihen struct { + core.BaseRecordProxy +} + +func (r *Reihen) TableName() string { + return GeneratePageTableName(P_REIHEN_NAME) +} + +func NewReihen(record *core.Record) *Reihen { + i := &Reihen{} + i.SetProxyRecord(record) + return i +} + +func (r *Reihen) Title() string { + return r.GetString(F_TITLE) +} + +func (r *Reihen) SetTitle(titel string) { + r.Set(F_TITLE, titel) +} + +func (r *Reihen) Description() string { + return r.GetString(F_DESCRIPTION) +} + +func (r *Reihen) SetDescription(beschreibung string) { + r.Set(F_DESCRIPTION, beschreibung) +} + +func (r *Reihen) Keywords() string { + return r.GetString(F_TAGS) +} + +func (r *Reihen) SetKeywords(keywords string) { + r.Set(F_TAGS, keywords) +} + +func (r *Reihen) Text() string { + return r.GetString(F_TEXT) +} + +func (r *Reihen) SetText(text string) { + r.Set(F_TEXT, text) +} + +func (r *Reihen) Image() string { + return r.GetString(F_IMAGE) +} + +func (r *Reihen) SetImage(image *filesystem.File) { + r.Set(F_IMAGE, image) +} diff --git a/pages/migrations_index/1739220544_index.go b/pages/migrations_index/1739220544_index.go index 689e98c..5f6fea5 100644 --- a/pages/migrations_index/1739220544_index.go +++ b/pages/migrations_index/1739220544_index.go @@ -7,31 +7,9 @@ import ( m "github.com/pocketbase/pocketbase/migrations" ) -var bilder_fields = core.NewFieldsList( - &core.TextField{Name: pagemodels.F_INDEX_BILDER_TITEL, Required: true, Presentable: true}, - &core.EditorField{Name: pagemodels.F_INDEX_BILDER_BESCHREIBUNG, Required: false, Presentable: false}, - &core.FileField{ - Name: pagemodels.F_INDEX_BILDER_BILD, - Required: true, - MaxSize: 100 * 1024 * 1024, - MaxSelect: 1000, - MimeTypes: dbmodels.MUSENALM_MIME_TYPES, - Thumbs: []string{"0x300", "0x500", "0x1000", "300x0", "500x0", "1000x0"}, - }, // 100 MB a file - &core.FileField{ - Name: pagemodels.F_INDEX_BILDER_VORSCHAU, - Required: true, - MaxSize: 100 * 1024 * 1024, - MaxSelect: 1000, - MimeTypes: dbmodels.MUSENALM_MIME_TYPES, - Thumbs: []string{"0x300", "0x500", "0x1000", "300x0", "500x0", "1000x0"}, - }, // 100 MB a file -) - var texte_fields = core.NewFieldsList( - &core.TextField{Name: pagemodels.F_INDEX_TEXTE_TITEL, Required: true, Presentable: true}, - &core.EditorField{Name: pagemodels.F_INDEX_TEXTE_ABS1, Required: false, Presentable: false}, - &core.EditorField{Name: pagemodels.F_INDEX_TEXTE_ABS2, Required: false, Presentable: false}, + pagemodels.EditorField(pagemodels.F_INDEX_TEXTE_ABS1), + pagemodels.EditorField(pagemodels.F_INDEX_TEXTE_ABS2), ) func init() { @@ -56,7 +34,7 @@ func init() { } collection_t, err := app.FindCollectionByNameOrId( - pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_TEXTE)) + pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME)) if err == nil && collection_t != nil { if err := app.Delete(collection_t); err != nil { return err @@ -71,15 +49,18 @@ func bilderCollection() *core.Collection { pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER)) c.ListRule = dbmodels.PUBLIC_LIST_RULE c.ViewRule = dbmodels.PUBLIC_VIEW_RULE - c.Fields = bilder_fields + c.Fields = core.NewFieldsList( + pagemodels.TextField(pagemodels.F_TITLE), + pagemodels.EditorField(pagemodels.F_DESCRIPTION), + pagemodels.RequiredImageField(pagemodels.F_IMAGE, false), + pagemodels.RequiredImageField(pagemodels.F_PREVIEW, false), + ) + return c } func texteCollection() *core.Collection { - c := core.NewBaseCollection( - pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_TEXTE)) - c.ListRule = dbmodels.PUBLIC_LIST_RULE - c.ViewRule = dbmodels.PUBLIC_VIEW_RULE - c.Fields = texte_fields + c := pagemodels.BasePageCollection(pagemodels.P_INDEX_NAME) + c.Fields = append(c.Fields, texte_fields...) return c } diff --git a/pages/migrations_index/1739226078_insert_data.go b/pages/migrations_index/1739226078_insert_data.go index e2cabfc..0c4ffc6 100644 --- a/pages/migrations_index/1739226078_insert_data.go +++ b/pages/migrations_index/1739226078_insert_data.go @@ -14,14 +14,36 @@ import ( "github.com/pocketbase/pocketbase/tools/filesystem" ) +const ABS1 = "
Die Epoche der Almanache und Taschenbücher in der deutschsprachigen Publizistik beginnt im Jahr 1770 und klingt ab 1848 allmählich aus.
Noch heute erstaunt die Vielfalt der im Almanachwesen anzutreffenden Gegenstände: es gab literarische, politische, historische, satirische, philosophische und naturwissenschaftliche Almanache und Taschenbücher; es gab solche die der Mode, der Forstwirtschaft, dem Laientheater, dem Schachspiel oder der leichten Abendunterhaltung gewidmet waren etc.
In ihrer thematischen Bandbreite stellen Almanache und Taschenbücher über ihre oft reizvolle Ausstattung und Illustration hinaus wichtige kulturhistorische Zeitzeugen dar.
" + +const ABS2 = "Die laufend aktualisierte Datenbank erfasst die Almanache nach Reihen, Personen und verschiedenen Arten von Beiträgen — Textbeiträgen, Graphiken oder Musikbeiträgen. Umfangreiche Suchfunktionen helfen bei der Erschließung des Materials." + func init() { m.Register(func(app core.App) error { + index_collection, err := app.FindCollectionByNameOrId( + pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME)) + if err != nil { + app.Logger().Error("Could not find Table Texte! You need to execute table migrations first!") + return err + } + images := readImages(app, xmlmodels.STATIC_IMG_PATH, xmlmodels.BESCHREIBUNGEN_FN) for _, image := range images { if err := app.Save(image); err != nil { app.Logger().Error("Failed to save image:", "error", err, "image", image) } } + + text := pagemodels.NewIndexTexte(core.NewRecord(index_collection)) + text.SetTitel("MUSENALM") + text.SetAbs1(ABS1) + text.SetAbs2(ABS2) + + if err := app.Save(text); err != nil { + app.Logger().Error("Failed to save text:", "error", err, "text", text) + return err + } + return nil }, func(app core.App) error { collection, err := app.FindCollectionByNameOrId( @@ -29,6 +51,12 @@ func init() { if err == nil && collection != nil { app.DB().NewQuery("DELETE FROM " + collection.TableName()).Execute() } + + index_collection, err := app.FindCollectionByNameOrId( + pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME)) + if err == nil && index_collection != nil { + app.DB().NewQuery("DELETE FROM " + index_collection.TableName()).Execute() + } return nil }) } diff --git a/pages/migrations_reihen/1739446527_reihen.go b/pages/migrations_reihen/1739446527_reihen.go new file mode 100644 index 0000000..ae8e40b --- /dev/null +++ b/pages/migrations_reihen/1739446527_reihen.go @@ -0,0 +1,39 @@ +package migrations_reihen + +import ( + "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +var reihen_fields = core.NewFieldsList( + pagemodels.EditorField(pagemodels.F_TEXT), + pagemodels.RequiredImageField(pagemodels.F_IMAGE, false), +) + +func init() { + m.Register(func(app core.App) error { + collection := pageCollection() + if err := app.Save(collection); err != nil { + app.Logger().Error("Failed to save collection:", "error", err, "collection", collection) + return err + } + return nil + }, func(app core.App) error { + collection, err := app.FindCollectionByNameOrId( + pagemodels.GeneratePageTableName(pagemodels.P_REIHEN_NAME)) + if err == nil && collection != nil { + if err := app.Delete(collection); err != nil { + app.Logger().Error("Failed to delete collection:", "error", err, "collection", collection) + return err + } + } + return nil + }) +} + +func pageCollection() *core.Collection { + c := pagemodels.BasePageCollection(pagemodels.P_REIHEN_NAME) + c.Fields = append(c.Fields, reihen_fields...) + return c +} diff --git a/pages/migrations_reihen/1739446703_insert_data_reihen.go b/pages/migrations_reihen/1739446703_insert_data_reihen.go new file mode 100644 index 0000000..dff973c --- /dev/null +++ b/pages/migrations_reihen/1739446703_insert_data_reihen.go @@ -0,0 +1,50 @@ +package migrations_reihen + +import ( + "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/tools/filesystem" +) + +const START = "Ziel der Musenalm ist die bibliographische Erfassung eines Jahrhunderts deutscher Almanache und Taschenbücher; das Projekt ist im Aufbau und wird kontinuierlich weitergeführt.
Verzeichnet werden:
Die Bibliographie ist zugänglich mit umfangreichen Suchfunktionen über:
Die Musenalm ist ein Projekt der Theodor Springmann Stiftung in Heidelberg.
" + +const START_BILD = "./Static-Bilder/musen.png" + +func init() { + m.Register(func(app core.App) error { + collection, err := app.FindCollectionByNameOrId( + pagemodels.GeneratePageTableName(pagemodels.P_REIHEN_NAME)) + if err != nil { + app.Logger().Error("Could not find Table Reihen! You need to execute table migrations first!") + return err + } + + record := pagemodels.NewReihen(core.NewRecord(collection)) + record.SetTitle("Musenalm") + record.SetText(START) + + img, err := filesystem.NewFileFromPath(START_BILD) + if err != nil { + app.Logger().Error("Failed to read image file", "error", err, "path", START_BILD) + return err + } + + record.SetImage(img) + + if err := app.Save(record); err != nil { + app.Logger().Error("Failed to save record", "error", err, "record", record) + return err + } + + return nil + }, func(app core.App) error { + coll, err := app.FindCollectionByNameOrId( + pagemodels.GeneratePageTableName(pagemodels.P_REIHEN_NAME)) + + if err == nil && coll != nil { + app.DB().NewQuery("DELETE FROM " + coll.TableName()).Execute() + } + return nil + }) +} diff --git a/pages/reihen.go b/pages/reihen.go new file mode 100644 index 0000000..6884fdf --- /dev/null +++ b/pages/reihen.go @@ -0,0 +1,75 @@ +package pages + +import ( + "fmt" + "net/http" + "strings" + + "github.com/Theodor-Springmann-Stiftung/musenalm/app" + "github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels" + "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" + "github.com/Theodor-Springmann-Stiftung/musenalm/templating" + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/tools/router" +) + +const ( + URL_REIHEN = "/reihen/" + PARAM_LETTER = "letter" +) + +func init() { + rp := &ReihenPage{ + Page: pagemodels.Page{ + Name: pagemodels.P_REIHEN_NAME, + }, + } + app.Register(rp) +} + +type ReihenPage struct { + pagemodels.Page +} + +func (p *ReihenPage) Up(app core.App) error { + return nil +} + +func (p *ReihenPage) Down(app core.App) error { + return nil +} + +func (p *ReihenPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error { + router.GET(URL_REIHEN, func(e *core.RequestEvent) error { + letter := e.Request.URL.Query().Get(PARAM_LETTER) + if letter == "" { + letter = "A" + } + + series := []*dbmodels.Series{} + err := app.RecordQuery(dbmodels.SERIES_TABLE). + AndWhere(dbx.NewExp(dbmodels.SERIES_TITLE_FIELD + " LIKE '" + letter + "%'")). + OrderBy(dbmodels.SERIES_TITLE_FIELD). + All(&series) + // INFO: this does not return an error if the result set is empty + if err != nil { + return err + } + + // INFO: We sort again since the query can't sort german umlauts correctly + dbmodels.SortSeriesByTitle(series) + + var builder strings.Builder + err = engine.Render(&builder, URL_REIHEN, map[string]interface{}{ + PARAM_LETTER: letter, + "series": series, + }) + if err != nil { + return err + } + + return e.HTML(http.StatusOK, builder.String()) + }) + return nil +} diff --git a/templating/engine.go b/templating/engine.go index b4d654a..462e90d 100644 --- a/templating/engine.go +++ b/templating/engine.go @@ -29,6 +29,7 @@ func NewEngine(layouts, templates *fs.FS) *Engine { LayoutRegistry: NewLayoutRegistry(*layouts), TemplateRegistry: NewTemplateRegistry(*templates), FuncMap: make(template.FuncMap), + GlobalData: make(map[string]interface{}), } e.funcs() return &e @@ -106,10 +107,8 @@ func (e *Engine) AddFuncs(funcs map[string]interface{}) { func (e *Engine) Render(out io.Writer, path string, ld map[string]interface{}, layout ...string) error { // TODO: check if a reload is needed if files on disk have changed gd := e.GlobalData - if e.GlobalData != nil { - for k, v := range ld { - gd[k] = v - } + for k, v := range ld { + gd[k] = v } e.mu.Lock() diff --git a/views/routes/reihen/body.gohtml b/views/routes/reihen/body.gohtml new file mode 100644 index 0000000..58cdee1 --- /dev/null +++ b/views/routes/reihen/body.gohtml @@ -0,0 +1,9 @@ +Hello {{ .name }} from the {{ .haus }}(default template)! +{{ range $id, $r := .series }} +