Migrate ModActions to new Plugin structure !!mutes dont work!!
This commit is contained in:
parent
ebcb28261b
commit
fd56664984
29 changed files with 1213 additions and 16 deletions
|
@ -9,6 +9,7 @@ import { Case } from "../../data/entities/Case";
|
||||||
import { postCaseToCaseLogChannel } from "./functions/postToCaseLogChannel";
|
import { postCaseToCaseLogChannel } from "./functions/postToCaseLogChannel";
|
||||||
import { CaseTypes } from "../../data/CaseTypes";
|
import { CaseTypes } from "../../data/CaseTypes";
|
||||||
import { getCaseTypeAmountForUserId } from "./functions/getCaseTypeAmountForUserId";
|
import { getCaseTypeAmountForUserId } from "./functions/getCaseTypeAmountForUserId";
|
||||||
|
import { getCaseEmbed } from "./functions/getCaseEmbed";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -45,6 +46,12 @@ export const CasesPlugin = zeppelinPlugin<CasesPluginType>()("cases", {
|
||||||
return getCaseTypeAmountForUserId(pluginData, userID, type);
|
return getCaseTypeAmountForUserId(pluginData, userID, type);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCaseEmbed(pluginData) {
|
||||||
|
return (caseOrCaseId: Case | number) => {
|
||||||
|
return getCaseEmbed(pluginData, caseOrCaseId);
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(pluginData) {
|
onLoad(pluginData) {
|
||||||
|
|
|
@ -9,6 +9,25 @@ import { UpdateCmd } from "./commands/UpdateCmd";
|
||||||
import { NoteCmd } from "./commands/NoteCmd";
|
import { NoteCmd } from "./commands/NoteCmd";
|
||||||
import { WarnCmd } from "./commands/WarnCmd";
|
import { WarnCmd } from "./commands/WarnCmd";
|
||||||
import { MuteCmd } from "./commands/MuteCmd";
|
import { MuteCmd } from "./commands/MuteCmd";
|
||||||
|
import { PostAlertOnMemberJoinEvt } from "./events/PostAlertOnMemberJoinEvt";
|
||||||
|
import { ForcemuteCmd } from "./commands/ForcemuteCmd";
|
||||||
|
import { UnmuteCmd } from "./commands/UnmuteCmd";
|
||||||
|
import { KickCmd } from "./commands/KickCmd";
|
||||||
|
import { SoftbanCmd } from "./commands/SoftbanCommand";
|
||||||
|
import { BanCmd } from "./commands/BanCmd";
|
||||||
|
import { UnbanCmd } from "./commands/UnbanCmd";
|
||||||
|
import { ForcebanCmd } from "./commands/ForcebanCmd";
|
||||||
|
import { MassbanCmd } from "./commands/MassBanCmd";
|
||||||
|
import { AddCaseCmd } from "./commands/AddCaseCmd";
|
||||||
|
import { CaseCmd } from "./commands/CaseCmd";
|
||||||
|
import { CasesUserCmd } from "./commands/CasesUserCmd";
|
||||||
|
import { CasesModCmd } from "./commands/CasesModCmd";
|
||||||
|
import { HideCaseCmd } from "./commands/HideCaseCmd";
|
||||||
|
import { UnhideCaseCmd } from "./commands/UnhideCaseCmd";
|
||||||
|
import { GuildMutes } from "src/data/GuildMutes";
|
||||||
|
import { GuildCases } from "src/data/GuildCases";
|
||||||
|
import { GuildLogs } from "src/data/GuildLogs";
|
||||||
|
import { ForceUnmuteCmd } from "./commands/ForceunmuteCmd";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -71,7 +90,42 @@ export const ModActionsPlugin = zeppelinPlugin<ModActionsPluginType>()("mod_acti
|
||||||
|
|
||||||
dependencies: [CasesPlugin, MutesPlugin],
|
dependencies: [CasesPlugin, MutesPlugin],
|
||||||
|
|
||||||
events: [CreateBanCaseOnManualBanEvt, CreateUnbanCaseOnManualUnbanEvt, CreateKickCaseOnManualKickEvt],
|
events: [
|
||||||
|
CreateBanCaseOnManualBanEvt,
|
||||||
|
CreateUnbanCaseOnManualUnbanEvt,
|
||||||
|
CreateKickCaseOnManualKickEvt,
|
||||||
|
PostAlertOnMemberJoinEvt,
|
||||||
|
],
|
||||||
|
|
||||||
commands: [UpdateCmd, NoteCmd, WarnCmd, MuteCmd],
|
commands: [
|
||||||
|
UpdateCmd,
|
||||||
|
NoteCmd,
|
||||||
|
WarnCmd,
|
||||||
|
MuteCmd,
|
||||||
|
ForcemuteCmd,
|
||||||
|
UnmuteCmd,
|
||||||
|
ForceUnmuteCmd,
|
||||||
|
KickCmd,
|
||||||
|
SoftbanCmd,
|
||||||
|
BanCmd,
|
||||||
|
UnbanCmd,
|
||||||
|
ForcebanCmd,
|
||||||
|
MassbanCmd,
|
||||||
|
AddCaseCmd,
|
||||||
|
CaseCmd,
|
||||||
|
CasesUserCmd,
|
||||||
|
CasesModCmd,
|
||||||
|
HideCaseCmd,
|
||||||
|
UnhideCaseCmd,
|
||||||
|
],
|
||||||
|
|
||||||
|
onLoad(pluginData) {
|
||||||
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
|
state.mutes = GuildMutes.getGuildInstance(guild.id);
|
||||||
|
state.cases = GuildCases.getGuildInstance(guild.id);
|
||||||
|
state.serverLogs = new GuildLogs(guild.id);
|
||||||
|
|
||||||
|
state.ignoredEvents = [];
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
90
backend/src/plugins/ModActions/commands/AddCaseCmd.ts
Normal file
90
backend/src/plugins/ModActions/commands/AddCaseCmd.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember, stripObjectToScalars } from "../../../utils";
|
||||||
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
|
import { CaseTypes } from "src/data/CaseTypes";
|
||||||
|
import { CasesPlugin } from "src/plugins/Cases/CasesPlugin";
|
||||||
|
import { Case } from "src/data/entities/Case";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AddCaseCmd = modActionsCommand({
|
||||||
|
trigger: "addcase",
|
||||||
|
permission: "can_addcase",
|
||||||
|
description: "Add an arbitrary case to the specified user without taking any action",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
type: ct.string(),
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
// If the user exists as a guild member, make sure we can act on them first
|
||||||
|
const member = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
if (member && !canActOn(pluginData, msg.member, member)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot add case on this user: 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 (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "No permission for -mod");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = args.mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the case type is valid
|
||||||
|
const type: string = args.type[0].toUpperCase() + args.type.slice(1).toLowerCase();
|
||||||
|
if (!CaseTypes[type]) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot add case: invalid case type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||||
|
|
||||||
|
// Create the case
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
const theCase: Case = await casesPlugin.createCase({
|
||||||
|
userId: user.id,
|
||||||
|
modId: mod.id,
|
||||||
|
type: CaseTypes[type],
|
||||||
|
reason,
|
||||||
|
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
sendSuccessMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`Case #${theCase.case_number} created for **${user.username}#${user.discriminator}**`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, `Case #${theCase.case_number} created`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the action
|
||||||
|
pluginData.state.serverLogs.log(LogType.CASE_CREATE, {
|
||||||
|
mod: stripObjectToScalars(mod.user),
|
||||||
|
userId: user.id,
|
||||||
|
caseNum: theCase.case_number,
|
||||||
|
caseType: type.toUpperCase(),
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
97
backend/src/plugins/ModActions/commands/BanCmd.ts
Normal file
97
backend/src/plugins/ModActions/commands/BanCmd.ts
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import { modActionsCommand, IgnoredEventType } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember } from "../../../utils";
|
||||||
|
import { isBanned } from "../functions/isBanned";
|
||||||
|
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
||||||
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
|
import { banUserId } from "../functions/banUserId";
|
||||||
|
import { ignoreEvent } from "../functions/ignoreEvent";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
notify: ct.string({ option: true }),
|
||||||
|
"notify-channel": ct.textChannel({ option: true }),
|
||||||
|
"delete-deays": ct.number({ option: true, shortcut: "d" }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BanCmd = modActionsCommand({
|
||||||
|
trigger: "ban",
|
||||||
|
permission: "can_ban",
|
||||||
|
description: "Ban the specified member",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
const memberToBan = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
|
||||||
|
if (!memberToBan) {
|
||||||
|
const banned = await isBanned(pluginData, user.id);
|
||||||
|
if (banned) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `User is already banned`);
|
||||||
|
} else {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `User not found on the server`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we're allowed to ban this member
|
||||||
|
if (!canActOn(pluginData, msg.member, memberToBan)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot ban: 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 (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "No permission for -mod");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = args.mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
let contactMethods;
|
||||||
|
try {
|
||||||
|
contactMethods = readContactMethodsFromArgs(args);
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteMessageDays = args["delete-days"] ?? pluginData.config.getForMessage(msg).ban_delete_message_days;
|
||||||
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||||
|
const banResult = await banUserId(pluginData, memberToBan.id, reason, {
|
||||||
|
contactMethods,
|
||||||
|
caseArgs: {
|
||||||
|
modId: mod.id,
|
||||||
|
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||||
|
},
|
||||||
|
deleteMessageDays,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (banResult.status === "failed") {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `Failed to ban member`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the action to the moderator
|
||||||
|
let response = `Banned **${memberToBan.user.username}#${memberToBan.user.discriminator}** (Case #${banResult.case.case_number})`;
|
||||||
|
|
||||||
|
if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`;
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, response);
|
||||||
|
},
|
||||||
|
});
|
29
backend/src/plugins/ModActions/commands/CaseCmd.ts
Normal file
29
backend/src/plugins/ModActions/commands/CaseCmd.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { CasesPlugin } from "src/plugins/Cases/CasesPlugin";
|
||||||
|
|
||||||
|
export const CaseCmd = modActionsCommand({
|
||||||
|
trigger: "case",
|
||||||
|
permission: "can_view",
|
||||||
|
description: "Show information about a specific case",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
caseNumber: ct.number(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const theCase = await pluginData.state.cases.findByCaseNumber(args.caseNumber);
|
||||||
|
|
||||||
|
if (!theCase) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Case not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
const embed = await casesPlugin.getCaseEmbed(theCase.id);
|
||||||
|
msg.channel.createMessage(embed);
|
||||||
|
},
|
||||||
|
});
|
43
backend/src/plugins/ModActions/commands/CasesModCmd.ts
Normal file
43
backend/src/plugins/ModActions/commands/CasesModCmd.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { trimLines, createChunkedMessage } from "src/utils";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CasesModCmd = modActionsCommand({
|
||||||
|
trigger: "cases",
|
||||||
|
permission: "can_view",
|
||||||
|
description: "Show the most recent 5 cases by the specified -mod",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const modId = args.mod ? args.mod.id : msg.author.id;
|
||||||
|
const recentCases = await pluginData.state.cases.with("notes").getRecentByModId(modId, 5);
|
||||||
|
|
||||||
|
const mod = pluginData.client.users.get(modId);
|
||||||
|
const modName = mod ? `${mod.username}#${mod.discriminator}` : modId;
|
||||||
|
|
||||||
|
if (recentCases.length === 0) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `No cases by **${modName}**`);
|
||||||
|
} else {
|
||||||
|
const lines = recentCases.map(c => pluginData.state.cases.getSummaryText(c));
|
||||||
|
const finalMessage = trimLines(`
|
||||||
|
Most recent 5 cases by **${modName}**:
|
||||||
|
|
||||||
|
${lines.join("\n")}
|
||||||
|
|
||||||
|
Use the \`case <num>\` command to see more info about individual cases
|
||||||
|
Use the \`cases <user>\` command to see a specific user's cases
|
||||||
|
`);
|
||||||
|
createChunkedMessage(msg.channel, finalMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
84
backend/src/plugins/ModActions/commands/CasesUserCmd.ts
Normal file
84
backend/src/plugins/ModActions/commands/CasesUserCmd.ts
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { CasesPlugin } from "src/plugins/Cases/CasesPlugin";
|
||||||
|
import { UnknownUser, multiSorter, trimLines, createChunkedMessage, resolveUser } from "src/utils";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
expand: ct.bool({ option: true, isSwitch: true, shortcut: "e" }),
|
||||||
|
hidden: ct.bool({ option: true, isSwitch: true, shortcut: "h" }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CasesUserCmd = modActionsCommand({
|
||||||
|
trigger: "cases",
|
||||||
|
permission: "can_view",
|
||||||
|
description: "Show a list of cases the specified user has",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
const cases = await pluginData.state.cases.with("notes").getByUserId(user.id);
|
||||||
|
const normalCases = cases.filter(c => !c.is_hidden);
|
||||||
|
const hiddenCases = cases.filter(c => c.is_hidden);
|
||||||
|
|
||||||
|
const userName =
|
||||||
|
user instanceof UnknownUser && cases.length
|
||||||
|
? cases[cases.length - 1].user_name
|
||||||
|
: `${user.username}#${user.discriminator}`;
|
||||||
|
|
||||||
|
if (cases.length === 0) {
|
||||||
|
msg.channel.createMessage(`No cases found for **${userName}**`);
|
||||||
|
} else {
|
||||||
|
const casesToDisplay = args.hidden ? cases : normalCases;
|
||||||
|
|
||||||
|
if (args.expand) {
|
||||||
|
if (casesToDisplay.length > 8) {
|
||||||
|
msg.channel.createMessage("Too many cases for expanded view. Please use compact view instead.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expanded view (= individual case embeds)
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
for (const theCase of casesToDisplay) {
|
||||||
|
const embed = await casesPlugin.getCaseEmbed(theCase.id);
|
||||||
|
msg.channel.createMessage(embed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Compact view (= regular message with a preview of each case)
|
||||||
|
const lines = [];
|
||||||
|
for (const theCase of casesToDisplay) {
|
||||||
|
theCase.notes.sort(multiSorter(["created_at", "id"]));
|
||||||
|
const caseSummary = pluginData.state.cases.getSummaryText(theCase);
|
||||||
|
lines.push(caseSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.hidden && hiddenCases.length) {
|
||||||
|
if (hiddenCases.length === 1) {
|
||||||
|
lines.push(`*+${hiddenCases.length} hidden case, use "-hidden" to show it*`);
|
||||||
|
} else {
|
||||||
|
lines.push(`*+${hiddenCases.length} hidden cases, use "-hidden" to show them*`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalMessage = trimLines(`
|
||||||
|
Cases for **${userName}**:
|
||||||
|
|
||||||
|
${lines.join("\n")}
|
||||||
|
|
||||||
|
Use the \`case <num>\` command to see more info about individual cases
|
||||||
|
`);
|
||||||
|
|
||||||
|
createChunkedMessage(msg.channel, finalMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
93
backend/src/plugins/ModActions/commands/ForcebanCmd.ts
Normal file
93
backend/src/plugins/ModActions/commands/ForcebanCmd.ts
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import { modActionsCommand, IgnoredEventType } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember, stripObjectToScalars } from "../../../utils";
|
||||||
|
import { isBanned } from "../functions/isBanned";
|
||||||
|
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
||||||
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
|
import { banUserId } from "../functions/banUserId";
|
||||||
|
import { ignoreEvent } from "../functions/ignoreEvent";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
import { CaseTypes } from "src/data/CaseTypes";
|
||||||
|
import { CasesPlugin } from "src/plugins/Cases/CasesPlugin";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ForcebanCmd = modActionsCommand({
|
||||||
|
trigger: "forceban",
|
||||||
|
permission: "can_ban",
|
||||||
|
description: "Force-ban the specified user, even if they aren't on the server",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
// If the user exists as a guild member, make sure we can act on them first
|
||||||
|
const member = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
if (member && !canActOn(pluginData, msg.member, member)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot forceban this user: insufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the user isn't already banned
|
||||||
|
const banned = await isBanned(pluginData, user.id);
|
||||||
|
if (banned) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `User is already banned`);
|
||||||
|
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 (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "No permission for -mod");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = args.mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||||
|
|
||||||
|
ignoreEvent(pluginData, IgnoredEventType.Ban, user.id);
|
||||||
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, user.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await pluginData.guild.banMember(user.id, 1);
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Failed to forceban member");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a case
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
const createdCase = await casesPlugin.createCase({
|
||||||
|
userId: user.id,
|
||||||
|
modId: mod.id,
|
||||||
|
type: CaseTypes.Ban,
|
||||||
|
reason,
|
||||||
|
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm the action
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, `Member forcebanned (Case #${createdCase.case_number})`);
|
||||||
|
|
||||||
|
// Log the action
|
||||||
|
pluginData.state.serverLogs.log(LogType.MEMBER_FORCEBAN, {
|
||||||
|
mod: stripObjectToScalars(mod.user),
|
||||||
|
userId: user.id,
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
48
backend/src/plugins/ModActions/commands/ForcemuteCmd.ts
Normal file
48
backend/src/plugins/ModActions/commands/ForcemuteCmd.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveMember, resolveUser } from "../../../utils";
|
||||||
|
import { actualMuteUserCmd } from "../functions/actualMuteUserCmd";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
notify: ct.string({ option: true }),
|
||||||
|
"notify-channel": ct.textChannel({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ForcemuteCmd = modActionsCommand({
|
||||||
|
trigger: "forcemute",
|
||||||
|
permission: "can_mute",
|
||||||
|
description: "Force-mute the specified user, even if they're not on the server",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
time: ct.delay(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
const memberToMute = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
|
||||||
|
// Make sure we're allowed to mute this user
|
||||||
|
if (memberToMute && !canActOn(pluginData, msg.member, memberToMute)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot mute: insufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actualMuteUserCmd(pluginData, user, msg, args);
|
||||||
|
},
|
||||||
|
});
|
53
backend/src/plugins/ModActions/commands/ForceunmuteCmd.ts
Normal file
53
backend/src/plugins/ModActions/commands/ForceunmuteCmd.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember } from "../../../utils";
|
||||||
|
import { actualUnmuteCmd } from "../functions/actualUnmuteUserCmd";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ForceUnmuteCmd = modActionsCommand({
|
||||||
|
trigger: "forceunmute",
|
||||||
|
permission: "can_mute",
|
||||||
|
description: "Force-unmute the specified user, even if they're not on the server",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
time: ct.delay(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
// Check if they're muted in the first place
|
||||||
|
if (!(await pluginData.state.mutes.isMuted(user.id))) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot unmute: member is not muted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the server member to unmute
|
||||||
|
const memberToUnmute = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
|
||||||
|
// Make sure we're allowed to unmute this member
|
||||||
|
if (memberToUnmute && !canActOn(pluginData, msg.member, memberToUnmute)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot unmute: insufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actualUnmuteCmd(pluginData, user, msg, args);
|
||||||
|
},
|
||||||
|
});
|
30
backend/src/plugins/ModActions/commands/HideCaseCmd.ts
Normal file
30
backend/src/plugins/ModActions/commands/HideCaseCmd.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
|
||||||
|
export const HideCaseCmd = modActionsCommand({
|
||||||
|
trigger: ["hide", "hidecase", "hide_case"],
|
||||||
|
permission: "can_hidecase",
|
||||||
|
description: "Hide the specified case so it doesn't appear in !cases or !info",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
caseNum: ct.number(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const theCase = await pluginData.state.cases.findByCaseNumber(args.caseNum);
|
||||||
|
if (!theCase) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Case not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pluginData.state.cases.setHidden(theCase.id, true);
|
||||||
|
sendSuccessMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`Case #${theCase.case_number} is now hidden! Use \`unhidecase\` to unhide it.`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
35
backend/src/plugins/ModActions/commands/KickCmd.ts
Normal file
35
backend/src/plugins/ModActions/commands/KickCmd.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember } from "../../../utils";
|
||||||
|
import { MutesPlugin } from "src/plugins/Mutes/MutesPlugin";
|
||||||
|
import { actualUnmuteCmd } from "../functions/actualUnmuteUserCmd";
|
||||||
|
import { isBanned } from "../functions/isBanned";
|
||||||
|
import { plugin } from "knub";
|
||||||
|
import { actualKickMemberCmd } from "../functions/actualKickMemberCmd";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
notify: ct.string({ option: true }),
|
||||||
|
"notify-channel": ct.textChannel({ option: true }),
|
||||||
|
clean: ct.bool({ option: true, isSwitch: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const KickCmd = modActionsCommand({
|
||||||
|
trigger: "kick",
|
||||||
|
permission: "can_kick",
|
||||||
|
description: "Kick the specified member",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
actualKickMemberCmd(pluginData, msg, args);
|
||||||
|
},
|
||||||
|
});
|
109
backend/src/plugins/ModActions/commands/MassBanCmd.ts
Normal file
109
backend/src/plugins/ModActions/commands/MassBanCmd.ts
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import { modActionsCommand, IgnoredEventType } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember, stripObjectToScalars } from "../../../utils";
|
||||||
|
import { isBanned } from "../functions/isBanned";
|
||||||
|
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
||||||
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
|
import { banUserId } from "../functions/banUserId";
|
||||||
|
import { CaseTypes } from "src/data/CaseTypes";
|
||||||
|
import { TextChannel } from "eris";
|
||||||
|
import { waitForReply } from "knub/dist/helpers";
|
||||||
|
import { ignoreEvent } from "../functions/ignoreEvent";
|
||||||
|
import { CasesPlugin } from "src/plugins/Cases/CasesPlugin";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
|
||||||
|
export const MassbanCmd = modActionsCommand({
|
||||||
|
trigger: "massban",
|
||||||
|
permission: "can_massban",
|
||||||
|
description: "Mass-ban a list of user IDs",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
userIds: ct.string({ rest: true }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
// Limit to 100 users at once (arbitrary?)
|
||||||
|
if (args.userIds.length > 100) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `Can only massban max 100 users at once`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask for ban reason (cleaner this way instead of trying to cram it into the args)
|
||||||
|
msg.channel.createMessage("Ban reason? `cancel` to cancel");
|
||||||
|
const banReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
||||||
|
if (!banReasonReply || !banReasonReply.content || banReasonReply.content.toLowerCase().trim() === "cancel") {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cancelled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const banReason = formatReasonWithAttachments(banReasonReply.content, msg.attachments);
|
||||||
|
|
||||||
|
// Verify we can act on each of the users specified
|
||||||
|
for (const userId of args.userIds) {
|
||||||
|
const member = pluginData.guild.members.get(userId); // TODO: Get members on demand?
|
||||||
|
if (member && !canActOn(pluginData, msg.member, member)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot massban one or more users: insufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore automatic ban cases and logs for these users
|
||||||
|
// We'll create our own cases below and post a single "mass banned" log instead
|
||||||
|
args.userIds.forEach(userId => {
|
||||||
|
// Use longer timeouts since this can take a while
|
||||||
|
ignoreEvent(pluginData, IgnoredEventType.Ban, userId, 120 * 1000);
|
||||||
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show a loading indicator since this can take a while
|
||||||
|
const loadingMsg = await msg.channel.createMessage("Banning...");
|
||||||
|
|
||||||
|
// Ban each user and count failed bans (if any)
|
||||||
|
const failedBans = [];
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
for (const userId of args.userIds) {
|
||||||
|
try {
|
||||||
|
await pluginData.guild.banMember(userId, 1);
|
||||||
|
|
||||||
|
await casesPlugin.createCase({
|
||||||
|
userId,
|
||||||
|
modId: msg.author.id,
|
||||||
|
type: CaseTypes.Ban,
|
||||||
|
reason: `Mass ban: ${banReason}`,
|
||||||
|
postInCaseLogOverride: false,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
failedBans.push(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear loading indicator
|
||||||
|
loadingMsg.delete();
|
||||||
|
|
||||||
|
const successfulBanCount = args.userIds.length - failedBans.length;
|
||||||
|
if (successfulBanCount === 0) {
|
||||||
|
// All bans failed - don't create a log entry and notify the user
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "All bans failed. Make sure the IDs are valid.");
|
||||||
|
} else {
|
||||||
|
// Some or all bans were successful. Create a log entry for the mass ban and notify the user.
|
||||||
|
pluginData.state.serverLogs.log(LogType.MASSBAN, {
|
||||||
|
mod: stripObjectToScalars(msg.author),
|
||||||
|
count: successfulBanCount,
|
||||||
|
reason: banReason,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (failedBans.length) {
|
||||||
|
sendSuccessMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`Banned ${successfulBanCount} users, ${failedBans.length} failed: ${failedBans.join(" ")}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, `Banned ${successfulBanCount} users successfully`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
35
backend/src/plugins/ModActions/commands/SoftbanCommand.ts
Normal file
35
backend/src/plugins/ModActions/commands/SoftbanCommand.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { trimPluginDescription } from "../../../utils";
|
||||||
|
import { actualKickMemberCmd } from "../functions/actualKickMemberCmd";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
notify: ct.string({ option: true }),
|
||||||
|
"notify-channel": ct.textChannel({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SoftbanCmd = modActionsCommand({
|
||||||
|
trigger: "softban",
|
||||||
|
permission: "can_kick",
|
||||||
|
description: trimPluginDescription(`
|
||||||
|
"Softban" the specified user by banning and immediately unbanning them. Effectively a kick with message deletions.
|
||||||
|
This command will be removed in the future, please use kick with the \`- clean\` argument instead
|
||||||
|
`),
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
await actualKickMemberCmd(pluginData, msg, { clean: true, ...args });
|
||||||
|
await msg.channel.createMessage(
|
||||||
|
"Softban will be removed in the future - please use the kick command with the `-clean` argument instead!",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
76
backend/src/plugins/ModActions/commands/UnbanCmd.ts
Normal file
76
backend/src/plugins/ModActions/commands/UnbanCmd.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { modActionsCommand, IgnoredEventType } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, stripObjectToScalars } from "../../../utils";
|
||||||
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
import { ignoreEvent } from "../functions/ignoreEvent";
|
||||||
|
import { CaseTypes } from "src/data/CaseTypes";
|
||||||
|
import { CasesPlugin } from "src/plugins/Cases/CasesPlugin";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UnbanCmd = modActionsCommand({
|
||||||
|
trigger: "unban",
|
||||||
|
permission: "can_ban",
|
||||||
|
description: "Unban the specified member",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
|
let mod = msg.member;
|
||||||
|
if (args.mod) {
|
||||||
|
if (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "No permission for -mod");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = args.mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, user.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ignoreEvent(pluginData, IgnoredEventType.Unban, user.id);
|
||||||
|
await pluginData.guild.unbanMember(user.id);
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Failed to unban member; are you sure they're banned?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||||
|
|
||||||
|
// Create a case
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
const createdCase = await casesPlugin.createCase({
|
||||||
|
userId: user.id,
|
||||||
|
modId: mod.id,
|
||||||
|
type: CaseTypes.Unban,
|
||||||
|
reason,
|
||||||
|
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm the action
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, `Member unbanned (Case #${createdCase.case_number})`);
|
||||||
|
|
||||||
|
// Log the action
|
||||||
|
pluginData.state.serverLogs.log(LogType.MEMBER_UNBAN, {
|
||||||
|
mod: stripObjectToScalars(mod.user),
|
||||||
|
userId: user.id,
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
26
backend/src/plugins/ModActions/commands/UnhideCaseCmd.ts
Normal file
26
backend/src/plugins/ModActions/commands/UnhideCaseCmd.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
|
||||||
|
export const UnhideCaseCmd = modActionsCommand({
|
||||||
|
trigger: ["unhide", "unhidecase", "unhide_case"],
|
||||||
|
permission: "can_hidecase",
|
||||||
|
description: "Un-hide the specified case, making it appear in !cases and !info again",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
caseNum: ct.number(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const theCase = await pluginData.state.cases.findByCaseNumber(args.caseNum);
|
||||||
|
if (!theCase) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Case not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pluginData.state.cases.setHidden(theCase.id, false);
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, `Case #${theCase.case_number} is no longer hidden!`);
|
||||||
|
},
|
||||||
|
});
|
76
backend/src/plugins/ModActions/commands/UnmuteCmd.ts
Normal file
76
backend/src/plugins/ModActions/commands/UnmuteCmd.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { modActionsCommand } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { canActOn, sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
import { resolveUser, resolveMember } from "../../../utils";
|
||||||
|
import { MutesPlugin } from "src/plugins/Mutes/MutesPlugin";
|
||||||
|
import { actualUnmuteCmd } from "../functions/actualUnmuteUserCmd";
|
||||||
|
import { isBanned } from "../functions/isBanned";
|
||||||
|
import { plugin } from "knub";
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
mod: ct.member({ option: true }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UnmuteCmd = modActionsCommand({
|
||||||
|
trigger: "unmute",
|
||||||
|
permission: "can_mute",
|
||||||
|
description: "Unmute the specified member",
|
||||||
|
|
||||||
|
signature: [
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
time: ct.delay(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: ct.string(),
|
||||||
|
reason: ct.string({ required: false, catchAll: true }),
|
||||||
|
|
||||||
|
...opts,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run({ pluginData, message: msg, args }) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
const memberToUnmute = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||||
|
const hasMuteRole = memberToUnmute && mutesPlugin.hasMutedRole(memberToUnmute);
|
||||||
|
|
||||||
|
// Check if they're muted in the first place
|
||||||
|
if (!(await pluginData.state.mutes.isMuted(args.user)) && !hasMuteRole) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot unmute: member is not muted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memberToUnmute) {
|
||||||
|
const banned = await isBanned(pluginData, memberToUnmute.id);
|
||||||
|
const prefix = pluginData.guildConfig.prefix;
|
||||||
|
if (banned) {
|
||||||
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`User is banned. Use \`${prefix}forceunmute\` to unmute them anyway.`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`User is not on the server. Use \`${prefix}forceunmute\` to unmute them anyway.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we're allowed to unmute this member
|
||||||
|
if (memberToUnmute && !canActOn(pluginData, msg.member, memberToUnmute)) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Cannot unmute: insufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actualUnmuteCmd(pluginData, user, msg, args);
|
||||||
|
},
|
||||||
|
});
|
|
@ -13,10 +13,15 @@ export const UpdateCmd = modActionsCommand({
|
||||||
description:
|
description:
|
||||||
"Update the specified case (or, if case number is omitted, your latest case) by adding more notes/details to it",
|
"Update the specified case (or, if case number is omitted, your latest case) by adding more notes/details to it",
|
||||||
|
|
||||||
signature: {
|
signature: [
|
||||||
caseNumber: ct.number(),
|
{
|
||||||
note: ct.string({ required: false, catchAll: true }),
|
caseNumber: ct.number(),
|
||||||
},
|
note: ct.string({ required: false, catchAll: true }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
note: ct.string({ catchAll: true }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
let theCase: Case;
|
let theCase: Case;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { eventListener } from "knub";
|
import { eventListener } from "knub";
|
||||||
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||||
import { isEventIgnored } from "../functions/isEventIgnored";
|
import { isEventIgnored } from "../functions/isEventIgnored";
|
||||||
import { clearIgnoredEvent } from "../functions/clearIgnoredEvents";
|
import { clearIgnoredEvents } from "../functions/clearIgnoredEvents";
|
||||||
import { Constants as ErisConstants } from "eris";
|
import { Constants as ErisConstants } from "eris";
|
||||||
import { safeFindRelevantAuditLogEntry } from "../functions/safeFindRelevantAuditLogEntry";
|
import { safeFindRelevantAuditLogEntry } from "../functions/safeFindRelevantAuditLogEntry";
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
|
@ -15,7 +15,7 @@ export const CreateBanCaseOnManualBanEvt = eventListener<ModActionsPluginType>()
|
||||||
"guildBanAdd",
|
"guildBanAdd",
|
||||||
async ({ pluginData, args: { guild, user } }) => {
|
async ({ pluginData, args: { guild, user } }) => {
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) {
|
||||||
clearIgnoredEvent(pluginData, IgnoredEventType.Ban, user.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Ban, user.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { eventListener } from "knub";
|
import { eventListener } from "knub";
|
||||||
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||||
import { isEventIgnored } from "../functions/isEventIgnored";
|
import { isEventIgnored } from "../functions/isEventIgnored";
|
||||||
import { clearIgnoredEvent } from "../functions/clearIgnoredEvents";
|
import { clearIgnoredEvents } from "../functions/clearIgnoredEvents";
|
||||||
import { Constants as ErisConstants } from "eris";
|
import { Constants as ErisConstants } from "eris";
|
||||||
import { safeFindRelevantAuditLogEntry } from "../functions/safeFindRelevantAuditLogEntry";
|
import { safeFindRelevantAuditLogEntry } from "../functions/safeFindRelevantAuditLogEntry";
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
|
@ -18,7 +18,7 @@ export const CreateKickCaseOnManualKickEvt = eventListener<ModActionsPluginType>
|
||||||
"guildMemberRemove",
|
"guildMemberRemove",
|
||||||
async ({ pluginData, args: { member } }) => {
|
async ({ pluginData, args: { member } }) => {
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Kick, member.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Kick, member.id)) {
|
||||||
clearIgnoredEvent(pluginData, IgnoredEventType.Kick, member.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Kick, member.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { eventListener } from "knub";
|
import { eventListener } from "knub";
|
||||||
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||||
import { isEventIgnored } from "../functions/isEventIgnored";
|
import { isEventIgnored } from "../functions/isEventIgnored";
|
||||||
import { clearIgnoredEvent } from "../functions/clearIgnoredEvents";
|
import { clearIgnoredEvents } from "../functions/clearIgnoredEvents";
|
||||||
import { Constants as ErisConstants } from "eris";
|
import { Constants as ErisConstants } from "eris";
|
||||||
import { safeFindRelevantAuditLogEntry } from "../functions/safeFindRelevantAuditLogEntry";
|
import { safeFindRelevantAuditLogEntry } from "../functions/safeFindRelevantAuditLogEntry";
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
|
@ -15,7 +15,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = eventListener<ModActionsPluginTyp
|
||||||
"guildBanRemove",
|
"guildBanRemove",
|
||||||
async ({ pluginData, args: { guild, user } }) => {
|
async ({ pluginData, args: { guild, user } }) => {
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) {
|
||||||
clearIgnoredEvent(pluginData, IgnoredEventType.Unban, user.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Unban, user.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { eventListener } from "knub";
|
||||||
|
import { ModActionsPluginType } from "../types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an alert if a member with prior notes joins the server
|
||||||
|
*/
|
||||||
|
export const PostAlertOnMemberJoinEvt = eventListener<ModActionsPluginType>()(
|
||||||
|
"guildMemberAdd",
|
||||||
|
async ({ pluginData, args: { guild, member } }) => {
|
||||||
|
const config = pluginData.config.get();
|
||||||
|
|
||||||
|
if (!config.alert_on_rejoin) return;
|
||||||
|
|
||||||
|
const alertChannelId = config.alert_channel;
|
||||||
|
if (!alertChannelId) return;
|
||||||
|
|
||||||
|
const actions = await pluginData.state.cases.getByUserId(member.id);
|
||||||
|
|
||||||
|
if (actions.length) {
|
||||||
|
const alertChannel: any = pluginData.guild.channels.get(alertChannelId);
|
||||||
|
alertChannel.send(
|
||||||
|
`<@!${member.id}> (${member.user.username}#${member.user.discriminator} \`${member.id}\`) joined with ${actions.length} prior record(s)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
107
backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
Normal file
107
backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import { Member, TextChannel } from "eris";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||||
|
import { errorMessage, resolveUser, resolveMember } from "src/utils";
|
||||||
|
import { PluginData } from "knub";
|
||||||
|
import { sendErrorMessage, canActOn, sendSuccessMessage } from "src/pluginUtils";
|
||||||
|
import { hasPermission } from "knub/dist/helpers";
|
||||||
|
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";
|
||||||
|
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
|
||||||
|
import { kickMember } from "./kickMember";
|
||||||
|
import { ignoreEvent } from "./ignoreEvent";
|
||||||
|
import { isBanned } from "./isBanned";
|
||||||
|
|
||||||
|
export async function actualKickMemberCmd(
|
||||||
|
pluginData: PluginData<ModActionsPluginType>,
|
||||||
|
msg,
|
||||||
|
args: {
|
||||||
|
user: string;
|
||||||
|
reason: string;
|
||||||
|
mod: Member;
|
||||||
|
notify?: string;
|
||||||
|
"notify-channel"?: TextChannel;
|
||||||
|
clean?: boolean;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const user = await resolveUser(pluginData.client, args.user);
|
||||||
|
if (!user) return sendErrorMessage(pluginData, msg.channel, `User not found`);
|
||||||
|
|
||||||
|
const memberToKick = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
|
|
||||||
|
if (!memberToKick) {
|
||||||
|
const banned = await isBanned(pluginData, user.id);
|
||||||
|
if (banned) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `User is banned`);
|
||||||
|
} else {
|
||||||
|
sendErrorMessage(pluginData, msg.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");
|
||||||
|
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 (!hasPermission(pluginData.config.getForMessage(msg), "can_act_as_other")) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "No permission for -mod");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = args.mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
let contactMethods;
|
||||||
|
try {
|
||||||
|
contactMethods = readContactMethodsFromArgs(args);
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||||
|
|
||||||
|
const kickResult = await kickMember(pluginData, memberToKick, reason, {
|
||||||
|
contactMethods,
|
||||||
|
caseArgs: {
|
||||||
|
modId: mod.id,
|
||||||
|
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (args.clean) {
|
||||||
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, memberToKick.id);
|
||||||
|
ignoreEvent(pluginData, IgnoredEventType.Ban, memberToKick.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await memberToKick.ban(1);
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Failed to ban the user to clean messages (-clean)");
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, memberToKick.id);
|
||||||
|
ignoreEvent(pluginData, IgnoredEventType.Unban, memberToKick.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await pluginData.guild.unbanMember(memberToKick.id);
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "Failed to unban the user after banning them (-clean)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kickResult.status === "failed") {
|
||||||
|
msg.channel.createMessage(errorMessage(`Failed to kick user`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the action to the moderator
|
||||||
|
let response = `Kicked **${memberToKick.user.username}#${memberToKick.user.discriminator}** (Case #${kickResult.case.case_number})`;
|
||||||
|
|
||||||
|
if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
|
||||||
|
sendSuccessMessage(pluginData, msg.channel, response);
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { PluginData } from "knub";
|
||||||
|
import { ModActionsPluginType } from "../types";
|
||||||
|
import { User, Message, Member } from "eris";
|
||||||
|
import { UnknownUser, asSingleLine } from "src/utils";
|
||||||
|
import { sendErrorMessage, sendSuccessMessage, hasPermission } from "src/pluginUtils";
|
||||||
|
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
|
||||||
|
import { MutesPlugin } from "src/plugins/Mutes/MutesPlugin";
|
||||||
|
import humanizeDuration from "humanize-duration";
|
||||||
|
|
||||||
|
export async function actualUnmuteCmd(
|
||||||
|
pluginData: PluginData<ModActionsPluginType>,
|
||||||
|
user: User | UnknownUser,
|
||||||
|
msg: Message,
|
||||||
|
args: { time?: number; reason?: string; mod?: Member },
|
||||||
|
) {
|
||||||
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
|
let mod = msg.author;
|
||||||
|
let pp = null;
|
||||||
|
|
||||||
|
if (args.mod) {
|
||||||
|
if (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "No permission for -mod");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = args.mod.user;
|
||||||
|
pp = msg.author;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||||
|
|
||||||
|
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||||
|
const result = await mutesPlugin.unmuteUser(user.id, args.time, {
|
||||||
|
modId: mod.id,
|
||||||
|
ppId: pp && pp.id,
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm the action to the moderator
|
||||||
|
if (args.time) {
|
||||||
|
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
||||||
|
sendSuccessMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
asSingleLine(`
|
||||||
|
Unmuting **${user.username}#${user.discriminator}**
|
||||||
|
in ${timeUntilUnmute} (Case #${result.case.case_number})
|
||||||
|
`),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sendSuccessMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
asSingleLine(`
|
||||||
|
Unmuted **${user.username}#${user.discriminator}**
|
||||||
|
(Case #${result.case.case_number})
|
||||||
|
`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { PluginData } from "knub";
|
import { PluginData } from "knub";
|
||||||
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||||
|
|
||||||
export function clearIgnoredEvent(
|
export function clearIgnoredEvents(
|
||||||
pluginData: PluginData<ModActionsPluginType>,
|
pluginData: PluginData<ModActionsPluginType>,
|
||||||
type: IgnoredEventType,
|
type: IgnoredEventType,
|
||||||
userId: string,
|
userId: string,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { PluginData } from "knub";
|
import { PluginData } from "knub";
|
||||||
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||||
import { SECONDS } from "../../../utils";
|
import { SECONDS } from "../../../utils";
|
||||||
import { clearIgnoredEvent } from "./clearIgnoredEvents";
|
import { clearIgnoredEvents } from "./clearIgnoredEvents";
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT = 15 * SECONDS;
|
const DEFAULT_TIMEOUT = 15 * SECONDS;
|
||||||
|
|
||||||
|
@ -15,6 +15,6 @@ export function ignoreEvent(
|
||||||
|
|
||||||
// Clear after expiry (15sec by default)
|
// Clear after expiry (15sec by default)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
clearIgnoredEvent(pluginData, type, userId);
|
clearIgnoredEvents(pluginData, type, userId);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { BasePluginType, command } from "knub";
|
||||||
import { GuildMutes } from "../../data/GuildMutes";
|
import { GuildMutes } from "../../data/GuildMutes";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
|
||||||
import { Case } from "../../data/entities/Case";
|
import { Case } from "../../data/entities/Case";
|
||||||
import { CaseArgs } from "../Cases/types";
|
import { CaseArgs } from "../Cases/types";
|
||||||
import { TextChannel } from "eris";
|
import { TextChannel } from "eris";
|
||||||
|
|
|
@ -12,6 +12,9 @@ import { ClearActiveMuteOnRoleRemovalEvt } from "./events/ClearActiveMuteOnRoleR
|
||||||
import { ClearMutesWithoutRoleCmd } from "./commands/ClearMutesWithoutRoleCmd";
|
import { ClearMutesWithoutRoleCmd } from "./commands/ClearMutesWithoutRoleCmd";
|
||||||
import { ClearMutesCmd } from "./commands/ClearMutesCmd";
|
import { ClearMutesCmd } from "./commands/ClearMutesCmd";
|
||||||
import { muteUser } from "./functions/muteUser";
|
import { muteUser } from "./functions/muteUser";
|
||||||
|
import { unmuteUser } from "./functions/unmuteUser";
|
||||||
|
import { CaseArgs } from "../Cases/types";
|
||||||
|
import { Member } from "eris";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -75,6 +78,16 @@ export const MutesPlugin = zeppelinPlugin<MutesPluginType>()("mutes", {
|
||||||
return muteUser(pluginData, userId, muteTime, reason, muteOptions);
|
return muteUser(pluginData, userId, muteTime, reason, muteOptions);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
unmuteUser(pluginData) {
|
||||||
|
return (userId: string, unmuteTime: number = null, args: Partial<CaseArgs>) => {
|
||||||
|
return unmuteUser(pluginData, userId, unmuteTime, args);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
hasMutedRole(pluginData) {
|
||||||
|
return (member: Member) => {
|
||||||
|
return member.roles.includes(pluginData.config.get().mute_role);
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(pluginData) {
|
onLoad(pluginData) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { GuildConfigReloaderPlugin } from "./GuildConfigReloader/GuildConfigRelo
|
||||||
import { CasesPlugin } from "./Cases/CasesPlugin";
|
import { CasesPlugin } from "./Cases/CasesPlugin";
|
||||||
import { MutesPlugin } from "./Mutes/MutesPlugin";
|
import { MutesPlugin } from "./Mutes/MutesPlugin";
|
||||||
import { TagsPlugin } from "./Tags/TagsPlugin";
|
import { TagsPlugin } from "./Tags/TagsPlugin";
|
||||||
|
import { ModActionsPlugin } from "./ModActions/ModActionsPlugin";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
export const guildPlugins: Array<ZeppelinPluginBlueprint<any>> = [
|
export const guildPlugins: Array<ZeppelinPluginBlueprint<any>> = [
|
||||||
|
@ -21,6 +22,7 @@ export const guildPlugins: Array<ZeppelinPluginBlueprint<any>> = [
|
||||||
PersistPlugin,
|
PersistPlugin,
|
||||||
PingableRolesPlugin,
|
PingableRolesPlugin,
|
||||||
MessageSaverPlugin,
|
MessageSaverPlugin,
|
||||||
|
ModActionsPlugin,
|
||||||
NameHistoryPlugin,
|
NameHistoryPlugin,
|
||||||
RemindersPlugin,
|
RemindersPlugin,
|
||||||
TagsPlugin,
|
TagsPlugin,
|
||||||
|
|
Loading…
Add table
Reference in a new issue