Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mod actions reason aliases (continued) #390

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
15 changes: 15 additions & 0 deletions backend/src/plugins/ModActions/ModActionsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const defaultOptions = {
can_deletecase: false,
can_act_as_other: false,
create_cases_for_manual_actions: true,
reason_aliases: {},
},
overrides: [
{
Expand Down Expand Up @@ -113,6 +114,19 @@ const defaultOptions = {
],
};

/**
* Config preprocessor to fix values
*/
const configPreprocessor = (options) => {
if (options.config?.reason_aliases) {
options.config.reason_aliases = Object.fromEntries(
Object.entries(options.config.reason_aliases).map(([k, v]) => [k.toLowerCase(), v]),
);
}

return options;
};

export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
name: "mod_actions",
showInDocs: true,
Expand All @@ -127,6 +141,7 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
configParser: makeIoTsConfigParser(ConfigSchema),
defaultOptions,
configPreprocessor,

events: [CreateBanCaseOnManualBanEvt, CreateUnbanCaseOnManualUnbanEvt, PostAlertOnMemberJoinEvt, AuditLogEvents],

Expand Down
7 changes: 4 additions & 3 deletions backend/src/plugins/ModActions/commands/AddCaseCmd.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes";
import { Case } from "../../../data/entities/Case";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { renderUserUsername, resolveMember, resolveUser } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { parseReason } from "../functions/parseReason";
import { modActionsCmd } from "../types";

const opts = {
Expand Down Expand Up @@ -58,8 +59,8 @@ export const AddCaseCmd = modActionsCmd({
sendErrorMessage(pluginData, msg.channel, "Cannot add case: invalid case type");
return;
}

const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]);
const config = pluginData.config.get();
const reason = formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()]);

// Create the case
const casesPlugin = pluginData.getPlugin(CasesPlugin);
Expand Down
5 changes: 3 additions & 2 deletions backend/src/plugins/ModActions/commands/ForcebanCmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { ignoreEvent } from "../functions/ignoreEvent";
import { isBanned } from "../functions/isBanned";
import { parseReason } from "../functions/parseReason";
import { IgnoredEventType, modActionsCmd } from "../types";

const opts = {
Expand Down Expand Up @@ -60,8 +61,8 @@ export const ForcebanCmd = modActionsCmd({

mod = args.mod;
}

const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]);
const config = pluginData.config.get();
const reason = formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()]);

ignoreEvent(pluginData, IgnoredEventType.Ban, user.id);
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, user.id);
Expand Down
7 changes: 5 additions & 2 deletions backend/src/plugins/ModActions/commands/MassUnbanCmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { ignoreEvent } from "../functions/ignoreEvent";
import { isBanned } from "../functions/isBanned";
import { parseReason } from "../functions/parseReason";
import { IgnoredEventType, modActionsCmd } from "../types";

