Files
HIPCTF2/backend/src/database/migrations/1700000000000-InitSchema.ts
T

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";`);
}
}