AI Implementation feature(820): Project Scaffold and Platform Foundations (#1)
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
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";`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user