From 6764340ea1d694feb017bc03a89ab7e848a42bbd Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 2 May 2026 16:57:29 +0300 Subject: [PATCH] Unify weapon report data model --- app/components/match-page/WeaponReporter.tsx | 1 - app/db/seed/index.ts | 5 +- app/db/tables.ts | 8 +-- .../LeaderboardRepository.server.ts | 7 +- .../ReportedWeaponRepository.server.ts | 65 ++++++------------ .../SQMatchRepository.server.test.ts | 16 +---- .../sendouq-match/SQMatchRepository.server.ts | 14 ++-- .../actions/q.match.$id.server.ts | 3 +- .../components/SendouQMatchActionTab.tsx | 8 +-- .../sendouq-match/core/match-timeline.test.ts | 2 +- .../sendouq-match/core/match-timeline.ts | 9 +-- .../core/reported-weapons.server.test.ts | 16 ++--- .../core/reported-weapons.server.ts | 8 ++- app/features/sendouq-match/q-match-schemas.ts | 2 +- .../queries/weaponUsageStats.server.ts | 8 ++- db-test.sqlite3 | Bin 1265664 -> 1265664 bytes migrations/134-match-page.js | 23 +++---- scripts/nuke-reported-weapons.ts | 22 ++++-- 18 files changed, 96 insertions(+), 121 deletions(-) diff --git a/app/components/match-page/WeaponReporter.tsx b/app/components/match-page/WeaponReporter.tsx index 8ceb414f2..19e9a263d 100644 --- a/app/components/match-page/WeaponReporter.tsx +++ b/app/components/match-page/WeaponReporter.tsx @@ -129,7 +129,6 @@ export function WeaponReporter({ { if (selectedWeapon === null) return; diff --git a/app/db/seed/index.ts b/app/db/seed/index.ts index 04b63c443..3ec6043b8 100644 --- a/app/db/seed/index.ts +++ b/app/db/seed/index.ts @@ -3079,7 +3079,7 @@ async function playedMatches() { if (faker.number.float(1) > 0.9) continue; const users = [...groupAlphaMembers, ...groupBravoMembers]; const mapsWithUsers = users.flatMap((u) => - finishedMatch.mapList.map((m) => ({ map: m, user: u })), + finishedMatch.mapList.map((_, mapIndex) => ({ mapIndex, user: u })), ); await ReportedWeaponRepository.createMany( @@ -3097,7 +3097,8 @@ async function playedMatches() { }; return { - groupMatchMapId: mu.map.id, + groupMatchId: match.id, + mapIndex: mu.mapIndex, userId: mu.user, weaponSplId: weapon(), }; diff --git a/app/db/tables.ts b/app/db/tables.ts index b00787aa3..57fde79a5 100644 --- a/app/db/tables.ts +++ b/app/db/tables.ts @@ -453,14 +453,10 @@ export interface PlusVotingResult { passedVoting: DBBoolean; } -// xxx: unify SendouQ side to also key on (matchId, mapIndex). Replace -// groupMatchMapId with groupMatchId, make mapIndex non-null, and have a -// single CHECK that exactly one of groupMatchId / tournamentMatchId is set. -// Backfill (groupMatchId, mapIndex) from GroupMatchMap.matchId/index. export interface ReportedWeapon { - groupMatchMapId: number | null; + groupMatchId: number | null; tournamentMatchId: number | null; - mapIndex: number | null; + mapIndex: number; userId: number; weaponSplId: MainWeaponId; } diff --git a/app/features/leaderboards/LeaderboardRepository.server.ts b/app/features/leaderboards/LeaderboardRepository.server.ts index 435e5db9c..a3147eb56 100644 --- a/app/features/leaderboards/LeaderboardRepository.server.ts +++ b/app/features/leaderboards/LeaderboardRepository.server.ts @@ -410,12 +410,7 @@ export async function seasonPopularUsersWeapon( .with("q1", (db) => db .selectFrom("ReportedWeapon") - .innerJoin( - "GroupMatchMap", - "ReportedWeapon.groupMatchMapId", - "GroupMatchMap.id", - ) - .innerJoin("GroupMatch", "GroupMatchMap.matchId", "GroupMatch.id") + .innerJoin("GroupMatch", "ReportedWeapon.groupMatchId", "GroupMatch.id") .select(({ fn }) => [ "ReportedWeapon.userId", "ReportedWeapon.weaponSplId", diff --git a/app/features/sendouq-match/ReportedWeaponRepository.server.ts b/app/features/sendouq-match/ReportedWeaponRepository.server.ts index df1db2221..234043720 100644 --- a/app/features/sendouq-match/ReportedWeaponRepository.server.ts +++ b/app/features/sendouq-match/ReportedWeaponRepository.server.ts @@ -15,19 +15,24 @@ export function createMany( } export async function upsertOne({ - groupMatchMapId, + groupMatchId, + mapIndex, userId, weaponSplId, -}: TablesInsertable["ReportedWeapon"] & { groupMatchMapId: number }) { +}: TablesInsertable["ReportedWeapon"] & { + groupMatchId: number; + mapIndex: number; +}) { await db .deleteFrom("ReportedWeapon") - .where("groupMatchMapId", "=", groupMatchMapId) + .where("groupMatchId", "=", groupMatchId) + .where("mapIndex", "=", mapIndex) .where("userId", "=", userId) .execute(); await db .insertInto("ReportedWeapon") - .values({ groupMatchMapId, userId, weaponSplId }) + .values({ groupMatchId, mapIndex, userId, weaponSplId }) .execute(); } @@ -38,23 +43,11 @@ export async function replaceByMatchId( ) { const executor = trx ?? db; - const groupMatchMaps = await executor - .selectFrom("GroupMatchMap") - .select("id") - .where("matchId", "=", matchId) + await executor + .deleteFrom("ReportedWeapon") + .where("groupMatchId", "=", matchId) .execute(); - if (groupMatchMaps.length > 0) { - await executor - .deleteFrom("ReportedWeapon") - .where( - "groupMatchMapId", - "in", - groupMatchMaps.map((m) => m.id), - ) - .execute(); - } - if (weapons.length > 0) { await executor.insertInto("ReportedWeapon").values(weapons).execute(); } @@ -69,18 +62,10 @@ export async function deleteByUserMapIndex({ userId: number; mapIndex: number; }) { - const groupMatchMap = await db - .selectFrom("GroupMatchMap") - .select("id") - .where("matchId", "=", matchId) - .where("index", "=", mapIndex) - .executeTakeFirst(); - - if (!groupMatchMap) return; - await db .deleteFrom("ReportedWeapon") - .where("groupMatchMapId", "=", groupMatchMap.id) + .where("groupMatchId", "=", matchId) + .where("mapIndex", "=", mapIndex) .where("userId", "=", userId) .execute(); } @@ -88,21 +73,16 @@ export async function deleteByUserMapIndex({ export async function findByMatchId(matchId: number) { const rows = await db .selectFrom("ReportedWeapon") - .innerJoin( - "GroupMatchMap", - "GroupMatchMap.id", - "ReportedWeapon.groupMatchMapId", - ) .select([ - "ReportedWeapon.groupMatchMapId", + "ReportedWeapon.groupMatchId", + "ReportedWeapon.mapIndex", "ReportedWeapon.weaponSplId", "ReportedWeapon.userId", - "GroupMatchMap.index as mapIndex", ]) - .where("GroupMatchMap.matchId", "=", matchId) - .orderBy("GroupMatchMap.index", "asc") + .where("ReportedWeapon.groupMatchId", "=", matchId) + .orderBy("ReportedWeapon.mapIndex", "asc") .orderBy("ReportedWeapon.userId", "asc") - .$narrowType<{ groupMatchMapId: NotNull }>() + .$narrowType<{ groupMatchId: NotNull }>() .execute(); if (rows.length === 0) return null; @@ -186,12 +166,7 @@ export async function seasonReportedWeaponsByUserId({ const sendouqWeapons = db .selectFrom("ReportedWeapon") - .innerJoin( - "GroupMatchMap", - "GroupMatchMap.id", - "ReportedWeapon.groupMatchMapId", - ) - .innerJoin("GroupMatch", "GroupMatch.id", "GroupMatchMap.matchId") + .innerJoin("GroupMatch", "GroupMatch.id", "ReportedWeapon.groupMatchId") .select(({ fn }) => [ "ReportedWeapon.weaponSplId", fn.countAll().as("count"), diff --git a/app/features/sendouq-match/SQMatchRepository.server.test.ts b/app/features/sendouq-match/SQMatchRepository.server.test.ts index 6ad0f90f2..f547416f8 100644 --- a/app/features/sendouq-match/SQMatchRepository.server.test.ts +++ b/app/features/sendouq-match/SQMatchRepository.server.test.ts @@ -101,13 +101,8 @@ const fetchSkills = async (matchId: number) => { const fetchReportedWeapons = async (matchId: number) => { return db .selectFrom("ReportedWeapon") - .innerJoin( - "GroupMatchMap", - "GroupMatchMap.id", - "ReportedWeapon.groupMatchMapId", - ) .selectAll("ReportedWeapon") - .where("GroupMatchMap.matchId", "=", matchId) + .where("ReportedWeapon.groupMatchId", "=", matchId) .execute(); }; @@ -266,20 +261,13 @@ describe("reportScore", () => { const bravoGroupId = await createGroup([5, 6, 7, 8]); const match = await createMatch(alphaGroupId, bravoGroupId); - const groupMatchMaps = await db - .selectFrom("GroupMatchMap") - .select(["id", "index"]) - .where("matchId", "=", match.id) - .orderBy("index", "asc") - .execute(); - const result = await SQMatchRepository.reportScore({ matchId: match.id, reportedByUserId: 1, winners: ["ALPHA", "ALPHA", "BRAVO", "ALPHA"], weapons: [ { - groupMatchMapId: groupMatchMaps[0].id, + groupMatchId: match.id, weaponSplId: 40, userId: 1, mapIndex: 0, diff --git a/app/features/sendouq-match/SQMatchRepository.server.ts b/app/features/sendouq-match/SQMatchRepository.server.ts index a970c518c..7108db6c2 100644 --- a/app/features/sendouq-match/SQMatchRepository.server.ts +++ b/app/features/sendouq-match/SQMatchRepository.server.ts @@ -261,9 +261,14 @@ const groupMatchResultsSubQuery = (eb: ExpressionBuilder) => { .selectFrom("ReportedWeapon") .select(["ReportedWeapon.userId", "ReportedWeapon.weaponSplId"]) .whereRef( - "ReportedWeapon.groupMatchMapId", + "ReportedWeapon.groupMatchId", "=", - "GroupMatchMap.id", + "GroupMatchMap.matchId", + ) + .whereRef( + "ReportedWeapon.mapIndex", + "=", + "GroupMatchMap.index", ), ).as("weapons"), ]) @@ -614,7 +619,7 @@ export type CancelMatchResult = | { status: "DUPLICATE"; shouldRefreshCaches: false }; type WeaponInput = { - groupMatchMapId: number; + groupMatchId: number; weaponSplId: MainWeaponId; userId: number; mapIndex: number; @@ -714,7 +719,8 @@ export async function reportScore({ newReportedMapsCount: winners.length, }); const weaponsForDb = mergedWeapons.map((w) => ({ - groupMatchMapId: w.groupMatchMapId, + groupMatchId: w.groupMatchId, + mapIndex: w.mapIndex, userId: w.userId, weaponSplId: w.weaponSplId, })); diff --git a/app/features/sendouq-match/actions/q.match.$id.server.ts b/app/features/sendouq-match/actions/q.match.$id.server.ts index 0ca5bd3f8..5a307384f 100644 --- a/app/features/sendouq-match/actions/q.match.$id.server.ts +++ b/app/features/sendouq-match/actions/q.match.$id.server.ts @@ -222,7 +222,8 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ); await ReportedWeaponRepository.upsertOne({ - groupMatchMapId: data.groupMatchMapId, + groupMatchId: matchId, + mapIndex: data.mapIndex, userId: user.id, weaponSplId: data.weaponSplId, }); diff --git a/app/features/sendouq-match/components/SendouQMatchActionTab.tsx b/app/features/sendouq-match/components/SendouQMatchActionTab.tsx index 1d31aa6bc..b3cbd3ef7 100644 --- a/app/features/sendouq-match/components/SendouQMatchActionTab.tsx +++ b/app/features/sendouq-match/components/SendouQMatchActionTab.tsx @@ -280,13 +280,12 @@ function WeaponReportSection({ onSubmit={(weaponSplId) => { addRecentlyReportedWeapon(weaponSplId); const mapIndex = pastReported.length; - const map = completedMaps[mapIndex]; - if (!map) return; + if (!completedMaps[mapIndex]) return; weaponFetcher.submit( { _action: "REPORT_WEAPON", weaponSplId: String(weaponSplId), - groupMatchMapId: String(map.id), + mapIndex: String(mapIndex), }, { method: "post" }, ); @@ -469,12 +468,11 @@ function InProgressTab({ onSubmit: (weaponSplId) => { addRecentlyReportedWeapon(weaponSplId); const mapIndex = weaponPastReported.length; - const map = data.match.mapList[mapIndex]; weaponFetcher.submit( { _action: "REPORT_WEAPON", weaponSplId: String(weaponSplId), - groupMatchMapId: String(map.id), + mapIndex: String(mapIndex), }, { method: "post" }, ); diff --git a/app/features/sendouq-match/core/match-timeline.test.ts b/app/features/sendouq-match/core/match-timeline.test.ts index a460473f7..f3d13fff9 100644 --- a/app/features/sendouq-match/core/match-timeline.test.ts +++ b/app/features/sendouq-match/core/match-timeline.test.ts @@ -151,7 +151,7 @@ describe("resolveTimelineMaps()", () => { members: [member({ id: 2 })], }, }), - [{ groupMatchMapId: 1, userId: 1, weaponSplId: 40 }] as never, + [{ mapIndex: 0, userId: 1, weaponSplId: 40 }] as never, ); expect(result[0].weapons).toEqual({ diff --git a/app/features/sendouq-match/core/match-timeline.ts b/app/features/sendouq-match/core/match-timeline.ts index a023680da..930a3e67f 100644 --- a/app/features/sendouq-match/core/match-timeline.ts +++ b/app/features/sendouq-match/core/match-timeline.ts @@ -39,17 +39,18 @@ export function resolveTimelineMaps( reportedWeapons: SendouQMatchLoaderData["reportedWeapons"], ): TimelineMap[] { return match.mapList - .filter((m) => m.winnerGroupId !== null) - .map((map) => { + .map((map, mapIndex) => ({ map, mapIndex })) + .filter(({ map }) => map.winnerGroupId !== null) + .map(({ map, mapIndex }) => { const alphaWeapons = match.groupAlpha.members.map((member) => { const w = reportedWeapons?.find( - (rw) => rw.groupMatchMapId === map.id && rw.userId === member.id, + (rw) => rw.mapIndex === mapIndex && rw.userId === member.id, ); return w ? w.weaponSplId : null; }); const bravoWeapons = match.groupBravo.members.map((member) => { const w = reportedWeapons?.find( - (rw) => rw.groupMatchMapId === map.id && rw.userId === member.id, + (rw) => rw.mapIndex === mapIndex && rw.userId === member.id, ); return w ? w.weaponSplId : null; }); diff --git a/app/features/sendouq-match/core/reported-weapons.server.test.ts b/app/features/sendouq-match/core/reported-weapons.server.test.ts index 0be1a82b9..e15cf22fe 100644 --- a/app/features/sendouq-match/core/reported-weapons.server.test.ts +++ b/app/features/sendouq-match/core/reported-weapons.server.test.ts @@ -5,7 +5,7 @@ import { mergeReportedWeapons } from "./reported-weapons.server"; describe("mergeReportedWeapons()", () => { const newWeapons = [ { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 1, weaponSplId: 0 as MainWeaponId, @@ -23,7 +23,7 @@ describe("mergeReportedWeapons()", () => { newWeapons, oldWeapons: [ { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 1, weaponSplId: 1 as MainWeaponId, @@ -39,7 +39,7 @@ describe("mergeReportedWeapons()", () => { newWeapons, oldWeapons: [ { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 2, weaponSplId: 0 as MainWeaponId, @@ -49,7 +49,7 @@ describe("mergeReportedWeapons()", () => { expect(result).toEqual([ { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 2, weaponSplId: 0 as MainWeaponId, @@ -63,13 +63,13 @@ describe("mergeReportedWeapons()", () => { newWeapons, oldWeapons: [ { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 1, weaponSplId: 1 as MainWeaponId, }, { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 2, weaponSplId: 0 as MainWeaponId, @@ -80,7 +80,7 @@ describe("mergeReportedWeapons()", () => { expect(result).toEqual([ ...newWeapons, { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 0, userId: 2, weaponSplId: 0 as MainWeaponId, @@ -93,7 +93,7 @@ describe("mergeReportedWeapons()", () => { newWeapons, oldWeapons: [ { - groupMatchMapId: 1, + groupMatchId: 1, mapIndex: 1, userId: 1, weaponSplId: 0 as MainWeaponId, diff --git a/app/features/sendouq-match/core/reported-weapons.server.ts b/app/features/sendouq-match/core/reported-weapons.server.ts index 63b56e9fa..6aa2cac5e 100644 --- a/app/features/sendouq-match/core/reported-weapons.server.ts +++ b/app/features/sendouq-match/core/reported-weapons.server.ts @@ -3,7 +3,7 @@ import type { MainWeaponId } from "~/modules/in-game-lists/types"; export type ReportedWeaponForMerging = { weaponSplId?: MainWeaponId; mapIndex: number; - groupMatchMapId: number; + groupMatchId: number; userId: number; }; type ReportedWeapon = ReportedWeaponForMerging & { weaponSplId: MainWeaponId }; @@ -22,7 +22,8 @@ export function mergeReportedWeapons({ for (const oldWeapon of oldWeapons) { const replacement = newWeapons.find( (newWeapon) => - newWeapon.groupMatchMapId === oldWeapon.groupMatchMapId && + newWeapon.groupMatchId === oldWeapon.groupMatchId && + newWeapon.mapIndex === oldWeapon.mapIndex && newWeapon.userId === oldWeapon.userId, ); @@ -38,7 +39,8 @@ export function mergeReportedWeapons({ if ( !result.some( (oldWeapon) => - newWeapon.groupMatchMapId === oldWeapon.groupMatchMapId && + newWeapon.groupMatchId === oldWeapon.groupMatchId && + newWeapon.mapIndex === oldWeapon.mapIndex && newWeapon.userId === oldWeapon.userId, ) ) { diff --git a/app/features/sendouq-match/q-match-schemas.ts b/app/features/sendouq-match/q-match-schemas.ts index 4d0d2e050..3a341ef60 100644 --- a/app/features/sendouq-match/q-match-schemas.ts +++ b/app/features/sendouq-match/q-match-schemas.ts @@ -19,7 +19,7 @@ export const matchSchema = z.union([ z.object({ _action: _action("REPORT_WEAPON"), weaponSplId, - groupMatchMapId: id, + mapIndex: z.coerce.number().int().nonnegative(), }), z.object({ _action: _action("ADD_PRIVATE_USER_NOTE"), diff --git a/app/features/sendouq/queries/weaponUsageStats.server.ts b/app/features/sendouq/queries/weaponUsageStats.server.ts index 14b0b47b2..7a6b59a26 100644 --- a/app/features/sendouq/queries/weaponUsageStats.server.ts +++ b/app/features/sendouq/queries/weaponUsageStats.server.ts @@ -23,11 +23,13 @@ const stm = sql.prepare(/* sql */ ` ) as "weaponUserGroupId" from "GroupMember" left join "Group" on "Group"."id" = "GroupMember"."groupId" - inner join "GroupMatch" on - "GroupMatch"."alphaGroupId" = "Group"."id" + inner join "GroupMatch" on + "GroupMatch"."alphaGroupId" = "Group"."id" or "GroupMatch"."bravoGroupId" = "Group"."id" left join "GroupMatchMap" on "GroupMatchMap"."matchId" = "GroupMatch"."id" - inner join "ReportedWeapon" on "ReportedWeapon"."groupMatchMapId" = "GroupMatchMap"."id" + inner join "ReportedWeapon" + on "ReportedWeapon"."groupMatchId" = "GroupMatch"."id" + and "ReportedWeapon"."mapIndex" = "GroupMatchMap"."index" where "GroupMember"."userId" = @userId and "GroupMatch"."createdAt" between @starts and @ends diff --git a/db-test.sqlite3 b/db-test.sqlite3 index f12b1b373a6628e5bc8bb83ae4dafe09b84c0cab..b9d779073c9f7b0f6e0d9de5d24570e652a12860 100644 GIT binary patch delta 4254 zcmeHKZAe>Z6pnhMP1L-;YQ7V1O#F&^^(Ha8=_twuLzqQb@go{tTGKRE6K5jr9Bj2? z3LR@<`Ej7@MzLjEVLwLqA!QRb#t?su!8%q78w?zb{U{w}+E%RW>NazZnEf9J_xw1V zujiciP0sV4z0!5|O4mn+xYq0N_*#7}tzJ1*%qy|l!EIQLa3@w%yb7ydQ|momfvxu9 zTCDa^^>wP=EN;Zk_lsRv6-x-nBP9*kI#*KJknYI&te|rFvmN@lN!&t&Adz&TM zFUe`2)SVIs&X7~ugw>8x8LKas5-=Z>5-_)^RnQY>kG>wKis;L*dQndbt>{H;y-!n# zhB|CLYADC*s|IspxoTW;@1w*i0sS#$1i9 z*Ubdv4`u=~%R;R6788y=VzE7+9-3G#sO&!3=apXEf5=r1K~<+Xc%;x&Qc8v*nGR#g zV#Z~Dv5@9W{mE6IowFbw&Z6&cQR?_?ib*{Hracqx`oWYFEg01h`NZoI3B=eTd zjh#LAT6`socCMtyFD1jFiA+;CZzlzA+RMG^VOJII%+lkPl5ypWk7vqKP*#t_^8XH# zr4!LJ(nM%7Q`lG;Y4$=H!Ln3l!%6dYlFH4}@z8iUHX54R|NK+=qP;2ILXBEbHTq<^ zNs1z4~sfj8EHm&urhYZ z_5XBb>@IQ7lb>}nSMILvl|kxdUaUuZ8K#5qPA_ZoqkT7(bD(&80H_~>}Qwq{8#%KCSAY= zD4xy%hW8>Q2N)&{aCMLV{Q#42f0_Wz?+;Ks(E#&d|Mvn6(`EQEz%Vg~tpLL`5adDX z|H2@v!wlxsHiPjf3}%~u)5 z3z0Q$GDoK3)017Hae56nT$_Q#X=L|Sn^*i#0f4u=H~g;M|^ShQL(-EFCAd%O8@`> delta 4338 zcmeHKT}WGZ6pwn__1?rNC>=^4hER)TMPvM0+N3ttCeB3a9CU5R z6!u`DdH6%eN^!8YFxIj!DQm{Y9>j;Sv5l3!4Sd-4FggmeRl2gj=||2Hv-g1^=i%J* z^*iVPPtNb2zt(^LTK}yB0k!p$@9Of(xpXf(NP@p&qK=V(WdO7Fykg zCa508>f2boZD@ne4-8(Yibe$Th_Mw~7manT`Hnmcze84n zvXb}7+%rlrLy4&!s=X!!s&AMOnCm74<}S8!X5_4zTVSe5b2U^inNgv2vk0vZa4ON# z46Vm3HBf!iVsFbg=g+|ShIMI`Ix#Or}42Ee@3#KU}~oofj(qK z=X%zPV0~mou~>m^Rp%p6oXGMkpuk;y`bk#*Q% znO_~K`6?%BzRQX3VBFaVW8Zb6*mWmrej7WtxSTNds0*FJg3AG|S6!&?cP^CqiOUC_ zRd*A-lKR}0RD*Il7CBRB3h%g4f!ppHe}35Yy4);Pzno68Z*sa&mdffD7^Zz1rpPDb z^YWRW(D}%9z{gv^IMeVPQJfqxS88687|8!-5 zCH}<#@s#tLjosv9CfnELP# zfh3MD4iQK->6b&e^!*_M`3Loc2;@O@AVeTtp%+3p{_|b_8zBNo7bU|OPv0M_xhe-hXe-I{+F4JGa1QK)lBupR;q{;~Pe|3a3Lk4qt zhry_f!R!#S9csEagQ3|G0+|T?ZG?0}T#cjnT*gK*?kl_O-;WZ=x9Q_iJlBpf(gpJ` zjA8p{W4PWQV+6jw(S~t+55nUFzFgAGIG*#`IDwp({xy#A%M%2?ThL<@M1}Y+O%V7# zO4lY(y%nivrKe{_(ZBe9qHy{pPSLM&ics`*4R=mM*2!gJsk&0-(|xFoYaRSTSrgw~ z@woIdx5=IRR2T?xtF?a%=AshQ#Z$ER4u6o&Z3<2F`W;@@E(I^f%B?g?hAEK={^#-c@sg$RO9|XG6pDUnP|iMi=%DUygvwD*x<9LYU?{>a1FbzdSHn}6!f u9{W(%gvy3o!Cl#(VSyFs@;`!oX=6)R-Pkg?2mb{#toXwK diff --git a/migrations/134-match-page.js b/migrations/134-match-page.js index 9d6b64f96..31cd69671 100644 --- a/migrations/134-match-page.js +++ b/migrations/134-match-page.js @@ -138,21 +138,17 @@ export function up(db) { db.prepare( /* sql */ ` create table "ReportedWeapon_new" ( - "groupMatchMapId" integer, + "groupMatchId" integer, "tournamentMatchId" integer, - "mapIndex" integer, + "mapIndex" integer not null, "weaponSplId" integer not null, "userId" integer not null, - foreign key ("groupMatchMapId") references "GroupMatchMap"("id") on delete restrict, + foreign key ("groupMatchId") references "GroupMatch"("id") on delete cascade, foreign key ("tournamentMatchId") references "TournamentMatch"("id") on delete cascade, foreign key ("userId") references "User"("id") on delete restrict, - unique("groupMatchMapId", "userId") on conflict rollback, + unique("groupMatchId", "mapIndex", "userId") on conflict rollback, unique("tournamentMatchId", "mapIndex", "userId") on conflict rollback, - check ( - ("groupMatchMapId" is not null and "tournamentMatchId" is null and "mapIndex" is null) - or - ("groupMatchMapId" is null and "tournamentMatchId" is not null and "mapIndex" is not null) - ) + check (("groupMatchId" is not null) <> ("tournamentMatchId" is not null)) ) strict `, ).run(); @@ -160,10 +156,13 @@ export function up(db) { db.prepare( /* sql */ ` insert into "ReportedWeapon_new" ( - "groupMatchMapId", "tournamentMatchId", "mapIndex", "weaponSplId", "userId" + "groupMatchId", "tournamentMatchId", "mapIndex", "weaponSplId", "userId" ) - select "groupMatchMapId", null, null, "weaponSplId", "userId" + select + "GroupMatchMap"."matchId", null, "GroupMatchMap"."index", + "ReportedWeapon"."weaponSplId", "ReportedWeapon"."userId" from "ReportedWeapon" + inner join "GroupMatchMap" on "GroupMatchMap"."id" = "ReportedWeapon"."groupMatchMapId" `, ).run(); @@ -173,7 +172,7 @@ export function up(db) { ).run(); db.prepare( - /* sql */ `create index reported_weapon_group_match_map_id on "ReportedWeapon"("groupMatchMapId")`, + /* sql */ `create index reported_weapon_group_match_id on "ReportedWeapon"("groupMatchId")`, ).run(); db.prepare( /* sql */ `create index reported_weapon_tournament_match_id on "ReportedWeapon"("tournamentMatchId")`, diff --git a/scripts/nuke-reported-weapons.ts b/scripts/nuke-reported-weapons.ts index 080ce6d09..7d43b356b 100644 --- a/scripts/nuke-reported-weapons.ts +++ b/scripts/nuke-reported-weapons.ts @@ -22,7 +22,7 @@ async function main() { .where("User.discordId", "=", discordId) .executeTakeFirstOrThrow(); - const groupMatchMaps = await db + const playedMaps = await db .selectFrom("GroupMember") .innerJoin("Group", "Group.id", "GroupMember.groupId") .innerJoin("GroupMatch", (join) => @@ -34,7 +34,7 @@ async function main() { ), ) .innerJoin("GroupMatchMap", "GroupMatchMap.matchId", "GroupMatch.id") - .select("GroupMatchMap.id") + .select(["GroupMatchMap.matchId", "GroupMatchMap.index"]) .where( "GroupMatch.createdAt", ">", @@ -49,16 +49,28 @@ async function main() { .where("GroupMatchMap.winnerGroupId", "is not", null) .execute(); - const groupMatchMapIds = groupMatchMaps.map((gmm) => gmm.id); + if (playedMaps.length === 0) { + logger.info(`No reported weapons to delete for user ${discordId}`); + return; + } await db .deleteFrom("ReportedWeapon") .where("userId", "=", user.id) - .where("ReportedWeapon.groupMatchMapId", "in", groupMatchMapIds) + .where((eb) => + eb.or( + playedMaps.map((m) => + eb.and([ + eb("ReportedWeapon.groupMatchId", "=", m.matchId), + eb("ReportedWeapon.mapIndex", "=", m.index), + ]), + ), + ), + ) .execute(); logger.info( - `Deleted ${groupMatchMapIds.length} reported weapons for user ${discordId}`, + `Deleted reported weapons across ${playedMaps.length} maps for user ${discordId}`, ); }