diff --git a/.gitignore b/.gitignore index 2a16763..efe24ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /media/ /redis/ /sqlite/ +/db.sqlite3* # 本地工具目录 .agents/ diff --git a/CLAUDE.md b/CLAUDE.md index e5df0f0..20a3c1d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,6 +67,10 @@ docker compose run --rm webpreview-api bun scripts/create-superuser.ts { password: z.string().min(6).max(20), }), ) - if (userExists(payload.username)) throw new HttpError(400, "用户已存在") await insertUser(payload) return c.json({ message: "创建成功" }) }) @@ -148,6 +150,8 @@ router.post("/batch", async (c) => { ) const ts = now() tx(() => { + // 算哈希期间可能有人建了同名用户,插入前在同一个同步事务里再查一次 + if (usernames.some(userExists)) throw new HttpError(400, "有些用户已经存在,创建失败") for (const u of users) { run( `INSERT INTO account_user @@ -172,7 +176,6 @@ router.post("/create", async (c) => { classname: z.string().trim().max(50).default(""), }), ) - if (userExists(payload.username)) throw new HttpError(400, "用户已存在") const id = await insertUser(payload) return c.json({ id, message: "创建成功" }) }) diff --git a/server/src/routes/files.ts b/server/src/routes/files.ts index 206599d..4a1a08e 100644 --- a/server/src/routes/files.ts +++ b/server/src/routes/files.ts @@ -96,15 +96,12 @@ for (const kind of ["challenge", "tutorial"] as const) { `tasks/${task.task_type}/${task.display}/${validFilename(name)}`, file, ) - if (existing) { - run(`UPDATE task_taskasset SET file = $file WHERE id = $id`, { file: stored, id: existing.id }) - } else { - run(`INSERT INTO task_taskasset (name, file, task_id) VALUES ($name, $file, $task_id)`, { - name, - file: stored, - task_id: task.id, - }) - } + // 上面 await 期间可能有同名上传先写入了,用 upsert 而不是按 existing 选 INSERT / UPDATE + run( + `INSERT INTO task_taskasset (name, file, task_id) VALUES ($name, $file, $task_id) + ON CONFLICT (task_id, name) DO UPDATE SET file = excluded.file`, + { name, file: stored, task_id: task.id }, + ) return c.json(assetOut({ name, file: stored })) })