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/posts/fields.yaml", "models/posts/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") } }