forked from wangziqi/gongxue-base
feat: add tenant role templates
This commit is contained in:
@@ -24,7 +24,15 @@ export interface TenantAdminAuth {
|
||||
tenantId: string;
|
||||
userId: string;
|
||||
role: string;
|
||||
roleTemplateId: string | null;
|
||||
roleTemplateCode: string | null;
|
||||
roleTemplateName: string | null;
|
||||
permissions: Record<string, unknown>;
|
||||
templatePermissions: Record<string, unknown>;
|
||||
menuPermissions: Record<string, unknown>;
|
||||
modulePermissions: Record<string, unknown>;
|
||||
fieldPermissions: Record<string, unknown>;
|
||||
dataScope: Record<string, unknown>;
|
||||
}
|
||||
|
||||
function permissionKeys(permission: string) {
|
||||
@@ -49,6 +57,9 @@ export function hasTenantPermission(auth: TenantAdminAuth, permission: string) {
|
||||
const explicit = explicitPermission(auth.permissions, permission);
|
||||
if (explicit !== null) return explicit;
|
||||
|
||||
const templateExplicit = explicitPermission(auth.templatePermissions, permission);
|
||||
if (templateExplicit !== null) return templateExplicit;
|
||||
|
||||
const defaults = ROLE_PERMISSION_DEFAULTS[auth.role] || [];
|
||||
return defaults.some(defaultPermission => {
|
||||
if (defaultPermission === '*') return true;
|
||||
@@ -93,9 +104,31 @@ export function tenantPermissionCatalog() {
|
||||
{ key: 'crm:write', label: 'CRM 入队和重试' },
|
||||
{ key: 'members:read', label: '成员查看' },
|
||||
{ key: 'members:write', label: '成员管理' },
|
||||
{ key: 'roles:read', label: '角色模板查看' },
|
||||
{ key: 'roles:write', label: '角色模板管理' },
|
||||
{ key: 'audit:read', label: '审计日志查看' },
|
||||
{ key: 'content:*', label: '内容维护' },
|
||||
],
|
||||
menuGroups: [
|
||||
{ key: 'dashboard', label: '数据看板' },
|
||||
{ key: 'content', label: '题库内容' },
|
||||
{ key: 'students', label: '学生管理' },
|
||||
{ key: 'teachers', label: '教师/班级' },
|
||||
{ key: 'marketing', label: '营销中心' },
|
||||
{ key: 'sales', label: '销售/代理' },
|
||||
{ key: 'crm', label: 'CRM' },
|
||||
{ key: 'commerce', label: '订单/权益' },
|
||||
{ key: 'settings', label: '租户设置' },
|
||||
{ key: 'audit', label: '审计日志' },
|
||||
],
|
||||
fieldGroups: [
|
||||
{ key: 'student.phone', label: '学生手机号' },
|
||||
{ key: 'student.wechat', label: '学生微信' },
|
||||
{ key: 'student.exam_intent', label: '考试意向' },
|
||||
{ key: 'order.amount', label: '订单金额' },
|
||||
{ key: 'referral.owner', label: '客资归属' },
|
||||
{ key: 'payment.secret_mask', label: '商户密钥掩码' },
|
||||
],
|
||||
roleDefaults: ROLE_PERMISSION_DEFAULTS,
|
||||
};
|
||||
}
|
||||
@@ -104,14 +137,37 @@ export async function requireTenantAdmin(ctx: RequestContext): Promise<TenantAdm
|
||||
const tenantId = await tenantIdFrom(ctx);
|
||||
const userId = await userIdFrom(ctx);
|
||||
|
||||
const membership = await queryOne<{ role: string; permissions: Record<string, unknown> }>(
|
||||
const membership = await queryOne<{
|
||||
role: string;
|
||||
roleTemplateId: string | null;
|
||||
roleTemplateCode: string | null;
|
||||
roleTemplateName: string | null;
|
||||
permissions: Record<string, unknown>;
|
||||
templatePermissions: Record<string, unknown>;
|
||||
menuPermissions: Record<string, unknown>;
|
||||
modulePermissions: Record<string, unknown>;
|
||||
fieldPermissions: Record<string, unknown>;
|
||||
dataScope: Record<string, unknown>;
|
||||
}>(
|
||||
`
|
||||
select role, permissions
|
||||
from public.tenant_memberships
|
||||
where tenant_id = $1
|
||||
and user_id = $2
|
||||
and status = 'active'
|
||||
and role = any($3::text[])
|
||||
select tm.role, tm.permissions,
|
||||
tm.role_template_id as "roleTemplateId",
|
||||
rt.code as "roleTemplateCode",
|
||||
rt.name as "roleTemplateName",
|
||||
coalesce(rt.permissions, '{}'::jsonb) as "templatePermissions",
|
||||
coalesce(rt.menu_permissions, '{}'::jsonb) as "menuPermissions",
|
||||
coalesce(rt.module_permissions, '{}'::jsonb) as "modulePermissions",
|
||||
coalesce(rt.field_permissions, '{}'::jsonb) as "fieldPermissions",
|
||||
coalesce(rt.data_scope, '{}'::jsonb) as "dataScope"
|
||||
from public.tenant_memberships tm
|
||||
left join public.tenant_role_templates rt
|
||||
on rt.id = tm.role_template_id
|
||||
and rt.tenant_id = tm.tenant_id
|
||||
and rt.status = 'active'
|
||||
where tm.tenant_id = $1
|
||||
and tm.user_id = $2
|
||||
and tm.status = 'active'
|
||||
and tm.role = any($3::text[])
|
||||
order by case role
|
||||
when 'tenant_owner' then 1
|
||||
when 'tenant_admin' then 2
|
||||
@@ -126,5 +182,18 @@ export async function requireTenantAdmin(ctx: RequestContext): Promise<TenantAdm
|
||||
throw new HttpError(403, 'Tenant admin access is required', 'TENANT_ADMIN_REQUIRED');
|
||||
}
|
||||
|
||||
return { tenantId, userId, role: membership.role, permissions: membership.permissions || {} };
|
||||
return {
|
||||
tenantId,
|
||||
userId,
|
||||
role: membership.role,
|
||||
roleTemplateId: membership.roleTemplateId,
|
||||
roleTemplateCode: membership.roleTemplateCode,
|
||||
roleTemplateName: membership.roleTemplateName,
|
||||
permissions: membership.permissions || {},
|
||||
templatePermissions: membership.templatePermissions || {},
|
||||
menuPermissions: membership.menuPermissions || {},
|
||||
modulePermissions: membership.modulePermissions || {},
|
||||
fieldPermissions: membership.fieldPermissions || {},
|
||||
dataScope: membership.dataScope || {},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user