gongxiangp2/lib/department-permission.ts

326 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { prisma } from './prisma';
/**
* 判断是否是超级管理员(从数据库读取)
*/
export async function isSuperAdmin(userId: string | null | undefined): Promise<boolean> {
if (!userId) {
return false;
}
const user = await prisma.user.findUnique({
where: { id: userId },
select: { isSuperAdmin: true },
});
return user?.isSuperAdmin ?? false;
}
/**
* 同步版本的超级管理员判断(用于已经获取到用户信息的情况)
*/
export function isSuperAdminSync(isSuperAdmin: boolean): boolean {
return isSuperAdmin;
}
/**
* 获取当前超级管理员数量
*/
export async function getSuperAdminCount(): Promise<number> {
return await prisma.user.count({
where: { isSuperAdmin: true },
});
}
/**
* 检查是否可以添加新的超级管理员(最多4个)
*/
export async function canAddSuperAdmin(): Promise<boolean> {
const count = await getSuperAdminCount();
return count < 4;
}
// 默认素材类型列表(作为后备,用于新部门创建默认权限配置时)
// 如果数据库中已有素材,会优先使用数据库中的素材类型
export const DEFAULT_MATERIAL_TYPES = [
'3D场景',
'详情页',
'材质',
'模特',
'实拍图片',
'买家秀图片',
'小红书种草',
'主图模版',
'SKU模版',
'主图视频',
'安装视频',
'种草视频',
'音乐',
'C4D模型',
'标准饰品',
'标准模型',
'品牌VI灵感',
'矢量文件',
'CAD',
] as const;
/**
* 从数据库中获取所有素材类型(去重)
*/
export async function getAllMaterialTypes(): Promise<string[]> {
try {
// 从materials表中查询所有不重复的materialType
const materials = await prisma.material.findMany({
select: {
materialType: true,
},
distinct: ['materialType'],
});
const dbTypes = materials.map((m) => m.materialType).filter(Boolean);
// 合并数据库中的类型和默认类型,去重并排序
const allTypes = Array.from(new Set([...dbTypes, ...DEFAULT_MATERIAL_TYPES])).sort();
return allTypes;
} catch (error) {
console.error('[getAllMaterialTypes] Error:', error);
// 如果查询失败,返回默认类型列表
return [...DEFAULT_MATERIAL_TYPES];
}
}
export interface DepartmentPermission {
department: string;
materialType: string;
canView: boolean;
canDownload: boolean;
canShare: boolean;
linkedToDepartment: string | null;
}
/**
* 获取部门的实际权限(考虑关联部门)
*/
export async function getDepartmentPermission(
department: string,
materialType: string
): Promise<DepartmentPermission | null> {
// 先查询当前部门的权限配置
const permission = await prisma.departmentMaterialPermission.findUnique({
where: {
department_materialType: {
department,
materialType,
},
},
});
// 如果有关联部门,从关联部门读取权限
if (permission?.linkedToDepartment) {
const linkedPermission = await prisma.departmentMaterialPermission.findUnique({
where: {
department_materialType: {
department: permission.linkedToDepartment,
materialType,
},
},
});
if (linkedPermission) {
return {
department,
materialType,
canView: linkedPermission.canView,
canDownload: linkedPermission.canDownload,
canShare: linkedPermission.canShare,
linkedToDepartment: permission.linkedToDepartment,
};
}
}
if (!permission) {
return null;
}
return {
department: permission.department,
materialType: permission.materialType,
canView: permission.canView,
canDownload: permission.canDownload,
canShare: permission.canShare,
linkedToDepartment: permission.linkedToDepartment,
};
}
/**
* 获取部门所有素材类型的权限
*/
export async function getDepartmentPermissions(
department: string
): Promise<Record<string, DepartmentPermission>> {
const permissions = await prisma.departmentMaterialPermission.findMany({
where: { department },
});
const result: Record<string, DepartmentPermission> = {};
for (const perm of permissions) {
// 如果有关联部门,从关联部门读取
if (perm.linkedToDepartment) {
const linkedPerm = await prisma.departmentMaterialPermission.findUnique({
where: {
department_materialType: {
department: perm.linkedToDepartment,
materialType: perm.materialType,
},
},
});
if (linkedPerm) {
result[perm.materialType] = {
department,
materialType: perm.materialType,
canView: linkedPerm.canView,
canDownload: linkedPerm.canDownload,
canShare: linkedPerm.canShare,
linkedToDepartment: perm.linkedToDepartment,
};
}
} else {
result[perm.materialType] = {
department: perm.department,
materialType: perm.materialType,
canView: perm.canView,
canDownload: perm.canDownload,
canShare: perm.canShare,
linkedToDepartment: null,
};
}
}
return result;
}
/**
* 获取用户有查看权限的素材类型列表
*/
export async function getUserViewableMaterialTypes(
userDepartment: string | null | undefined,
userRole: string,
managedDepartment: string | null | undefined,
userId?: string | null | undefined
): Promise<string[]> {
// 超级管理员可以看到所有素材类型
if (userId && await isSuperAdmin(userId)) {
return await getAllMaterialTypes();
}
// 如果没有部门信息,返回空数组
const department = managedDepartment || userDepartment;
if (!department) {
return [];
}
// 获取该部门所有素材类型的权限
const permissions = await getDepartmentPermissions(department);
// 返回有查看权限的素材类型
return Object.values(permissions)
.filter((p) => p.canView)
.map((p) => p.materialType);
}
/**
* 检查用户是否有查看权限
*/
export async function canUserViewMaterial(
userDepartment: string | null | undefined,
userRole: string,
managedDepartment: string | null | undefined,
materialType: string,
userId?: string | null | undefined
): Promise<boolean> {
// 超级管理员可以查看所有素材
if (userId && await isSuperAdmin(userId)) {
return true;
}
// 如果没有部门信息,不允许查看
const department = managedDepartment || userDepartment;
if (!department) {
return false;
}
const permission = await getDepartmentPermission(department, materialType);
return permission?.canView ?? false;
}
/**
* 检查用户是否有下载权限
*/
export async function canUserDownloadMaterial(
userDepartment: string | null | undefined,
userRole: string,
managedDepartment: string | null | undefined,
materialType: string,
userId?: string | null | undefined
): Promise<boolean> {
// 超级管理员可以下载所有素材
if (userId && await isSuperAdmin(userId)) {
return true;
}
// 如果没有部门信息,不允许下载
const department = managedDepartment || userDepartment;
if (!department) {
return false;
}
const permission = await getDepartmentPermission(department, materialType);
return permission?.canDownload ?? false;
}
/**
* 检查是否是分享链接访问
*/
export function isShareLinkAccess(request: Request): boolean {
const url = new URL(request.url);
return url.searchParams.has('share') || url.searchParams.has('shareId');
}
/**
* 为部门创建默认权限配置
* 使用数据库中实际存在的所有素材类型
*/
export async function createDefaultPermissionsForDepartment(
department: string
): Promise<void> {
const existingPermissions = await prisma.departmentMaterialPermission.findMany({
where: { department },
});
const existingTypes = new Set(existingPermissions.map((p: any) => p.materialType));
// 获取数据库中所有素材类型
const allMaterialTypes = await getAllMaterialTypes();
const newPermissions = allMaterialTypes
.filter((type) => !existingTypes.has(type))
.map((materialType) => ({
department,
materialType,
canView: false, // 默认不允许查看
canDownload: false, // 默认不允许下载
canShare: true, // 默认允许分享
linkedToDepartment: null,
}));
if (newPermissions.length > 0) {
await prisma.departmentMaterialPermission.createMany({
data: newPermissions,
});
}
}