fix(projects): 执行和任务的按钮控制
This commit is contained in:
179
tests/task-permission-rules.test.ts
Normal file
179
tests/task-permission-rules.test.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
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> = {}): 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> = {}): 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
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user