task-l
This commit is contained in:
151
src/lib/auth/crm-access.ts
Normal file
151
src/lib/auth/crm-access.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { and, eq, isNull } from 'drizzle-orm';
|
||||
import { crmRoleProfiles, memberships } from '@/db/schema';
|
||||
import { db } from '@/lib/db';
|
||||
import {
|
||||
ALL_PERMISSIONS,
|
||||
type CrmApprovalAuthority,
|
||||
type CrmOwnershipScope,
|
||||
type CrmScopeMode,
|
||||
getDefaultBusinessRole,
|
||||
getRoleProfileDefinition,
|
||||
isApprovalAuthority,
|
||||
isMembershipRole,
|
||||
isOwnershipScope,
|
||||
isScopeMode,
|
||||
resolveEffectivePermissions,
|
||||
type MembershipRole,
|
||||
type Permission,
|
||||
type SystemRole
|
||||
} from './rbac';
|
||||
|
||||
export interface ResolvedCrmAccess {
|
||||
membershipRole: MembershipRole;
|
||||
businessRole: string;
|
||||
permissions: Permission[];
|
||||
branchScopeIds: string[];
|
||||
productTypeScopeIds: string[];
|
||||
ownershipScope: CrmOwnershipScope;
|
||||
branchScopeMode: CrmScopeMode;
|
||||
productScopeMode: CrmScopeMode;
|
||||
approvalAuthority: CrmApprovalAuthority;
|
||||
roleProfileName: string | null;
|
||||
}
|
||||
|
||||
type BranchScopedAccess = Pick<
|
||||
ResolvedCrmAccess,
|
||||
'branchScopeMode' | 'branchScopeIds'
|
||||
> | {
|
||||
branchScopeMode: string;
|
||||
branchScopeIds: string[];
|
||||
};
|
||||
|
||||
type ProductScopedAccess = Pick<
|
||||
ResolvedCrmAccess,
|
||||
'productScopeMode' | 'productTypeScopeIds'
|
||||
> | {
|
||||
productScopeMode: string;
|
||||
productTypeScopeIds: string[];
|
||||
};
|
||||
|
||||
function normalizeStringArray(value: unknown) {
|
||||
return Array.isArray(value)
|
||||
? [...new Set(value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0))]
|
||||
: [];
|
||||
}
|
||||
|
||||
export async function resolveCrmMembershipAccess(input: {
|
||||
systemRole: SystemRole;
|
||||
organizationId: string;
|
||||
membership: typeof memberships.$inferSelect;
|
||||
}): Promise<ResolvedCrmAccess> {
|
||||
if (input.systemRole === 'super_admin') {
|
||||
return {
|
||||
membershipRole: 'admin',
|
||||
businessRole: input.membership.businessRole,
|
||||
permissions: ALL_PERMISSIONS,
|
||||
branchScopeIds: [],
|
||||
productTypeScopeIds: [],
|
||||
ownershipScope: 'organization',
|
||||
branchScopeMode: 'all',
|
||||
productScopeMode: 'all',
|
||||
approvalAuthority: 'final',
|
||||
roleProfileName: 'System Admin'
|
||||
};
|
||||
}
|
||||
|
||||
const membershipRole = isMembershipRole(input.membership.role)
|
||||
? input.membership.role
|
||||
: 'user';
|
||||
const businessRole = input.membership.businessRole || getDefaultBusinessRole(membershipRole);
|
||||
const [roleProfile] = await db
|
||||
.select()
|
||||
.from(crmRoleProfiles)
|
||||
.where(
|
||||
and(
|
||||
eq(crmRoleProfiles.organizationId, input.organizationId),
|
||||
eq(crmRoleProfiles.code, businessRole),
|
||||
eq(crmRoleProfiles.isActive, true),
|
||||
isNull(crmRoleProfiles.deletedAt)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
const defaultDefinition = getRoleProfileDefinition(businessRole);
|
||||
|
||||
const ownershipScope: CrmOwnershipScope = isOwnershipScope(roleProfile?.ownershipScope ?? '')
|
||||
? (roleProfile.ownershipScope as CrmOwnershipScope)
|
||||
: (defaultDefinition?.ownershipScope ?? 'own');
|
||||
const branchScopeMode: CrmScopeMode = isScopeMode(roleProfile?.branchScopeMode ?? '')
|
||||
? (roleProfile.branchScopeMode as CrmScopeMode)
|
||||
: (defaultDefinition?.branchScopeMode ?? 'assigned');
|
||||
const productScopeMode: CrmScopeMode = isScopeMode(roleProfile?.productScopeMode ?? '')
|
||||
? (roleProfile.productScopeMode as CrmScopeMode)
|
||||
: (defaultDefinition?.productScopeMode ?? 'assigned');
|
||||
const approvalAuthority: CrmApprovalAuthority = isApprovalAuthority(
|
||||
roleProfile?.approvalAuthority ?? ''
|
||||
)
|
||||
? (roleProfile.approvalAuthority as CrmApprovalAuthority)
|
||||
: (defaultDefinition?.approvalAuthority ?? 'none');
|
||||
|
||||
return {
|
||||
membershipRole,
|
||||
businessRole,
|
||||
permissions: resolveEffectivePermissions({
|
||||
systemRole: input.systemRole,
|
||||
membershipRole,
|
||||
businessRole,
|
||||
rolePermissions: roleProfile?.permissions ?? defaultDefinition?.permissions ?? [],
|
||||
directPermissions: input.membership.permissions
|
||||
}),
|
||||
branchScopeIds: normalizeStringArray(input.membership.branchScopeIds),
|
||||
productTypeScopeIds: normalizeStringArray(input.membership.productTypeScopeIds),
|
||||
ownershipScope,
|
||||
branchScopeMode,
|
||||
productScopeMode,
|
||||
approvalAuthority,
|
||||
roleProfileName: roleProfile?.name ?? defaultDefinition?.name ?? null
|
||||
};
|
||||
}
|
||||
|
||||
export function hasBranchScopeAccess(access: BranchScopedAccess, branchId?: string | null) {
|
||||
if (!branchId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (access.branchScopeMode === 'all' || access.branchScopeIds.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return access.branchScopeIds.includes(branchId);
|
||||
}
|
||||
|
||||
export function hasProductScopeAccess(access: ProductScopedAccess, productTypeId?: string | null) {
|
||||
if (!productTypeId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (access.productScopeMode === 'all' || access.productTypeScopeIds.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return access.productTypeScopeIds.includes(productTypeId);
|
||||
}
|
||||
Reference in New Issue
Block a user