+extra page table

This commit is contained in:
Simon Martens
2026-01-14 16:36:23 +01:00
parent ca2df2da8a
commit 941ecbecaf
6 changed files with 126 additions and 46 deletions

104
app/pb.go
View File

@@ -38,6 +38,8 @@ type App struct {
dataMutex sync.RWMutex dataMutex sync.RWMutex
htmlCache *PrefixCache htmlCache *PrefixCache
htmlMutex sync.RWMutex htmlMutex sync.RWMutex
pagesCache map[string]PageMetaData
pagesMutex sync.RWMutex
imagesCache map[string]*dbmodels.Image imagesCache map[string]*dbmodels.Image
imagesMutex sync.RWMutex imagesMutex sync.RWMutex
} }
@@ -205,48 +207,39 @@ func (app *App) createEngine() (*templating.Engine, error) {
} }
return template.HTML(value) return template.HTML(value)
}) })
app.ResetPagesCache()
engine.AddFunc("pageMeta", func(name string) map[string]any { engine.AddFunc("pageMeta", func(name string) map[string]any {
app.ensureDataCache() app.ensurePagesCache()
key := "page." + name app.pagesMutex.RLock()
app.dataMutex.RLock() meta, ok := app.pagesCache[name]
value := app.dataCache.Get(key) app.pagesMutex.RUnlock()
app.dataMutex.RUnlock() if !ok {
if value == nil {
return map[string]any{} return map[string]any{}
} }
if meta, ok := value.(map[string]any); ok { return map[string]any{
return meta "title": meta.Title,
"description": meta.Description,
"keywords": meta.Keywords,
} }
if meta, ok := value.(map[string]interface{}); ok {
return meta
}
return map[string]any{}
}) })
engine.AddFunc("pageMetaField", func(name, field string) string { engine.AddFunc("pageMetaField", func(name, field string) string {
app.ensureDataCache() app.ensurePagesCache()
key := "page." + name app.pagesMutex.RLock()
app.dataMutex.RLock() meta, ok := app.pagesCache[name]
value := app.dataCache.Get(key) app.pagesMutex.RUnlock()
app.dataMutex.RUnlock()
if value == nil {
return ""
}
meta, ok := value.(map[string]any)
if !ok { if !ok {
if metaAlt, ok := value.(map[string]interface{}); ok {
meta = map[string]any(metaAlt)
} else {
return "" return ""
} }
} switch field {
fieldValue, ok := meta[field] case "title":
if !ok || fieldValue == nil { return meta.Title
case "description":
return meta.Description
case "keywords":
return meta.Keywords
default:
return "" return ""
} }
if s, ok := fieldValue.(string); ok {
return s
}
return fmt.Sprint(fieldValue)
}) })
engine.AddFunc("pageHtml", func(name string, section ...string) template.HTML { engine.AddFunc("pageHtml", func(name string, section ...string) template.HTML {
app.ensureHtmlCache() app.ensureHtmlCache()
@@ -305,11 +298,23 @@ func (app *App) ResetImagesCache() {
app.imagesCache = make(map[string]*dbmodels.Image) app.imagesCache = make(map[string]*dbmodels.Image)
} }
func (app *App) ResetPagesCache() {
app.pagesMutex.Lock()
defer app.pagesMutex.Unlock()
app.pagesCache = make(map[string]PageMetaData)
}
type PrefixCache struct { type PrefixCache struct {
data map[string]any data map[string]any
keys []string keys []string
} }
type PageMetaData struct {
Title string
Description string
Keywords string
}
func NewPrefixCache() *PrefixCache { func NewPrefixCache() *PrefixCache {
return &PrefixCache{ return &PrefixCache{
data: make(map[string]any), data: make(map[string]any),
@@ -418,6 +423,43 @@ func (app *App) ensureHtmlCache() {
app.htmlMutex.Unlock() app.htmlMutex.Unlock()
} }
func (app *App) ensurePagesCache() {
app.pagesMutex.RLock()
if app.pagesCache != nil && len(app.pagesCache) > 0 {
app.pagesMutex.RUnlock()
return
}
app.pagesMutex.RUnlock()
pages, err := dbmodels.Pages_All(app.PB.App)
if err != nil {
app.PB.Logger().Error("Failed to fetch pages cache: %v", err)
return
}
cache := make(map[string]PageMetaData, len(pages))
for _, page := range pages {
meta := PageMetaData{
Title: page.Title(),
}
if data := page.Data(); data != nil {
if value, ok := data["description"]; ok && value != nil {
meta.Description = fmt.Sprint(value)
}
if value, ok := data["keywords"]; ok && value != nil {
meta.Keywords = fmt.Sprint(value)
}
}
cache[page.Key()] = meta
}
app.pagesMutex.Lock()
if app.pagesCache == nil || len(app.pagesCache) == 0 {
app.pagesCache = cache
}
app.pagesMutex.Unlock()
}
func (app *App) ensureImagesCache() { func (app *App) ensureImagesCache() {
app.imagesMutex.RLock() app.imagesMutex.RLock()
if app.imagesCache != nil && len(app.imagesCache) > 0 { if app.imagesCache != nil && len(app.imagesCache) > 0 {

View File

@@ -18,6 +18,14 @@ func (p *Page) URL() string {
return p.GetString(URL_FIELD) return p.GetString(URL_FIELD)
} }
func (p *Page) Title() string {
return p.GetString(TITLE_FIELD)
}
func (p *Page) SetTitle(title string) {
p.Set(TITLE_FIELD, title)
}
func (p *Page) SetURL(url string) { func (p *Page) SetURL(url string) {
p.Set(URL_FIELD, url) p.Set(URL_FIELD, url)
} }

View File

@@ -155,6 +155,12 @@ func Data_All(app core.App) ([]*Data, error) {
return data, err return data, err
} }
func Pages_All(app core.App) ([]*Page, error) {
pages := make([]*Page, 0)
err := app.RecordQuery(PAGES_TABLE).All(&pages)
return pages, err
}
func Html_All(app core.App) ([]*HTML, error) { func Html_All(app core.App) ([]*HTML, error) {
html := make([]*HTML, 0) html := make([]*HTML, 0)
err := app.RecordQuery(HTML_TABLE).All(&html) err := app.RecordQuery(HTML_TABLE).All(&html)

View File

@@ -582,6 +582,7 @@ func pagesTable() *core.Collection {
func pagesTableFields() core.FieldsList { func pagesTableFields() core.FieldsList {
fields := core.NewFieldsList( fields := core.NewFieldsList(
&core.TextField{Name: dbmodels.KEY_FIELD, Required: true, Presentable: true}, &core.TextField{Name: dbmodels.KEY_FIELD, Required: true, Presentable: true},
&core.TextField{Name: dbmodels.TITLE_FIELD, Required: false},
&core.TextField{Name: dbmodels.URL_FIELD, Required: false}, &core.TextField{Name: dbmodels.URL_FIELD, Required: false},
&core.TextField{Name: dbmodels.TEMPLATE_FIELD, Required: false}, &core.TextField{Name: dbmodels.TEMPLATE_FIELD, Required: false},
&core.TextField{Name: dbmodels.LAYOUT_FIELD, Required: false}, &core.TextField{Name: dbmodels.LAYOUT_FIELD, Required: false},

View File

@@ -325,42 +325,42 @@ const (
) )
var pageMetaSeed = map[string]PageMeta{ var pageMetaSeed = map[string]PageMeta{
pageDataKey(pagemodels.P_INDEX_NAME): { pagemodels.P_INDEX_NAME: {
Title: INDEX_TITLE, Title: INDEX_TITLE,
Description: INDEX_DESCRIPTION, Description: INDEX_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_REIHEN_NAME): { pagemodels.P_REIHEN_NAME: {
Title: REIHEN_TITLE, Title: REIHEN_TITLE,
Description: REIHEN_DESCRIPTION, Description: REIHEN_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_DANK_NAME): { pagemodels.P_DANK_NAME: {
Title: "Danksagungen", Title: "Danksagungen",
Description: DANKSAGUNGEN_DESCRIPTION, Description: DANKSAGUNGEN_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_EINFUEHRUNG_NAME): { pagemodels.P_EINFUEHRUNG_NAME: {
Title: EINLEITUNG_TITLE, Title: EINLEITUNG_TITLE,
Description: EINLEITUNG_DESCRIPTION, Description: EINLEITUNG_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_KONTAKT_NAME): { pagemodels.P_KONTAKT_NAME: {
Title: KONTAKT_TITLE, Title: KONTAKT_TITLE,
Description: KONTAKT_DESCRIPTION, Description: KONTAKT_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_LIT_NAME): { pagemodels.P_LIT_NAME: {
Title: LITERATUR_TITLE, Title: LITERATUR_TITLE,
Description: LITERATUR_DESCRIPTION, Description: LITERATUR_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_DOK_NAME): { pagemodels.P_DOK_NAME: {
Title: DOKUMENTATION_TITLE, Title: DOKUMENTATION_TITLE,
Description: DOKUMENTATION_DESCRIPTION, Description: DOKUMENTATION_DESCRIPTION,
Keywords: "", Keywords: "",
}, },
pageDataKey(pagemodels.P_KABINETT_NAME): { pagemodels.P_KABINETT_NAME: {
Title: KABINETT_TITLE, Title: KABINETT_TITLE,
Description: KABINETT_DESCRIPTION, Description: KABINETT_DESCRIPTION,
Keywords: "", Keywords: "",
@@ -382,7 +382,7 @@ var pageHTMLSeed = map[string]string{
func init() { func init() {
m.Register(func(app core.App) error { m.Register(func(app core.App) error {
for key, meta := range pageMetaSeed { for key, meta := range pageMetaSeed {
if err := upsertData(app, key, meta); err != nil { if err := upsertPageMeta(app, key, meta); err != nil {
return err return err
} }
} }
@@ -413,7 +413,7 @@ func init() {
} }
for key := range pageMetaSeed { for key := range pageMetaSeed {
if err := deleteByKey(app, dbmodels.DATA_TABLE, key); err != nil { if err := deleteByKey(app, dbmodels.PAGES_TABLE, key); err != nil {
return err return err
} }
} }

View File

@@ -11,10 +11,6 @@ type PageMeta struct {
Keywords string `json:"keywords"` Keywords string `json:"keywords"`
} }
func pageDataKey(name string) string {
return "page." + name
}
func pageHTMLKey(name, section string) string { func pageHTMLKey(name, section string) string {
if section == "" { if section == "" {
return "page." + name return "page." + name
@@ -22,6 +18,33 @@ func pageHTMLKey(name, section string) string {
return "page." + name + "." + section return "page." + name + "." + section
} }
func upsertPageMeta(app core.App, key string, meta PageMeta) error {
collection, err := app.FindCollectionByNameOrId(dbmodels.PAGES_TABLE)
if err != nil {
return err
}
record, _ := app.FindFirstRecordByData(collection.Id, dbmodels.KEY_FIELD, key)
if record == nil {
record = core.NewRecord(collection)
record.Set(dbmodels.KEY_FIELD, key)
}
record.Set(dbmodels.TITLE_FIELD, meta.Title)
data := map[string]any{}
if existing := record.Get(dbmodels.DATA_FIELD); existing != nil {
if existingMap, ok := existing.(map[string]any); ok {
data = existingMap
} else if existingMap, ok := existing.(map[string]interface{}); ok {
data = map[string]any(existingMap)
}
}
data["description"] = meta.Description
data["keywords"] = meta.Keywords
record.Set(dbmodels.DATA_FIELD, data)
return app.Save(record)
}
func upsertHTML(app core.App, key, value string) error { func upsertHTML(app core.App, key, value string) error {
collection, err := app.FindCollectionByNameOrId(dbmodels.HTML_TABLE) collection, err := app.FindCollectionByNameOrId(dbmodels.HTML_TABLE)
if err != nil { if err != nil {