refactor(后端): 清掉 Django 遗留的死列与手工级联,角色字符串收成一份
三条迁移,一次部署(0008/0009 含 DROP COLUMN,需要 OJ2_ALLOW_DESTRUCTIVE=1): - 0008 删 IP 相关:比赛 IP 白名单(前端本来就没有输入框,detail.vue 无条件置空)、 submission.ip(前端从未显示过)、以及一次都没被调用过的 IP 限流桶。 judge_server.ip 是运维数据,保留。 - 0009 删九个只有 Django 时代写过、OJ2 一次都没读过的列:user 的 auth_token / open_api / open_api_appkey / session_keys,user_profile 的 blog / github / school / major / language。open_api 后台连开关都没有,那段「已经开着就不重置 appkey」的逻辑从上线起没进过 if。判据是「全仓零读取」而不是「看着没用」—— raw_password 同样刺眼却是在用的,别一起清掉。 - 0010 给 17 条外键补上删除动作,不再是 Django 留下的一律 NO ACTION。父行消失后 必然无意义、且不构成学生留痕的走 CASCADE(中间表、题单/教程/成就的组成部分、 user_profile 与 user_stat);需要人看见的继续拦着——submission.problem_id、 以及 user 的绝大多数外键,删用户撞外键会被 handler 翻译成「请改为禁用账号」, 这是有意的:全 CASCADE 会静默抹掉成就与进度,而 submission.user_id 压根没有 外键,结果是一半删一半留。六处手工级联随之删掉。 角色字符串收进 packages/contract/src/roles.ts:原先 ADMIN_ROLES / TEACHER_ROLES 在两个文件各抄一份、学生口径在四个文件各写一遍、前端 USER_TYPE 是第三份副本。 AuthUser.adminType 与 drizzle 的列都收窄成联合类型,二十多处 `=== "Super Admin"` 从此受编译器管着($type 是纯 TS 层的,generate 确认不产生任何 SQL 变更)。 顺带删掉 db/relations.ts —— drizzle-kit pull 的产物,全仓零引用。 一处行为变化:后台用户列表传非法的 ?type= 回 400,不再静默返回空列表;界面上的 下拉只有合法值,打不到这条。 验证:tsc / vue-tsc / vite build / check:routes 全过;三条迁移在 dev 库执行, 并逐条建 fixture 走 HTTP 接口验过删除连坐与拦截(题单五张子表连坐、user_badge 二级连坐、删有提交的题目仍 409、删有表情的用户仍 409)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeJoYc2t2d7cThVqMBYrBF
This commit is contained in:
1 parent
e624c62502
commit
2c4d56b29a
41 files changed
+12081
-491
No files matched your search
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "contest" DROP COLUMN "allowed_ip_ranges";--> statement-breakpoint
|
||||
ALTER TABLE "submission" DROP COLUMN "ip";
|
||||
@@ -0,0 +1,9 @@
|
||||
ALTER TABLE "user" DROP COLUMN "auth_token";--> statement-breakpoint
|
||||
ALTER TABLE "user" DROP COLUMN "open_api";--> statement-breakpoint
|
||||
ALTER TABLE "user" DROP COLUMN "open_api_appkey";--> statement-breakpoint
|
||||
ALTER TABLE "user" DROP COLUMN "session_keys";--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" DROP COLUMN "blog";--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" DROP COLUMN "github";--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" DROP COLUMN "school";--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" DROP COLUMN "major";--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" DROP COLUMN "language";
|
||||
@@ -0,0 +1,51 @@
|
||||
ALTER TABLE "exercise" DROP CONSTRAINT "exercise_tutorial_id_6fd04055_fk_tutorial_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "flowchart_submission" DROP CONSTRAINT "flowchart_submission_problem_id_8551edbf_fk_problem_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "message" DROP CONSTRAINT "message_submission_id_2fdf8a47_fk_submission_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problem_tags" DROP CONSTRAINT "problem_tags_problem_id_866ecb8d_fk_problem_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problem_tags" DROP CONSTRAINT "problem_tags_problemtag_id_72d20571_fk_problem_tag_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_badge" DROP CONSTRAINT "problemset_badge_problemset_id_6cb6c74f_fk_problemset_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_problem" DROP CONSTRAINT "problemset_problem_problem_id_fff2d686_fk_problem_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_problem" DROP CONSTRAINT "problemset_problem_problemset_id_350d17fb_fk_problemset_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_progress" DROP CONSTRAINT "problemset_progress_problemset_id_20a9632e_fk_problemset_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_submission" DROP CONSTRAINT "problemset_submission_problem_id_5629b105_fk_problem_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_submission" DROP CONSTRAINT "problemset_submission_problemset_id_85290e17_fk_problemset_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "problemset_submission" DROP CONSTRAINT "problemset_submission_submission_id_78e2b807_fk_submission_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "reaction" DROP CONSTRAINT "reaction_problem_id_a7f3b9f3_fk_problem_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "user_achievement" DROP CONSTRAINT "user_achievement_achievement_id_29db600d_fk_achievement_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "user_badge" DROP CONSTRAINT "user_badge_badge_id_92a983e9_fk_problemset_badge_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" DROP CONSTRAINT "user_profile_user_id_8fdce8e2_fk_user_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "user_stat" DROP CONSTRAINT "user_stat_user_id_73337fc0_fk_user_id";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "exercise" ADD CONSTRAINT "exercise_tutorial_id_6fd04055_fk_tutorial_id" FOREIGN KEY ("tutorial_id") REFERENCES "public"."tutorial"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "flowchart_submission" ADD CONSTRAINT "flowchart_submission_problem_id_8551edbf_fk_problem_id" FOREIGN KEY ("problem_id") REFERENCES "public"."problem"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "message" ADD CONSTRAINT "message_submission_id_2fdf8a47_fk_submission_id" FOREIGN KEY ("submission_id") REFERENCES "public"."submission"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problem_tags" ADD CONSTRAINT "problem_tags_problem_id_866ecb8d_fk_problem_id" FOREIGN KEY ("problem_id") REFERENCES "public"."problem"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problem_tags" ADD CONSTRAINT "problem_tags_problemtag_id_72d20571_fk_problem_tag_id" FOREIGN KEY ("problemtag_id") REFERENCES "public"."problem_tag"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_badge" ADD CONSTRAINT "problemset_badge_problemset_id_6cb6c74f_fk_problemset_id" FOREIGN KEY ("problemset_id") REFERENCES "public"."problemset"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_problem" ADD CONSTRAINT "problemset_problem_problem_id_fff2d686_fk_problem_id" FOREIGN KEY ("problem_id") REFERENCES "public"."problem"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_problem" ADD CONSTRAINT "problemset_problem_problemset_id_350d17fb_fk_problemset_id" FOREIGN KEY ("problemset_id") REFERENCES "public"."problemset"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_progress" ADD CONSTRAINT "problemset_progress_problemset_id_20a9632e_fk_problemset_id" FOREIGN KEY ("problemset_id") REFERENCES "public"."problemset"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_submission" ADD CONSTRAINT "problemset_submission_problem_id_5629b105_fk_problem_id" FOREIGN KEY ("problem_id") REFERENCES "public"."problem"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_submission" ADD CONSTRAINT "problemset_submission_problemset_id_85290e17_fk_problemset_id" FOREIGN KEY ("problemset_id") REFERENCES "public"."problemset"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "problemset_submission" ADD CONSTRAINT "problemset_submission_submission_id_78e2b807_fk_submission_id" FOREIGN KEY ("submission_id") REFERENCES "public"."submission"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "reaction" ADD CONSTRAINT "reaction_problem_id_a7f3b9f3_fk_problem_id" FOREIGN KEY ("problem_id") REFERENCES "public"."problem"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "user_achievement" ADD CONSTRAINT "user_achievement_achievement_id_29db600d_fk_achievement_id" FOREIGN KEY ("achievement_id") REFERENCES "public"."achievement"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "user_badge" ADD CONSTRAINT "user_badge_badge_id_92a983e9_fk_problemset_badge_id" FOREIGN KEY ("badge_id") REFERENCES "public"."problemset_badge"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "user_profile" ADD CONSTRAINT "user_profile_user_id_8fdce8e2_fk_user_id" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "user_stat" ADD CONSTRAINT "user_stat_user_id_73337fc0_fk_user_id" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -57,6 +57,27 @@
|
||||
"when": 1788408053304,
|
||||
"tag": "0007_add_submission_problemset_id",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "7",
|
||||
"when": 1788409130862,
|
||||
"tag": "0008_drop_ip_columns",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "7",
|
||||
"when": 1788409690565,
|
||||
"tag": "0009_drop_django_dead_columns",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "7",
|
||||
"when": 1788409961010,
|
||||
"tag": "0010_fk_cascade_on_delete",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
import { relations } from "drizzle-orm/relations";
|
||||
import { user, aiAnalysis, announcement, contest, problem, flowchartSubmission, message, submission, tutorial, exercise, problemset, problemsetProblem, problemsetProgress, problemsetSubmission, reaction, problemTags, problemTag, userStat, achievement, userAchievement, problemsetBadge, userBadge, userProfile, acmContestRank } from "./schema";
|
||||
|
||||
export const aiAnalysisRelations = relations(aiAnalysis, ({one}) => ({
|
||||
user: one(user, {
|
||||
fields: [aiAnalysis.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const userRelations = relations(user, ({many}) => ({
|
||||
aiAnalyses: many(aiAnalysis),
|
||||
announcements: many(announcement),
|
||||
contests: many(contest),
|
||||
flowchartSubmissions: many(flowchartSubmission),
|
||||
messages_recipientId: many(message, {
|
||||
relationName: "message_recipientId_user_id"
|
||||
}),
|
||||
messages_senderId: many(message, {
|
||||
relationName: "message_senderId_user_id"
|
||||
}),
|
||||
problemsets: many(problemset),
|
||||
problemsetProgresses: many(problemsetProgress),
|
||||
problemsetSubmissions: many(problemsetSubmission),
|
||||
reactions: many(reaction),
|
||||
problems: many(problem),
|
||||
tutorials: many(tutorial),
|
||||
userStats: many(userStat),
|
||||
userAchievements: many(userAchievement),
|
||||
userBadges: many(userBadge),
|
||||
userProfiles: many(userProfile),
|
||||
acmContestRanks: many(acmContestRank),
|
||||
}));
|
||||
|
||||
export const announcementRelations = relations(announcement, ({one}) => ({
|
||||
user: one(user, {
|
||||
fields: [announcement.createdById],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const contestRelations = relations(contest, ({one, many}) => ({
|
||||
user: one(user, {
|
||||
fields: [contest.createdById],
|
||||
references: [user.id]
|
||||
}),
|
||||
problems: many(problem),
|
||||
submissions: many(submission),
|
||||
acmContestRanks: many(acmContestRank),
|
||||
}));
|
||||
|
||||
export const flowchartSubmissionRelations = relations(flowchartSubmission, ({one}) => ({
|
||||
problem: one(problem, {
|
||||
fields: [flowchartSubmission.problemId],
|
||||
references: [problem.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [flowchartSubmission.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemRelations = relations(problem, ({one, many}) => ({
|
||||
flowchartSubmissions: many(flowchartSubmission),
|
||||
problemsetProblems: many(problemsetProblem),
|
||||
problemsetSubmissions: many(problemsetSubmission),
|
||||
reactions: many(reaction),
|
||||
contest: one(contest, {
|
||||
fields: [problem.contestId],
|
||||
references: [contest.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [problem.createdById],
|
||||
references: [user.id]
|
||||
}),
|
||||
problemTags: many(problemTags),
|
||||
submissions: many(submission),
|
||||
}));
|
||||
|
||||
export const messageRelations = relations(message, ({one}) => ({
|
||||
user_recipientId: one(user, {
|
||||
fields: [message.recipientId],
|
||||
references: [user.id],
|
||||
relationName: "message_recipientId_user_id"
|
||||
}),
|
||||
user_senderId: one(user, {
|
||||
fields: [message.senderId],
|
||||
references: [user.id],
|
||||
relationName: "message_senderId_user_id"
|
||||
}),
|
||||
submission: one(submission, {
|
||||
fields: [message.submissionId],
|
||||
references: [submission.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const submissionRelations = relations(submission, ({one, many}) => ({
|
||||
messages: many(message),
|
||||
problemsetSubmissions: many(problemsetSubmission),
|
||||
contest: one(contest, {
|
||||
fields: [submission.contestId],
|
||||
references: [contest.id]
|
||||
}),
|
||||
problem: one(problem, {
|
||||
fields: [submission.problemId],
|
||||
references: [problem.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const exerciseRelations = relations(exercise, ({one}) => ({
|
||||
tutorial: one(tutorial, {
|
||||
fields: [exercise.tutorialId],
|
||||
references: [tutorial.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const tutorialRelations = relations(tutorial, ({one, many}) => ({
|
||||
exercises: many(exercise),
|
||||
user: one(user, {
|
||||
fields: [tutorial.createdById],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemsetRelations = relations(problemset, ({one, many}) => ({
|
||||
user: one(user, {
|
||||
fields: [problemset.createdById],
|
||||
references: [user.id]
|
||||
}),
|
||||
problemsetProblems: many(problemsetProblem),
|
||||
problemsetProgresses: many(problemsetProgress),
|
||||
problemsetSubmissions: many(problemsetSubmission),
|
||||
problemsetBadges: many(problemsetBadge),
|
||||
}));
|
||||
|
||||
export const problemsetProblemRelations = relations(problemsetProblem, ({one}) => ({
|
||||
problem: one(problem, {
|
||||
fields: [problemsetProblem.problemId],
|
||||
references: [problem.id]
|
||||
}),
|
||||
problemset: one(problemset, {
|
||||
fields: [problemsetProblem.problemsetId],
|
||||
references: [problemset.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemsetProgressRelations = relations(problemsetProgress, ({one}) => ({
|
||||
problemset: one(problemset, {
|
||||
fields: [problemsetProgress.problemsetId],
|
||||
references: [problemset.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [problemsetProgress.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemsetSubmissionRelations = relations(problemsetSubmission, ({one}) => ({
|
||||
problem: one(problem, {
|
||||
fields: [problemsetSubmission.problemId],
|
||||
references: [problem.id]
|
||||
}),
|
||||
problemset: one(problemset, {
|
||||
fields: [problemsetSubmission.problemsetId],
|
||||
references: [problemset.id]
|
||||
}),
|
||||
submission: one(submission, {
|
||||
fields: [problemsetSubmission.submissionId],
|
||||
references: [submission.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [problemsetSubmission.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const reactionRelations = relations(reaction, ({one}) => ({
|
||||
problem: one(problem, {
|
||||
fields: [reaction.problemId],
|
||||
references: [problem.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [reaction.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemTagsRelations = relations(problemTags, ({one}) => ({
|
||||
problem: one(problem, {
|
||||
fields: [problemTags.problemId],
|
||||
references: [problem.id]
|
||||
}),
|
||||
problemTag: one(problemTag, {
|
||||
fields: [problemTags.problemtagId],
|
||||
references: [problemTag.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemTagRelations = relations(problemTag, ({many}) => ({
|
||||
problemTags: many(problemTags),
|
||||
}));
|
||||
|
||||
export const userStatRelations = relations(userStat, ({one}) => ({
|
||||
user: one(user, {
|
||||
fields: [userStat.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const userAchievementRelations = relations(userAchievement, ({one}) => ({
|
||||
achievement: one(achievement, {
|
||||
fields: [userAchievement.achievementId],
|
||||
references: [achievement.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [userAchievement.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const achievementRelations = relations(achievement, ({many}) => ({
|
||||
userAchievements: many(userAchievement),
|
||||
}));
|
||||
|
||||
export const userBadgeRelations = relations(userBadge, ({one}) => ({
|
||||
problemsetBadge: one(problemsetBadge, {
|
||||
fields: [userBadge.badgeId],
|
||||
references: [problemsetBadge.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [userBadge.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const problemsetBadgeRelations = relations(problemsetBadge, ({one, many}) => ({
|
||||
userBadges: many(userBadge),
|
||||
problemset: one(problemset, {
|
||||
fields: [problemsetBadge.problemsetId],
|
||||
references: [problemset.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const userProfileRelations = relations(userProfile, ({one}) => ({
|
||||
user: one(user, {
|
||||
fields: [userProfile.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const acmContestRankRelations = relations(acmContestRank, ({one}) => ({
|
||||
contest: one(contest, {
|
||||
fields: [acmContestRank.contestId],
|
||||
references: [contest.id]
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [acmContestRank.userId],
|
||||
references: [user.id]
|
||||
}),
|
||||
}));
|
||||
+28
-30
@@ -5,6 +5,12 @@
|
||||
// django_session)已由 0002_drop_django_leftovers 删除,drizzle.config.ts 的
|
||||
// tablesFilter 随之移除。库里现在就是这 27 张业务表。
|
||||
//
|
||||
// 2026-09-02:又清了一批只有 Django 时代写过、OJ2 一次都没读过的列 ——
|
||||
// 0008 删比赛 IP 白名单与 submission.ip(判题机的 judge_server.ip 保留,那是运维数据),
|
||||
// 0009 删 user 的 auth_token / open_api / open_api_appkey / session_keys 和
|
||||
// user_profile 的 blog / github / school / major / language。**删的判据是「全仓零读取」**,
|
||||
// 不是「看着没用」:raw_password 同样刺眼却是在用的(老师要能查学生密码),别一起清掉。
|
||||
//
|
||||
// 手工修正(都是 `pull` 自己没法无损 round-trip 的地方,改回去会让 generate 产生假 diff,
|
||||
// 详见 CLAUDE.md「改 schema 走 drizzle migration」):
|
||||
// * bigint identity 的 maxValue 用字符串,不能写成 JS number 字面量(会丢精度)。
|
||||
@@ -16,6 +22,7 @@
|
||||
// problem、contest、submission)都是 int4。现存最大 id 一万出头,确实都用不上 bigint,
|
||||
// 但 2026-08-26 评估后决定**不改**:省 4 字节/行毫无意义,ALTER TYPE 要重写整表并拿
|
||||
// ACCESS EXCLUSIVE 锁,而且其中 6 处 id 被外键绑着得连坐。别再提这件事了。
|
||||
import type { AdminType, ProblemPermission } from "@oj2/contract"
|
||||
import { pgTable, index, foreignKey, primaryKey, bigint, text, jsonb, timestamp, integer, boolean, serial, doublePrecision, varchar, unique, uniqueIndex } from "drizzle-orm/pg-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
|
||||
@@ -90,7 +97,6 @@ export const contest = pgTable("contest", {
|
||||
lastUpdateTime: timestamp("last_update_time", { withTimezone: true, mode: 'string' }).notNull(),
|
||||
visible: boolean().notNull(),
|
||||
createdById: integer("created_by_id").notNull(),
|
||||
allowedIpRanges: jsonb("allowed_ip_ranges").notNull(),
|
||||
tag: text().notNull(),
|
||||
}, (table) => [
|
||||
index("contest_created_by_id_a763ca7e").using("btree", table.createdById.asc().nullsLast().op("int4_ops")),
|
||||
@@ -129,7 +135,7 @@ export const flowchartSubmission = pgTable("flowchart_submission", {
|
||||
columns: [table.problemId],
|
||||
foreignColumns: [problem.id],
|
||||
name: "flowchart_submission_problem_id_8551edbf_fk_problem_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
@@ -164,7 +170,7 @@ export const message = pgTable("message", {
|
||||
columns: [table.submissionId],
|
||||
foreignColumns: [submission.id],
|
||||
name: "message_submission_id_2fdf8a47_fk_submission_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
|
||||
export const judgeServer = pgTable("judge_server", {
|
||||
@@ -195,7 +201,7 @@ export const exercise = pgTable("exercise", {
|
||||
columns: [table.tutorialId],
|
||||
foreignColumns: [tutorial.id],
|
||||
name: "exercise_tutorial_id_6fd04055_fk_tutorial_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
|
||||
export const optionsSysoptions = pgTable("options_sysoptions", {
|
||||
@@ -244,12 +250,12 @@ export const problemsetProblem = pgTable("problemset_problem", {
|
||||
columns: [table.problemId],
|
||||
foreignColumns: [problem.id],
|
||||
name: "problemset_problem_problem_id_fff2d686_fk_problem_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.problemsetId],
|
||||
foreignColumns: [problemset.id],
|
||||
name: "problemset_problem_problemset_id_350d17fb_fk_problemset_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
unique("unique_problemset_problem").on(table.problemId, table.problemsetId),
|
||||
]);
|
||||
|
||||
@@ -274,7 +280,7 @@ export const problemsetProgress = pgTable("problemset_progress", {
|
||||
columns: [table.problemsetId],
|
||||
foreignColumns: [problemset.id],
|
||||
name: "problemset_progress_problemset_id_20a9632e_fk_problemset_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
@@ -304,17 +310,17 @@ export const problemsetSubmission = pgTable("problemset_submission", {
|
||||
columns: [table.problemId],
|
||||
foreignColumns: [problem.id],
|
||||
name: "problemset_submission_problem_id_5629b105_fk_problem_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.problemsetId],
|
||||
foreignColumns: [problemset.id],
|
||||
name: "problemset_submission_problemset_id_85290e17_fk_problemset_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.submissionId],
|
||||
foreignColumns: [submission.id],
|
||||
name: "problemset_submission_submission_id_78e2b807_fk_submission_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
@@ -336,7 +342,7 @@ export const reaction = pgTable("reaction", {
|
||||
columns: [table.problemId],
|
||||
foreignColumns: [problem.id],
|
||||
name: "reaction_problem_id_a7f3b9f3_fk_problem_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
@@ -414,12 +420,12 @@ export const problemTags = pgTable("problem_tags", {
|
||||
columns: [table.problemId],
|
||||
foreignColumns: [problem.id],
|
||||
name: "problem_tags_problem_id_866ecb8d_fk_problem_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.problemtagId],
|
||||
foreignColumns: [problemTag.id],
|
||||
name: "problem_tags_problemtag_id_72d20571_fk_problem_tag_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
unique("problem_tags_problem_id_problemtag_id_318459d1_uniq").on(table.problemId, table.problemtagId),
|
||||
]);
|
||||
|
||||
@@ -443,7 +449,6 @@ export const submission = pgTable("submission", {
|
||||
shared: boolean().default(false).notNull(),
|
||||
statisticInfo: jsonb("statistic_info").default({}).notNull(),
|
||||
username: text().notNull(),
|
||||
ip: text(),
|
||||
// 来源题单:学生从题单入口(/problemset/:id/problem/:pid)提交时记下来,
|
||||
// 提交列表据此标出「这条来自题单」。**只是来源标记**,题单进度、奖章一概不看它,
|
||||
// 那些由判完之后的 recordSolvedProblem 按「已加入且含这道题的所有题单」记账。
|
||||
@@ -534,7 +539,7 @@ export const userStat = pgTable("user_stat", {
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
name: "user_stat_user_id_73337fc0_fk_user_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
unique("user_stat_user_id_key").on(table.userId),
|
||||
]);
|
||||
|
||||
@@ -556,7 +561,7 @@ export const userAchievement = pgTable("user_achievement", {
|
||||
columns: [table.achievementId],
|
||||
foreignColumns: [achievement.id],
|
||||
name: "user_achievement_achievement_id_29db600d_fk_achievement_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
@@ -579,7 +584,7 @@ export const userBadge = pgTable("user_badge", {
|
||||
columns: [table.badgeId],
|
||||
foreignColumns: [problemsetBadge.id],
|
||||
name: "user_badge_badge_id_92a983e9_fk_problemset_badge_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
@@ -592,22 +597,17 @@ export const userProfile = pgTable("user_profile", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
acmProblemsStatus: jsonb("acm_problems_status").default({}).notNull(),
|
||||
avatar: text().notNull(),
|
||||
blog: varchar({ length: 200 }),
|
||||
mood: text(),
|
||||
acceptedNumber: integer("accepted_number").default(0).notNull(),
|
||||
submissionNumber: integer("submission_number").default(0).notNull(),
|
||||
github: text(),
|
||||
school: text(),
|
||||
major: text(),
|
||||
userId: integer("user_id").notNull(),
|
||||
realName: text("real_name"),
|
||||
language: text(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.userId],
|
||||
foreignColumns: [user.id],
|
||||
name: "user_profile_user_id_8fdce8e2_fk_user_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
unique("user_profile_user_id_key").on(table.userId),
|
||||
]);
|
||||
|
||||
@@ -644,13 +644,11 @@ export const user = pgTable("user", {
|
||||
username: text().notNull(),
|
||||
email: text(),
|
||||
createTime: timestamp("create_time", { withTimezone: true, mode: 'string' }),
|
||||
adminType: text("admin_type").notNull(),
|
||||
authToken: text("auth_token"),
|
||||
openApi: boolean("open_api").default(false).notNull(),
|
||||
openApiAppkey: text("open_api_appkey"),
|
||||
// $type 只是 TS 层的收窄,不产生任何 SQL —— 让 eq(schema.user.adminType, "...")
|
||||
// 里的角色名也受类型检查。运行时的兜底仍在 auth/session.ts 的 toAdminType。
|
||||
adminType: text("admin_type").notNull().$type<AdminType>(),
|
||||
isDisabled: boolean("is_disabled").default(false).notNull(),
|
||||
problemPermission: text("problem_permission").notNull(),
|
||||
sessionKeys: jsonb("session_keys").default([]).notNull(),
|
||||
problemPermission: text("problem_permission").notNull().$type<ProblemPermission>(),
|
||||
rawPassword: varchar("raw_password", { length: 20 }),
|
||||
className: text("class_name"),
|
||||
}, (table) => [
|
||||
@@ -673,7 +671,7 @@ export const problemsetBadge = pgTable("problemset_badge", {
|
||||
columns: [table.problemsetId],
|
||||
foreignColumns: [problemset.id],
|
||||
name: "problemset_badge_problemset_id_6cb6c74f_fk_problemset_id"
|
||||
}),
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user