- posts: FormAfterCreate/Update purge after the content_html translations, new FormAfterDelete; categories: FormAfterCreate and FormAfterDelete - NewSiteCachePurger refuses half configuration, non-http(s) URLs, user info, fragments, http to a non-loopback host and tokens under 32 chars; Boot logs the endpoint host and path once - TestPostsAdminPurgesSiteCache smoke test - README: Configuration section (keys, contract, timing, scope), API rows
121 lines
4.2 KiB
Go
121 lines
4.2 KiB
Go
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{}
|
|
)
|