- TestBackendLink: the fresh sign-in rule at the second, 1:1 on the frontend side, the show route's three keys, SetLink and RemoveLink events (none after a rollback), deactivated or deleted administrators, and deactivating the frontend user - TestFrontendPermissionCatalog: a second plugin's duplicate and an empty code dropped; a group saved with a declared code grants it - TestUserMCPGuard: parser refusals, a soft-deleted user, an expired token, and the dispatch credential against the route's own user.scope:read
96 lines
3.8 KiB
Go
96 lines
3.8 KiB
Go
package user
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/sm-user-plugin/classes"
|
|
"git.golem15.com/golem15/sm-user-plugin/models"
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
"git.golem15.com/golem15/summercms/modules/party"
|
|
)
|
|
|
|
const acmeShopOrders = "acme.shop.orders"
|
|
|
|
// acmeShopPermissions declares a code of its own and acme.blog's manage code
|
|
// again, under another label: activated after acme.blog, its duplicate is
|
|
// dropped.
|
|
type acmeShopPermissions struct{}
|
|
|
|
func (acmeShopPermissions) ID() string { return "acme.shop" }
|
|
func (acmeShopPermissions) Requires() []string { return nil }
|
|
func (acmeShopPermissions) Register(*backpack.App) error { return nil }
|
|
func (acmeShopPermissions) Boot(*backpack.App) error { return nil }
|
|
func (acmeShopPermissions) FrontendPermissions() []pact.FrontendPermission {
|
|
return []pact.FrontendPermission{
|
|
{Code: acmeBlogManage, Label: "Shop's copy", Tab: "Shop"},
|
|
{Code: acmeShopOrders, Label: "Manage orders", Tab: "Shop"},
|
|
{Code: " ", Label: "Empty code", Tab: "Shop"},
|
|
}
|
|
}
|
|
|
|
func init() { party.Register(acmeShopPermissions{}) }
|
|
|
|
// TestFrontendPermissionCatalog (D-09) extends the smoke: with two declaring
|
|
// plugins the editors offer the seeded rows, then the first plugin's codes,
|
|
// then the second's, a code the first already declared and an empty code
|
|
// left out; a group saved with a declared code keeps it, and the member's
|
|
// grants (what user.permission checks) include it. Skips under -short.
|
|
func TestFrontendPermissionCatalog(t *testing.T) {
|
|
env := newAdminEnvWith(t, []string{"acme.blog", "acme.shop"})
|
|
if err := env.gdb.Exec(`INSERT INTO golem15_user_frontend_permissions (code, label, tab) VALUES (?, 'Seeded label', 'Blog') ON CONFLICT (code) DO NOTHING`, acmeBlogSeeded).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var seeded int64
|
|
if err := env.gdb.Raw(`SELECT COUNT(*) FROM golem15_user_frontend_permissions`).Scan(&seeded).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
token := env.admin(t, permAccessUsers, permAccessGroups)
|
|
|
|
t.Run("second plugin's duplicate dropped", func(t *testing.T) {
|
|
for _, path := range []string{adminUsersPath, adminGroupsPath} {
|
|
options := env.permissionOptions(t, token, path)
|
|
declared := options[seeded:]
|
|
var codes []string
|
|
for _, o := range declared {
|
|
codes = append(codes, o.Code)
|
|
}
|
|
if len(declared) != 2 || declared[len(declared)-2].Code != acmeBlogManage || declared[len(declared)-2].Label != "Manage blog posts" ||
|
|
declared[len(declared)-1] != (offeredPermission{Code: acmeShopOrders, Label: "Manage orders", Tab: "Shop"}) {
|
|
t.Fatalf("%s declared options = %+v", path, declared)
|
|
}
|
|
seen := map[string]int{}
|
|
for _, o := range options {
|
|
seen[o.Code]++
|
|
if o.Code == "" || o.Code == " " {
|
|
t.Fatalf("%s offers an empty code", path)
|
|
}
|
|
}
|
|
if seen[acmeBlogManage] != 1 || seen[acmeShopOrders] != 1 {
|
|
t.Fatalf("%s codes offered %v (declared %v)", path, seen, codes)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("group saved with a declared code grants it", func(t *testing.T) {
|
|
stamp := adminStamp()
|
|
group := env.seedGroup(t, "Orders "+stamp, "orders-"+stamp)
|
|
member := env.seedUser(t, "orders", nil)
|
|
env.join(t, member, group)
|
|
env.expect(t, http.StatusOK, http.MethodPut, groupPath(group.ID), token, map[string]any{
|
|
"name": group.Name, "code": *group.Code, "permissions": map[string]int{acmeShopOrders: 1},
|
|
})
|
|
var saved models.UserGroup
|
|
if err := env.gdb.First(&saved, group.ID).Error; err != nil || saved.Permissions == nil || !strings.Contains(*saved.Permissions, `"`+acmeShopOrders+`"`) {
|
|
t.Fatalf("saved permissions = %v, %v", saved.Permissions, err)
|
|
}
|
|
grants, err := classes.UserPermissionGrants(context.Background(), env.gdb, member.ID)
|
|
if err != nil || !grants[acmeShopOrders] {
|
|
t.Fatalf("member grants = %v, %v", grants, err)
|
|
}
|
|
})
|
|
}
|