fix: 删除项目时先清理关联数据,避免外键约束报错
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m2s

- 删除项目前清理 userProjectPermissions、projectRepos、OKR 数据
- 修复 admin 和普通路由两处删除逻辑

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
zyc 2026-04-14 13:46:31 +08:00
parent 17696f9049
commit 18e3ee18da
2 changed files with 25 additions and 1 deletions

View File

@ -5,7 +5,7 @@ import { eq, desc } from 'drizzle-orm';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import { db } from '../db/index'; import { db } from '../db/index';
import { users, authorMappings, syncLogs, projects, projectRepos, gitCommits, gitPRs, userProjectPermissions } from '../db/schema'; import { users, authorMappings, syncLogs, projects, projectRepos, gitCommits, gitPRs, userProjectPermissions, objectives, keyResults, krLogs } from '../db/schema';
import { requireRole } from '../middleware/role'; import { requireRole } from '../middleware/role';
import { AppError } from '../middleware/error-handler'; import { AppError } from '../middleware/error-handler';
@ -178,6 +178,17 @@ adminRoutes.patch('/admin/projects/:id', zValidator('json', updateProjectSchema)
adminRoutes.delete('/admin/projects/:id', async (c) => { adminRoutes.delete('/admin/projects/:id', async (c) => {
const id = c.req.param('id'); const id = c.req.param('id');
await db.delete(userProjectPermissions).where(eq(userProjectPermissions.projectId, id));
await db.delete(projectRepos).where(eq(projectRepos.projectId, id));
const objs = await db.select().from(objectives).where(eq(objectives.projectId, id));
for (const obj of objs) {
const krs = await db.select().from(keyResults).where(eq(keyResults.objectiveId, obj.id));
for (const kr of krs) {
await db.delete(krLogs).where(eq(krLogs.krId, kr.id));
}
await db.delete(keyResults).where(eq(keyResults.objectiveId, obj.id));
}
await db.delete(objectives).where(eq(objectives.projectId, id));
await db.delete(projects).where(eq(projects.id, id)); await db.delete(projects).where(eq(projects.id, id));
return c.json({ code: 0, data: null, message: 'success' }); return c.json({ code: 0, data: null, message: 'success' });
}); });

View File

@ -76,6 +76,19 @@ projectRoutes.delete('/projects/:id',
requireRole('admin'), requireRole('admin'),
async (c) => { async (c) => {
const id = c.req.param('id'); const id = c.req.param('id');
// 先清理关联数据(外键约束)
await db.delete(userProjectPermissions).where(eq(userProjectPermissions.projectId, id));
await db.delete(projectRepos).where(eq(projectRepos.projectId, id));
// 清理 OKRKR logs → KR → Objectives
const objs = await db.select().from(objectives).where(eq(objectives.projectId, id));
for (const obj of objs) {
const krs = await db.select().from(keyResults).where(eq(keyResults.objectiveId, obj.id));
for (const kr of krs) {
await db.delete(krLogs).where(eq(krLogs.krId, kr.id));
}
await db.delete(keyResults).where(eq(keyResults.objectiveId, obj.id));
}
await db.delete(objectives).where(eq(objectives.projectId, id));
await db.delete(projects).where(eq(projects.id, id)); await db.delete(projects).where(eq(projects.id, id));
return c.json({ code: 0, data: null, message: 'success' }); return c.json({ code: 0, data: null, message: 'success' });
} }