Deploy / deploy (push) Has been cancelled
原来只有 `apps/web` 在 Prettier 下(配置在 `apps/web/.prettierrc.toml`、脚本在 web 的 package.json),后端和契约从来没格式化过 —— 手写在 100 列上下,`db/schema.ts` 还是 drizzle-kit pull 留下的 tab 缩进。两套口径分叉久了,跨端改一处就得记着「这边 什么风格」。 - 配置搬到根目录 `.prettierrc.toml`,内容不变(`semi=false`,其余全默认, printWidth 80 —— 和前端已有的格式一致,不另立一套宽度); - 脚本统一成根目录 `bun run fmt`,覆盖 `apps/*/src`、`apps/web/tests` 和两个构建 配置;web 自己那份 `fmt` 和重复的 prettier 依赖删掉; - `.prettierignore` 挡掉两类不该碰的:drizzle-kit 生成的 `src/db/meta/` 结构快照 (它是 db:generate 的比对输入,只该由 drizzle-kit 写)、unplugin 每次 dev 都会 重写的 `auto-imports.d.ts` / `components.d.ts`; - 全量跑了一遍。纯格式,无行为改动:api typecheck / check:routes / check:ast、 前端 type-check 全过,起 api 打了接口确认正常。前端这 39 个文件的小改动是 prettier 版本漂移(类型断言的换行口径变了),不是新配置带来的。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
119 lines
3.8 KiB
TypeScript
119 lines
3.8 KiB
TypeScript
import { eq, sql } from "drizzle-orm"
|
|
|
|
import { hashPassword } from "../auth/password"
|
|
import { db, schema } from "../db"
|
|
|
|
/**
|
|
* 本机开发用的账号。**只能对本地库跑** —— 它会重置账号密码并把明文写进
|
|
* raw_password,其中一个还是超管。对着生产库跑一次就是把超管密码改掉,
|
|
* 所以这里按 DATABASE_URL 的主机名拦一道,需要绕过时显式设 OJ2_SEED_FORCE=true。
|
|
*/
|
|
const url =
|
|
process.env.DATABASE_URL ??
|
|
"postgres://onlinejudge:onlinejudge@localhost:5433/onlinejudge"
|
|
const host = (() => {
|
|
try {
|
|
return new URL(url).hostname
|
|
} catch {
|
|
return ""
|
|
}
|
|
})()
|
|
const LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "::1", ""])
|
|
if (!LOCAL_HOSTS.has(host) && process.env.OJ2_SEED_FORCE !== "true") {
|
|
console.error(
|
|
`[seed:dev] DATABASE_URL 指向 ${host},不是本机。这个脚本会重置账号密码` +
|
|
`(含一个超管)并写明文 raw_password,拒绝执行。\n` +
|
|
` 确实要对这个库跑,设 OJ2_SEED_FORCE=true。`,
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
const now = new Date().toISOString()
|
|
|
|
// 阶段 1 是带着显式 id 导入的,PostgreSQL 的序列没跟着走,先对齐
|
|
await db.execute(
|
|
sql`select setval(pg_get_serial_sequence('"user"', 'id'), coalesce(max(${schema.user.id}), 1), true) from ${schema.user}`,
|
|
)
|
|
|
|
interface SeedAccount {
|
|
username: string
|
|
password: string
|
|
adminType: "Regular User" | "Super Admin"
|
|
problemPermission: "None" | "All"
|
|
realName: string
|
|
}
|
|
|
|
/**
|
|
* 建号或就地更新。**user_profile 那一行不能省** —— 缺了它 `/api/me` 返回
|
|
* profile-not-found,前端的 getMyProfile 抛异常、localStorage 的 authed 存不
|
|
* 进去,于是所有 /admin 路由被守卫弹回首页,而且不报错。本机的 devadmin 原来
|
|
* 就缺 profile 和 email,后台页面一律进不去,排查了很久才找到这里。
|
|
*/
|
|
async function seed(account: SeedAccount) {
|
|
// 走 hashPassword,和线上五个写入点同一条路
|
|
const passwordHash = await hashPassword(account.password)
|
|
const email = `${account.username}@example.test`
|
|
const [user] = await db
|
|
.insert(schema.user)
|
|
.values({
|
|
username: account.username,
|
|
password: passwordHash,
|
|
rawPassword: account.password,
|
|
email,
|
|
createTime: now,
|
|
adminType: account.adminType,
|
|
problemPermission: account.problemPermission,
|
|
isDisabled: false,
|
|
})
|
|
.onConflictDoUpdate({
|
|
target: schema.user.username,
|
|
set: {
|
|
password: passwordHash,
|
|
rawPassword: account.password,
|
|
email,
|
|
adminType: account.adminType,
|
|
problemPermission: account.problemPermission,
|
|
isDisabled: false,
|
|
},
|
|
})
|
|
.returning({ id: schema.user.id, username: schema.user.username })
|
|
|
|
if (!user) throw new Error(`Failed to seed ${account.username}`)
|
|
|
|
const [profile] = await db
|
|
.select({ id: schema.userProfile.id })
|
|
.from(schema.userProfile)
|
|
.where(eq(schema.userProfile.userId, user.id))
|
|
.limit(1)
|
|
|
|
if (!profile) {
|
|
await db.insert(schema.userProfile).values({
|
|
userId: user.id,
|
|
acmProblemsStatus: { problems: {}, contest_problems: {} },
|
|
avatar: "/public/avatar/default.png",
|
|
realName: account.realName,
|
|
})
|
|
}
|
|
|
|
console.log(
|
|
` ${account.adminType.padEnd(13)} ${user.username} / ${account.password}`,
|
|
)
|
|
}
|
|
|
|
console.log("Seeded development logins:")
|
|
await seed({
|
|
username: process.env.OJ2_DEV_USERNAME ?? "student",
|
|
password: process.env.OJ2_DEV_PASSWORD ?? "student123",
|
|
adminType: "Regular User",
|
|
problemPermission: "None",
|
|
realName: "开发用学生",
|
|
})
|
|
await seed({
|
|
username: process.env.OJ2_DEV_ADMIN_USERNAME ?? "devadmin",
|
|
password: process.env.OJ2_DEV_ADMIN_PASSWORD ?? "devadmin123",
|
|
adminType: "Super Admin",
|
|
problemPermission: "All",
|
|
realName: "开发用超管",
|
|
})
|
|
process.exit(0)
|