diff --git a/; b/; new file mode 100644 index 0000000..f2e33eb --- /dev/null +++ b/; @@ -0,0 +1,36 @@ +package main + +import ( + "log" + + "github.com/Theodor-Springmann-Stiftung/musenalm/app" + "github.com/Theodor-Springmann-Stiftung/musenalm/cmd" + "github.com/Theodor-Springmann-Stiftung/musenalm/helpers" + _ "github.com/Theodor-Springmann-Stiftung/musenalm/migrations" + _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages" + "github.com/pocketbase/pocketbase/plugins/migratecmd" +) + +const ( + DEV_CONFIG = "config.dev.json" + DEFAULT_CONFIG = "config.json" +) + +func main() { + cfg := app.NewConfigProvider([]string{DEFAULT_CONFIG}, []string{DEV_CONFIG}) + if err := cfg.Read(); err != nil { + helpers.Assert(err, "Error reading config") + } + + app := app.New(*cfg.Config) + app.PB.RootCmd.AddCommand(cmd.AddResetPagesCommand(app.PB, &app)) + + migratecmd.MustRegister(app.PB, app.PB.RootCmd, migratecmd.Config{ + Automigrate: false, + TemplateLang: migratecmd.TemplateLangGo, + }) + + if err := app.Serve(); err != nil { + log.Fatal(err) + } +} diff --git a/app/pages.go b/app/pages.go new file mode 100644 index 0000000..c60b236 --- /dev/null +++ b/app/pages.go @@ -0,0 +1,9 @@ +package app + +import "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" + +var pages []pagemodels.IPage + +func Register(page pagemodels.IPage) { + pages = append(pages, page) +} diff --git a/app/pb.go b/app/pb.go index 4f90c6e..3262254 100644 --- a/app/pb.go +++ b/app/pb.go @@ -4,6 +4,9 @@ import ( "database/sql" "fmt" + "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" + "github.com/Theodor-Springmann-Stiftung/musenalm/templating" + "github.com/Theodor-Springmann-Stiftung/musenalm/views" "github.com/mattn/go-sqlite3" "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase" @@ -14,11 +17,12 @@ import ( type App struct { PB *pocketbase.PocketBase MAConfig Config + Pages []pagemodels.IPage } const ( - TEST_SUPERUSER_MAIL = "test@test.de" - TEST_SUPERUSER_PASS = "passwort" + TEST_SUPERUSER_MAIL = "demo@example.com" + TEST_SUPERUSER_PASS = "password" ) func init() { @@ -94,3 +98,35 @@ func (app *App) setupTestuser() { return e.Next() }) } + +func (app *App) Serve() error { + engine := templating.NewEngine(&views.LayoutFS, &views.RoutesFS) + + app.PB.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error { + e.Next() + for _, page := range pages { + err := page.Up(e.App) + if err != nil { + page.Down(e.App) + continue + } + app.Pages = append(app.Pages, page) + } + return nil + }) + + app.PB.OnServe().BindFunc(func(e *core.ServeEvent) error { + for _, page := range app.Pages { + page.Setup(e.Router, e.App, engine) + } + return e.Next() + }) + return app.PB.Start() +} + +func (app *App) ResetPages() error { + for _, page := range pages { + page.Down(app.PB) + } + return nil +} diff --git a/cmd/resetpages.go b/cmd/resetpages.go new file mode 100644 index 0000000..63def75 --- /dev/null +++ b/cmd/resetpages.go @@ -0,0 +1,26 @@ +package cmd + +import ( + "github.com/Theodor-Springmann-Stiftung/musenalm/app" + "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/core" + "github.com/spf13/cobra" +) + +func AddResetPagesCommand(pb *pocketbase.PocketBase, app *app.App) *cobra.Command { + var resetPagesCmd = &cobra.Command{ + Use: "resetpages", + Short: "Reset all pages", + Run: func(cmd *cobra.Command, args []string) { + pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error { + e.Next() + if err := app.ResetPages(); err != nil { + panic(err) + } + return nil + }) + }, + } + + return resetPagesCmd +} diff --git a/musenalm.go b/musenalm.go index f65937f..f2e33eb 100644 --- a/musenalm.go +++ b/musenalm.go @@ -4,8 +4,10 @@ import ( "log" "github.com/Theodor-Springmann-Stiftung/musenalm/app" + "github.com/Theodor-Springmann-Stiftung/musenalm/cmd" "github.com/Theodor-Springmann-Stiftung/musenalm/helpers" _ "github.com/Theodor-Springmann-Stiftung/musenalm/migrations" + _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages" "github.com/pocketbase/pocketbase/plugins/migratecmd" ) @@ -15,20 +17,20 @@ const ( ) func main() { - cfg := app.NewConfigProvider([]string{DEFAULT_CONFIG}, []string{DEV_CONFIG}) if err := cfg.Read(); err != nil { helpers.Assert(err, "Error reading config") } app := app.New(*cfg.Config) + app.PB.RootCmd.AddCommand(cmd.AddResetPagesCommand(app.PB, &app)) migratecmd.MustRegister(app.PB, app.PB.RootCmd, migratecmd.Config{ Automigrate: false, TemplateLang: migratecmd.TemplateLangGo, }) - if err := app.PB.Start(); err != nil { + if err := app.Serve(); err != nil { log.Fatal(err) } } diff --git a/pagemodels/page.go b/pagemodels/page.go new file mode 100644 index 0000000..c8d73b2 --- /dev/null +++ b/pagemodels/page.go @@ -0,0 +1,70 @@ +package pagemodels + +import ( + "github.com/Theodor-Springmann-Stiftung/musenalm/templating" + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/tools/router" +) + +const ( + PAGE_DB_PREFIX = "page_" +) + +type IPage interface { + Up(app core.App) error + Down(app core.App) error + // TODO: pass the cache here + Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error +} + +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 +} diff --git a/pages/index.go b/pages/index.go new file mode 100644 index 0000000..4204299 --- /dev/null +++ b/pages/index.go @@ -0,0 +1,108 @@ +package pages + +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, + }, + } + app.Register(ip) +} + +type IndexPage struct { + pagemodels.Page +} + +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!") + }) + return nil +} diff --git a/pages/start.go b/pages/start.go new file mode 100644 index 0000000..76e382d --- /dev/null +++ b/pages/start.go @@ -0,0 +1 @@ +package pages