Files
summercms/docs/examples/blog/controllers/posts_test.go
Jakub Zych 8bc18c90b6 feat(build): scaffold working admin controllers with model, AdminFS and delete (quick-261028-pq8)
- make:admin-controller edits the singular of its name (--model overrides):
  ModelName, modelClass and the YAML under models/<model>/
- NewRecord returns &models.<Model>{} when the model exists; otherwise the
  nil body stays and the command says to run make:model
- config_list.yaml offers create and delete with showCheckboxes
- registry.gen.go embeds controllers/*/*.yaml and models/*/*.yaml once they
  exist and exposes generatedAdminFS(); scaffolded plugins implement
  pact.AdminAssets through it, and a plugin without AdminFS gets a note
- blog example moves its YAML to models/post; docs and help text follow
2026-10-28 19:15:23 +01:00

100 lines
3.6 KiB
Go

package controllers_test
import (
"io/fs"
"slices"
"testing"
"git.golem15.com/golem15/summercms/docs/examples/blog"
"git.golem15.com/golem15/summercms/docs/examples/blog/controllers"
"git.golem15.com/golem15/summercms/docs/examples/blog/models"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/bouncer"
"git.golem15.com/golem15/summercms/modules/cabana"
"git.golem15.com/golem15/summercms/modules/compass"
"git.golem15.com/golem15/summercms/modules/pact"
"git.golem15.com/golem15/summercms/modules/party"
)
func TestPostsControllerDeclaration(t *testing.T) {
ctl := controllers.PostsController()
if ctl.ID() != "acme.blog.posts" {
t.Errorf("ID = %q, want acme.blog.posts", ctl.ID())
}
if ctl.ModelName() != "Post" {
t.Errorf("ModelName = %q, want Post", ctl.ModelName())
}
if ctl.ConfigDir() != "controllers/posts" {
t.Errorf("ConfigDir = %q, want controllers/posts", ctl.ConfigDir())
}
perm, ok := ctl.(pact.AdminPermissioned)
if !ok {
t.Fatal("the controller does not declare a permission (pact.AdminPermissioned)")
}
if got := perm.RequiredPermissions(); !slices.Equal(got, []string{"acme.blog.access_posts"}) {
t.Errorf("RequiredPermissions = %v, want [acme.blog.access_posts]", got)
}
src, ok := ctl.(pact.AdminRecordSource)
if !ok {
t.Fatal("the controller does not implement pact.AdminRecordSource")
}
if _, ok := src.NewRecord().(*models.Post); !ok {
t.Errorf("NewRecord is %T, want *models.Post", src.NewRecord())
}
plugin := &blog.Plugin{}
fsys := plugin.AdminFS()
form, err := cabana.CompileForm("acme.blog", ctl, fsys)
if err != nil {
t.Fatalf("CompileForm: %v", err)
}
var fields []string
for _, f := range form.Fields {
fields = append(fields, f.Name)
}
if want := []string{"title", "slug", "body"}; !slices.Equal(fields, want) {
t.Errorf("form fields = %v, want %v", fields, want)
}
list, err := cabana.CompileList("acme.blog", ctl, fsys)
if err != nil {
t.Fatalf("CompileList: %v", err)
}
if list.ModelClass != "Post" || list.DefaultSort == nil {
t.Errorf("list = %+v, want modelClass Post with a default sort", list)
}
for _, name := range []string{"controllers/posts/config_form.yaml", "controllers/posts/config_list.yaml", "models/post/fields.yaml", "models/post/columns.yaml"} {
if _, err := fs.Stat(fsys, name); err != nil {
t.Errorf("AdminFS is missing %s: %v", name, err)
}
}
// cabana compiles every admin controller at start-up without a database.
cfg, err := compass.Open(compass.Options{Dir: t.TempDir(), Env: "testing", Environ: []string{}})
if err != nil {
t.Fatal(err)
}
if err := cfg.Set("admin.jwt.secret", "test-only-secret-with-at-least-32-bytes"); err != nil {
t.Fatal(err)
}
routes, err := cabana.Activate(backpack.New(cfg), []party.Plugin{plugin})
if err != nil {
t.Fatalf("cabana.Activate: %v", err)
}
if routes == nil {
t.Fatal("cabana.Activate mounted no admin routes")
}
editor := &bouncer.Principal{ID: 1, Backend: true, PermissionGrants: map[string]bool{"acme.blog.access_posts": true}}
visitor := &bouncer.Principal{ID: 2, Backend: true, PermissionGrants: map[string]bool{}}
if !cabana.Allows(editor, perm.RequiredPermissions()) {
t.Error("an administrator with acme.blog.access_posts is refused")
}
if cabana.Allows(visitor, perm.RequiredPermissions()) {
t.Error("an administrator without acme.blog.access_posts is allowed")
}
declared := slices.ContainsFunc(plugin.Permissions(), func(p pact.Permission) bool { return p.Code == "acme.blog.access_posts" })
if !declared {
t.Error("the plugin does not declare acme.blog.access_posts in Permissions")
}
}