Skip to content

Commit 37da2ae

Browse files
committed
feat: add reason filtering to cases command
1 parent 6795bf7 commit 37da2ae

5 files changed

Lines changed: 85 additions & 17 deletions

File tree

backend/src/data/GuildCases.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,30 @@ export class GuildCases extends BaseGuildRepository {
144144
});
145145
}
146146

147+
async getByModId(
148+
modId: string,
149+
filters: Omit<FindOptionsWhere<Case>, "guild_id" | "mod_id"> = {},
150+
): Promise<Case[]> {
151+
const where: FindOptionsWhere<Case> = {
152+
guild_id: this.guildId,
153+
mod_id: modId,
154+
is_hidden: false,
155+
...filters,
156+
};
157+
158+
if (where.is_hidden === true) {
159+
delete where.is_hidden;
160+
}
161+
162+
return this.cases.find({
163+
relations: this.getRelations(),
164+
where,
165+
order: {
166+
case_number: "DESC",
167+
},
168+
});
169+
}
170+
147171
async getMinCaseNumber(): Promise<number> {
148172
const result = await this.cases
149173
.createQueryBuilder()

backend/src/plugins/ModActions/commands/cases/CasesModMsgCmd.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ const opts = {
77
mod: ct.userId({ option: true }),
88
expand: ct.bool({ option: true, isSwitch: true, shortcut: "e" }),
99
hidden: ct.bool({ option: true, isSwitch: true, shortcut: "h" }),
10-
reverseFilters: ct.switchOption({ def: false, shortcut: "r" }),
10+
reverseFilters: ct.switchOption({ def: false, shortcut: "rf" }),
11+
reason: ct.string({ option: true, shortcut: "r" }),
1112
notes: ct.switchOption({ def: false, shortcut: "n" }),
1213
warns: ct.switchOption({ def: false, shortcut: "w" }),
1314
mutes: ct.switchOption({ def: false, shortcut: "m" }),
@@ -45,6 +46,7 @@ export const CasesModMsgCmd = modActionsMsgCmd({
4546
args.bans,
4647
args.unbans,
4748
args.reverseFilters,
49+
args.reason ?? null,
4850
args.hidden,
4951
args.expand,
5052
args.show,

backend/src/plugins/ModActions/commands/cases/CasesSlashCmd.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ const opts = [
1313
description: "To treat case type filters as exclusive instead of inclusive",
1414
required: false,
1515
}),
16+
slashOptions.string({
17+
name: "reason",
18+
description: "Filter cases containing this text in the case reason",
19+
required: false,
20+
}),
1621
slashOptions.boolean({ name: "notes", description: "To filter notes", required: false }),
1722
slashOptions.boolean({ name: "warns", description: "To filter warns", required: false }),
1823
slashOptions.boolean({ name: "mutes", description: "To filter mutes", required: false }),
@@ -48,6 +53,7 @@ export const CasesSlashCmd = modActionsSlashCmd({
4853
options.bans,
4954
options.unbans,
5055
options["reverse-filters"],
56+
options.reason ?? null,
5157
options.hidden,
5258
options.expand,
5359
options.show,

backend/src/plugins/ModActions/commands/cases/CasesUserMsgCmd.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const opts = {
88
mod: ct.userId({ option: true }),
99
expand: ct.bool({ option: true, isSwitch: true, shortcut: "e" }),
1010
hidden: ct.bool({ option: true, isSwitch: true, shortcut: "h" }),
11-
reverseFilters: ct.switchOption({ def: false, shortcut: "r" }),
11+
reverseFilters: ct.switchOption({ def: false, shortcut: "rf" }),
12+
reason: ct.string({ option: true, shortcut: "r" }),
1213
notes: ct.switchOption({ def: false, shortcut: "n" }),
1314
warns: ct.switchOption({ def: false, shortcut: "w" }),
1415
mutes: ct.switchOption({ def: false, shortcut: "m" }),
@@ -58,6 +59,7 @@ export const CasesUserMsgCmd = modActionsMsgCmd({
5859
args.bans,
5960
args.unbans,
6061
args.reverseFilters,
62+
args.reason ?? null,
6163
args.hidden,
6264
args.expand,
6365
args.show,

backend/src/plugins/ModActions/commands/cases/actualCasesCmd.ts

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ import { ModActionsPluginType } from "../../types.js";
2222
const casesPerPage = 5;
2323
const maxExpandedCases = 8;
2424

25+
function filterCasesByReason(cases: Case[], reason: string): Case[] {
26+
const normalizedReason = reason.toLowerCase();
27+
28+
return cases.filter((theCase) =>
29+
theCase.notes?.some((note) => note.body.toLowerCase().includes(normalizedReason)),
30+
);
31+
}
32+
2533
async function sendExpandedCases(
2634
pluginData: GuildPluginData<ModActionsPluginType>,
2735
context: Message | ChatInputCommandInteraction,
@@ -54,6 +62,7 @@ async function casesUserCmd(
5462
user: GuildMember | User | UnknownUser,
5563
modName: string,
5664
typesToShow: CaseTypes[],
65+
reason: string | null,
5766
hidden: boolean | null,
5867
expand: boolean | null,
5968
show: boolean | null,
@@ -66,26 +75,29 @@ async function casesUserCmd(
6675
}
6776

6877
const cases = await pluginData.state.cases.with("notes").getByUserId(user.id, casesFilters);
69-
const normalCases = cases.filter((c) => !c.is_hidden);
70-
const hiddenCases = cases.filter((c) => c.is_hidden);
78+
const matchingCases = reason ? filterCasesByReason(cases, reason) : cases;
79+
const normalCases = matchingCases.filter((c) => !c.is_hidden);
80+
const hiddenCases = matchingCases.filter((c) => c.is_hidden);
7181

7282
const userName =
7383
user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUsername(user);
7484

75-
if (cases.length === 0) {
85+
if (matchingCases.length === 0) {
7686
await sendContextResponse(context, {
77-
content: `No cases found for **${userName}**${modId ? ` by ${modName}` : ""}.`,
87+
content: `No cases found for **${userName}**${modId ? ` by ${modName}` : ""}${
88+
reason ? ` with reason matching "${reason}"` : ""
89+
}.`,
7890
ephemeral: !show,
7991
});
8092

8193
return;
8294
}
8395

84-
const casesToDisplay = hidden ? cases : normalCases;
96+
const casesToDisplay = hidden ? matchingCases : normalCases;
8597

8698
if (!casesToDisplay.length) {
8799
await sendContextResponse(context, {
88-
content: `No normal cases found for **${userName}**. Use "-hidden" to show ${cases.length} hidden cases.`,
100+
content: `No normal cases found for **${userName}**. Use "-hidden" to show ${matchingCases.length} hidden cases.`,
89101
ephemeral: !show,
90102
});
91103

@@ -148,17 +160,31 @@ async function casesModCmd(
148160
mod: GuildMember | User | UnknownUser,
149161
modName: string,
150162
typesToShow: CaseTypes[],
163+
reason: string | null,
151164
hidden: boolean | null,
152165
expand: boolean | null,
153166
show: boolean | null,
154167
) {
155168
const casesPlugin = pluginData.getPlugin(CasesPlugin);
156169
const casesFilters = { type: In(typesToShow), is_hidden: !!hidden };
157170

158-
const totalCases = await casesPlugin.getTotalCasesByMod(modId ?? author.id, casesFilters);
171+
const filteredCases = reason
172+
? filterCasesByReason(
173+
await pluginData.state.cases.with("notes").getByModId(modId ?? author.id, casesFilters),
174+
reason,
175+
)
176+
: null;
177+
178+
const totalCases = filteredCases?.length ?? (await casesPlugin.getTotalCasesByMod(modId ?? author.id, casesFilters));
159179

160180
if (totalCases === 0) {
161-
pluginData.state.common.sendErrorMessage(context, `No cases by **${modName}**`, undefined, undefined, !show);
181+
pluginData.state.common.sendErrorMessage(
182+
context,
183+
`No cases by **${modName}**${reason ? ` with reason matching "${reason}"` : ""}`,
184+
undefined,
185+
undefined,
186+
!show,
187+
);
162188

163189
return;
164190
}
@@ -168,7 +194,10 @@ async function casesModCmd(
168194

169195
if (expand) {
170196
// Expanded view (= individual case embeds)
171-
const cases = totalCases > 8 ? [] : await casesPlugin.getRecentCasesByMod(modId ?? author.id, 8, 0, casesFilters);
197+
const cases =
198+
filteredCases && totalCases > maxExpandedCases
199+
? filteredCases.slice(0, maxExpandedCases)
200+
: filteredCases ?? (await casesPlugin.getRecentCasesByMod(modId ?? author.id, 8, 0, casesFilters));
172201

173202
await sendExpandedCases(pluginData, context, totalCases, cases, show);
174203
return;
@@ -179,12 +208,14 @@ async function casesModCmd(
179208
context,
180209
totalPages,
181210
async (page) => {
182-
const cases = await casesPlugin.getRecentCasesByMod(
183-
modId ?? author.id,
184-
casesPerPage,
185-
(page - 1) * casesPerPage,
186-
casesFilters,
187-
);
211+
const cases = filteredCases
212+
? filteredCases.slice((page - 1) * casesPerPage, (page - 1) * casesPerPage + casesPerPage)
213+
: await casesPlugin.getRecentCasesByMod(
214+
modId ?? author.id,
215+
casesPerPage,
216+
(page - 1) * casesPerPage,
217+
casesFilters,
218+
);
188219

189220
const lines = await asyncMap(cases, (c) => casesPlugin.getCaseSummary(c, true, author.id));
190221
const firstCaseNum = (page - 1) * casesPerPage + 1;
@@ -230,6 +261,7 @@ export async function actualCasesCmd(
230261
bans: boolean | null,
231262
unbans: boolean | null,
232263
reverseFilters: boolean | null,
264+
reason: string | null,
233265
hidden: boolean | null,
234266
expand: boolean | null,
235267
show: boolean | null,
@@ -275,6 +307,7 @@ export async function actualCasesCmd(
275307
user,
276308
modName,
277309
typesToShow,
310+
reason,
278311
hidden,
279312
expand,
280313
show === true,
@@ -287,6 +320,7 @@ export async function actualCasesCmd(
287320
mod ?? author,
288321
modName,
289322
typesToShow,
323+
reason,
290324
hidden,
291325
expand,
292326
show === true,

0 commit comments

Comments
 (0)