using System; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable namespace Content.Server.Database.Migrations.Sqlite { /// public partial class BanRefactor : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "ban", columns: table => new { ban_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), type = table.Column(type: "INTEGER", nullable: false), playtime_at_note = table.Column(type: "TEXT", nullable: false), ban_time = table.Column(type: "TEXT", nullable: false), expiration_time = table.Column(type: "TEXT", nullable: true), reason = table.Column(type: "TEXT", nullable: false), severity = table.Column(type: "INTEGER", nullable: false), banning_admin = table.Column(type: "TEXT", nullable: true), last_edited_by_id = table.Column(type: "TEXT", nullable: true), last_edited_at = table.Column(type: "TEXT", nullable: true), exempt_flags = table.Column(type: "INTEGER", nullable: false), auto_delete = table.Column(type: "INTEGER", nullable: false), hidden = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_ban", x => x.ban_id); table.CheckConstraint("NoExemptOnRoleBan", "type = 0 OR exempt_flags = 0"); table.ForeignKey( name: "FK_ban_player_banning_admin", column: x => x.banning_admin, principalTable: "player", principalColumn: "user_id", onDelete: ReferentialAction.SetNull); table.ForeignKey( name: "FK_ban_player_last_edited_by_id", column: x => x.last_edited_by_id, principalTable: "player", principalColumn: "user_id", onDelete: ReferentialAction.SetNull); }); migrationBuilder.CreateTable( name: "ban_address", columns: table => new { ban_address_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), address = table.Column(type: "TEXT", nullable: false), ban_id = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_ban_address", x => x.ban_address_id); table.ForeignKey( name: "FK_ban_address_ban_ban_id", column: x => x.ban_id, principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "ban_hwid", columns: table => new { ban_hwid_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), hwid = table.Column(type: "BLOB", nullable: false), hwid_type = table.Column(type: "INTEGER", nullable: false), ban_id = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_ban_hwid", x => x.ban_hwid_id); table.ForeignKey( name: "FK_ban_hwid_ban_ban_id", column: x => x.ban_id, principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "ban_player", columns: table => new { ban_player_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), user_id = table.Column(type: "TEXT", nullable: false), ban_id = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_ban_player", x => x.ban_player_id); table.ForeignKey( name: "FK_ban_player_ban_ban_id", column: x => x.ban_id, principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "ban_role", columns: table => new { ban_role_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), role_type = table.Column(type: "TEXT", nullable: false), role_id = table.Column(type: "TEXT", nullable: false), ban_id = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_ban_role", x => x.ban_role_id); table.ForeignKey( name: "FK_ban_role_ban_ban_id", column: x => x.ban_id, principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "ban_round", columns: table => new { ban_round_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), ban_id = table.Column(type: "INTEGER", nullable: false), round_id = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_ban_round", x => x.ban_round_id); table.ForeignKey( name: "FK_ban_round_ban_ban_id", column: x => x.ban_id, principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_ban_round_round_round_id", column: x => x.round_id, principalTable: "round", principalColumn: "round_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "unban", columns: table => new { unban_id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), ban_id = table.Column(type: "INTEGER", nullable: false), unbanning_admin = table.Column(type: "TEXT", nullable: true), unban_time = table.Column(type: "TEXT", nullable: false) }, constraints: table => { table.PrimaryKey("PK_unban", x => x.unban_id); table.ForeignKey( name: "FK_unban_ban_ban_id", column: x => x.ban_id, principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_ban_banning_admin", table: "ban", column: "banning_admin"); migrationBuilder.CreateIndex( name: "IX_ban_last_edited_by_id", table: "ban", column: "last_edited_by_id"); migrationBuilder.CreateIndex( name: "IX_ban_address_ban_id", table: "ban_address", column: "ban_id"); migrationBuilder.CreateIndex( name: "IX_ban_hwid_ban_id", table: "ban_hwid", column: "ban_id"); migrationBuilder.CreateIndex( name: "IX_ban_player_ban_id", table: "ban_player", column: "ban_id"); migrationBuilder.CreateIndex( name: "IX_ban_player_user_id_ban_id", table: "ban_player", columns: new[] { "user_id", "ban_id" }, unique: true); migrationBuilder.CreateIndex( name: "IX_ban_role_ban_id", table: "ban_role", column: "ban_id"); migrationBuilder.CreateIndex( name: "IX_ban_role_role_type_role_id_ban_id", table: "ban_role", columns: new[] { "role_type", "role_id", "ban_id" }, unique: true); migrationBuilder.CreateIndex( name: "IX_ban_round_ban_id", table: "ban_round", column: "ban_id"); migrationBuilder.CreateIndex( name: "IX_ban_round_round_id_ban_id", table: "ban_round", columns: new[] { "round_id", "ban_id" }, unique: true); migrationBuilder.CreateIndex( name: "IX_unban_ban_id", table: "unban", column: "ban_id", unique: true); migrationBuilder.Sql(""" CREATE UNIQUE INDEX "IX_ban_hwid_hwid_ban_id" ON ban_hwid (hwid_type, hwid, ban_id); CREATE UNIQUE INDEX "IX_ban_address_address_ban_id" ON ban_address (address, ban_id); """); migrationBuilder.Sql(""" -- -- Insert game bans -- INSERT INTO ban (ban_id, type, playtime_at_note, ban_time, expiration_time, reason, severity, banning_admin, last_edited_by_id, last_edited_at, exempt_flags, auto_delete, hidden) SELECT server_ban_id, 0, playtime_at_note, ban_time, expiration_time, reason, severity, banning_admin, last_edited_by_id, last_edited_at, exempt_flags, auto_delete, hidden FROM server_ban; -- Insert ban player records. INSERT INTO ban_player (user_id, ban_id) SELECT player_user_id, server_ban_id FROM server_ban WHERE player_user_id IS NOT NULL; -- Insert ban address records. INSERT INTO ban_address (address, ban_id) SELECT address, server_ban_id FROM server_ban WHERE address IS NOT NULL; -- Insert ban HWID records. INSERT INTO ban_hwid (hwid, hwid_type, ban_id) SELECT hwid, hwid_type, server_ban_id FROM server_ban WHERE hwid IS NOT NULL; -- Insert ban unban records. INSERT INTO unban (ban_id, unbanning_admin, unban_time) SELECT ban_id, unbanning_admin, unban_time FROM server_unban; -- Insert ban round records. INSERT INTO ban_round (round_id, ban_id) SELECT round_id, server_ban_id FROM server_ban WHERE round_id IS NOT NULL; -- -- Insert role bans -- This shit is a pain in the ass -- > Declarative language -- > Has to write procedural code in it -- -- Create mapping table from role ban -> server ban. -- We have to manually calculate the new ban IDs by using the sequence. -- We also want to merge role ban records because the game code previously did that in some UI, -- and that code is now gone, expecting the DB to do it. -- Create a table to store IDs to merge. CREATE TEMPORARY TABLE _role_ban_import_merge_map (merge_id INTEGER, server_role_ban_id INTEGER UNIQUE); -- Create a table to store merged IDs -> new ban IDs CREATE TEMPORARY TABLE _role_ban_import_id_map (ban_id INTEGER UNIQUE, merge_id INTEGER UNIQUE); -- Calculate merged role bans. INSERT INTO _role_ban_import_merge_map SELECT ( SELECT sub.server_role_ban_id FROM server_role_ban AS sub LEFT JOIN server_role_unban AS sub_unban ON sub_unban.ban_id = sub.server_role_ban_id WHERE main.reason IS NOT DISTINCT FROM sub.reason AND main.player_user_id IS NOT DISTINCT FROM sub.player_user_id AND main.address IS NOT DISTINCT FROM sub.address AND main.hwid IS NOT DISTINCT FROM sub.hwid AND main.hwid_type IS NOT DISTINCT FROM sub.hwid_type AND main.ban_time = sub.ban_time AND ( (main.expiration_time IS NULL) = (sub.expiration_time IS NULL) OR main.expiration_time = sub.expiration_time ) AND main.round_id IS NOT DISTINCT FROM sub.round_id AND main.severity IS NOT DISTINCT FROM sub.severity AND main.hidden IS NOT DISTINCT FROM sub.hidden AND main.banning_admin IS NOT DISTINCT FROM sub.banning_admin AND (sub_unban.ban_id IS NULL) = (main_unban.ban_id IS NULL) ORDER BY sub.server_role_ban_id ASC LIMIT 1 ), main.server_role_ban_id FROM server_role_ban AS main LEFT JOIN server_role_unban AS main_unban ON main_unban.ban_id = main.server_role_ban_id; -- Assign new ban IDs for merged IDs. INSERT OR IGNORE INTO _role_ban_import_id_map SELECT merge_id + (SELECT seq FROM sqlite_sequence WHERE name = 'ban'), merge_id FROM _role_ban_import_merge_map; -- I sure fucking wish CTEs could span multiple queries... -- Insert new ban records INSERT INTO ban (ban_id, type, playtime_at_note, ban_time, expiration_time, reason, severity, banning_admin, last_edited_by_id, last_edited_at, exempt_flags, auto_delete, hidden) SELECT im.ban_id, 1, playtime_at_note, ban_time, expiration_time, reason, severity, banning_admin, last_edited_by_id, last_edited_at, 0, FALSE, hidden FROM _role_ban_import_id_map im INNER JOIN _role_ban_import_merge_map mm ON im.merge_id = mm.merge_id INNER JOIN server_role_ban srb ON srb.server_role_ban_id = im.merge_id WHERE mm.merge_id = mm.server_role_ban_id; -- Insert role ban player records. INSERT INTO ban_player (user_id, ban_id) SELECT player_user_id, im.ban_id FROM _role_ban_import_id_map im INNER JOIN _role_ban_import_merge_map mm ON im.merge_id = mm.merge_id INNER JOIN server_role_ban srb ON srb.server_role_ban_id = im.merge_id WHERE mm.merge_id = mm.server_role_ban_id AND player_user_id IS NOT NULL; -- Insert role ban address records. INSERT INTO ban_address (address, ban_id) SELECT address, im.ban_id FROM _role_ban_import_id_map im INNER JOIN _role_ban_import_merge_map mm ON im.merge_id = mm.merge_id INNER JOIN server_role_ban srb ON srb.server_role_ban_id = im.merge_id WHERE mm.merge_id = mm.server_role_ban_id AND address IS NOT NULL; -- Insert role ban HWID records. INSERT INTO ban_hwid (hwid, hwid_type, ban_id) SELECT hwid, hwid_type, im.ban_id FROM _role_ban_import_id_map im INNER JOIN _role_ban_import_merge_map mm ON im.merge_id = mm.merge_id INNER JOIN server_role_ban srb ON srb.server_role_ban_id = im.merge_id WHERE mm.merge_id = mm.server_role_ban_id AND hwid IS NOT NULL; -- Insert role ban role records. INSERT INTO ban_role (role_type, role_id, ban_id) SELECT substr(role_id, 1, instr(role_id, ':')-1), substr(role_id, instr(role_id, ':')+1), im.ban_id FROM _role_ban_import_id_map im INNER JOIN _role_ban_import_merge_map mm ON im.merge_id = mm.merge_id INNER JOIN server_role_ban srb ON srb.server_role_ban_id = mm.server_role_ban_id -- Yes, we have some messy ban records which, after merging, end up with duplicate roles. ON CONFLICT DO NOTHING; -- Insert role unban records. INSERT INTO unban (ban_id, unbanning_admin, unban_time) SELECT im.ban_id, unbanning_admin, unban_time FROM server_role_unban sru INNER JOIN _role_ban_import_id_map im ON im.merge_id = sru.ban_id; -- Insert role rounds INSERT INTO ban_round (round_id, ban_id) SELECT round_id, im.ban_id FROM _role_ban_import_id_map im INNER JOIN _role_ban_import_merge_map mm ON im.merge_id = mm.merge_id INNER JOIN server_role_ban srb ON srb.server_role_ban_id = im.merge_id WHERE mm.merge_id = mm.server_role_ban_id AND round_id IS NOT NULL; """); migrationBuilder.AddForeignKey( name: "FK_server_ban_hit_ban_ban_id", table: "server_ban_hit", column: "ban_id", principalTable: "ban", principalColumn: "ban_id", onDelete: ReferentialAction.Cascade); migrationBuilder.DropForeignKey( name: "FK_server_ban_hit_server_ban_ban_id", table: "server_ban_hit"); migrationBuilder.DropTable( name: "server_role_unban"); migrationBuilder.DropTable( name: "server_unban"); migrationBuilder.DropTable( name: "server_role_ban"); migrationBuilder.DropTable( name: "server_ban"); } /// protected override void Down(MigrationBuilder migrationBuilder) { throw new NotSupportedException("This migration cannot be rolled back"); } } }