124 lines
5.2 KiB
TypeScript
124 lines
5.2 KiB
TypeScript
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
|
|
export class InitSchema1700000000000 implements MigrationInterface {
|
|
name = 'InitSchema1700000000000';
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`PRAGMA foreign_keys = ON;`);
|
|
await queryRunner.query(`PRAGMA journal_mode = WAL;`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "user" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"username" TEXT NOT NULL UNIQUE,
|
|
"password_hash" TEXT NOT NULL,
|
|
"role" TEXT NOT NULL DEFAULT 'player',
|
|
"status" TEXT NOT NULL DEFAULT 'enabled',
|
|
"created_at" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
);
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "setting" (
|
|
"key" TEXT PRIMARY KEY,
|
|
"value" TEXT NOT NULL DEFAULT ''
|
|
);
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "category" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"system_key" TEXT,
|
|
"name" TEXT NOT NULL,
|
|
"abbreviation" TEXT NOT NULL,
|
|
"description" TEXT NOT NULL DEFAULT '',
|
|
"icon_path" TEXT NOT NULL DEFAULT ''
|
|
);
|
|
`);
|
|
await queryRunner.query(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_category_system_key" ON "category"("system_key") WHERE "system_key" IS NOT NULL;`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "challenge" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"name" TEXT NOT NULL,
|
|
"description_md" TEXT NOT NULL DEFAULT '',
|
|
"category_id" TEXT NOT NULL,
|
|
"difficulty" TEXT NOT NULL DEFAULT 'low',
|
|
"initial_points" INTEGER NOT NULL DEFAULT 0,
|
|
"minimum_points" INTEGER NOT NULL DEFAULT 0,
|
|
"decay_solves" INTEGER NOT NULL DEFAULT 0,
|
|
"flag" TEXT NOT NULL DEFAULT '',
|
|
"protocol" TEXT NOT NULL DEFAULT 'nc',
|
|
"port" INTEGER,
|
|
"ip_address" TEXT NOT NULL DEFAULT '',
|
|
"created_at" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
CONSTRAINT "fk_challenge_category" FOREIGN KEY ("category_id") REFERENCES "category"("id") ON DELETE RESTRICT
|
|
);
|
|
`);
|
|
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "idx_challenge_category" ON "challenge"("category_id");`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "challenge_file" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"challenge_id" TEXT NOT NULL,
|
|
"original_filename" TEXT NOT NULL,
|
|
"stored_path" TEXT NOT NULL,
|
|
CONSTRAINT "fk_challenge_file_challenge" FOREIGN KEY ("challenge_id") REFERENCES "challenge"("id") ON DELETE RESTRICT
|
|
);
|
|
`);
|
|
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "idx_challenge_file_challenge" ON "challenge_file"("challenge_id");`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "solve" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"challenge_id" TEXT NOT NULL,
|
|
"user_id" TEXT NOT NULL,
|
|
"solved_at" TEXT NOT NULL,
|
|
"points_awarded" INTEGER NOT NULL DEFAULT 0,
|
|
"base_points" INTEGER NOT NULL DEFAULT 0,
|
|
"rank_bonus" INTEGER NOT NULL DEFAULT 0,
|
|
CONSTRAINT "fk_solve_challenge" FOREIGN KEY ("challenge_id") REFERENCES "challenge"("id") ON DELETE RESTRICT,
|
|
CONSTRAINT "fk_solve_user" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE RESTRICT
|
|
);
|
|
`);
|
|
await queryRunner.query(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_solve_challenge_user" ON "solve"("challenge_id","user_id");`);
|
|
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "idx_solve_user" ON "solve"("user_id");`);
|
|
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "idx_solve_challenge" ON "solve"("challenge_id");`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "refresh_token" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"user_id" TEXT NOT NULL,
|
|
"token_hash" TEXT NOT NULL UNIQUE,
|
|
"issued_at" TEXT NOT NULL,
|
|
"expires_at" TEXT NOT NULL,
|
|
"revoked_at" TEXT
|
|
);
|
|
`);
|
|
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "idx_refresh_token_user" ON "refresh_token"("user_id");`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE IF NOT EXISTS "blog_post" (
|
|
"id" TEXT PRIMARY KEY,
|
|
"title" TEXT NOT NULL,
|
|
"body_md" TEXT NOT NULL DEFAULT '',
|
|
"status" TEXT NOT NULL DEFAULT 'draft',
|
|
"created_at" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
"updated_at" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
"published_at" TEXT
|
|
);
|
|
`);
|
|
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "idx_blog_status_published" ON "blog_post"("status","published_at");`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "blog_post";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "refresh_token";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "solve";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "challenge_file";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "challenge";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "category";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "setting";`);
|
|
await queryRunner.query(`DROP TABLE IF EXISTS "user";`);
|
|
}
|
|
} |