Files
sm-sitemap-plugin/controllers/definitions.go
Jakub Zych 7d937e3cf5 feat(17-03): sitemap admin, permissions, lang and README
- definitions singleton controller (theme default, first or create) with a
  repeater on data: type dropdown (url plus registry types), reference
  dependsOn type through signpost.ReferenceOptions
- Settings page entries: Sitemap (link to the controller) and Sitemap
  settings (form), both behind golem15.sitemap.access_definitions
- en and pl phrasebooks with the PHP keys
- README with the PHP parity rules, tiers, hooks, commands and the Winter
  YAML adaptations
- TestSitemapAdminSmoke: singleton, PHP-keyed rows, 422 on a foreign
  reference, settings save, 403 without the permission
2026-10-12 17:14:04 +02:00

107 lines
3.7 KiB
Go

// Package controllers holds the sitemap plugin's admin controllers.
package controllers
import (
"context"
"errors"
"git.golem15.com/golem15/sm-sitemap-plugin/models"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/pact"
"git.golem15.com/golem15/summercms/modules/signpost"
"gorm.io/gorm"
)
const (
// DefinitionsControllerID is the cabana controller id of the sitemap
// definition form.
DefinitionsControllerID = "golem15.sitemap.definitions"
// PermissionAccessDefinitions is Definitions::$requiredPermissions.
PermissionAccessDefinitions = "golem15.sitemap.access_definitions"
)
// typeURLLabel is the label of the built-in url item type.
const typeURLLabel = "golem15.sitemap::lang.item.url"
// definitionsAdminController edits the one sitemap definition of the
// application (theme default): a singleton form whose items are a repeater
// with a type dropdown (url plus the registry types) and a reference
// dropdown that depends on it.
type definitionsAdminController struct {
app func() *backpack.App
}
func (definitionsAdminController) ID() string { return DefinitionsControllerID }
func (definitionsAdminController) ModelName() string { return `Golem15\Sitemap\Models\Definition` }
func (definitionsAdminController) ConfigDir() string { return "controllers/definitions" }
func (definitionsAdminController) RequiredPermissions() []string {
return []string{PermissionAccessDefinitions}
}
func (definitionsAdminController) NewRecord() any { return &models.Definition{} }
// The singleton record is the definition with the fixed theme key, created
// with no items when there is none (PHP index(): firstOrCreate, then the
// update form).
func (definitionsAdminController) SingletonRecord(_ context.Context, db *gorm.DB) (any, error) {
if db == nil {
return nil, errors.New("golem15.sitemap: database is not configured")
}
var defs []models.Definition
if err := db.Where("theme = ?", models.DefinitionTheme).Order("id ASC").Limit(1).Find(&defs).Error; err != nil {
return nil, err
}
if len(defs) > 0 {
return &defs[0], nil
}
theme := models.DefinitionTheme
def := &models.Definition{Theme: &theme}
def.SetItems(nil)
if err := db.Create(def).Error; err != nil {
return nil, err
}
return def, nil
}
func (c definitionsAdminController) registry() *signpost.Registry {
if c.app == nil {
return nil
}
app := c.app()
if app == nil {
return nil
}
reg, _ := app.Lookup[*signpost.Registry]()
return reg
}
// DropdownOptions serves the item type dropdown: url, then every registry
// type in registry order with its label (PHP getTypeOptions).
func (c definitionsAdminController) DropdownOptions(string) []pact.Option {
out := []pact.Option{{Value: models.ItemTypeURL, Label: typeURLLabel}}
for _, t := range c.registry().Types() {
out = append(out, pact.Option{Value: t.Key, Label: t.Label})
}
return out
}
// DependentOptions serves the reference dropdown of an item row: the
// references of the row's type through signpost.ReferenceOptions; url and a
// type without references answer Applies false.
func (c definitionsAdminController) DependentOptions(ctx context.Context, _ string, values map[string]any) (pact.DependentOptionSet, error) {
typ, _ := values["type"].(string)
return signpost.ReferenceOptions(ctx, c.registry(), typ)
}
var (
_ pact.AdminController = definitionsAdminController{}
_ pact.AdminPermissioned = definitionsAdminController{}
_ pact.AdminRecordSource = definitionsAdminController{}
_ pact.AdminSingleton = definitionsAdminController{}
_ pact.DropdownOptionsProvider = definitionsAdminController{}
_ pact.DependentOptionsProvider = definitionsAdminController{}
)