Bilder & Vorschau / Tabellen für die Satrtseite

This commit is contained in:
Simon Martens
2025-02-11 00:13:42 +01:00
parent deae787e2d
commit 0f87df8e94
13 changed files with 412 additions and 128 deletions

View File

@@ -1,6 +1,9 @@
package dbmodels
import "github.com/pocketbase/pocketbase/core"
import (
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/filesystem"
)
var _ core.RecordProxy = (*Content)(nil)
@@ -150,7 +153,7 @@ func (c *Content) Scans() []string {
return c.GetStringSlice(SCAN_FIELD)
}
func (c *Content) SetScans(scans []string) {
func (c *Content) SetScans(scans []*filesystem.File) {
c.Set(SCAN_FIELD, scans)
}

View File

@@ -411,7 +411,8 @@ var SERIES_RELATIONS = []string{
}
const (
PUBLIC_VIEW_RULE = "@request.auth.id != ''"
PUBLIC_VIEW_RULE = ""
PUBLIC_LIST_RULE = ""
PLACES_TABLE = "places"
AGENTS_TABLE = "agents"

2
go.mod
View File

@@ -7,6 +7,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.24
github.com/pocketbase/dbx v1.11.0
github.com/pocketbase/pocketbase v0.25.0
github.com/spf13/cobra v1.8.1
github.com/yalue/merged_fs v1.3.0
)
@@ -48,7 +49,6 @@ require (
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
go.opencensus.io v0.24.0 // indirect
gocloud.dev v0.40.0 // indirect

View File

@@ -2,12 +2,16 @@ package seed
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
"github.com/Theodor-Springmann-Stiftung/musenalm/xmlmodels"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/filesystem"
)
const NO_TITLE = "[No Title]"
@@ -20,6 +24,8 @@ func RecordsFromInhalte(app core.App, inhalte xmlmodels.Inhalte) ([]*dbmodels.Co
return records, err
}
images := getImages(xmlmodels.IMG_PATH)
for i := 0; i < len(inhalte.Inhalte); i++ {
record := dbmodels.NewContent(core.NewRecord(collection))
inhalt := inhalte.Inhalte[i]
@@ -28,6 +34,7 @@ func RecordsFromInhalte(app core.App, inhalte xmlmodels.Inhalte) ([]*dbmodels.Co
app.Logger().Error("Error finding band record for inhalt", "error", err, "inhalt", inhalt)
continue
}
record.SetEntry(band.Id)
record.SetAnnotation(NormalizeString(inhalt.Anmerkungen))
record.SetMusenalmID(inhalt.ID)
@@ -48,6 +55,21 @@ func RecordsFromInhalte(app core.App, inhalte xmlmodels.Inhalte) ([]*dbmodels.Co
}
record.SetNumbering(no)
images, ok := images[inhalt.ID]
if ok {
files := []*filesystem.File{}
for _, image := range images {
file, err := filesystem.NewFileFromPath(image)
if err != nil {
app.Logger().Error("Error creating file from path", "error", err, "path", image)
continue
}
files = append(files, file)
}
record.SetScans(files)
}
handlePreferredTitle(inhalt, record)
n := record.PreferredTitle()
if n == "" || n == NO_TITLE {
@@ -104,3 +126,36 @@ func commatizeArray(array []string) string {
}
return array[0]
}
func getImages(path string) map[string][]string {
/// BUG: there is a bug somewhere, where files ending with numbers after a comma (",001") etc dont get added
ret := make(map[string][]string)
if _, err := os.Stat(path); os.IsNotExist(err) {
return ret
}
e := func(path string, fileInfo os.FileInfo, inpErr error) (err error) {
if !fileInfo.IsDir() {
basesplit := strings.Split(fileInfo.Name(), "-")
if len(basesplit) == 3 {
extensionsplit := strings.Split(basesplit[2], ".")
if len(extensionsplit) == 2 {
// BUG: prob here
commaseperatorsplit := strings.Split(extensionsplit[0], ",")
id := commaseperatorsplit[1]
if _, ok := ret[id]; !ok {
ret[id] = make([]string, 0)
}
ret[id] = append(ret[id], path)
}
}
}
return nil
}
if err := filepath.Walk(path, e); err != nil {
log.Fatal(err)
}
return ret
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/Theodor-Springmann-Stiftung/musenalm/helpers"
_ "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/pocketbase/pocketbase/plugins/migratecmd"
)

7
pagemodels/common.go Normal file
View File

@@ -0,0 +1,7 @@
package pagemodels
const PAGE_DB_PREFIX = "page_"
func GeneratePageTableName(pagename, tablename string) string {
return PAGE_DB_PREFIX + pagename + "_" + tablename
}

105
pagemodels/index.go Normal file
View File

@@ -0,0 +1,105 @@
package pagemodels
import (
"github.com/pocketbase/pocketbase/core"
"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
}
func (b *IndexBilder) TableName() string {
return GeneratePageTableName(P_INDEX_NAME, T_INDEX_BILDER)
}
func NewIndexBilder(record *core.Record) *IndexBilder {
i := &IndexBilder{}
i.SetProxyRecord(record)
return i
}
func (b *IndexBilder) Titel() string {
return b.GetString(F_INDEX_BILDER_TITEL)
}
func (b *IndexBilder) SetTitel(titel string) {
b.Set(F_INDEX_BILDER_TITEL, titel)
}
func (b *IndexBilder) Beschreibung() string {
return b.GetString(F_INDEX_BILDER_BESCHREIBUNG)
}
func (b *IndexBilder) SetBeschreibung(beschreibung string) {
b.Set(F_INDEX_BILDER_BESCHREIBUNG, beschreibung)
}
func (b *IndexBilder) Bild() string {
return b.GetString(F_INDEX_BILDER_BILD)
}
func (b *IndexBilder) SetBild(bild *filesystem.File) {
b.Set(F_INDEX_BILDER_BILD, bild)
}
func (b *IndexBilder) Vorschau() string {
return b.GetString(F_INDEX_BILDER_VORSCHAU)
}
func (b *IndexBilder) SetVorschau(vorschau *filesystem.File) {
b.Set(F_INDEX_BILDER_VORSCHAU, vorschau)
}
type IndexTexte struct {
core.BaseRecordProxy
}
func (t *IndexTexte) TableName() string {
return GeneratePageTableName(P_INDEX_NAME, T_INDEX_TEXTE)
}
func NewIndexTexte(record *core.Record) *IndexTexte {
i := &IndexTexte{}
i.SetProxyRecord(record)
return i
}
func (t *IndexTexte) Titel() string {
return t.GetString(F_INDEX_TEXTE_TITEL)
}
func (t *IndexTexte) SetTitel(titel string) {
t.Set(F_INDEX_TEXTE_TITEL, titel)
}
func (t *IndexTexte) Abs1() string {
return t.GetString(F_INDEX_TEXTE_ABS1)
}
func (t *IndexTexte) SetAbs1(abs1 string) {
t.Set(F_INDEX_TEXTE_ABS1, abs1)
}
func (t *IndexTexte) Abs2() string {
return t.GetString(F_INDEX_TEXTE_ABS2)
}
func (t *IndexTexte) SetAbs2(abs2 string) {
t.Set(F_INDEX_TEXTE_ABS2, abs2)
}

View File

@@ -6,10 +6,6 @@ import (
"github.com/pocketbase/pocketbase/tools/router"
)
const (
PAGE_DB_PREFIX = "page_"
)
type IPage interface {
Up(app core.App) error
Down(app core.App) error
@@ -19,52 +15,5 @@ type IPage interface {
type Page struct {
// WARNING: this is not thread safe, just set this once in setup
Tables []string
Name string
}
func (p *Page) TableExists(app core.App, name string) bool {
coll, _ := app.FindCollectionByNameOrId(p.generateName(name))
if coll != nil {
p.Tables = append(p.Tables, coll.Name)
}
return coll != nil
}
func (p *Page) CreateTable(app core.App, collection *core.Collection) error {
collection.Name = p.generateName(collection.Name)
err := app.Save(collection)
if err != nil {
app.Logger().Error("Error creating table", "error", err, "collection", collection, "name", p.Name)
return err
}
p.Tables = append(p.Tables, collection.Name)
return nil
}
func (p *Page) DropTable(app core.App, name string) error {
coll, _ := app.FindCollectionByNameOrId(p.generateName(name))
if coll != nil {
err := app.Delete(coll)
if err != nil {
app.Logger().Error("Error deleting table", "error", err, "collection", coll, "name", p.Name)
return err
}
}
return nil
}
func (p *Page) DropTables(app core.App) error {
for _, table := range p.Tables {
err := p.DropTable(app, table)
if err != nil {
return err
}
}
return nil
}
func (p *Page) generateName(name string) string {
return PAGE_DB_PREFIX + p.Name + "_" + name
Name string
}

View File

@@ -4,49 +4,16 @@ import (
"net/http"
"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/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/router"
"github.com/pocketbase/pocketbase/tools/types"
)
const INDEX_NAME = "index"
const BILDER_T_NAME = "bilder"
const TEXTE_T_NAME = "texte"
var bilder_fields = core.NewFieldsList(
&core.TextField{Name: "Titel", Required: true, Presentable: true},
&core.EditorField{Name: "Beschreibung", Required: false, Presentable: false},
&core.FileField{
Name: "Bilder",
Required: false,
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: "Vorschau",
Required: false,
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: "Titel", Required: true, Presentable: true},
&core.EditorField{Name: "Abs1", Required: false, Presentable: false},
&core.EditorField{Name: "Abs2", Required: false, Presentable: false},
)
func init() {
ip := &IndexPage{
Page: pagemodels.Page{
Name: INDEX_NAME,
Name: pagemodels.P_INDEX_NAME,
},
}
app.Register(ip)
@@ -57,49 +24,13 @@ type IndexPage struct {
}
func (p *IndexPage) Up(app core.App) error {
if !p.TableExists(app, BILDER_T_NAME) {
err := p.CreateTable(app, p.bilderCollection())
if err != nil {
return err
}
}
if !p.TableExists(app, TEXTE_T_NAME) {
err := p.CreateTable(app, p.texteCollection())
if err != nil {
return err
}
}
return nil
}
func (p *IndexPage) Down(app core.App) error {
err := p.DropTable(app, BILDER_T_NAME)
if err != nil {
return err
}
err = p.DropTable(app, TEXTE_T_NAME)
if err != nil {
return err
}
return nil
}
func (p *IndexPage) bilderCollection() *core.Collection {
c := core.NewBaseCollection(BILDER_T_NAME)
c.ListRule = types.Pointer("")
c.ViewRule = types.Pointer("")
c.Fields = bilder_fields
return c
}
func (p *IndexPage) texteCollection() *core.Collection {
c := core.NewBaseCollection(TEXTE_T_NAME)
c.ListRule = types.Pointer("")
c.ViewRule = types.Pointer("")
c.Fields = texte_fields
return c
}
func (p *IndexPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
router.GET("/{$}", func(e *core.RequestEvent) error {
return e.String(http.StatusOK, "Hello, World!")

View File

@@ -0,0 +1,86 @@
package migrations_index
import (
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/tools/types"
)
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},
)
func init() {
m.Register(func(app core.App) error {
collection_b := bilderCollection()
if err := app.Save(collection_b); err != nil {
return err
}
collection_t := texteCollection()
if err := app.Save(collection_t); err != nil {
return err
}
return nil
}, func(app core.App) error {
collection_b, err := app.FindCollectionByNameOrId(
pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER))
if err == nil && collection_b != nil {
if err := app.Delete(collection_b); err != nil {
return err
}
}
collection_t, err := app.FindCollectionByNameOrId(
pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_TEXTE))
if err == nil && collection_t != nil {
if err := app.Delete(collection_t); err != nil {
return err
}
}
return nil
})
}
func bilderCollection() *core.Collection {
c := core.NewBaseCollection(
pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER))
c.ListRule = types.Pointer("")
c.ViewRule = types.Pointer("")
c.Fields = bilder_fields
return c
}
func texteCollection() *core.Collection {
c := core.NewBaseCollection(
pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_TEXTE))
c.ListRule = types.Pointer("")
c.ViewRule = types.Pointer("")
c.Fields = texte_fields
return c
}

View File

@@ -0,0 +1,142 @@
package migrations_index
import (
"bufio"
"log"
"os"
"path/filepath"
"strings"
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
"github.com/Theodor-Springmann-Stiftung/musenalm/xmlmodels"
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/tools/filesystem"
)
func init() {
m.Register(func(app core.App) error {
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)
}
}
return nil
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId(
pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER))
if err == nil && collection != nil {
app.DB().NewQuery("DELETE FROM " + collection.TableName()).Execute()
}
return nil
})
}
func readDescriptions(collection *core.Collection, filePath string) (map[string]*pagemodels.IndexBilder, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
images := make(map[string]*pagemodels.IndexBilder)
var filename string
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "# ") {
filename = strings.TrimPrefix(line, "# ")
images[filename] = pagemodels.NewIndexBilder(core.NewRecord(collection))
} else if strings.HasPrefix(line, "## ") {
title := strings.TrimPrefix(line, "## ")
images[filename].SetTitel(title)
} else if strings.HasPrefix(line, "### ") {
beschr := strings.TrimPrefix(line, "### ")
images[filename].SetBeschreibung(beschr)
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return images, nil
}
func readImages(app core.App, path, description_fn string) []*pagemodels.IndexBilder {
ret := make([]*pagemodels.IndexBilder, 0)
collection, err := app.FindCollectionByNameOrId(
pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER))
if err != nil {
app.Logger().Error("Could not find Table Bilder! You need to execute table migrations first!")
return ret
}
if _, err := os.Stat(path); os.IsNotExist(err) {
return ret
}
descriptionPath := filepath.Join(path, description_fn)
images, err := readDescriptions(collection, descriptionPath)
if err != nil {
app.Logger().Error("Failed to read descriptions file:", "error", err)
app.Logger().Info("Proceeding without descriptions")
return ret
}
e := func(path string, fileInfo os.FileInfo, inpErr error) (err error) {
name := fileInfo.Name()
titleWithoutExt := strings.TrimSuffix(name, filepath.Ext(name))
if !fileInfo.IsDir() &&
(strings.HasSuffix(name, ".png") ||
strings.HasSuffix(name, ".jpg") ||
strings.HasSuffix(name, ".jpeg")) {
if strings.HasSuffix(strings.TrimSuffix(name, filepath.Ext(name)), "-vorschau") {
return nil
}
info, exists := images[name]
if exists {
info.SetTitel(titleWithoutExt)
} else {
fn := strings.TrimSuffix(name, "-hintergrund"+filepath.Ext(name))
info, exists = images[fn]
if exists {
info.SetTitel(titleWithoutExt)
} else {
return nil
}
}
f, err := filesystem.NewFileFromPath(path)
if err != nil {
app.Logger().Error("Failed to create file from path:", "error", err)
return nil
}
info.SetBild(f)
previewName := strings.TrimSuffix(name, filepath.Ext(name)) + "-vorschau" + filepath.Ext(name)
previewPath := filepath.Join(filepath.Dir(path), previewName)
if _, err := os.Stat(previewPath); err == nil {
previewFile, err := filesystem.NewFileFromPath(previewPath)
if err != nil {
log.Println(err)
return nil
}
info.SetVorschau(previewFile)
ret = append(ret, info)
}
}
return nil
}
if err := filepath.Walk(path, e); err != nil {
app.Logger().Error("Failed to walk path:", "error", err)
}
return ret
}

View File

@@ -1 +0,0 @@
package pages

View File

@@ -1,3 +1,8 @@
package xmlmodels
const DATA_PATH = "data/"
const (
BESCHREIBUNGEN_FN = "beschreibungen.txt"
STATIC_IMG_PATH = "Static-Bilder/"
DATA_PATH = "data/"
IMG_PATH = "Almanach-Bilder/"
)