diff --git a/app/api/organization/permission-groups/route.test.ts b/app/api/organization/permission-groups/route.test.ts new file mode 100644 index 0000000..522eb94 --- /dev/null +++ b/app/api/organization/permission-groups/route.test.ts @@ -0,0 +1,80 @@ +/** @jest-environment node */ + +import { getServerSession } from 'next-auth' +import { prisma } from '@/lib/prisma' +import { isSuperAdmin } from '@/lib/department-permission' +import { savePermissionPackItems } from '@/lib/user-permission-inherit' + +jest.mock('next-auth', () => ({ + getServerSession: jest.fn(), +})) + +jest.mock('@/lib/auth', () => ({ + authOptions: {}, +})) + +jest.mock('@/lib/prisma', () => ({ + prisma: { + materialPermissionPack: { + findUnique: jest.fn(), + }, + }, +})) + +jest.mock('@/lib/department-permission', () => ({ + getAllMaterialTypes: jest.fn(), + isSuperAdmin: jest.fn(), +})) + +jest.mock('@/lib/user-permission-inherit', () => ({ + ensureDefaultPermissionPacks: jest.fn(), + packItemsToMap: jest.fn(), + savePermissionPackItems: jest.fn(), +})) + +jest.mock('@/lib/permission-groups', () => ({ + findConflictingDepartmentGroup: jest.fn(), + makePermissionGroupSlug: jest.fn(), + seedDefaultGroupDepartments: jest.fn(), +})) + +const { PUT } = require('@/app/api/organization/permission-groups/route') as typeof import('@/app/api/organization/permission-groups/route') + +describe('/api/organization/permission-groups 保存权限', () => { + beforeEach(() => { + jest.clearAllMocks() + ;(getServerSession as jest.Mock).mockResolvedValue({ user: { id: 'super-admin' } }) + ;(isSuperAdmin as jest.Mock).mockResolvedValue(true) + ;(prisma.materialPermissionPack.findUnique as jest.Mock).mockResolvedValue({ + id: 'visual-pack', + slug: 'visual', + name: '视觉', + }) + }) + + test('任务详情编辑图片勾选值应原样保存,不能回退为 false', async () => { + const response = await PUT({ + json: async () => ({ + action: 'save-pack', + slug: 'visual', + permissions: [ + { + materialType: '任务-详情', + canView: true, + canDownload: true, + canDownloadSource: true, + canEditAssets: true, + }, + ], + }), + } as never) + + expect(response.status).toBe(200) + expect(savePermissionPackItems).toHaveBeenCalledWith('visual', [ + expect.objectContaining({ + materialType: '任务-详情', + canEditAssets: true, + }), + ]) + }) +}) diff --git a/lib/__tests__/department-permission-roster.test.ts b/lib/__tests__/department-permission-roster.test.ts index 9e5703c..c628da8 100644 --- a/lib/__tests__/department-permission-roster.test.ts +++ b/lib/__tests__/department-permission-roster.test.ts @@ -2,6 +2,7 @@ import { canUserViewMaterial, getUserViewableMaterialTypes } from '@/lib/department-permission' import { prisma } from '@/lib/prisma' +import { canUserEditTaskDetailAssets } from '@/lib/user-permission-inherit' jest.mock('@/lib/prisma', () => ({ prisma: { @@ -132,6 +133,46 @@ describe('roster material visibility', () => { ]) }) + test('部门权限组勾选任务详情编辑图片后,运行时读取该授权', async () => { + ;(prisma.userEmployeeBinding.findFirst as jest.Mock).mockResolvedValue({ + employeeProfile: { + departmentPath: '江苏简尚品牌管理有限公司/品牌中心/空间视觉部', + }, + }) + ;(prisma.materialPermissionPackDepartment.findMany as jest.Mock).mockResolvedValue([ + { + departmentPath: '江苏简尚品牌管理有限公司/品牌中心', + pack: { + items: [ + { + materialType: '任务-详情', + canView: true, + canDownload: true, + canDownloadSource: true, + canShare: true, + canEditAssets: true, + }, + ], + }, + }, + ]) + + await expect(canUserEditTaskDetailAssets('visual-department-member')).resolves.toBe(true) + expect(prisma.materialPermissionPackDepartment.findMany).toHaveBeenCalledWith( + expect.objectContaining({ + select: expect.objectContaining({ + pack: { + select: { + items: { + select: expect.objectContaining({ canEditAssets: true }), + }, + }, + }, + }), + }), + ) + }) + test('人进多组时,各组能看的取并集', async () => { ;(prisma.userEmployeeBinding.findFirst as jest.Mock).mockResolvedValue({ employeeProfile: { diff --git a/lib/permission-groups.ts b/lib/permission-groups.ts index 9e831fb..f3be4c0 100644 --- a/lib/permission-groups.ts +++ b/lib/permission-groups.ts @@ -22,6 +22,7 @@ const PACK_ITEM_SELECT = { canDownload: true, canDownloadSource: true, canShare: true, + canEditAssets: true, } as const function packTargetDepartment(slug: string): string | null {