Skip to content

Commit

Permalink
refactor: case history
Browse files Browse the repository at this point in the history
  • Loading branch information
didinele committed Jul 19, 2024
1 parent 05271d2 commit fc97d23
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 18 deletions.
6 changes: 6 additions & 0 deletions packages/core/src/notifications/INotifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export interface LogModCaseOptions {
target: APIUser | null;
}

export interface HistoryEmbedOptions {
cases: CaseWithLogMessage[];
target: APIUser;
}

@injectable()
export abstract class INotifier {
public readonly ACTION_COLORS_MAP = {
Expand Down Expand Up @@ -55,4 +60,5 @@ export abstract class INotifier {
public abstract generateModCaseEmbed(options: LogModCaseOptions): APIEmbed;
public abstract logModCase(options: LogModCaseOptions): Promise<void>;
public abstract tryNotifyTargetModCase(modCase: Selectable<ModCase>): Promise<boolean>;
public abstract generateHistoryEmbed(options: HistoryEmbedOptions): APIEmbed;
}
70 changes: 67 additions & 3 deletions packages/core/src/notifications/Notifier.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { addFields, truncateEmbed } from '@chatsift/discord-utils';
import { API, type APIEmbed, type APIMessage } from '@discordjs/core';
import { messageLink } from '@discordjs/formatters';
import { messageLink, time, TimestampStyles } from '@discordjs/formatters';
import { inject, injectable } from 'inversify';
import type { Selectable } from 'kysely';
import type { Logger } from 'pino';
import { INJECTION_TOKENS } from '../container.js';
import { IDatabase } from '../database/IDatabase.js';
import { LogWebhookKind, type ModCase } from '../db.js';
import { LogWebhookKind, ModCaseKind, type ModCase } from '../db.js';
import { computeAvatarUrl } from '../util/computeAvatar.js';
import { userToEmbedAuthor } from '../util/userToEmbedData.js';
import { INotifier, type DMUserOptions, type LogModCaseOptions } from './INotifier.js';
import { INotifier, type DMUserOptions, type HistoryEmbedOptions, type LogModCaseOptions } from './INotifier.js';

@injectable()
export class Notifier extends INotifier {
Expand Down Expand Up @@ -138,4 +138,68 @@ export class Notifier extends INotifier {
return false;
}
}

public override generateHistoryEmbed(options: HistoryEmbedOptions): APIEmbed {
let points = 0;
const counts = {
ban: 0,
kick: 0,
timeout: 0,
warn: 0,
};

const colors = [0x80f31f, 0xc7c101, 0xf47b7b, 0xf04848] as const;
const details: string[] = [];

for (const cs of options.cases) {
if (cs.kind === ModCaseKind.Ban) {
counts.ban++;
points += 3;
} else if (cs.kind === ModCaseKind.Kick) {
counts.kick++;
points += 2;
} else if (cs.kind === ModCaseKind.Timeout) {
counts.timeout++;
points += 0.5;
} else if (cs.kind === ModCaseKind.Warn) {
counts.warn++;
points += 0.25;
} else {
continue;
}

const action = cs.kind.toUpperCase();
const caseId = cs.logMessage
? `[#${cs.id}](${messageLink(cs.logMessage.channelId, cs.logMessage.messageId, cs.guildId)})`
: `#${cs.id}`;
const reason = cs.reason ? ` - ${cs.reason}` : '';

details.push(`• ${time(cs.createdAt, TimestampStyles.LongDate)} \`${action}\` ${caseId}${reason}`);
}

const color = colors[points > 0 && points < 1 ? 1 : Math.min(Math.floor(points), 3)];

const embed: APIEmbed = {
author: userToEmbedAuthor(options.target, options.target.id),
color,
};

if (points === 0) {
embed.description = 'No moderation history';
return embed;
}

const footer = Object.entries(counts).reduce<string[]>((arr, [type, count]) => {
if (count > 0) {
arr.push(`${count} ${type}${count === 1 ? '' : 's'}`);
}

return arr;
}, []);

embed.footer = { text: footer.join(' | ') };
embed.description = details.join('\n');

return embed;
}
}
16 changes: 5 additions & 11 deletions services/interactions/src/handlers/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,16 @@ export default class HistoryHandler implements HandlerModule<CoralInteractionHan
);
}

const modIds = new Set<string>(cases.map((cs) => cs.modId));
const mods = await Promise.all([...modIds].map(async (id) => this.api.users.get(id)));
const modsMap = new Map(mods.map((mod) => [mod.id, mod]));
const historyEmbed = this.notifier.generateHistoryEmbed({
cases,
target,
});

yield* HandlerStep.from({
action: ActionKind.Reply,
options: {
content: `Mod history for ${target.username}; page ${page + 1}`,
embeds: cases.map((cs) =>
this.notifier.generateModCaseEmbed({
mod: modsMap.get(cs.modId) ?? null,
modCase: cs,
references: [],
target,
}),
),
embeds: [historyEmbed],
},
});
}
Expand Down
9 changes: 5 additions & 4 deletions services/interactions/src/handlers/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,10 @@ export default class ModHandler implements HandlerModule<CoralInteractionHandler
return;
}

const embeds = previousCases.map((modCase) =>
this.notifier.generateModCaseEmbed({ modCase, mod: interaction.member!.user, target, references: [] }),
);
const historyEmbed = this.notifier.generateHistoryEmbed({
cases: previousCases,
target,
});

const stateId = nanoid();
await this.stateStore.setPendingModCase(stateId, {
Expand All @@ -590,7 +591,7 @@ export default class ModHandler implements HandlerModule<CoralInteractionHandler
options: {
content:
'This user has been actioned in the past hour. Would you still like to proceed? Note that the logs below do not include some information, refer to your log channel for details such as references.',
embeds,
embeds: [historyEmbed],
components: [
{
type: ComponentType.ActionRow,
Expand Down

0 comments on commit fc97d23

Please sign in to comment.