export const MassunbanCmd = modActionsCmd({
Expand Down Expand Up @@ -36,8 +37,10 @@ export const MassunbanCmd = modActionsCmd({
sendErrorMessage(pluginData, msg.channel, "Cancelled");
return;
}

const unbanReason = formatReasonWithAttachments(unbanReasonReply.content, [...msg.attachments.values()]);
const config = pluginData.config.get();
const unbanReason = formatReasonWithAttachments(parseReason(config, unbanReasonReply.content), [
...msg.attachments.values(),
]);

// Ignore automatic unban cases and logs for these users
// We'll create our own cases below and post a single "mass unbanned" log instead
Expand Down
6 changes: 5 additions & 1 deletion backend/src/plugins/ModActions/commands/MassmuteCmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginU
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { parseReason } from "../functions/parseReason";
import { modActionsCmd } from "../types";

export const MassmuteCmd = modActionsCmd({
Expand Down Expand Up @@ -39,7 +40,10 @@ export const MassmuteCmd = modActionsCmd({
return;
}

const muteReason = formatReasonWithAttachments(muteReasonReceived.content, [...msg.attachments.values()]);
const config = pluginData.config.get();
const muteReason = formatReasonWithAttachments(parseReason(config, muteReasonReceived.content), [
...msg.attachments.values(),
]);

// Verify we can act upon all users
for (const userId of args.userIds) {
Expand Down
4 changes: 3 additions & 1 deletion backend/src/plugins/ModActions/commands/UnbanCmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { resolveUser } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { ignoreEvent } from "../functions/ignoreEvent";
import { parseReason } from "../functions/parseReason";
import { IgnoredEventType, modActionsCmd } from "../types";

const opts = {
Expand Down Expand Up @@ -48,7 +49,8 @@ export const UnbanCmd = modActionsCmd({
}

pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, user.id);
const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]);
const config = pluginData.config.get();
const reason = formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()]);

try {
ignoreEvent(pluginData, IgnoredEventType.Unban, user.id);
Expand Down
3 changes: 2 additions & 1 deletion backend/src/plugins/ModActions/commands/WarnCmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
import { CasesPlugin } from "../../Cases/CasesPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { isBanned } from "../functions/isBanned";
import { parseReason } from "../functions/parseReason";
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
import { warnMember } from "../functions/warnMember";
import { modActionsCmd } from "../types";
Expand Down Expand Up @@ -62,7 +63,7 @@ export const WarnCmd = modActionsCmd({
}

const config = pluginData.config.get();
const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]);
const reason = formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()]);

const casesPlugin = pluginData.getPlugin(CasesPlugin);
const priorWarnAmount = await casesPlugin.getCaseTypeAmountForUserId(memberToWarn.id, CaseTypes.Warn);
Expand Down
31 changes: 17 additions & 14 deletions backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GuildMember, GuildTextBasedChannel } from "discord.js";
import { GuildMember, GuildTextBasedChannel, Message, TextChannel } from "discord.js";
import { GuildPluginData } from "knub";
import { hasPermission } from "knub/helpers";
import { LogType } from "../../../data/LogType";
Expand All @@ -9,11 +9,12 @@ import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
import { ignoreEvent } from "./ignoreEvent";
import { isBanned } from "./isBanned";
import { kickMember } from "./kickMember";
import { parseReason } from "./parseReason";
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";

export async function actualKickMemberCmd(
pluginData: GuildPluginData<ModActionsPluginType>,
msg,
msg: Message,
args: {
user: string;
reason: string;
Expand All @@ -24,8 +25,9 @@ export async function actualKickMemberCmd(
},
) {
const user = await resolveUser(pluginData.client, args.user);
if (!user.id) {
sendErrorMessage(pluginData, msg.channel, `User not found`);
const channel = msg.channel as TextChannel;
if (!user.id || !msg.member) {
sendErrorMessage(pluginData, channel, `User not found`);
return;
}

Expand All @@ -34,25 +36,25 @@ export async function actualKickMemberCmd(
if (!memberToKick) {
const banned = await isBanned(pluginData, user.id);
if (banned) {
sendErrorMessage(pluginData, msg.channel, `User is banned`);
sendErrorMessage(pluginData, channel, `User is banned`);
} else {
sendErrorMessage(pluginData, msg.channel, `User not found on the server`);
sendErrorMessage(pluginData, channel, `User not found on the server`);
}

return;
}

// Make sure we're allowed to kick this member
if (!canActOn(pluginData, msg.member, memberToKick)) {
sendErrorMessage(pluginData, msg.channel, "Cannot kick: insufficient permissions");
sendErrorMessage(pluginData, channel, "Cannot kick: insufficient permissions");
return;
}

// The moderator who did the action is the message author or, if used, the specified -mod
let mod = msg.member;
if (args.mod) {
if (!(await hasPermission(await pluginData.config.getForMessage(msg), "can_act_as_other"))) {
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
sendErrorMessage(pluginData, channel, "You don't have permission to use -mod");
return;
}

Expand All @@ -63,17 +65,18 @@ export async function actualKickMemberCmd(
try {
contactMethods = readContactMethodsFromArgs(args);
} catch (e) {
sendErrorMessage(pluginData, msg.channel, e.message);
sendErrorMessage(pluginData, channel, e.message);
return;
}

const reason = formatReasonWithAttachments(args.reason, msg.attachments);
const config = pluginData.config.get();
const reason = formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()]);

const kickResult = await kickMember(pluginData, memberToKick, reason, {
contactMethods,
caseArgs: {
modId: mod.id,
ppId: mod.id !== msg.author.id ? msg.author.id : null,
ppId: mod.id !== msg.author.id ? msg.author.id : undefined,
},
});

Expand All @@ -84,7 +87,7 @@ export async function actualKickMemberCmd(
try {
await memberToKick.ban({ deleteMessageSeconds: (1 * DAYS) / SECONDS, reason: "kick -clean" });
} catch {
sendErrorMessage(pluginData, msg.channel, "Failed to ban the user to clean messages (-clean)");
sendErrorMessage(pluginData, channel, "Failed to ban the user to clean messages (-clean)");
}

pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, memberToKick.id);
Expand All @@ -93,7 +96,7 @@ export async function actualKickMemberCmd(
try {
await pluginData.guild.bans.remove(memberToKick.id, "kick -clean");
} catch {
sendErrorMessage(pluginData, msg.channel, "Failed to unban the user after banning them (-clean)");
sendErrorMessage(pluginData, channel, "Failed to unban the user after banning them (-clean)");
}
}

Expand All @@ -106,5 +109,5 @@ export async function actualKickMemberCmd(
let response = `Kicked **${renderUserUsername(memberToKick.user)}** (Case #${kickResult.case.case_number})`;

if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
sendSuccessMessage(pluginData, msg.channel, response);
sendSuccessMessage(pluginData, channel, response);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MutesPlugin } from "../../Mutes/MutesPlugin";
import { MuteResult } from "../../Mutes/types";
import { ModActionsPluginType } from "../types";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
import { parseReason } from "./parseReason";
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";

/**
Expand Down Expand Up @@ -42,7 +43,10 @@ export async function actualMuteUserCmd(
}

const timeUntilUnmute = args.time && humanizeDuration(args.time);
const reason = args.reason ? formatReasonWithAttachments(args.reason, [...msg.attachments.values()]) : undefined;
const config = pluginData.config.get();
const reason = args.reason
? formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()])
: undefined;

let muteResult: MuteResult;
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
import { UnknownUser, asSingleLine, renderUserUsername } from "../../../utils";
import { ModActionsPluginType } from "../types";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
import { parseReason } from "./parseReason";

export async function actualUnmuteCmd(
pluginData: GuildPluginData<ModActionsPluginType>,
Expand All @@ -27,7 +28,10 @@ export async function actualUnmuteCmd(
pp = msg.author;
}

const reason = args.reason ? formatReasonWithAttachments(args.reason, [...msg.attachments.values()]) : undefined;
const config = pluginData.config.get();
const reason = args.reason
? formatReasonWithAttachments(parseReason(config, args.reason), [...msg.attachments.values()])
: undefined;

const mutesPlugin = pluginData.getPlugin(MutesPlugin);
const result = await mutesPlugin.unmuteUser(user.id, args.time, {
Expand Down
2 changes: 2 additions & 0 deletions backend/src/plugins/ModActions/functions/banUserId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { LogsPlugin } from "../../Logs/LogsPlugin";
import { BanOptions, BanResult, IgnoredEventType, ModActionsPluginType } from "../types";
import { getDefaultContactMethods } from "./getDefaultContactMethods";
import { ignoreEvent } from "./ignoreEvent";
import { parseReason } from "./parseReason";

/**
* Ban the specified user id, whether or not they're actually on the server at the time. Generates a case.
Expand All @@ -41,6 +42,7 @@ export async function banUserId(
error: "Invalid user",
};
}
reason &&= parseReason(config, reason);

// Attempt to message the user *before* banning them, as doing it after may not be possible
const member = await resolveMember(pluginData.client, pluginData.guild, userId);
Expand Down
2 changes: 2 additions & 0 deletions backend/src/plugins/ModActions/functions/kickMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LogsPlugin } from "../../Logs/LogsPlugin";
import { IgnoredEventType, KickOptions, KickResult, ModActionsPluginType } from "../types";
import { getDefaultContactMethods } from "./getDefaultContactMethods";
import { ignoreEvent } from "./ignoreEvent";
import { parseReason } from "./parseReason";

/**
* Kick the specified server member. Generates a case.
Expand All @@ -25,6 +26,7 @@ export async function kickMember(
// Attempt to message the user *before* kicking them, as doing it after may not be possible
let notifyResult: UserNotificationResult = { method: null, success: true };
if (reason && member) {
reason = parseReason(config, reason);
const contactMethods = kickOptions?.contactMethods
? kickOptions.contactMethods
: getDefaultContactMethods(pluginData, "kick");
Expand Down
14 changes: 14 additions & 0 deletions backend/src/plugins/ModActions/functions/parseReason.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TConfigSchema } from "../types";
Copy link

Choose a reason for hiding this comment

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

Suggested change
import { TConfigSchema } from "../types";
import z from "zod";
import { zModActionsConfig } from "../types";


const MAX_REASON_LENGTH = 512;

export function parseReason(config: TConfigSchema, reason: string): string {
Copy link

Choose a reason for hiding this comment

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

Suggested change
export function parseReason(config: TConfigSchema, reason: string): string {
export function parseReason(config: z.infer<typeof zModActionsConfig>, reason: string): string {

I don't know whether there is a nicer way of getting the config schema without having to import zod, but this works.

if (!reason) return reason;
if (config?.reason_aliases) {
reason = config.reason_aliases[reason.toLowerCase()] ?? reason;
}
if (reason!.length > MAX_REASON_LENGTH) {
reason = reason!.substring(0, MAX_REASON_LENGTH - 4) + " […]";
}
return reason;
}
9 changes: 7 additions & 2 deletions backend/src/plugins/ModActions/functions/updateCase.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Message } from "discord.js";
import { GuildPluginData } from "knub";
import { CaseTypes } from "../../../data/CaseTypes";
import { Case } from "../../../data/entities/Case";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { ModActionsPluginType } from "../types.js";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
import { parseReason } from "./parseReason.js";

export async function updateCase(pluginData, msg: Message, args) {
let theCase: Case | undefined;
export async function updateCase(pluginData: GuildPluginData<ModActionsPluginType>, msg: Message, args) {
let theCase: Case | null;
if (args.caseNumber != null) {
theCase = await pluginData.state.cases.findByCaseNumber(args.caseNumber);
} else {
Expand All @@ -23,6 +26,8 @@ export async function updateCase(pluginData, msg: Message, args) {
sendErrorMessage(pluginData, msg.channel, "Text or attachment required");
return;
}
const config = pluginData.config.get();
args.note &&= parseReason(config, args.note);

const note = formatReasonWithAttachments(args.note, [...msg.attachments.values()]);

Expand Down
3 changes: 2 additions & 1 deletion backend/src/plugins/ModActions/functions/warnMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CasesPlugin } from "../../Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { ModActionsPluginType, WarnOptions, WarnResult } from "../types";
import { getDefaultContactMethods } from "./getDefaultContactMethods";
import { parseReason } from "./parseReason";

export async function warnMember(
pluginData: GuildPluginData<ModActionsPluginType>,
Expand All @@ -17,7 +18,7 @@ export async function warnMember(
warnOptions: WarnOptions = {},
): Promise<WarnResult> {
const config = pluginData.config.get();

reason = parseReason(config, reason);
let notifyResult: UserNotificationResult;
if (config.warn_message) {
const warnMessage = await renderTemplate(
Expand Down
Loading
Loading