feat: 接入真实登录与成员权限

- auth/members/messages: 新增超级管理员登录、成员权限和密码消息流程
- agent-config/agent: 支持服务端保存 Agent 配置并取消未配置 mock 成功结果
- projects/deploy-runs/settings: 按当前用户权限保护真实接口
- prisma: 新增用户、项目权限和平台消息表结构
This commit is contained in:
湛兮
2026-06-12 00:38:23 +08:00
parent cf1bebf625
commit bc3aa31289
83 changed files with 3844 additions and 378 deletions
+43 -23
View File
@@ -1,4 +1,5 @@
import { AuditService } from '../audit/audit.service';
import { AuthService } from '../auth/auth.service';
import { AppError } from '../common/errors/app-error';
import { DeployNotificationService } from '../notifications/wecom/deploy-notification.service';
import { JenkinsClient } from '../integrations/jenkins/jenkins.client';
@@ -58,30 +59,36 @@ describe('DeployRunsService', () => {
findById: jest.fn((id: string) =>
Promise.resolve(runs.find((run) => run.id === id) ?? null),
),
create: jest.fn((input: CreateDeployRunInput) => ({
...baseRun,
id: input.idempotencyKey ?? 'generated_run',
projectKey: input.projectKey,
environment: input.environment,
ref: input.ref,
operator: input.operator,
trigger: input.trigger ?? 'manual',
})),
create: jest.fn((input: CreateDeployRunInput) =>
Promise.resolve({
...baseRun,
id: input.idempotencyKey ?? 'generated_run',
projectKey: input.projectKey,
environment: input.environment,
ref: input.ref,
operator: input.operator,
trigger: input.trigger ?? 'manual',
}),
),
updateRun: jest.fn((id: string, patch: { status?: DeployRunStatus }) =>
runs.some((run) => run.id === id)
? {
...(runs.find((run) => run.id === id) ?? baseRun),
...patch,
}
: null,
Promise.resolve(
runs.some((run) => run.id === id)
? {
...(runs.find((run) => run.id === id) ?? baseRun),
...patch,
}
: null,
),
),
updateStep: jest.fn((id: string) =>
runs.some((run) => run.id === id)
? {
...(runs.find((run) => run.id === id) ?? baseRun),
status: 'canceled' as const,
}
: null,
Promise.resolve(
runs.some((run) => run.id === id)
? {
...(runs.find((run) => run.id === id) ?? baseRun),
status: 'canceled' as const,
}
: null,
),
),
} satisfies Pick<
DeployRunRepository,
@@ -130,10 +137,22 @@ describe('DeployRunsService', () => {
JenkinsClient,
'healthSummary' | 'cancelQueueItem' | 'stopBuild'
>;
const auth = {
listAllowedProjectKeys: jest.fn(() =>
Promise.resolve(runs.map((run) => run.projectKey)),
),
requireProjectPermission: jest.fn(() => Promise.resolve()),
assertSuperAdmin: jest.fn(),
} satisfies Pick<
AuthService,
'listAllowedProjectKeys' | 'requireProjectPermission' | 'assertSuperAdmin'
>;
return {
audit,
auth,
execution,
jenkins,
notification,
projects,
repository,
@@ -144,6 +163,7 @@ describe('DeployRunsService', () => {
notification as unknown as DeployNotificationService,
execution as unknown as DeployExecutionService,
jenkins as unknown as JenkinsClient,
auth as unknown as AuthService,
),
};
}
@@ -222,7 +242,7 @@ describe('DeployRunsService', () => {
expect.objectContaining({
action: 'DEPLOY_REJECTED',
after: expect.objectContaining({
reason: 'Environment is not configured',
reason: '环境未配置',
}),
}),
);
@@ -258,7 +278,7 @@ describe('DeployRunsService', () => {
expect.objectContaining({
action: 'DEPLOY_REJECTED',
after: expect.objectContaining({
reason: 'Ref does not match release policy',
reason: 'Ref 不符合发布策略',
}),
}),
);