package controllers import ( "context" "errors" "strings" "git.golem15.com/golem15/sm-journal-plugin/classes" "git.golem15.com/golem15/sm-journal-plugin/models" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/cabana" "git.golem15.com/golem15/summercms/modules/pact" ) const ( // CategoriesControllerID is the cabana controller id of the Categories screen. CategoriesControllerID = "golem15.journal.categories" // PermissionAccessCategories is Categories::$requiredPermissions. PermissionAccessCategories = "golem15.journal.access_categories" ) type categoriesAdminController struct { app func() *backpack.App } func (categoriesAdminController) ID() string { return CategoriesControllerID } func (categoriesAdminController) ModelName() string { return `Golem15\Journal\Models\Category` } func (categoriesAdminController) ConfigDir() string { return "controllers/categories" } func (categoriesAdminController) RequiredPermissions() []string { return []string{PermissionAccessCategories} } func (categoriesAdminController) NewRecord() any { return &models.Category{} } func (categoriesAdminController) AdminFieldRelations() []cabana.FieldRelationContract { return []cabana.FieldRelationContract{{ Field: "parent", Kind: "belongsTo", NewRelated: func() any { return &models.Category{} }, ForeignKey: "parent_id", LabelColumn: "name", }} } func (categoriesAdminController) FormBeforeCreate(ctx context.Context, model any) error { cat, ok := model.(*models.Category) if !ok || cat == nil { return errors.New("categories admin: form model is not a category") } return prepareCategoryWrite(cat) } func (categoriesAdminController) FormBeforeUpdate(ctx context.Context, model any) error { cat, ok := model.(*models.Category) if !ok || cat == nil { return errors.New("categories admin: form model is not a category") } return prepareCategoryWrite(cat) } // FormAfterCreate purges the host site's page caches once the save // transaction commits (G-16.2-2, D-19). func (c categoriesAdminController) FormAfterCreate(ctx context.Context, model any) error { return c.purgeAfterCommit(ctx, model) } // FormAfterUpdate purges the host site's page caches once the save // transaction commits (G-16.2-2, D-19). func (c categoriesAdminController) FormAfterUpdate(ctx context.Context, model any) error { return c.purgeAfterCommit(ctx, model) } // FormAfterDelete purges the host site's page caches once the delete // commits. func (c categoriesAdminController) FormAfterDelete(ctx context.Context, model any) error { return c.purgeAfterCommit(ctx, model) } func (c categoriesAdminController) purgeAfterCommit(ctx context.Context, model any) error { cat, ok := model.(*models.Category) if !ok || cat == nil { return errors.New("categories admin: form model is not a category") } purger, tx := siteCachePurger(ctx, c.app) classes.PurgeSiteCacheAfterCommit(ctx, tx, purger, "category", cat.Slug) return nil } // prepareCategoryWrite stores blank category content (white space only) as // NULL and accepts any other content it receives. Since Phase 16.2 the // content field is the blogeditor type, whose Decode already stored the HTML // policy's output (classes.SanitizeHTMLReport) and told the administrator // what it removed, so an admin save is never refused because of markup // (D-10 amended, see the bluemonday decision note). Rows written by SQL or // by the import commands do not pass through here and are not sanitized by // it. func prepareCategoryWrite(cat *models.Category) error { if cat.Content == nil { return nil } if strings.TrimSpace(*cat.Content) == "" { cat.Content = nil } return nil } var ( _ pact.AdminController = categoriesAdminController{} _ pact.AdminPermissioned = categoriesAdminController{} _ pact.AdminRecordSource = categoriesAdminController{} _ pact.FormBeforeCreate = categoriesAdminController{} _ pact.FormBeforeUpdate = categoriesAdminController{} _ pact.FormAfterCreate = categoriesAdminController{} _ pact.FormAfterUpdate = categoriesAdminController{} _ pact.FormAfterDelete = categoriesAdminController{} _ cabana.FieldRelationProvider = categoriesAdminController{} )