Make warn/kick/ban actions in ModActions available to other plugins via public methods

This commit is contained in:
Dragory 2019-08-22 01:18:36 +03:00
parent 404039e196
commit 6bdb05e678

View file

@ -27,7 +27,7 @@ import { LogType } from "../data/LogType";
import { ZeppelinPlugin } from "./ZeppelinPlugin"; import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { Case } from "../data/entities/Case"; import { Case } from "../data/entities/Case";
import { renderTemplate } from "../templateFormatter"; import { renderTemplate } from "../templateFormatter";
import { CasesPlugin } from "./Cases"; import { CaseArgs, CasesPlugin } from "./Cases";
import { MuteResult, MutesPlugin } from "./Mutes"; import { MuteResult, MutesPlugin } from "./Mutes";
import * as t from "io-ts"; import * as t from "io-ts";
@ -328,8 +328,115 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
} }
/** /**
* Update the specified case (or, if case number is omitted, your latest case) by adding more notes/details to it * Kick the specified server member. Generates a case.
*/ */
async kickMember(member: Member, reason: string = null, caseArgs: Partial<CaseArgs> = {}): Promise<KickResult> {
const config = this.getConfig();
// Attempt to message the user *before* kicking them, as doing it after may not be possible
let notifyResult: INotifyUserResult = { status: NotifyUserStatus.Ignored };
if (reason) {
const kickMessage = await renderTemplate(config.kick_message, {
guildName: this.guild.name,
reason,
});
notifyResult = await notifyUser(this.bot, this.guild, member.user, kickMessage, {
useDM: config.dm_on_kick,
useChannel: config.message_on_kick,
channelId: config.message_channel,
});
}
// Kick the user
this.serverLogs.ignoreLog(LogType.MEMBER_KICK, member.id);
this.ignoreEvent(IgnoredEventType.Kick, member.id);
try {
await member.kick();
} catch (e) {
return {
status: "failed",
error: e.getMessage(),
};
}
// Create a case for this action
const casesPlugin = this.getPlugin<CasesPlugin>("cases");
const createdCase = await casesPlugin.createCase({
...caseArgs,
userId: member.id,
modId: caseArgs.modId,
type: CaseTypes.Kick,
reason,
noteDetails: notifyResult.status !== NotifyUserStatus.Ignored ? [ucfirst(notifyResult.text)] : [],
});
// Log the action
const mod = await this.resolveUser(caseArgs.modId);
this.serverLogs.log(LogType.MEMBER_KICK, {
mod: stripObjectToScalars(mod),
user: stripObjectToScalars(member.user),
});
return {
status: "success",
case: createdCase,
notifyResult,
};
}
/**
* Ban the specified user id, whether or not they're actually on the server at the time. Generates a case.
*/
async banUserId(userId: string, reason: string = null, caseArgs: Partial<CaseArgs> = {}): Promise<BanResult> {
const config = this.getConfig();
const user = await this.resolveUser(userId);
// Attempt to message the user *before* banning them, as doing it after may not be possible
let notifyResult: INotifyUserResult = { status: NotifyUserStatus.Ignored };
if (reason && user instanceof User) {
const banMessage = await renderTemplate(config.ban_message, {
guildName: this.guild.name,
reason,
});
notifyResult = await notifyUser(this.bot, this.guild, user, banMessage, {
useDM: config.dm_on_ban,
useChannel: config.message_on_ban,
channelId: config.message_channel,
});
}
// (Try to) ban the user
this.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId);
this.ignoreEvent(IgnoredEventType.Ban, userId);
try {
await this.guild.banMember(userId, 1);
} catch (e) {
return {
status: "failed",
error: e.getMessage(),
};
}
// Create a case for this action
const casesPlugin = this.getPlugin<CasesPlugin>("cases");
const createdCase = await casesPlugin.createCase({
...caseArgs,
userId,
modId: caseArgs.modId,
type: CaseTypes.Ban,
reason,
noteDetails: notifyResult.status !== NotifyUserStatus.Ignored ? [ucfirst(notifyResult.text)] : [],
});
// Log the action
const mod = await this.resolveUser(caseArgs.modId);
this.serverLogs.log(LogType.MEMBER_BAN, {
mod: stripObjectToScalars(mod),
user: stripObjectToScalars(user),
});
}
@d.command("update", "<caseNumber:number> [note:string$]", { @d.command("update", "<caseNumber:number> [note:string$]", {
overloads: ["[note:string$]"], overloads: ["[note:string$]"],
}) })
@ -433,37 +540,27 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
const reason = this.formatReasonWithAttachments(args.reason, msg.attachments); const reason = this.formatReasonWithAttachments(args.reason, msg.attachments);
const warnMessage = config.warn_message.replace("{guildName}", this.guild.name).replace("{reason}", reason); const warnMessage = config.warn_message.replace("{guildName}", this.guild.name).replace("{reason}", reason);
const warnResult = await this.warnMember(
memberToWarn,
warnMessage,
{
modId: mod.id,
ppId: mod.id !== msg.author.id ? msg.author.id : null,
},
msg.channel as TextChannel,
);
const userMessageResult = await notifyUser(this.bot, this.guild, memberToWarn.user, warnMessage, { if (warnResult.status === "failed") {
useDM: config.dm_on_warn, msg.channel.createMessage(errorMessage("Failed to warn user"));
useChannel: config.message_on_warn, return;
});
if (userMessageResult.status === NotifyUserStatus.Failed) {
const failedMsg = await msg.channel.createMessage("Failed to message the user. Log the warning anyway?");
const reply = await waitForReaction(this.bot, failedMsg, ["✅", "❌"], msg.author.id);
failedMsg.delete();
if (!reply || reply.name === "❌") {
return;
}
} }
const casesPlugin = this.getPlugin<CasesPlugin>("cases"); const messageResultText = warnResult.notifyResult.text ? ` (${warnResult.notifyResult.text})` : "";
const createdCase = await casesPlugin.createCase({
userId: memberToWarn.id,
modId: mod.id,
type: CaseTypes.Warn,
reason,
ppId: mod.id !== msg.author.id ? msg.author.id : null,
noteDetails: userMessageResult.status !== NotifyUserStatus.Ignored ? [ucfirst(userMessageResult.text)] : [],
});
const messageResultText = userMessageResult.text ? ` (${userMessageResult.text})` : "";
msg.channel.createMessage( msg.channel.createMessage(
successMessage( successMessage(
`Warned **${memberToWarn.user.username}#${memberToWarn.user.discriminator}** (Case #${ `Warned **${memberToWarn.user.username}#${memberToWarn.user.discriminator}** (Case #${
createdCase.case_number warnResult.case.case_number
})${messageResultText}`, })${messageResultText}`,
), ),
); );
@ -474,6 +571,61 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
}); });
} }
async warnMember(
member: Member,
warnMessage: string,
caseArgs: Partial<CaseArgs> = {},
retryPromptChannel: TextChannel = null,
): Promise<WarnResult | null> {
const config = this.getConfig();
const notifyResult = await notifyUser(this.bot, this.guild, member.user, warnMessage, {
useDM: config.dm_on_warn,
useChannel: config.message_on_warn,
});
if (notifyResult.status === NotifyUserStatus.Failed) {
if (retryPromptChannel && this.guild.channels.has(retryPromptChannel.id)) {
const failedMsg = await retryPromptChannel.createMessage("Failed to message the user. Log the warning anyway?");
const reply = await waitForReaction(this.bot, failedMsg, ["✅", "❌"]);
failedMsg.delete();
if (!reply || reply.name === "❌") {
return {
status: "failed",
error: "Failed to message user",
};
}
} else {
return {
status: "failed",
error: "Failed to message user",
};
}
}
const casesPlugin = this.getPlugin<CasesPlugin>("cases");
const createdCase = await casesPlugin.createCase({
...caseArgs,
userId: member.id,
modId: caseArgs.modId,
type: CaseTypes.Warn,
reason: warnMessage,
noteDetails: notifyResult.status !== NotifyUserStatus.Ignored ? [ucfirst(notifyResult.text)] : [],
});
const mod = await this.resolveUser(caseArgs.modId);
this.serverLogs.log(LogType.MEMBER_WARN, {
mod: stripObjectToScalars(mod),
member: stripObjectToScalars(member, ["user", "roles"]),
});
return {
status: "success",
case: createdCase,
notifyResult,
};
}
/** /**
* The actual function run by both !mute and !forcemute. * The actual function run by both !mute and !forcemute.
* The only difference between the two commands is in target member validation. * The only difference between the two commands is in target member validation.
@ -767,58 +919,24 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
mod = args.mod; mod = args.mod;
} }
const config = this.getConfig();
const reason = this.formatReasonWithAttachments(args.reason, msg.attachments); const reason = this.formatReasonWithAttachments(args.reason, msg.attachments);
const kickResult = await this.kickMember(memberToKick, reason, {
modId: mod.id,
ppId: mod.id !== msg.author.id ? msg.author.id : null,
});
// Attempt to message the user *before* kicking them, as doing it after may not be possible if (kickResult.status === "failed") {
let userMessageResult: INotifyUserResult = { status: NotifyUserStatus.Ignored }; msg.channel.createMessage(errorMessage(`Failed to kick user`));
if (args.reason) {
const kickMessage = await renderTemplate(config.kick_message, {
guildName: this.guild.name,
reason,
});
userMessageResult = await notifyUser(this.bot, this.guild, memberToKick.user, kickMessage, {
useDM: config.dm_on_kick,
useChannel: config.message_on_kick,
channelId: config.message_channel,
});
}
// Kick the user
this.serverLogs.ignoreLog(LogType.MEMBER_KICK, memberToKick.id);
this.ignoreEvent(IgnoredEventType.Kick, memberToKick.id);
try {
await memberToKick.kick();
} catch (e) {
msg.channel.create(errorMessage("Failed to kick the user"));
return; return;
} }
// Create a case for this action
const casesPlugin = this.getPlugin<CasesPlugin>("cases");
const createdCase = await casesPlugin.createCase({
userId: memberToKick.id,
modId: mod.id,
type: CaseTypes.Kick,
reason,
ppId: mod.id !== msg.author.id ? msg.author.id : null,
noteDetails: userMessageResult.status !== NotifyUserStatus.Ignored ? [ucfirst(userMessageResult.text)] : [],
});
// Confirm the action to the moderator // Confirm the action to the moderator
let response = `Kicked **${memberToKick.user.username}#${memberToKick.user.discriminator}** (Case #${ let response = `Kicked **${memberToKick.user.username}#${memberToKick.user.discriminator}** (Case #${
createdCase.case_number kickResult.case.case_number
})`; })`;
if (userMessageResult.text) response += ` (${userMessageResult.text})`; if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
msg.channel.createMessage(successMessage(response)); msg.channel.createMessage(successMessage(response));
// Log the action
this.serverLogs.log(LogType.MEMBER_KICK, {
mod: stripObjectToScalars(mod.user),
user: stripObjectToScalars(memberToKick.user),
});
} }
@d.command("ban", "<user:string> [reason:string$]", { @d.command("ban", "<user:string> [reason:string$]", {