import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { canDeleteExecutionByIdentity, canDeleteTaskByIdentity, canEditExecutionByIdentity, canEditTaskByIdentity } from '../src/views/project/project/execution/composables/task-permission-rules'; function createExecution(overrides: Partial = {}): Api.Project.ProjectExecution { return { id: 'execution-1', projectId: 'project-1', projectRequirementId: null, projectRequirementName: null, projectRequirementStatusCode: null, executionName: 'execution', executionType: null, ownerId: 'execution-owner', ownerNickname: null, statusCode: 'active', statusName: null, terminal: false, allowEdit: true, availableActions: [], plannedStartDate: null, plannedEndDate: null, actualStartDate: null, actualEndDate: null, progressRate: 0, priority: '2', priorityName: null, executionDesc: null, lastStatusReason: null, createTime: '2026-07-07 10:00:00', updateTime: '2026-07-07 10:00:00', ...overrides }; } function createTask(overrides: Partial = {}): Api.Project.ProjectTask { return { id: 'task-1', projectId: 'project-1', executionId: 'execution-1', executionName: '执行', executionStatusCode: 'active', parentTaskId: null, projectRequirementId: null, projectRequirementName: null, projectRequirementStatusCode: null, taskTitle: '任务', type: '', ownerId: 'task-owner', ownerNickname: null, executionOwnerId: 'execution-owner', parentTaskOwnerId: null, statusCode: 'active', statusName: null, terminal: false, allowEdit: true, availableActions: [], progressRate: 0, plannedStartDate: null, plannedEndDate: null, actualStartDate: null, actualEndDate: null, priority: '2', priorityName: null, taskDesc: null, lastStatusReason: null, assignees: null, attachments: [], totalSpentHours: null, createTime: '2026-07-07 10:00:00', updateTime: '2026-07-07 10:00:00', ...overrides }; } describe('task mutation permission rules', () => { it('allows task owner, execution owner, and project manager to edit mutable tasks', () => { const task = createTask(); assert.equal( canEditTaskByIdentity(task, { currentUserId: 'task-owner', projectManagerUserId: 'project-manager' }), true ); assert.equal( canEditTaskByIdentity(task, { currentUserId: 'execution-owner', projectManagerUserId: 'project-manager' }), true ); assert.equal( canEditTaskByIdentity(task, { currentUserId: 'project-manager', projectManagerUserId: 'project-manager' }), true ); }); it('does not allow unrelated users to edit just because they have a task permission code', () => { const task = createTask(); assert.equal( canEditTaskByIdentity(task, { currentUserId: 'developer', projectManagerUserId: 'project-manager' }), false ); }); it('uses the same identity rule for delete and only blocks completed tasks by status', () => { assert.equal( canDeleteTaskByIdentity(createTask({ statusCode: 'active' }), { currentUserId: 'execution-owner', projectManagerUserId: 'project-manager' }), true ); assert.equal( canDeleteTaskByIdentity(createTask({ statusCode: 'completed' }), { currentUserId: 'execution-owner', projectManagerUserId: 'project-manager' }), false ); }); }); describe('execution mutation permission rules', () => { it('allows only execution owner and project manager to edit mutable executions', () => { const execution = createExecution(); assert.equal( canEditExecutionByIdentity(execution, { currentUserId: 'execution-owner', projectManagerUserId: 'project-manager' }), true ); assert.equal( canEditExecutionByIdentity(execution, { currentUserId: 'project-manager', projectManagerUserId: 'project-manager' }), true ); assert.equal( canEditExecutionByIdentity(execution, { currentUserId: 'developer', projectManagerUserId: 'project-manager' }), false ); }); it('uses the same identity rule for delete and only blocks completed executions by status', () => { assert.equal( canDeleteExecutionByIdentity(createExecution({ statusCode: 'active' }), { currentUserId: 'execution-owner', projectManagerUserId: 'project-manager' }), true ); assert.equal( canDeleteExecutionByIdentity(createExecution({ statusCode: 'active' }), { currentUserId: 'developer', projectManagerUserId: 'project-manager' }), false ); assert.equal( canDeleteExecutionByIdentity(createExecution({ statusCode: 'completed' }), { currentUserId: 'execution-owner', projectManagerUserId: 'project-manager' }), false ); }); });