初次提交
Build VoiceHub FPK / build-fpk (push) Failing after 56m5s
Build and Push Docker Image / build-and-push (push) Canceled after 1h9m35s

This commit is contained in:
2026-09-06 08:19:02 +08:00
commit 4ce4649aaf
1061 changed files with 337258 additions and 0 deletions
@@ -0,0 +1,132 @@
DO $$ BEGIN
CREATE TYPE "public"."BlacklistType" AS ENUM('SONG', 'KEYWORD');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;--> statement-breakpoint
CREATE TABLE "NotificationSettings" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"userId" integer NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
"songRequestEnabled" boolean DEFAULT true NOT NULL,
"songVotedEnabled" boolean DEFAULT true NOT NULL,
"songPlayedEnabled" boolean DEFAULT true NOT NULL,
"refreshInterval" integer DEFAULT 60 NOT NULL,
"songVotedThreshold" integer DEFAULT 1 NOT NULL,
CONSTRAINT "NotificationSettings_userId_unique" UNIQUE("userId")
);
--> statement-breakpoint
CREATE TABLE "Notification" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"type" text NOT NULL,
"message" text NOT NULL,
"read" boolean DEFAULT false NOT NULL,
"userId" integer NOT NULL,
"songId" integer
);
--> statement-breakpoint
CREATE TABLE "PlayTime" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"name" text NOT NULL,
"startTime" text,
"endTime" text,
"enabled" boolean DEFAULT true NOT NULL,
"description" text
);
--> statement-breakpoint
CREATE TABLE "Schedule" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"songId" integer NOT NULL,
"playDate" timestamp NOT NULL,
"played" boolean DEFAULT false NOT NULL,
"sequence" integer DEFAULT 1 NOT NULL,
"playTimeId" integer
);
--> statement-breakpoint
CREATE TABLE "Semester" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"name" text NOT NULL,
"isActive" boolean DEFAULT false NOT NULL,
CONSTRAINT "Semester_name_unique" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE "SongBlacklist" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"type" "BlacklistType" NOT NULL,
"value" text NOT NULL,
"reason" text,
"isActive" boolean DEFAULT true NOT NULL,
"createdBy" integer
);
--> statement-breakpoint
CREATE TABLE "Song" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"title" text NOT NULL,
"artist" text NOT NULL,
"requesterId" integer NOT NULL,
"played" boolean DEFAULT false NOT NULL,
"playedAt" timestamp,
"semester" text,
"preferredPlayTimeId" integer,
"cover" text,
"musicPlatform" text,
"musicId" text
);
--> statement-breakpoint
CREATE TABLE "SystemSettings" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"enablePlayTimeSelection" boolean DEFAULT false NOT NULL,
"siteTitle" text,
"siteLogoUrl" text,
"schoolLogoHomeUrl" text,
"schoolLogoPrintUrl" text,
"siteDescription" text,
"submissionGuidelines" text,
"icpNumber" text,
"enableSubmissionLimit" boolean DEFAULT false NOT NULL,
"dailySubmissionLimit" integer,
"weeklySubmissionLimit" integer,
"showBlacklistKeywords" boolean DEFAULT false NOT NULL,
"hideStudentInfo" boolean DEFAULT true NOT NULL
);
--> statement-breakpoint
CREATE TABLE "User" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"username" text NOT NULL,
"name" text,
"grade" text,
"class" text,
"role" text DEFAULT 'USER' NOT NULL,
"password" text NOT NULL,
"lastLogin" timestamp,
"lastLoginIp" text,
"passwordChangedAt" timestamp,
"forcePasswordChange" boolean DEFAULT true NOT NULL,
"meowNickname" text,
"meowBoundAt" timestamp,
CONSTRAINT "User_username_unique" UNIQUE("username")
);
--> statement-breakpoint
CREATE TABLE "Vote" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"songId" integer NOT NULL,
"userId" integer NOT NULL
);
@@ -0,0 +1,14 @@
-- 为排期表添加草稿支持
-- 添加草稿状态标识字段
ALTER TABLE "Schedule" ADD COLUMN "isDraft" boolean DEFAULT false NOT NULL;
-- 添加发布时间字段(发布后记录发布时间)
ALTER TABLE "Schedule" ADD COLUMN "publishedAt" timestamp;
-- 为现有排期设置为已发布状态(因为现有的都应该是已发布的)
UPDATE "Schedule" SET "isDraft" = false, "publishedAt" = "updatedAt" WHERE "isDraft" IS NULL;
-- 创建索引以优化查询性能
CREATE INDEX "idx_schedule_is_draft" ON "Schedule" ("isDraft");
CREATE INDEX "idx_schedule_published_at" ON "Schedule" ("publishedAt");
CREATE INDEX "idx_schedule_draft_date" ON "Schedule" ("isDraft", "playDate");
@@ -0,0 +1,33 @@
-- 创建用户状态枚举类型
CREATE TYPE "public"."user_status" AS ENUM('active', 'withdrawn');--> statement-breakpoint
-- 添加用户状态相关字段到用户表
ALTER TABLE "User" ADD COLUMN "status" "user_status" DEFAULT 'active' NOT NULL;--> statement-breakpoint
ALTER TABLE "User" ADD COLUMN "statusChangedAt" timestamp DEFAULT now();--> statement-breakpoint
ALTER TABLE "User" ADD COLUMN "statusChangedBy" integer;--> statement-breakpoint
-- 创建用户状态变更日志表
CREATE TABLE IF NOT EXISTS "user_status_logs" (
"id" serial PRIMARY KEY NOT NULL,
"user_id" integer NOT NULL,
"old_status" "user_status",
"new_status" "user_status" NOT NULL,
"reason" text,
"operator_id" integer,
"created_at" timestamp DEFAULT now() NOT NULL
);--> statement-breakpoint
-- 创建索引以提高查询性能
CREATE INDEX IF NOT EXISTS "idx_user_status" ON "User" USING btree ("status");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "idx_user_status_logs_user_id" ON "user_status_logs" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "idx_user_status_logs_created_at" ON "user_status_logs" USING btree ("created_at" DESC);--> statement-breakpoint
-- 添加外键约束
ALTER TABLE "User" ADD CONSTRAINT "User_statusChangedBy_User_id_fk" FOREIGN KEY ("statusChangedBy") REFERENCES "User"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user_status_logs" ADD CONSTRAINT "user_status_logs_user_id_User_id_fk" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user_status_logs" ADD CONSTRAINT "user_status_logs_operator_id_User_id_fk" FOREIGN KEY ("operator_id") REFERENCES "User"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
-- 为现有用户初始化状态变更日志
INSERT INTO "user_status_logs" ("user_id", "old_status", "new_status", "reason", "created_at")
SELECT "id", NULL, 'active', '系统迁移初始化', "createdAt"
FROM "User";
@@ -0,0 +1 @@
ALTER TABLE "Semester" DROP CONSTRAINT "Semester_name_unique";
@@ -0,0 +1,56 @@
-- 创建API Keys表
CREATE TABLE "api_keys" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"name" varchar(255) NOT NULL,
"description" text,
"key_hash" varchar(255) NOT NULL,
"key_prefix" varchar(10) NOT NULL,
"is_active" boolean DEFAULT true NOT NULL,
"expires_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
"last_used_at" timestamp with time zone,
"created_by_user_id" integer NOT NULL,
"usage_count" integer DEFAULT 0 NOT NULL,
CONSTRAINT "api_keys_key_hash_unique" UNIQUE("key_hash")
);--> statement-breakpoint
-- 创建API Key权限表
CREATE TABLE "api_key_permissions" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"api_key_id" uuid NOT NULL,
"permission" varchar(100) NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "api_key_permissions_api_key_id_permission_unique" UNIQUE("api_key_id", "permission")
);--> statement-breakpoint
-- 创建API访问日志表
CREATE TABLE "api_logs" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"api_key_id" uuid,
"endpoint" varchar(500) NOT NULL,
"method" varchar(10) NOT NULL,
"ip_address" inet NOT NULL,
"user_agent" text,
"status_code" integer NOT NULL,
"response_time_ms" integer NOT NULL,
"request_body" text,
"response_body" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"error_message" text
);--> statement-breakpoint
-- 创建外键约束
ALTER TABLE "api_keys" ADD CONSTRAINT "api_keys_created_by_user_id_User_id_fk" FOREIGN KEY ("created_by_user_id") REFERENCES "User"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "api_key_permissions" ADD CONSTRAINT "api_key_permissions_api_key_id_api_keys_id_fk" FOREIGN KEY ("api_key_id") REFERENCES "api_keys"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "api_logs" ADD CONSTRAINT "api_logs_api_key_id_api_keys_id_fk" FOREIGN KEY ("api_key_id") REFERENCES "api_keys"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
-- 创建索引
CREATE INDEX "idx_api_keys_key_hash" ON "api_keys"("key_hash");--> statement-breakpoint
CREATE INDEX "idx_api_keys_created_by" ON "api_keys"("created_by_user_id");--> statement-breakpoint
CREATE INDEX "idx_api_keys_active" ON "api_keys"("is_active") WHERE "is_active" = true;--> statement-breakpoint
CREATE INDEX "idx_api_key_permissions_api_key_id" ON "api_key_permissions"("api_key_id");--> statement-breakpoint
CREATE INDEX "idx_api_logs_api_key_id" ON "api_logs"("api_key_id");--> statement-breakpoint
CREATE INDEX "idx_api_logs_created_at" ON "api_logs"("created_at" DESC);--> statement-breakpoint
CREATE INDEX "idx_api_logs_status_code" ON "api_logs"("status_code");--> statement-breakpoint
CREATE INDEX "idx_api_logs_endpoint" ON "api_logs"("endpoint");
@@ -0,0 +1,2 @@
ALTER TABLE "NotificationSettings" DROP CONSTRAINT "NotificationSettings_userId_unique";--> statement-breakpoint
ALTER TABLE "User" DROP CONSTRAINT "User_username_unique";
@@ -0,0 +1,20 @@
-- 添加用户邮箱字段
ALTER TABLE "User" ADD COLUMN "email" text;
ALTER TABLE "User" ADD COLUMN "emailVerified" boolean DEFAULT false NOT NULL;
ALTER TABLE "User" ADD COLUMN "emailVerifiedAt" timestamp;
-- 添加系统设置SMTP配置字段
ALTER TABLE "SystemSettings" ADD COLUMN "smtpEnabled" boolean DEFAULT false NOT NULL;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpHost" text;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpPort" integer DEFAULT 587;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpSecure" boolean DEFAULT false NOT NULL;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpUsername" text;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpPassword" text;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpFromEmail" text;
ALTER TABLE "SystemSettings" ADD COLUMN "smtpFromName" text;
-- 添加通知设置邮件通知字段
ALTER TABLE "NotificationSettings" ADD COLUMN "emailSongRequestEnabled" boolean DEFAULT true NOT NULL;
ALTER TABLE "NotificationSettings" ADD COLUMN "emailSongVotedEnabled" boolean DEFAULT true NOT NULL;
ALTER TABLE "NotificationSettings" ADD COLUMN "emailSongPlayedEnabled" boolean DEFAULT true NOT NULL;
ALTER TABLE "NotificationSettings" ADD COLUMN "emailSystemNoticeEnabled" boolean DEFAULT true NOT NULL;
@@ -0,0 +1,10 @@
ALTER TABLE "SystemSettings" ADD COLUMN "smtpEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpHost" text;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpPort" integer DEFAULT 587;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpSecure" boolean DEFAULT false;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpUsername" text;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpPassword" text;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpFromEmail" text;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "smtpFromName" text DEFAULT '校园广播站';--> statement-breakpoint
ALTER TABLE "User" ADD COLUMN "email" text;--> statement-breakpoint
ALTER TABLE "User" ADD COLUMN "emailVerified" boolean DEFAULT false;
@@ -0,0 +1,10 @@
CREATE TABLE "EmailTemplate" (
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"key" varchar(100) NOT NULL,
"name" varchar(200) NOT NULL,
"subject" varchar(300) NOT NULL,
"html" text NOT NULL,
"updatedByUserId" integer
);
@@ -0,0 +1,2 @@
-- 添加歌曲播放地址字段
ALTER TABLE "Song" ADD COLUMN "playUrl" text;
@@ -0,0 +1,3 @@
ALTER TABLE "Schedule" ADD COLUMN "isDraft" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "Schedule" ADD COLUMN "publishedAt" timestamp;--> statement-breakpoint
ALTER TABLE "Song" ADD COLUMN "playUrl" text;
@@ -0,0 +1,42 @@
CREATE TYPE "public"."collaborator_status" AS ENUM ('PENDING', 'ACCEPTED', 'REJECTED');--> statement-breakpoint
CREATE TABLE "collaboration_logs"
(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"collaborator_id" uuid NOT NULL,
"action" varchar(50) NOT NULL,
"operator_id" integer NOT NULL,
"ip_address" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "RequestTime"
(
"id" serial PRIMARY KEY NOT NULL,
"createdAt" timestamp(6) DEFAULT now() NOT NULL,
"updatedAt" timestamp(6) DEFAULT now() NOT NULL,
"name" text NOT NULL,
"startTime" timestamp NOT NULL,
"endTime" timestamp NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
"description" text,
"expected" bigint DEFAULT 0 NOT NULL,
"accepted" bigint DEFAULT 0 NOT NULL,
"past" boolean DEFAULT false NOT NULL
);
--> statement-breakpoint
CREATE TABLE "song_collaborators"
(
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"song_id" integer NOT NULL,
"user_id" integer NOT NULL,
"status" "collaborator_status" DEFAULT 'PENDING' NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "Song"
ADD COLUMN "hitRequestId" integer;--> statement-breakpoint
ALTER TABLE "SystemSettings"
ADD COLUMN "enableRequestTimeLimitation" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "SystemSettings"
ADD COLUMN "forceBlockAllRequests" boolean DEFAULT false NOT NULL;
@@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS "song_replay_requests" (
"id" serial PRIMARY KEY NOT NULL,
"song_id" integer NOT NULL,
"user_id" integer NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "song_replay_requests_song_id_user_id_unique" UNIQUE("song_id","user_id")
);
ALTER TABLE "SystemSettings" ADD COLUMN "enableReplayRequests" boolean DEFAULT false NOT NULL;
@@ -0,0 +1,2 @@
CREATE TYPE "public"."replay_request_status" AS ENUM('PENDING', 'FULFILLED', 'REJECTED');--> statement-breakpoint
ALTER TABLE "song_replay_requests" ADD COLUMN "status" "replay_request_status" DEFAULT 'PENDING' NOT NULL;
@@ -0,0 +1,11 @@
CREATE TABLE "UserIdentity" (
"id" serial PRIMARY KEY NOT NULL,
"userId" integer NOT NULL,
"provider" text NOT NULL,
"providerUserId" text NOT NULL,
"providerUsername" text,
"createdAt" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "UserIdentity_provider_providerUserId_unique" UNIQUE("provider","providerUserId")
);
--> statement-breakpoint
ALTER TABLE "UserIdentity" ADD CONSTRAINT "UserIdentity_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE no action;
@@ -0,0 +1 @@
ALTER TABLE "SystemSettings" ADD COLUMN "monthlySubmissionLimit" integer;
@@ -0,0 +1,2 @@
ALTER TABLE "SystemSettings" ADD COLUMN "gonganNumber" text;--> statement-breakpoint
ALTER TABLE "SystemSettings" ADD COLUMN "gonganLink" text;
@@ -0,0 +1 @@
ALTER TABLE "SystemSettings" DROP COLUMN "gonganLink";
@@ -0,0 +1 @@
ALTER TABLE "SystemSettings" ADD COLUMN "enableCollaborativeSubmission" boolean DEFAULT true NOT NULL;
@@ -0,0 +1,3 @@
ALTER TABLE "Song" ADD COLUMN "submissionNote" text;
ALTER TABLE "Song" ADD COLUMN "submissionNotePublic" boolean DEFAULT false NOT NULL;
ALTER TABLE "SystemSettings" ADD COLUMN "enableSubmissionRemarks" boolean DEFAULT false NOT NULL;
@@ -0,0 +1 @@
ALTER TYPE "public"."user_status" ADD VALUE 'graduate';
@@ -0,0 +1,791 @@
{
"id": "7431b15e-7067-4715-87c6-cc4c83712e0b",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.NotificationSettings": {
"name": "NotificationSettings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songRequestEnabled": {
"name": "songRequestEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songVotedEnabled": {
"name": "songVotedEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songPlayedEnabled": {
"name": "songPlayedEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"refreshInterval": {
"name": "refreshInterval",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 60
},
"songVotedThreshold": {
"name": "songVotedThreshold",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"NotificationSettings_userId_unique": {
"name": "NotificationSettings_userId_unique",
"nullsNotDistinct": false,
"columns": [
"userId"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Notification": {
"name": "Notification",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"message": {
"name": "message",
"type": "text",
"primaryKey": false,
"notNull": true
},
"read": {
"name": "read",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.PlayTime": {
"name": "PlayTime",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"startTime": {
"name": "startTime",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endTime": {
"name": "endTime",
"type": "text",
"primaryKey": false,
"notNull": false
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Schedule": {
"name": "Schedule",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"playDate": {
"name": "playDate",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"played": {
"name": "played",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"sequence": {
"name": "sequence",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"playTimeId": {
"name": "playTimeId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Semester": {
"name": "Semester",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"Semester_name_unique": {
"name": "Semester_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.SongBlacklist": {
"name": "SongBlacklist",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"type": {
"name": "type",
"type": "BlacklistType",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true
},
"reason": {
"name": "reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"createdBy": {
"name": "createdBy",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Song": {
"name": "Song",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"artist": {
"name": "artist",
"type": "text",
"primaryKey": false,
"notNull": true
},
"requesterId": {
"name": "requesterId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"played": {
"name": "played",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"playedAt": {
"name": "playedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"semester": {
"name": "semester",
"type": "text",
"primaryKey": false,
"notNull": false
},
"preferredPlayTimeId": {
"name": "preferredPlayTimeId",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cover": {
"name": "cover",
"type": "text",
"primaryKey": false,
"notNull": false
},
"musicPlatform": {
"name": "musicPlatform",
"type": "text",
"primaryKey": false,
"notNull": false
},
"musicId": {
"name": "musicId",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.SystemSettings": {
"name": "SystemSettings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"enablePlayTimeSelection": {
"name": "enablePlayTimeSelection",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"siteTitle": {
"name": "siteTitle",
"type": "text",
"primaryKey": false,
"notNull": false
},
"siteLogoUrl": {
"name": "siteLogoUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"schoolLogoHomeUrl": {
"name": "schoolLogoHomeUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"schoolLogoPrintUrl": {
"name": "schoolLogoPrintUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"siteDescription": {
"name": "siteDescription",
"type": "text",
"primaryKey": false,
"notNull": false
},
"submissionGuidelines": {
"name": "submissionGuidelines",
"type": "text",
"primaryKey": false,
"notNull": false
},
"icpNumber": {
"name": "icpNumber",
"type": "text",
"primaryKey": false,
"notNull": false
},
"enableSubmissionLimit": {
"name": "enableSubmissionLimit",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"dailySubmissionLimit": {
"name": "dailySubmissionLimit",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"weeklySubmissionLimit": {
"name": "weeklySubmissionLimit",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"showBlacklistKeywords": {
"name": "showBlacklistKeywords",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"hideStudentInfo": {
"name": "hideStudentInfo",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"grade": {
"name": "grade",
"type": "text",
"primaryKey": false,
"notNull": false
},
"class": {
"name": "class",
"type": "text",
"primaryKey": false,
"notNull": false
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'USER'"
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true
},
"lastLogin": {
"name": "lastLogin",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"lastLoginIp": {
"name": "lastLoginIp",
"type": "text",
"primaryKey": false,
"notNull": false
},
"passwordChangedAt": {
"name": "passwordChangedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"forcePasswordChange": {
"name": "forcePasswordChange",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"meowNickname": {
"name": "meowNickname",
"type": "text",
"primaryKey": false,
"notNull": false
},
"meowBoundAt": {
"name": "meowBoundAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"User_username_unique": {
"name": "User_username_unique",
"nullsNotDistinct": false,
"columns": [
"username"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
"public.BlacklistType": {
"name": "BlacklistType",
"schema": "public",
"values": [
"SONG",
"KEYWORD"
]
}
},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
@@ -0,0 +1,783 @@
{
"id": "5412e543-4a9c-416f-87b1-b8a405a19172",
"prevId": "7431b15e-7067-4715-87c6-cc4c83712e0b",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.NotificationSettings": {
"name": "NotificationSettings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songRequestEnabled": {
"name": "songRequestEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songVotedEnabled": {
"name": "songVotedEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songPlayedEnabled": {
"name": "songPlayedEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"refreshInterval": {
"name": "refreshInterval",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 60
},
"songVotedThreshold": {
"name": "songVotedThreshold",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"NotificationSettings_userId_unique": {
"name": "NotificationSettings_userId_unique",
"nullsNotDistinct": false,
"columns": [
"userId"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Notification": {
"name": "Notification",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"message": {
"name": "message",
"type": "text",
"primaryKey": false,
"notNull": true
},
"read": {
"name": "read",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.PlayTime": {
"name": "PlayTime",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"startTime": {
"name": "startTime",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endTime": {
"name": "endTime",
"type": "text",
"primaryKey": false,
"notNull": false
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Schedule": {
"name": "Schedule",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"playDate": {
"name": "playDate",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"played": {
"name": "played",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"sequence": {
"name": "sequence",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"playTimeId": {
"name": "playTimeId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Semester": {
"name": "Semester",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.SongBlacklist": {
"name": "SongBlacklist",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"type": {
"name": "type",
"type": "BlacklistType",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true
},
"reason": {
"name": "reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"createdBy": {
"name": "createdBy",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Song": {
"name": "Song",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"artist": {
"name": "artist",
"type": "text",
"primaryKey": false,
"notNull": true
},
"requesterId": {
"name": "requesterId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"played": {
"name": "played",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"playedAt": {
"name": "playedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"semester": {
"name": "semester",
"type": "text",
"primaryKey": false,
"notNull": false
},
"preferredPlayTimeId": {
"name": "preferredPlayTimeId",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cover": {
"name": "cover",
"type": "text",
"primaryKey": false,
"notNull": false
},
"musicPlatform": {
"name": "musicPlatform",
"type": "text",
"primaryKey": false,
"notNull": false
},
"musicId": {
"name": "musicId",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.SystemSettings": {
"name": "SystemSettings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"enablePlayTimeSelection": {
"name": "enablePlayTimeSelection",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"siteTitle": {
"name": "siteTitle",
"type": "text",
"primaryKey": false,
"notNull": false
},
"siteLogoUrl": {
"name": "siteLogoUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"schoolLogoHomeUrl": {
"name": "schoolLogoHomeUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"schoolLogoPrintUrl": {
"name": "schoolLogoPrintUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"siteDescription": {
"name": "siteDescription",
"type": "text",
"primaryKey": false,
"notNull": false
},
"submissionGuidelines": {
"name": "submissionGuidelines",
"type": "text",
"primaryKey": false,
"notNull": false
},
"icpNumber": {
"name": "icpNumber",
"type": "text",
"primaryKey": false,
"notNull": false
},
"enableSubmissionLimit": {
"name": "enableSubmissionLimit",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"dailySubmissionLimit": {
"name": "dailySubmissionLimit",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"weeklySubmissionLimit": {
"name": "weeklySubmissionLimit",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"showBlacklistKeywords": {
"name": "showBlacklistKeywords",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"hideStudentInfo": {
"name": "hideStudentInfo",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"grade": {
"name": "grade",
"type": "text",
"primaryKey": false,
"notNull": false
},
"class": {
"name": "class",
"type": "text",
"primaryKey": false,
"notNull": false
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'USER'"
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true
},
"lastLogin": {
"name": "lastLogin",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"lastLoginIp": {
"name": "lastLoginIp",
"type": "text",
"primaryKey": false,
"notNull": false
},
"passwordChangedAt": {
"name": "passwordChangedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"forcePasswordChange": {
"name": "forcePasswordChange",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"meowNickname": {
"name": "meowNickname",
"type": "text",
"primaryKey": false,
"notNull": false
},
"meowBoundAt": {
"name": "meowBoundAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"User_username_unique": {
"name": "User_username_unique",
"nullsNotDistinct": false,
"columns": [
"username"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
"public.BlacklistType": {
"name": "BlacklistType",
"schema": "public",
"values": [
"SONG",
"KEYWORD"
]
}
},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
@@ -0,0 +1,767 @@
{
"id": "b7406ed0-51d0-4217-92f0-0131b12db197",
"prevId": "5412e543-4a9c-416f-87b1-b8a405a19172",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.NotificationSettings": {
"name": "NotificationSettings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songRequestEnabled": {
"name": "songRequestEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songVotedEnabled": {
"name": "songVotedEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"songPlayedEnabled": {
"name": "songPlayedEnabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"refreshInterval": {
"name": "refreshInterval",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 60
},
"songVotedThreshold": {
"name": "songVotedThreshold",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Notification": {
"name": "Notification",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"message": {
"name": "message",
"type": "text",
"primaryKey": false,
"notNull": true
},
"read": {
"name": "read",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.PlayTime": {
"name": "PlayTime",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"startTime": {
"name": "startTime",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endTime": {
"name": "endTime",
"type": "text",
"primaryKey": false,
"notNull": false
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Schedule": {
"name": "Schedule",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"playDate": {
"name": "playDate",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"played": {
"name": "played",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"sequence": {
"name": "sequence",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"playTimeId": {
"name": "playTimeId",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Semester": {
"name": "Semester",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.SongBlacklist": {
"name": "SongBlacklist",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"type": {
"name": "type",
"type": "BlacklistType",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true
},
"reason": {
"name": "reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"createdBy": {
"name": "createdBy",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Song": {
"name": "Song",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"artist": {
"name": "artist",
"type": "text",
"primaryKey": false,
"notNull": true
},
"requesterId": {
"name": "requesterId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"played": {
"name": "played",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"playedAt": {
"name": "playedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"semester": {
"name": "semester",
"type": "text",
"primaryKey": false,
"notNull": false
},
"preferredPlayTimeId": {
"name": "preferredPlayTimeId",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cover": {
"name": "cover",
"type": "text",
"primaryKey": false,
"notNull": false
},
"musicPlatform": {
"name": "musicPlatform",
"type": "text",
"primaryKey": false,
"notNull": false
},
"musicId": {
"name": "musicId",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.SystemSettings": {
"name": "SystemSettings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"enablePlayTimeSelection": {
"name": "enablePlayTimeSelection",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"siteTitle": {
"name": "siteTitle",
"type": "text",
"primaryKey": false,
"notNull": false
},
"siteLogoUrl": {
"name": "siteLogoUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"schoolLogoHomeUrl": {
"name": "schoolLogoHomeUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"schoolLogoPrintUrl": {
"name": "schoolLogoPrintUrl",
"type": "text",
"primaryKey": false,
"notNull": false
},
"siteDescription": {
"name": "siteDescription",
"type": "text",
"primaryKey": false,
"notNull": false
},
"submissionGuidelines": {
"name": "submissionGuidelines",
"type": "text",
"primaryKey": false,
"notNull": false
},
"icpNumber": {
"name": "icpNumber",
"type": "text",
"primaryKey": false,
"notNull": false
},
"enableSubmissionLimit": {
"name": "enableSubmissionLimit",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"dailySubmissionLimit": {
"name": "dailySubmissionLimit",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"weeklySubmissionLimit": {
"name": "weeklySubmissionLimit",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"showBlacklistKeywords": {
"name": "showBlacklistKeywords",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"hideStudentInfo": {
"name": "hideStudentInfo",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"grade": {
"name": "grade",
"type": "text",
"primaryKey": false,
"notNull": false
},
"class": {
"name": "class",
"type": "text",
"primaryKey": false,
"notNull": false
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'USER'"
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true
},
"lastLogin": {
"name": "lastLogin",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"lastLoginIp": {
"name": "lastLoginIp",
"type": "text",
"primaryKey": false,
"notNull": false
},
"passwordChangedAt": {
"name": "passwordChangedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"forcePasswordChange": {
"name": "forcePasswordChange",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"meowNickname": {
"name": "meowNickname",
"type": "text",
"primaryKey": false,
"notNull": false
},
"meowBoundAt": {
"name": "meowBoundAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"songId": {
"name": "songId",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "integer",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
"public.BlacklistType": {
"name": "BlacklistType",
"schema": "public",
"values": [
"SONG",
"KEYWORD"
]
}
},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
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
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
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
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
@@ -0,0 +1,118 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1756291495622,
"tag": "0000_friendly_garia",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1756299330141,
"tag": "20250827125530_little_james_howlett",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1756368610365,
"tag": "20250828081010_careful_shinobi_shaw",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1757772919975,
"tag": "20250913141519_clumsy_maria_hill",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1757819341115,
"tag": "20250914030901_majestic_black_widow",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1759395147253,
"tag": "20251002085227_deep_silver_sable",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1767777840967,
"tag": "20260107092400_add_collaboration_and_request_time",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1768042908810,
"tag": "20260110000001_add_replay_requests",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1769766215307,
"tag": "20260130094335_add_replay_request_status",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1770895837437,
"tag": "20260212113037_add_user_identities_table",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1772187630689,
"tag": "20260227102030_add_monthly_submission_limit",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1772889825480,
"tag": "20260307132345_add_gongan_filing",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1772890398452,
"tag": "20260307133318_remove_gongan_link",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1773923154561,
"tag": "20260319122554_add_collaborative_submission_toggle",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1773927000000,
"tag": "20260319133000_add_submission_remarks",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1775136952492,
"tag": "20260402133552_remarkable_star_brand",
"breakpoints": true
}
]
}
@@ -0,0 +1,13 @@
import { relations } from "drizzle-orm/relations";
import { user, userIdentity } from "./schema";
export const userIdentityRelations = relations(userIdentity, ({one}) => ({
user: one(user, {
fields: [userIdentity.userId],
references: [user.id]
}),
}));
export const userRelations = relations(user, ({many}) => ({
userIdentities: many(userIdentity),
}));
@@ -0,0 +1,284 @@
import { pgTable, serial, timestamp, varchar, text, integer, boolean, bigint, uuid, unique, foreignKey, pgEnum } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"
export const blacklistType = pgEnum("BlacklistType", ['SONG', 'KEYWORD'])
export const collaboratorStatus = pgEnum("collaborator_status", ['PENDING', 'ACCEPTED', 'REJECTED'])
export const replayRequestStatus = pgEnum("replay_request_status", ['PENDING', 'FULFILLED', 'REJECTED'])
export const userStatus = pgEnum("user_status", ['active', 'withdrawn'])
export const emailTemplate = pgTable("EmailTemplate", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
key: varchar({ length: 100 }).notNull(),
name: varchar({ length: 200 }).notNull(),
subject: varchar({ length: 300 }).notNull(),
html: text().notNull(),
updatedByUserId: integer(),
});
export const notification = pgTable("Notification", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
type: text().notNull(),
message: text().notNull(),
read: boolean().default(false).notNull(),
userId: integer().notNull(),
songId: integer(),
});
export const notificationSettings = pgTable("NotificationSettings", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
userId: integer().notNull(),
enabled: boolean().default(true).notNull(),
songRequestEnabled: boolean().default(true).notNull(),
songVotedEnabled: boolean().default(true).notNull(),
songPlayedEnabled: boolean().default(true).notNull(),
refreshInterval: integer().default(60).notNull(),
songVotedThreshold: integer().default(1).notNull(),
});
export const playTime = pgTable("PlayTime", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
name: text().notNull(),
startTime: text(),
endTime: text(),
enabled: boolean().default(true).notNull(),
description: text(),
});
export const requestTime = pgTable("RequestTime", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ precision: 6, mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ precision: 6, mode: 'string' }).defaultNow().notNull(),
name: text().notNull(),
startTime: timestamp({ mode: 'string' }).notNull(),
endTime: timestamp({ mode: 'string' }).notNull(),
enabled: boolean().default(true).notNull(),
description: text(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
expected: bigint({ mode: "number" }).default(0).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
accepted: bigint({ mode: "number" }).default(0).notNull(),
past: boolean().default(false).notNull(),
});
export const schedule = pgTable("Schedule", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
songId: integer().notNull(),
playDate: timestamp({ mode: 'string' }).notNull(),
played: boolean().default(false).notNull(),
sequence: integer().default(1).notNull(),
playTimeId: integer(),
isDraft: boolean().default(false).notNull(),
publishedAt: timestamp({ mode: 'string' }),
});
export const semester = pgTable("Semester", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
name: text().notNull(),
isActive: boolean().default(false).notNull(),
});
export const song = pgTable("Song", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
title: text().notNull(),
artist: text().notNull(),
requesterId: integer().notNull(),
played: boolean().default(false).notNull(),
playedAt: timestamp({ mode: 'string' }).defaultNow(),
semester: text(),
preferredPlayTimeId: integer(),
cover: text(),
playUrl: text(),
musicPlatform: text(),
musicId: text(),
hitRequestId: integer(),
});
export const songBlacklist = pgTable("SongBlacklist", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
type: blacklistType().notNull(),
value: text().notNull(),
reason: text(),
isActive: boolean().default(true).notNull(),
createdBy: integer(),
});
export const systemSettings = pgTable("SystemSettings", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
enablePlayTimeSelection: boolean().default(false).notNull(),
siteTitle: text(),
siteLogoUrl: text(),
schoolLogoHomeUrl: text(),
schoolLogoPrintUrl: text(),
siteDescription: text(),
submissionGuidelines: text(),
icpNumber: text(),
enableSubmissionLimit: boolean().default(false).notNull(),
dailySubmissionLimit: integer(),
weeklySubmissionLimit: integer(),
showBlacklistKeywords: boolean().default(false).notNull(),
hideStudentInfo: boolean().default(true).notNull(),
smtpEnabled: boolean().default(false).notNull(),
smtpHost: text(),
smtpPort: integer().default(587),
smtpSecure: boolean().default(false),
smtpUsername: text(),
smtpPassword: text(),
smtpFromEmail: text(),
smtpFromName: text().default('校园广播站'),
enableRequestTimeLimitation: boolean().default(false).notNull(),
forceBlockAllRequests: boolean().default(false).notNull(),
enableReplayRequests: boolean().default(false).notNull(),
monthlySubmissionLimit: integer(),
gonganNumber: text(),
enableCollaborativeSubmission: boolean().default(true).notNull(),
});
export const vote = pgTable("Vote", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
songId: integer().notNull(),
userId: integer().notNull(),
});
export const apiKeyPermissions = pgTable("api_key_permissions", {
id: uuid().defaultRandom().primaryKey().notNull(),
apiKeyId: uuid("api_key_id").notNull(),
permission: varchar({ length: 100 }).notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
});
export const apiKeys = pgTable("api_keys", {
id: uuid().defaultRandom().primaryKey().notNull(),
name: varchar({ length: 255 }).notNull(),
description: text(),
keyHash: varchar("key_hash", { length: 255 }).notNull(),
keyPrefix: varchar("key_prefix", { length: 10 }).notNull(),
isActive: boolean("is_active").default(true).notNull(),
expiresAt: timestamp("expires_at", { withTimezone: true, mode: 'string' }),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
lastUsedAt: timestamp("last_used_at", { withTimezone: true, mode: 'string' }),
createdByUserId: integer("created_by_user_id").notNull(),
usageCount: integer("usage_count").default(0).notNull(),
}, (table) => [
unique("api_keys_key_hash_unique").on(table.keyHash),
]);
export const apiLogs = pgTable("api_logs", {
id: uuid().defaultRandom().primaryKey().notNull(),
apiKeyId: uuid("api_key_id"),
endpoint: varchar({ length: 500 }).notNull(),
method: varchar({ length: 10 }).notNull(),
ipAddress: text("ip_address").notNull(),
userAgent: text("user_agent"),
statusCode: integer("status_code").notNull(),
responseTimeMs: integer("response_time_ms").notNull(),
requestBody: text("request_body"),
responseBody: text("response_body"),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
errorMessage: text("error_message"),
});
export const collaborationLogs = pgTable("collaboration_logs", {
id: uuid().defaultRandom().primaryKey().notNull(),
collaboratorId: uuid("collaborator_id").notNull(),
action: varchar({ length: 50 }).notNull(),
operatorId: integer("operator_id").notNull(),
ipAddress: text("ip_address"),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
});
export const songCollaborators = pgTable("song_collaborators", {
id: uuid().defaultRandom().primaryKey().notNull(),
songId: integer("song_id").notNull(),
userId: integer("user_id").notNull(),
status: collaboratorStatus().default('PENDING').notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
});
export const songReplayRequests = pgTable("song_replay_requests", {
id: serial().primaryKey().notNull(),
songId: integer("song_id").notNull(),
userId: integer("user_id").notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
status: replayRequestStatus().default('PENDING').notNull(),
}, (table) => [
unique("song_replay_requests_song_id_user_id_unique").on(table.songId, table.userId),
]);
export const userStatusLogs = pgTable("user_status_logs", {
id: serial().primaryKey().notNull(),
userId: integer("user_id").notNull(),
oldStatus: userStatus("old_status"),
newStatus: userStatus("new_status").notNull(),
reason: text(),
operatorId: integer("operator_id"),
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
});
export const user = pgTable("User", {
id: serial().primaryKey().notNull(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
username: text().notNull(),
name: text(),
grade: text(),
class: text(),
role: text().default('USER').notNull(),
password: text().notNull(),
email: text(),
emailVerified: boolean().default(false),
lastLogin: timestamp({ mode: 'string' }),
lastLoginIp: text(),
passwordChangedAt: timestamp({ mode: 'string' }),
forcePasswordChange: boolean().default(true).notNull(),
meowNickname: text(),
meowBoundAt: timestamp({ mode: 'string' }),
status: userStatus().default('active').notNull(),
statusChangedAt: timestamp({ mode: 'string' }).defaultNow(),
statusChangedBy: integer(),
});
export const userIdentity = pgTable("UserIdentity", {
id: serial().primaryKey().notNull(),
userId: integer().notNull(),
provider: text().notNull(),
providerUserId: text().notNull(),
providerUsername: text(),
createdAt: timestamp({ mode: 'string' }).defaultNow().notNull(),
}, (table) => [
foreignKey({
columns: [table.userId],
foreignColumns: [user.id],
name: "UserIdentity_userId_User_id_fk"
}).onDelete("cascade"),
unique("UserIdentity_provider_providerUserId_unique").on(table.provider, table.providerUserId),
]);
export const drizzleMigrations = pgTable("__drizzle_migrations__", {
id: serial().primaryKey().notNull(),
hash: text().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
createdAt: bigint("created_at", { mode: "number" }),
});