Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/commands/report/automodLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const ActionTypeLabels: Record<AutoModerationActionType, string> = {
[AutoModerationActionType.BlockMemberInteraction]: "blocked interaction",
};

const logAutomod = ({
export const logAutomod = ({
guild,
user,
channelId,
Expand Down
43 changes: 31 additions & 12 deletions app/commands/report/modActionLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,22 @@ export type ModActionReport =
| {
guild: Guild;
user: User;
actionType: "kick" | "ban";
actionType: "kick" | "ban" | "unban";
executor: User | PartialUser | null;
reason: string;
}
| {
guild: Guild;
user: User;
actionType: "timeout";
executor: User | PartialUser | null;
reason: string;
duration: string;
}
| {
guild: Guild;
user: User;
actionType: "timeout_removed";
executor: User | PartialUser | null;
reason: string;
}
Expand All @@ -25,14 +40,9 @@ export type ModActionReport =
reason: undefined;
};

export const logModAction = ({
guild,
user,
actionType,
executor,
reason,
}: ModActionReport) =>
export const logModAction = (report: ModActionReport) =>
Effect.gen(function* () {
const { guild, user, actionType, executor, reason } = report;
yield* logEffect(
"info",
"logModAction",
Expand Down Expand Up @@ -67,6 +77,9 @@ export const logModAction = ({
const actionLabels: Record<ModActionReport["actionType"], string> = {
ban: "was banned",
kick: "was kicked",
unban: "was unbanned",
timeout: "was timed out",
timeout_removed: "had timeout removed",
left: "left",
};
const actionLabel = actionLabels[actionType];
Expand All @@ -75,9 +88,11 @@ export const logModAction = ({
: " by unknown";

const reasonText = reason ? ` ${reason}` : " for no reason";
const durationText =
actionType === "timeout" ? ` for ${report.duration}` : "";
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

durationText reads report.duration based on actionType === "timeout", but actionType was destructured from report, so TypeScript typically won’t narrow report here (and duration doesn’t exist on the other union variants). This is likely a type error under strict. Narrow on report.actionType (or use an if (report.actionType === "timeout") block) before accessing report.duration.

Suggested change
actionType === "timeout" ? ` for ${report.duration}` : "";
report.actionType === "timeout" ? ` for ${report.duration}` : "";

Copilot uses AI. Check for mistakes.

const logContent = truncateMessage(
`<@${user.id}> (${user.username}) ${actionLabel}
`<@${user.id}> (${user.username}) ${actionLabel}${durationText}
-# ${executorMention}${reasonText} <t:${Math.floor(Date.now() / 1000)}:R>`,
).trim();

Expand Down Expand Up @@ -108,13 +123,17 @@ export const logModAction = ({
);
}).pipe(
Effect.withSpan("logModAction", {
attributes: { userId: user.id, guildId: guild.id, actionType },
attributes: {
userId: report.user.id,
guildId: report.guild.id,
actionType: report.actionType,
},
}),
);

/**
* Logs a mod action (kick/ban) to the user's persistent thread.
* Used when Discord events indicate a kick or ban occurred.
* Logs a mod action (kick/ban/unban/timeout) to the user's persistent thread.
* Used when Discord events indicate a moderation action occurred.
*/
export const logModActionLegacy = (report: ModActionReport): Promise<void> =>
runEffect(Effect.provide(logModAction(report), DatabaseLayer));
Loading