refactor(permissions): 精简默认权限组初始化逻辑
- 将固定默认权限组收敛为基础组,并新增对历史默认权限组的清理流程。 - 兼容保留已被用户引用的旧权限组,避免误删现有授权关系。 - 更新测试以覆盖新权限组创建与旧权限组迁移场景。
This commit is contained in:
@@ -912,7 +912,7 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
t.Fatalf("missing fixed permission group %s in %+v", group.ID, groups.Items)
|
t.Fatalf("missing fixed permission group %s in %+v", group.ID, groups.Items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if groups.Items[0].ID != PermissionGroupSuperAdmin || groups.Items[1].ID != PermissionGroupRegular || groupByID[PermissionGroupMailboxAdmin].UserCount != 0 {
|
if groups.Items[0].ID != PermissionGroupSuperAdmin || groups.Items[1].ID != PermissionGroupRegular {
|
||||||
t.Fatalf("unexpected fixed permission groups: %+v", groups.Items)
|
t.Fatalf("unexpected fixed permission groups: %+v", groups.Items)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,14 +931,14 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
if customGroup.System || customGroup.ID == "" || !userHasPermission(&User{Role: "user", Permissions: customGroup.Permissions}, PermissionMailboxesView) || userHasPermission(&User{Role: "user", Permissions: customGroup.Permissions}, PermissionMailboxesCreate) {
|
if customGroup.System || customGroup.ID == "" || !userHasPermission(&User{Role: "user", Permissions: customGroup.Permissions}, PermissionMailboxesView) || userHasPermission(&User{Role: "user", Permissions: customGroup.Permissions}, PermissionMailboxesCreate) {
|
||||||
t.Fatalf("custom permission group permissions=%+v", customGroup)
|
t.Fatalf("custom permission group permissions=%+v", customGroup)
|
||||||
}
|
}
|
||||||
if code := admin.do("POST", "/api/admin/permission-groups/"+PermissionGroupMailboxAdmin, map[string]any{
|
if code := admin.do("POST", "/api/admin/permission-groups/"+PermissionGroupSuperAdmin, map[string]any{
|
||||||
"name": "Changed",
|
"name": "Changed",
|
||||||
"description": "Should not change",
|
"description": "Should not change",
|
||||||
"permissions": []string{PermissionMailboxesView},
|
"permissions": []string{PermissionMailboxesView},
|
||||||
}, &errBody); code != http.StatusForbidden {
|
}, &errBody); code != http.StatusForbidden {
|
||||||
t.Fatalf("system permission group update should be forbidden code=%d body=%v", code, errBody)
|
t.Fatalf("system permission group update should be forbidden code=%d body=%v", code, errBody)
|
||||||
}
|
}
|
||||||
if code := admin.do("DELETE", "/api/admin/permission-groups/"+PermissionGroupMailboxAdmin, nil, &errBody); code != http.StatusForbidden {
|
if code := admin.do("DELETE", "/api/admin/permission-groups/"+PermissionGroupSuperAdmin, nil, &errBody); code != http.StatusForbidden {
|
||||||
t.Fatalf("system permission group delete should be forbidden code=%d body=%v", code, errBody)
|
t.Fatalf("system permission group delete should be forbidden code=%d body=%v", code, errBody)
|
||||||
}
|
}
|
||||||
if code := admin.do("POST", "/api/admin/users", map[string]any{
|
if code := admin.do("POST", "/api/admin/users", map[string]any{
|
||||||
@@ -952,6 +952,40 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
t.Fatalf("assigning super admin group should be rejected code=%d body=%v", code, errBody)
|
t.Fatalf("assigning super admin group should be rejected code=%d body=%v", code, errBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mailboxAdminGroup PermissionGroup
|
||||||
|
if code := admin.do("POST", "/api/admin/permission-groups", map[string]any{
|
||||||
|
"name": "Mailbox Admins",
|
||||||
|
"description": "Can manage mailboxes",
|
||||||
|
"permissions": []string{
|
||||||
|
PermissionAdminOverview,
|
||||||
|
PermissionUsersView,
|
||||||
|
PermissionDomainsView,
|
||||||
|
PermissionMailboxesView,
|
||||||
|
PermissionMailboxesCreate,
|
||||||
|
PermissionMailboxesUpdate,
|
||||||
|
PermissionMailboxesDelete,
|
||||||
|
},
|
||||||
|
}, &mailboxAdminGroup); code != http.StatusCreated {
|
||||||
|
t.Fatalf("create mailbox admin group code=%d group=%+v", code, mailboxAdminGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
var userAdminGroup PermissionGroup
|
||||||
|
if code := admin.do("POST", "/api/admin/permission-groups", map[string]any{
|
||||||
|
"name": "User Admins",
|
||||||
|
"description": "Can manage users",
|
||||||
|
"permissions": []string{
|
||||||
|
PermissionAdminOverview,
|
||||||
|
PermissionUsersView,
|
||||||
|
PermissionUsersCreate,
|
||||||
|
PermissionUsersUpdate,
|
||||||
|
PermissionUsersDelete,
|
||||||
|
PermissionUsersResetPassword,
|
||||||
|
PermissionGroupsView,
|
||||||
|
},
|
||||||
|
}, &userAdminGroup); code != http.StatusCreated {
|
||||||
|
t.Fatalf("create user admin group code=%d group=%+v", code, userAdminGroup)
|
||||||
|
}
|
||||||
|
|
||||||
var mailboxUser AdminUser
|
var mailboxUser AdminUser
|
||||||
if code := admin.do("POST", "/api/admin/users", map[string]any{
|
if code := admin.do("POST", "/api/admin/users", map[string]any{
|
||||||
"email": "mailbox-admin@lanqin.local",
|
"email": "mailbox-admin@lanqin.local",
|
||||||
@@ -959,11 +993,11 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
"role": "user",
|
"role": "user",
|
||||||
"password": "Password123!",
|
"password": "Password123!",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"permissionGroupIds": []string{PermissionGroupMailboxAdmin},
|
"permissionGroupIds": []string{mailboxAdminGroup.ID},
|
||||||
}, &mailboxUser); code != http.StatusCreated {
|
}, &mailboxUser); code != http.StatusCreated {
|
||||||
t.Fatalf("create mailbox admin user code=%d user=%+v", code, mailboxUser)
|
t.Fatalf("create mailbox admin user code=%d user=%+v", code, mailboxUser)
|
||||||
}
|
}
|
||||||
if mailboxUser.Role != "user" || len(mailboxUser.PermissionGroupIDs) != 1 || mailboxUser.PermissionGroupIDs[0] != PermissionGroupMailboxAdmin || !userHasPermission(&mailboxUser.User, PermissionMailboxesManage) || userHasPermission(&mailboxUser.User, PermissionSystemSettings) {
|
if mailboxUser.Role != "user" || len(mailboxUser.PermissionGroupIDs) != 1 || mailboxUser.PermissionGroupIDs[0] != mailboxAdminGroup.ID || !userHasPermission(&mailboxUser.User, PermissionMailboxesManage) || userHasPermission(&mailboxUser.User, PermissionSystemSettings) {
|
||||||
t.Fatalf("mailbox admin authorization=%+v", mailboxUser.User)
|
t.Fatalf("mailbox admin authorization=%+v", mailboxUser.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1024,7 +1058,7 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
"role": "user",
|
"role": "user",
|
||||||
"password": "Password123!",
|
"password": "Password123!",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"permissionGroupIds": []string{PermissionGroupMailboxAdmin},
|
"permissionGroupIds": []string{mailboxAdminGroup.ID},
|
||||||
}, &errBody); code != http.StatusForbidden {
|
}, &errBody); code != http.StatusForbidden {
|
||||||
t.Fatalf("mailbox admin should not create users code=%d body=%v", code, errBody)
|
t.Fatalf("mailbox admin should not create users code=%d body=%v", code, errBody)
|
||||||
}
|
}
|
||||||
@@ -1036,7 +1070,7 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
"role": "user",
|
"role": "user",
|
||||||
"password": "Password123!",
|
"password": "Password123!",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"permissionGroupIds": []string{PermissionGroupUserAdmin},
|
"permissionGroupIds": []string{userAdminGroup.ID},
|
||||||
}, &userManager); code != http.StatusCreated {
|
}, &userManager); code != http.StatusCreated {
|
||||||
t.Fatalf("create user admin code=%d user=%+v", code, userManager)
|
t.Fatalf("create user admin code=%d user=%+v", code, userManager)
|
||||||
}
|
}
|
||||||
@@ -1053,7 +1087,7 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
"role": "user",
|
"role": "user",
|
||||||
"password": "Password123!",
|
"password": "Password123!",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"permissionGroupIds": []string{PermissionGroupMailboxAdmin},
|
"permissionGroupIds": []string{mailboxAdminGroup.ID},
|
||||||
}, &errBody); code != http.StatusBadRequest {
|
}, &errBody); code != http.StatusBadRequest {
|
||||||
t.Fatalf("user admin should not assign mailbox admin group code=%d body=%v", code, errBody)
|
t.Fatalf("user admin should not assign mailbox admin group code=%d body=%v", code, errBody)
|
||||||
}
|
}
|
||||||
@@ -1064,7 +1098,7 @@ func TestFixedRolesProtectAdminRoutesAndDefaultAdmin(t *testing.T) {
|
|||||||
"role": "user",
|
"role": "user",
|
||||||
"password": "Password123!",
|
"password": "Password123!",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"permissionGroupIds": []string{PermissionGroupUserAdmin},
|
"permissionGroupIds": []string{userAdminGroup.ID},
|
||||||
}, ®ularUser); code != http.StatusCreated {
|
}, ®ularUser); code != http.StatusCreated {
|
||||||
t.Fatalf("user admin should assign own group code=%d user=%+v", code, regularUser)
|
t.Fatalf("user admin should assign own group code=%d user=%+v", code, regularUser)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,17 @@ const (
|
|||||||
PermissionGroupSystemAdmin = "pg_system_admin"
|
PermissionGroupSystemAdmin = "pg_system_admin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var legacyDefaultPermissionGroupIDs = []string{
|
||||||
|
PermissionGroupUserAdmin,
|
||||||
|
PermissionGroupPermissionAdmin,
|
||||||
|
PermissionGroupDomainAdmin,
|
||||||
|
PermissionGroupDNSAdmin,
|
||||||
|
PermissionGroupMailboxAdmin,
|
||||||
|
PermissionGroupAliasAdmin,
|
||||||
|
PermissionGroupMessageAudit,
|
||||||
|
PermissionGroupSystemAdmin,
|
||||||
|
}
|
||||||
|
|
||||||
type PermissionInfo struct {
|
type PermissionInfo struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
@@ -257,117 +268,6 @@ func defaultPermissionGroups() []PermissionGroup {
|
|||||||
Permissions: []string{},
|
Permissions: []string{},
|
||||||
System: true,
|
System: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
ID: PermissionGroupUserAdmin,
|
|
||||||
Name: "用户管理员",
|
|
||||||
Description: "查看并管理用户账号、状态、密码和用户权限组分配。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionUsersView,
|
|
||||||
PermissionUsersCreate,
|
|
||||||
PermissionUsersUpdate,
|
|
||||||
PermissionUsersDelete,
|
|
||||||
PermissionUsersResetPassword,
|
|
||||||
PermissionGroupsView,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupPermissionAdmin,
|
|
||||||
Name: "权限组管理员",
|
|
||||||
Description: "管理自定义权限组和权限目录。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionGroupsView,
|
|
||||||
PermissionGroupsCreate,
|
|
||||||
PermissionGroupsUpdate,
|
|
||||||
PermissionGroupsDelete,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupDomainAdmin,
|
|
||||||
Name: "域名管理员",
|
|
||||||
Description: "查看、添加、启停和删除邮件域名。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionDomainsView,
|
|
||||||
PermissionDomainsCreate,
|
|
||||||
PermissionDomainsUpdate,
|
|
||||||
PermissionDomainsDelete,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupDNSAdmin,
|
|
||||||
Name: "DNS 检测员",
|
|
||||||
Description: "查看 DNS 记录并执行 DNS 检测。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionDomainsView,
|
|
||||||
PermissionDNSView,
|
|
||||||
PermissionDNSCheck,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupMailboxAdmin,
|
|
||||||
Name: "邮箱账号管理员",
|
|
||||||
Description: "查看用户和域名,创建、编辑和删除邮箱账号。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionUsersView,
|
|
||||||
PermissionDomainsView,
|
|
||||||
PermissionMailboxesView,
|
|
||||||
PermissionMailboxesCreate,
|
|
||||||
PermissionMailboxesUpdate,
|
|
||||||
PermissionMailboxesDelete,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupAliasAdmin,
|
|
||||||
Name: "别名转发管理员",
|
|
||||||
Description: "查看域名,创建、编辑和删除别名转发。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionDomainsView,
|
|
||||||
PermissionAliasesView,
|
|
||||||
PermissionAliasesCreate,
|
|
||||||
PermissionAliasesUpdate,
|
|
||||||
PermissionAliasesDelete,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupMessageAudit,
|
|
||||||
Name: "邮件审计员",
|
|
||||||
Description: "查看全局邮件列表、正文和附件。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionMailboxesView,
|
|
||||||
PermissionMessagesView,
|
|
||||||
PermissionMessagesRead,
|
|
||||||
PermissionMessagesAttachment,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: PermissionGroupSystemAdmin,
|
|
||||||
Name: "系统设置管理员",
|
|
||||||
Description: "查看并修改系统设置、SMTP 测试和邮件模板。",
|
|
||||||
Permissions: []string{
|
|
||||||
PermissionAdminOverview,
|
|
||||||
PermissionDomainsView,
|
|
||||||
PermissionSettingsView,
|
|
||||||
PermissionSettingsUpdate,
|
|
||||||
PermissionSettingsTestSMTP,
|
|
||||||
PermissionTemplatesView,
|
|
||||||
PermissionTemplatesUpdate,
|
|
||||||
PermissionTemplatesReset,
|
|
||||||
},
|
|
||||||
System: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,6 +319,28 @@ func (a *App) ensureDefaultPermissionGroups(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := a.cleanupLegacyDefaultPermissionGroups(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) cleanupLegacyDefaultPermissionGroups(ctx context.Context) error {
|
||||||
|
for _, groupID := range legacyDefaultPermissionGroupIDs {
|
||||||
|
var userCount int
|
||||||
|
if err := a.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM user_permission_groups WHERE group_id=?`, groupID).Scan(&userCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if userCount == 0 {
|
||||||
|
if _, err := a.db.ExecContext(ctx, `DELETE FROM permission_groups WHERE id=? AND system=1`, groupID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := a.db.ExecContext(ctx, `UPDATE permission_groups SET system=0, updated_at=? WHERE id=? AND system=1`, a.now().UTC().Format(time.RFC3339Nano), groupID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user