mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-05-10 12:25:02 +00:00
Turn on strict TS compilation. Fix up and tweak types accordingly.
This commit is contained in:
parent
690955a399
commit
629002b8d9
172 changed files with 720 additions and 534 deletions
|
@ -4,6 +4,7 @@ import { tDelayString, MINUTES } from "../../utils";
|
|||
import { GuildLogs } from "../../data/GuildLogs";
|
||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||
import Timeout = NodeJS.Timeout;
|
||||
|
||||
export const MAX_DELAY = 5 * MINUTES;
|
||||
|
||||
|
@ -25,8 +26,8 @@ export interface AutoDeletePluginType extends BasePluginType {
|
|||
guildLogs: GuildLogs;
|
||||
|
||||
deletionQueue: IDeletionQueueItem[];
|
||||
nextDeletion: number;
|
||||
nextDeletionTimeout;
|
||||
nextDeletion: number | null;
|
||||
nextDeletionTimeout: Timeout | null;
|
||||
|
||||
maxDelayWarningSent: boolean;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ export async function onMessageCreate(pluginData: GuildPluginData<AutoDeletePlug
|
|||
const member = await resolveMember(pluginData.client, pluginData.guild, msg.user_id);
|
||||
const config = pluginData.config.getMatchingConfig({ member, channelId: msg.channel_id });
|
||||
if (config.enabled) {
|
||||
let delay = convertDelayStringToMS(config.delay);
|
||||
let delay = convertDelayStringToMS(config.delay)!;
|
||||
|
||||
if (delay > MAX_DELAY) {
|
||||
delay = MAX_DELAY;
|
||||
|
|
|
@ -4,11 +4,11 @@ import { deleteNextItem } from "./deleteNextItem";
|
|||
|
||||
export function scheduleNextDeletion(pluginData: GuildPluginData<AutoDeletePluginType>) {
|
||||
if (pluginData.state.deletionQueue.length === 0) {
|
||||
clearTimeout(pluginData.state.nextDeletionTimeout);
|
||||
clearTimeout(pluginData.state.nextDeletionTimeout!);
|
||||
return;
|
||||
}
|
||||
|
||||
const firstDeleteAt = pluginData.state.deletionQueue[0].deleteAt;
|
||||
clearTimeout(pluginData.state.nextDeletionTimeout);
|
||||
clearTimeout(pluginData.state.nextDeletionTimeout!);
|
||||
pluginData.state.nextDeletionTimeout = setTimeout(() => deleteNextItem(pluginData), firstDeleteAt - Date.now());
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ export const NewAutoReactionsCmd = autoReactionsCmd({
|
|||
},
|
||||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
const finalReactions = [];
|
||||
const finalReactions: string[] = [];
|
||||
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id);
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||
const missingPermissions = getMissingChannelPermissions(me, args.channel as GuildChannel, requiredPermissions);
|
||||
if (missingPermissions) {
|
||||
sendErrorMessage(
|
||||
|
|
|
@ -19,7 +19,7 @@ export const AddReactionsEvt = autoReactionsEvt({
|
|||
const autoReaction = await pluginData.state.autoReactions.getForChannel(message.channel.id);
|
||||
if (!autoReaction) return;
|
||||
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id);
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||
const missingPermissions = getMissingChannelPermissions(
|
||||
me,
|
||||
message.channel as GuildChannel,
|
||||
|
|
|
@ -158,7 +158,7 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod",
|
|||
configPreprocessor,
|
||||
|
||||
customOverrideMatcher(pluginData, criteria, matchParams) {
|
||||
return criteria?.antiraid_level && criteria.antiraid_level === pluginData.state.cachedAntiraidLevel;
|
||||
return criteria?.antiraid_level ? criteria.antiraid_level === pluginData.state.cachedAntiraidLevel : false;
|
||||
},
|
||||
|
||||
events: [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { unique } from "../../../utils";
|
||||
import { nonNullish, unique } from "../../../utils";
|
||||
import { Constants } from "eris";
|
||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
|
@ -17,8 +17,8 @@ export const AddRolesAction = automodAction({
|
|||
defaultConfig: [],
|
||||
|
||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||
const members = unique(contexts.map(c => c.member).filter(Boolean));
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id);
|
||||
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||
|
||||
const missingPermissions = getMissingPermissions(me.permission, p.manageRoles);
|
||||
if (missingPermissions) {
|
||||
|
@ -29,8 +29,8 @@ export const AddRolesAction = automodAction({
|
|||
return;
|
||||
}
|
||||
|
||||
const rolesToAssign = [];
|
||||
const rolesWeCannotAssign = [];
|
||||
const rolesToAssign: string[] = [];
|
||||
const rolesWeCannotAssign: string[] = [];
|
||||
for (const roleId of actionConfig) {
|
||||
if (canAssignRole(pluginData.guild, me, roleId)) {
|
||||
rolesToAssign.push(roleId);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
|
||||
|
@ -20,14 +20,14 @@ export const BanAction = automodAction({
|
|||
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
||||
const reason = actionConfig.reason || "Kicked automatically";
|
||||
const contactMethods = resolveActionContactMethods(pluginData, actionConfig);
|
||||
const deleteMessageDays = actionConfig.deleteMessageDays;
|
||||
const deleteMessageDays = actionConfig.deleteMessageDays || undefined;
|
||||
|
||||
const caseArgs = {
|
||||
modId: pluginData.client.user.id,
|
||||
extraNotes: [matchResult.fullSummary],
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
};
|
||||
|
||||
const userIdsToBan = unique(contexts.map(c => c.user?.id).filter(Boolean));
|
||||
const userIdsToBan = unique(contexts.map(c => c.user?.id).filter(nonNullish));
|
||||
|
||||
const modActions = pluginData.getPlugin(ModActionsPlugin);
|
||||
for (const userId of userIdsToBan) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as t from "io-ts";
|
|||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { unique } from "../../../utils";
|
||||
import { nonNullish, unique } from "../../../utils";
|
||||
|
||||
export const ChangeNicknameAction = automodAction({
|
||||
configType: t.union([
|
||||
|
@ -15,7 +15,7 @@ export const ChangeNicknameAction = automodAction({
|
|||
defaultConfig: {},
|
||||
|
||||
async apply({ pluginData, contexts, actionConfig }) {
|
||||
const members = unique(contexts.map(c => c.member).filter(Boolean));
|
||||
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
||||
|
||||
for (const member of members) {
|
||||
if (pluginData.state.recentNicknameChanges.has(member.id)) continue;
|
||||
|
|
|
@ -15,12 +15,12 @@ export const CleanAction = automodAction({
|
|||
messageIdsToDeleteByChannelId.set(context.message.channel_id, []);
|
||||
}
|
||||
|
||||
if (messageIdsToDeleteByChannelId.get(context.message.channel_id).includes(context.message.id)) {
|
||||
if (messageIdsToDeleteByChannelId.get(context.message.channel_id)!.includes(context.message.id)) {
|
||||
console.warn(`Message ID to delete was already present: ${pluginData.guild.name}, rule ${ruleName}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
messageIdsToDeleteByChannelId.get(context.message.channel_id).push(context.message.id);
|
||||
messageIdsToDeleteByChannelId.get(context.message.channel_id)!.push(context.message.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
|
||||
|
@ -22,14 +22,15 @@ export const KickAction = automodAction({
|
|||
|
||||
const caseArgs = {
|
||||
modId: pluginData.client.user.id,
|
||||
extraNotes: [matchResult.fullSummary],
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
};
|
||||
|
||||
const userIdsToKick = unique(contexts.map(c => c.user?.id).filter(Boolean));
|
||||
const userIdsToKick = unique(contexts.map(c => c.user?.id).filter(nonNullish));
|
||||
const membersToKick = await asyncMap(userIdsToKick, id => resolveMember(pluginData.client, pluginData.guild, id));
|
||||
|
||||
const modActions = pluginData.getPlugin(ModActionsPlugin);
|
||||
for (const member of membersToKick) {
|
||||
if (!member) continue;
|
||||
await modActions.kickMember(member, reason, { contactMethods, caseArgs });
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, convertDelayStringToMS, resolveMember, tDelayString, tNullable, unique } from "../../../utils";
|
||||
import {
|
||||
asyncMap,
|
||||
convertDelayStringToMS,
|
||||
nonNullish,
|
||||
resolveMember,
|
||||
tDelayString,
|
||||
tNullable,
|
||||
unique,
|
||||
} from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
||||
|
@ -21,16 +29,16 @@ export const MuteAction = automodAction({
|
|||
},
|
||||
|
||||
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
||||
const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration) : null;
|
||||
const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined;
|
||||
const reason = actionConfig.reason || "Muted automatically";
|
||||
const contactMethods = resolveActionContactMethods(pluginData, actionConfig);
|
||||
|
||||
const caseArgs = {
|
||||
modId: pluginData.client.user.id,
|
||||
extraNotes: [matchResult.fullSummary],
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
};
|
||||
|
||||
const userIdsToMute = unique(contexts.map(c => c.user?.id).filter(Boolean));
|
||||
const userIdsToMute = unique(contexts.map(c => c.user?.id).filter(nonNullish));
|
||||
|
||||
const mutes = pluginData.getPlugin(MutesPlugin);
|
||||
for (const userId of userIdsToMute) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||
|
@ -19,8 +19,8 @@ export const RemoveRolesAction = automodAction({
|
|||
defaultConfig: [],
|
||||
|
||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||
const members = unique(contexts.map(c => c.member).filter(Boolean));
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id);
|
||||
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||
|
||||
const missingPermissions = getMissingPermissions(me.permission, p.manageRoles);
|
||||
if (missingPermissions) {
|
||||
|
@ -31,8 +31,8 @@ export const RemoveRolesAction = automodAction({
|
|||
return;
|
||||
}
|
||||
|
||||
const rolesToRemove = [];
|
||||
const rolesWeCannotRemove = [];
|
||||
const rolesToRemove: string[] = [];
|
||||
const rolesWeCannotRemove: string[] = [];
|
||||
for (const roleId of actionConfig) {
|
||||
if (canAssignRole(pluginData.guild, me, roleId)) {
|
||||
rolesToRemove.push(roleId);
|
||||
|
|
|
@ -28,14 +28,14 @@ export const ReplyAction = automodAction({
|
|||
async apply({ pluginData, contexts, actionConfig }) {
|
||||
const contextsWithTextChannels = contexts
|
||||
.filter(c => c.message?.channel_id)
|
||||
.filter(c => pluginData.guild.channels.get(c.message.channel_id) instanceof TextChannel);
|
||||
.filter(c => pluginData.guild.channels.get(c.message!.channel_id) instanceof TextChannel);
|
||||
|
||||
const contextsByChannelId = contextsWithTextChannels.reduce((map: Map<string, AutomodContext[]>, context) => {
|
||||
if (!map.has(context.message.channel_id)) {
|
||||
map.set(context.message.channel_id, []);
|
||||
if (!map.has(context.message!.channel_id)) {
|
||||
map.set(context.message!.channel_id, []);
|
||||
}
|
||||
|
||||
map.get(context.message.channel_id).push(context);
|
||||
map.get(context.message!.channel_id)!.push(context);
|
||||
return map;
|
||||
}, new Map());
|
||||
|
||||
|
@ -57,7 +57,7 @@ export const ReplyAction = automodAction({
|
|||
const replyMsg = await channel.createMessage(formatted);
|
||||
|
||||
if (typeof actionConfig === "object" && actionConfig.auto_delete) {
|
||||
const delay = convertDelayStringToMS(String(actionConfig.auto_delete));
|
||||
const delay = convertDelayStringToMS(String(actionConfig.auto_delete))!;
|
||||
setTimeout(() => replyMsg.delete().catch(noop), delay);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
|||
|
||||
export const SetAntiraidLevelAction = automodAction({
|
||||
configType: t.string,
|
||||
defaultConfig: null,
|
||||
defaultConfig: "",
|
||||
|
||||
async apply({ pluginData, contexts, actionConfig }) {
|
||||
setAntiraidLevel(pluginData, actionConfig);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
|
||||
|
@ -22,14 +22,15 @@ export const WarnAction = automodAction({
|
|||
|
||||
const caseArgs = {
|
||||
modId: pluginData.client.user.id,
|
||||
extraNotes: [matchResult.fullSummary],
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
};
|
||||
|
||||
const userIdsToWarn = unique(contexts.map(c => c.user?.id).filter(Boolean));
|
||||
const userIdsToWarn = unique(contexts.map(c => c.user?.id).filter(nonNullish));
|
||||
const membersToWarn = await asyncMap(userIdsToWarn, id => resolveMember(pluginData.client, pluginData.guild, id));
|
||||
|
||||
const modActions = pluginData.getPlugin(ModActionsPlugin);
|
||||
for (const member of membersToWarn) {
|
||||
if (!member) continue;
|
||||
await modActions.warnMember(member, reason, { contactMethods, caseArgs });
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4,8 +4,9 @@ import { RECENT_ACTION_EXPIRY_TIME, RecentActionType } from "../constants";
|
|||
import { getEmojiInString, getRoleMentions, getUrlsInString, getUserMentions } from "../../../utils";
|
||||
|
||||
export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodPluginType>, context: AutomodContext) {
|
||||
const globalIdentifier = context.message.user_id;
|
||||
const perChannelIdentifier = `${context.message.channel_id}-${context.message.user_id}`;
|
||||
const message = context.message!;
|
||||
const globalIdentifier = message.user_id;
|
||||
const perChannelIdentifier = `${message.channel_id}-${message.user_id}`;
|
||||
const expiresAt = Date.now() + RECENT_ACTION_EXPIRY_TIME;
|
||||
|
||||
pluginData.state.recentActions.push({
|
||||
|
@ -23,8 +24,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
});
|
||||
|
||||
const mentionCount =
|
||||
getUserMentions(context.message.data.content || "").length +
|
||||
getRoleMentions(context.message.data.content || "").length;
|
||||
getUserMentions(message.data.content || "").length + getRoleMentions(message.data.content || "").length;
|
||||
if (mentionCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
@ -41,7 +41,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
});
|
||||
}
|
||||
|
||||
const linkCount = getUrlsInString(context.message.data.content || "").length;
|
||||
const linkCount = getUrlsInString(message.data.content || "").length;
|
||||
if (linkCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
@ -58,7 +58,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
});
|
||||
}
|
||||
|
||||
const attachmentCount = context.message.data.attachments && context.message.data.attachments.length;
|
||||
const attachmentCount = message.data.attachments && message.data.attachments.length;
|
||||
if (attachmentCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
@ -75,7 +75,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
});
|
||||
}
|
||||
|
||||
const emojiCount = getEmojiInString(context.message.data.content || "").length;
|
||||
const emojiCount = getEmojiInString(message.data.content || "").length;
|
||||
if (emojiCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
@ -93,7 +93,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
}
|
||||
|
||||
// + 1 is for the first line of the message (which doesn't have a line break)
|
||||
const lineCount = context.message.data.content ? (context.message.data.content.match(/\n/g) || []).length + 1 : 0;
|
||||
const lineCount = message.data.content ? (message.data.content.match(/\n/g) || []).length + 1 : 0;
|
||||
if (lineCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
@ -110,7 +110,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
});
|
||||
}
|
||||
|
||||
const characterCount = [...(context.message.data.content || "")].length;
|
||||
const characterCount = [...(message.data.content || "")].length;
|
||||
if (characterCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
@ -127,7 +127,7 @@ export function addRecentActionsFromMessage(pluginData: GuildPluginData<AutomodP
|
|||
});
|
||||
}
|
||||
|
||||
const stickerCount = (context.message.data.stickers || []).length;
|
||||
const stickerCount = (message.data.stickers || []).length;
|
||||
if (stickerCount) {
|
||||
pluginData.state.recentActions.push({
|
||||
context,
|
||||
|
|
|
@ -4,8 +4,9 @@ import { RECENT_ACTION_EXPIRY_TIME, RecentActionType } from "../constants";
|
|||
import { getEmojiInString, getRoleMentions, getUrlsInString, getUserMentions } from "../../../utils";
|
||||
|
||||
export function clearRecentActionsForMessage(pluginData: GuildPluginData<AutomodPluginType>, context: AutomodContext) {
|
||||
const globalIdentifier = context.message.user_id;
|
||||
const perChannelIdentifier = `${context.message.channel_id}-${context.message.user_id}`;
|
||||
const message = context.message!;
|
||||
const globalIdentifier = message.user_id;
|
||||
const perChannelIdentifier = `${message.channel_id}-${message.user_id}`;
|
||||
|
||||
pluginData.state.recentActions = pluginData.state.recentActions.filter(act => {
|
||||
return act.identifier !== globalIdentifier && act.identifier !== perChannelIdentifier;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { findRecentSpam } from "./findRecentSpam";
|
|||
import { getMatchingMessageRecentActions } from "./getMatchingMessageRecentActions";
|
||||
import * as t from "io-ts";
|
||||
import { getMessageSpamIdentifier } from "./getSpamIdentifier";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||
|
||||
const MessageSpamTriggerConfig = t.type({
|
||||
amount: t.number,
|
||||
|
@ -29,22 +30,25 @@ export function createMessageSpamTrigger(spamType: RecentActionType, prettyName:
|
|||
return;
|
||||
}
|
||||
|
||||
const spamIdentifier = getMessageSpamIdentifier(context.message, triggerConfig.per_channel);
|
||||
const spamIdentifier = getMessageSpamIdentifier(context.message, Boolean(triggerConfig.per_channel));
|
||||
|
||||
const recentSpam = findRecentSpam(pluginData, spamType, spamIdentifier);
|
||||
if (recentSpam) {
|
||||
await pluginData.state.archives.addSavedMessagesToArchive(
|
||||
recentSpam.archiveId,
|
||||
[context.message],
|
||||
pluginData.guild,
|
||||
);
|
||||
if (recentSpam.archiveId) {
|
||||
await pluginData.state.archives.addSavedMessagesToArchive(
|
||||
recentSpam.archiveId,
|
||||
[context.message],
|
||||
pluginData.guild,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
silentClean: true,
|
||||
extra: { archiveId: "" }, // FIXME: Fix up automod trigger match() typings so extra is not required when doing a silentClean
|
||||
};
|
||||
}
|
||||
|
||||
const within = convertDelayStringToMS(triggerConfig.within);
|
||||
const within = convertDelayStringToMS(triggerConfig.within) ?? 0;
|
||||
const matchedSpam = getMatchingMessageRecentActions(
|
||||
pluginData,
|
||||
context.message,
|
||||
|
@ -58,7 +62,7 @@ export function createMessageSpamTrigger(spamType: RecentActionType, prettyName:
|
|||
const messages = matchedSpam.recentActions
|
||||
.map(action => action.context.message)
|
||||
.filter(Boolean)
|
||||
.sort(sorter("posted_at"));
|
||||
.sort(sorter("posted_at")) as SavedMessage[];
|
||||
|
||||
const archiveId = await pluginData.state.archives.createFromSavedMessages(messages, pluginData.guild);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ export function getMatchingRecentActions(
|
|||
action.type === type &&
|
||||
(!identifier || action.identifier === identifier) &&
|
||||
action.context.timestamp >= since &&
|
||||
action.context.timestamp <= to &&
|
||||
action.context.timestamp <= to! &&
|
||||
!action.context.actioned
|
||||
);
|
||||
});
|
||||
|
|
|
@ -10,23 +10,25 @@ export function getTextMatchPartialSummary(
|
|||
context: AutomodContext,
|
||||
) {
|
||||
if (type === "message") {
|
||||
const channel = pluginData.guild.channels.get(context.message.channel_id);
|
||||
const channelMention = channel ? verboseChannelMention(channel) : `\`#${context.message.channel_id}\``;
|
||||
const message = context.message!;
|
||||
const channel = pluginData.guild.channels.get(message.channel_id);
|
||||
const channelMention = channel ? verboseChannelMention(channel) : `\`#${message.channel_id}\``;
|
||||
|
||||
return `message in ${channelMention}:\n${messageSummary(context.message)}`;
|
||||
return `message in ${channelMention}:\n${messageSummary(message)}`;
|
||||
} else if (type === "embed") {
|
||||
const channel = pluginData.guild.channels.get(context.message.channel_id);
|
||||
const channelMention = channel ? verboseChannelMention(channel) : `\`#${context.message.channel_id}\``;
|
||||
const message = context.message!;
|
||||
const channel = pluginData.guild.channels.get(message.channel_id);
|
||||
const channelMention = channel ? verboseChannelMention(channel) : `\`#${message.channel_id}\``;
|
||||
|
||||
return `message embed in ${channelMention}:\n${messageSummary(context.message)}`;
|
||||
return `message embed in ${channelMention}:\n${messageSummary(message)}`;
|
||||
} else if (type === "username") {
|
||||
return `username: ${context.user.username}`;
|
||||
return `username: ${context.user!.username}`;
|
||||
} else if (type === "nickname") {
|
||||
return `nickname: ${context.member.nick}`;
|
||||
return `nickname: ${context.member!.nick}`;
|
||||
} else if (type === "visiblename") {
|
||||
const visibleName = context.member?.nick || context.user.username;
|
||||
const visibleName = context.member?.nick || context.user!.username;
|
||||
return `visible name: ${visibleName}`;
|
||||
} else if (type === "customstatus") {
|
||||
return `custom status: ${context.member.game.state}`;
|
||||
return `custom status: ${context.member!.game!.state}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ import { AutomodPluginType } from "../types";
|
|||
export function resolveActionContactMethods(
|
||||
pluginData: GuildPluginData<AutomodPluginType>,
|
||||
actionConfig: {
|
||||
notify?: string;
|
||||
notifyChannel?: string;
|
||||
notify?: string | null;
|
||||
notifyChannel?: string | null;
|
||||
},
|
||||
): UserNotificationMethod[] | null {
|
||||
): UserNotificationMethod[] {
|
||||
if (actionConfig.notify === "dm") {
|
||||
return [{ type: "dm" }];
|
||||
} else if (actionConfig.notify === "channel") {
|
||||
|
@ -28,5 +28,5 @@ export function resolveActionContactMethods(
|
|||
return [];
|
||||
}
|
||||
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -5,13 +5,14 @@ import { availableActions } from "../actions/availableActions";
|
|||
import { AutomodTriggerMatchResult } from "../helpers";
|
||||
import { CleanAction } from "../actions/clean";
|
||||
import { checkAndUpdateCooldown } from "./checkAndUpdateCooldown";
|
||||
import { TextChannel } from "eris";
|
||||
|
||||
export async function runAutomod(pluginData: GuildPluginData<AutomodPluginType>, context: AutomodContext) {
|
||||
const userId = context.user?.id || context.member?.id || context.message?.user_id;
|
||||
const user = context.user || (userId && pluginData.client.users.get(userId));
|
||||
const member = context.member || (userId && pluginData.guild.members.get(userId));
|
||||
const member = context.member || (userId && pluginData.guild.members.get(userId)) || null;
|
||||
const channelId = context.message?.channel_id;
|
||||
const channel = channelId && pluginData.guild.channels.get(channelId);
|
||||
const channel = channelId ? (pluginData.guild.channels.get(channelId) as TextChannel) : null;
|
||||
const categoryId = channel?.parentID;
|
||||
|
||||
const config = pluginData.config.getMatchingConfig({
|
||||
|
@ -29,8 +30,8 @@ export async function runAutomod(pluginData: GuildPluginData<AutomodPluginType>,
|
|||
return;
|
||||
}
|
||||
|
||||
let matchResult: AutomodTriggerMatchResult<any>;
|
||||
let contexts: AutomodContext[];
|
||||
let matchResult: AutomodTriggerMatchResult<any> | null | undefined;
|
||||
let contexts: AutomodContext[] = [];
|
||||
|
||||
triggerLoop: for (const triggerItem of rule.triggers) {
|
||||
for (const [triggerName, triggerConfig] of Object.entries(triggerItem)) {
|
||||
|
|
|
@ -3,9 +3,8 @@ import { Awaitable } from "knub/dist/utils";
|
|||
import * as t from "io-ts";
|
||||
import { AutomodContext, AutomodPluginType } from "./types";
|
||||
|
||||
export interface AutomodTriggerMatchResult<TExtra extends any = unknown> {
|
||||
interface BaseAutomodTriggerMatchResult {
|
||||
extraContexts?: AutomodContext[];
|
||||
extra?: TExtra;
|
||||
|
||||
silentClean?: boolean; // TODO: Maybe generalize to a "silent" value in general, which mutes alert/log
|
||||
|
||||
|
@ -13,12 +12,16 @@ export interface AutomodTriggerMatchResult<TExtra extends any = unknown> {
|
|||
fullSummary?: string;
|
||||
}
|
||||
|
||||
export type AutomodTriggerMatchResult<TExtra extends any = unknown> = unknown extends TExtra
|
||||
? BaseAutomodTriggerMatchResult
|
||||
: BaseAutomodTriggerMatchResult & { extra: TExtra };
|
||||
|
||||
type AutomodTriggerMatchFn<TConfigType, TMatchResultExtra> = (meta: {
|
||||
ruleName: string;
|
||||
pluginData: GuildPluginData<AutomodPluginType>;
|
||||
context: AutomodContext;
|
||||
triggerConfig: TConfigType;
|
||||
}) => Awaitable<null | AutomodTriggerMatchResult<TMatchResultExtra>>;
|
||||
}) => Awaitable<null | undefined | AutomodTriggerMatchResult<TMatchResultExtra>>;
|
||||
|
||||
type AutomodTriggerRenderMatchInformationFn<TConfigType, TMatchResultExtra> = (meta: {
|
||||
ruleName: string;
|
||||
|
|
|
@ -73,15 +73,15 @@ export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
|
|||
},
|
||||
|
||||
renderMatchInformation({ pluginData, contexts, matchResult }) {
|
||||
const channel = pluginData.guild.channels.get(contexts[0].message.channel_id);
|
||||
const channel = pluginData.guild.channels.get(contexts[0].message!.channel_id)!;
|
||||
const prettyChannel = verboseChannelMention(channel);
|
||||
|
||||
return (
|
||||
asSingleLine(`
|
||||
Matched attachment type \`${disableInlineCode(matchResult.extra.matchedType)}\`
|
||||
(${matchResult.extra.mode === "blacklist" ? "(blacklisted)" : "(not in whitelist)"})
|
||||
in message (\`${contexts[0].message.id}\`) in ${prettyChannel}:
|
||||
`) + messageSummary(contexts[0].message)
|
||||
in message (\`${contexts[0].message!.id}\`) in ${prettyChannel}:
|
||||
`) + messageSummary(contexts[0].message!)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import * as t from "io-ts";
|
||||
import { GuildInvite } from "eris";
|
||||
import { automodTrigger } from "../helpers";
|
||||
import {
|
||||
disableCodeBlocks,
|
||||
disableInlineCode,
|
||||
getInviteCodesInString,
|
||||
GuildInvite,
|
||||
isGuildInvite,
|
||||
resolveInvite,
|
||||
tNullable,
|
||||
|
|
|
@ -19,7 +19,7 @@ export const MemberJoinTrigger = automodTrigger<unknown>()({
|
|||
}
|
||||
|
||||
if (triggerConfig.only_new) {
|
||||
const threshold = Date.now() - convertDelayStringToMS(triggerConfig.new_threshold);
|
||||
const threshold = Date.now() - convertDelayStringToMS(triggerConfig.new_threshold)!;
|
||||
return context.member.createdAt >= threshold ? {} : null;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,6 @@ export const MemberJoinTrigger = automodTrigger<unknown>()({
|
|||
},
|
||||
|
||||
renderMatchInformation({ pluginData, contexts, triggerConfig }) {
|
||||
return null;
|
||||
return "";
|
||||
},
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ export const MemberJoinSpamTrigger = automodTrigger<unknown>()({
|
|||
return {};
|
||||
}
|
||||
|
||||
const since = Date.now() - convertDelayStringToMS(triggerConfig.within);
|
||||
const since = Date.now() - convertDelayStringToMS(triggerConfig.within)!;
|
||||
const matchingActions = getMatchingRecentActions(pluginData, RecentActionType.MemberJoin, null, since);
|
||||
const totalCount = sumRecentActionCounts(matchingActions);
|
||||
|
||||
|
@ -46,6 +46,6 @@ export const MemberJoinSpamTrigger = automodTrigger<unknown>()({
|
|||
},
|
||||
|
||||
renderMatchInformation({ pluginData, contexts, triggerConfig }) {
|
||||
return null;
|
||||
return "";
|
||||
},
|
||||
});
|
||||
|
|
|
@ -9,16 +9,16 @@ interface RoleAddedMatchResult {
|
|||
export const RoleAddedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
||||
configType: t.union([t.string, t.array(t.string)]),
|
||||
|
||||
defaultConfig: null,
|
||||
defaultConfig: [],
|
||||
|
||||
async match({ triggerConfig, context, pluginData }) {
|
||||
if (!context.member || !context.rolesChanged || context.rolesChanged.added.length === 0) {
|
||||
if (!context.member || !context.rolesChanged || context.rolesChanged.added!.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const triggerRoles = Array.isArray(triggerConfig) ? triggerConfig : [triggerConfig];
|
||||
for (const roleId of triggerRoles) {
|
||||
if (context.rolesChanged.added.includes(roleId)) {
|
||||
if (context.rolesChanged.added!.includes(roleId)) {
|
||||
if (consumeIgnoredRoleChange(pluginData, context.member.id, roleId)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ interface RoleAddedMatchResult {
|
|||
export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
||||
configType: t.union([t.string, t.array(t.string)]),
|
||||
|
||||
defaultConfig: null,
|
||||
defaultConfig: [],
|
||||
|
||||
async match({ triggerConfig, context, pluginData }) {
|
||||
if (!context.member || !context.rolesChanged || context.rolesChanged.removed.length === 0) {
|
||||
if (!context.member || !context.rolesChanged || context.rolesChanged.removed!.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
|||
continue;
|
||||
}
|
||||
|
||||
if (context.rolesChanged.removed.includes(roleId)) {
|
||||
if (context.rolesChanged.removed!.includes(roleId)) {
|
||||
return {
|
||||
extra: {
|
||||
matchedRoleId: roleId,
|
||||
|
|
|
@ -105,13 +105,13 @@ export interface AutomodContext {
|
|||
|
||||
export interface RecentAction {
|
||||
type: RecentActionType;
|
||||
identifier: string;
|
||||
identifier: string | null;
|
||||
count: number;
|
||||
context: AutomodContext;
|
||||
}
|
||||
|
||||
export interface RecentSpam {
|
||||
archiveId: string;
|
||||
archiveId: string | null;
|
||||
type: RecentActionType;
|
||||
identifiers: string[];
|
||||
timestamp: number;
|
||||
|
|
|
@ -45,8 +45,9 @@ export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()("bo
|
|||
pluginData.state.configs = new Configs();
|
||||
pluginData.state.apiPermissionAssignments = new ApiPermissionAssignments();
|
||||
|
||||
if (getActiveReload()) {
|
||||
const [guildId, channelId] = getActiveReload();
|
||||
const activeReload = getActiveReload();
|
||||
if (activeReload) {
|
||||
const [guildId, channelId] = activeReload;
|
||||
resetActiveReload();
|
||||
|
||||
const guild = pluginData.client.guilds.get(guildId);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let activeReload: [string, string] = null;
|
||||
let activeReload: [string, string] | null = null;
|
||||
|
||||
export function getActiveReload() {
|
||||
return activeReload;
|
||||
|
|
|
@ -19,7 +19,7 @@ export const LeaveServerCmd = botControlCmd({
|
|||
return;
|
||||
}
|
||||
|
||||
const guildToLeave = pluginData.client.guilds.get(args.guildId);
|
||||
const guildToLeave = pluginData.client.guilds.get(args.guildId)!;
|
||||
const guildName = guildToLeave.name;
|
||||
|
||||
try {
|
||||
|
|
|
@ -21,7 +21,7 @@ export const ServersCmd = botControlCmd({
|
|||
|
||||
async run({ pluginData, message: msg, args }) {
|
||||
const showList = Boolean(args.all || args.initialized || args.uninitialized || args.search);
|
||||
const search = args.search && new RegExp([...args.search].map(s => escapeStringRegexp(s)).join(".*"), "i");
|
||||
const search = args.search ? new RegExp([...args.search].map(s => escapeStringRegexp(s)).join(".*"), "i") : null;
|
||||
|
||||
const joinedGuilds = Array.from(pluginData.client.guilds.values());
|
||||
const loadedGuilds = pluginData.getKnubInstance().getLoadedGuilds();
|
||||
|
@ -39,7 +39,7 @@ export const ServersCmd = botControlCmd({
|
|||
}
|
||||
|
||||
if (args.search) {
|
||||
filteredGuilds = filteredGuilds.filter(g => search.test(`${g.id} ${g.name}`));
|
||||
filteredGuilds = filteredGuilds.filter(g => search!.test(`${g.id} ${g.name}`));
|
||||
}
|
||||
|
||||
if (filteredGuilds.length) {
|
||||
|
|
|
@ -12,7 +12,7 @@ export async function createCase(pluginData: GuildPluginData<CasesPluginType>, a
|
|||
const mod = await resolveUser(pluginData.client, args.modId);
|
||||
const modName = `${mod.username}#${mod.discriminator}`;
|
||||
|
||||
let ppName = null;
|
||||
let ppName: string | null = null;
|
||||
if (args.ppId) {
|
||||
const pp = await resolveUser(pluginData.client, args.ppId);
|
||||
ppName = `${pp.username}#${pp.discriminator}`;
|
||||
|
|
|
@ -15,7 +15,9 @@ export async function getCaseEmbed(
|
|||
requestMemberId?: string,
|
||||
): Promise<AdvancedMessageContent> {
|
||||
const theCase = await pluginData.state.cases.with("notes").find(resolveCaseId(caseOrCaseId));
|
||||
if (!theCase) return null;
|
||||
if (!theCase) {
|
||||
throw new Error("Unknown case");
|
||||
}
|
||||
|
||||
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
|
||||
|
||||
|
|
|
@ -28,12 +28,13 @@ export async function getCaseSummary(
|
|||
caseOrCaseId: Case | number,
|
||||
withLinks = false,
|
||||
requestMemberId?: string,
|
||||
) {
|
||||
): Promise<string | null> {
|
||||
const config = pluginData.config.get();
|
||||
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
|
||||
|
||||
const caseId = caseOrCaseId instanceof Case ? caseOrCaseId.id : caseOrCaseId;
|
||||
const theCase = await pluginData.state.cases.with("notes").find(caseId);
|
||||
if (!theCase) return null;
|
||||
|
||||
const firstNote = theCase.notes[0];
|
||||
let reason = firstNote ? firstNote.body : "";
|
||||
|
@ -47,7 +48,7 @@ export async function getCaseSummary(
|
|||
|
||||
if (reason.length > CASE_SUMMARY_REASON_MAX_LENGTH) {
|
||||
const match = reason.slice(CASE_SUMMARY_REASON_MAX_LENGTH, 100).match(/(?:[.,!?\s]|$)/);
|
||||
const nextWhitespaceIndex = match ? CASE_SUMMARY_REASON_MAX_LENGTH + match.index : CASE_SUMMARY_REASON_MAX_LENGTH;
|
||||
const nextWhitespaceIndex = match ? CASE_SUMMARY_REASON_MAX_LENGTH + match.index! : CASE_SUMMARY_REASON_MAX_LENGTH;
|
||||
if (nextWhitespaceIndex < reason.length) {
|
||||
reason = reason.slice(0, nextWhitespaceIndex - 1) + "...";
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ export async function getCaseSummary(
|
|||
reason = disableLinkPreviews(reason);
|
||||
|
||||
const timestamp = moment.utc(theCase.created_at, DBDateFormat);
|
||||
const relativeTimeCutoff = convertDelayStringToMS(config.relative_time_cutoff);
|
||||
const relativeTimeCutoff = convertDelayStringToMS(config.relative_time_cutoff)!;
|
||||
const useRelativeTime = config.show_relative_times && Date.now() - timestamp.valueOf() < relativeTimeCutoff;
|
||||
const timestampWithTz = requestMemberId
|
||||
? await timeAndDate.inMemberTz(requestMemberId, timestamp)
|
||||
|
|
|
@ -11,13 +11,13 @@ import { logger } from "../../../logger";
|
|||
export async function postToCaseLogChannel(
|
||||
pluginData: GuildPluginData<CasesPluginType>,
|
||||
content: MessageContent,
|
||||
file: MessageFile = null,
|
||||
file?: MessageFile,
|
||||
): Promise<Message | null> {
|
||||
const caseLogChannelId = pluginData.config.get().case_log_channel;
|
||||
if (!caseLogChannelId) return;
|
||||
if (!caseLogChannelId) return null;
|
||||
|
||||
const caseLogChannel = pluginData.guild.channels.get(caseLogChannelId);
|
||||
if (!caseLogChannel || !(caseLogChannel instanceof TextChannel)) return;
|
||||
if (!caseLogChannel || !(caseLogChannel instanceof TextChannel)) return null;
|
||||
|
||||
let result;
|
||||
try {
|
||||
|
@ -30,7 +30,7 @@ export async function postToCaseLogChannel(
|
|||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Missing permissions to post mod cases in <#${caseLogChannel.id}>`,
|
||||
});
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
throw e;
|
||||
|
@ -44,17 +44,17 @@ export async function postCaseToCaseLogChannel(
|
|||
caseOrCaseId: Case | number,
|
||||
): Promise<Message | null> {
|
||||
const theCase = await pluginData.state.cases.find(resolveCaseId(caseOrCaseId));
|
||||
if (!theCase) return;
|
||||
if (!theCase) return null;
|
||||
|
||||
const caseEmbed = await getCaseEmbed(pluginData, caseOrCaseId);
|
||||
if (!caseEmbed) return;
|
||||
if (!caseEmbed) return null;
|
||||
|
||||
if (theCase.log_message_id) {
|
||||
const [channelId, messageId] = theCase.log_message_id.split("-");
|
||||
|
||||
try {
|
||||
await pluginData.client.editMessage(channelId, messageId, caseEmbed);
|
||||
return;
|
||||
return null;
|
||||
} catch (e) {} // tslint:disable-line:no-empty
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
import { GuildPluginData } from "knub";
|
||||
import { CensorPluginType } from "../types";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||
import { AnyInvite, Embed, GuildInvite } from "eris";
|
||||
import { Embed, Invite } from "eris";
|
||||
import { ZalgoRegex } from "../../../data/Zalgo";
|
||||
import {
|
||||
getInviteCodesInString,
|
||||
getUrlsInString,
|
||||
resolveMember,
|
||||
resolveInvite,
|
||||
isGuildInvite,
|
||||
isRESTGuildInvite,
|
||||
} from "../../../utils";
|
||||
import { getInviteCodesInString, getUrlsInString, resolveMember, resolveInvite, isGuildInvite } from "../../../utils";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { censorMessage } from "./censorMessage";
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
|
@ -59,7 +52,7 @@ export async function applyFiltersToMsg(
|
|||
|
||||
const inviteCodes = getInviteCodesInString(messageContent);
|
||||
|
||||
const invites: Array<AnyInvite | null> = await Promise.all(
|
||||
const invites: Array<Invite | null> = await Promise.all(
|
||||
inviteCodes.map(code => resolveInvite(pluginData.client, code)),
|
||||
);
|
||||
|
||||
|
@ -75,7 +68,7 @@ export async function applyFiltersToMsg(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (isRESTGuildInvite(invite)) {
|
||||
if (isGuildInvite(invite)) {
|
||||
if (inviteGuildWhitelist && !inviteGuildWhitelist.includes(invite.guild.id)) {
|
||||
censorMessage(
|
||||
pluginData,
|
||||
|
|
|
@ -46,9 +46,9 @@ export const ArchiveChannelCmd = channelArchiverCmd({
|
|||
const maxMessagesToArchive = args.messages ? Math.min(args.messages, MAX_ARCHIVED_MESSAGES) : MAX_ARCHIVED_MESSAGES;
|
||||
if (maxMessagesToArchive <= 0) return;
|
||||
|
||||
const archiveLines = [];
|
||||
const archiveLines: string[] = [];
|
||||
let archivedMessages = 0;
|
||||
let previousId;
|
||||
let previousId: string | undefined;
|
||||
|
||||
const startTime = Date.now();
|
||||
const progressMsg = await msg.channel.createMessage("Creating archive...");
|
||||
|
@ -80,7 +80,7 @@ export const ArchiveChannelCmd = channelArchiverCmd({
|
|||
}
|
||||
|
||||
if (message.reactions && Object.keys(message.reactions).length > 0) {
|
||||
const reactionCounts = [];
|
||||
const reactionCounts: string[] = [];
|
||||
for (const [emoji, info] of Object.entries(message.reactions)) {
|
||||
reactionCounts.push(`${info.count}x ${emoji}`);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ export function getCompanionChannelOptsForVoiceChannelId(
|
|||
return Object.values(config.entries)
|
||||
.filter(
|
||||
opts =>
|
||||
opts.voice_channel_ids.includes(voiceChannel.id) || opts.voice_channel_ids.includes(voiceChannel.parentID),
|
||||
opts.voice_channel_ids.includes(voiceChannel.id) ||
|
||||
(voiceChannel.parentID && opts.voice_channel_ids.includes(voiceChannel.parentID)),
|
||||
)
|
||||
.map(opts => Object.assign({}, defaultCompanionChannelOpts, opts));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ export async function handleCompanionPermissions(
|
|||
export async function handleCompanionPermissions(
|
||||
pluginData: GuildPluginData<CompanionChannelsPluginType>,
|
||||
userId: string,
|
||||
voiceChannel?: VoiceChannel,
|
||||
voiceChannel: VoiceChannel | null,
|
||||
oldChannel?: VoiceChannel,
|
||||
) {
|
||||
if (pluginData.state.errorCooldownManager.isOnCooldown(ERROR_COOLDOWN_KEY)) {
|
||||
|
@ -65,7 +65,7 @@ export async function handleCompanionPermissions(
|
|||
for (const channelId of permsToDelete) {
|
||||
const channel = pluginData.guild.channels.get(channelId);
|
||||
if (!channel || !(channel instanceof TextChannel)) continue;
|
||||
await channel.deletePermission(userId, `Companion Channel for ${oldChannel.id} | User Left`);
|
||||
await channel.deletePermission(userId, `Companion Channel for ${oldChannel!.id} | User Left`);
|
||||
}
|
||||
|
||||
for (const [channelId, permissions] of permsToSet) {
|
||||
|
@ -76,7 +76,7 @@ export async function handleCompanionPermissions(
|
|||
permissions,
|
||||
0,
|
||||
"member",
|
||||
`Companion Channel for ${voiceChannel.id} | User Joined`,
|
||||
`Companion Channel for ${voiceChannel!.id} | User Joined`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -25,7 +25,7 @@ export async function addRoleAction(
|
|||
const target = await resolveMember(pluginData.client, pluginData.guild, targetId);
|
||||
if (!target) throw new ActionError(`Unknown target member: ${targetId}`);
|
||||
|
||||
if (event.trigger.type === "command" && !canActOn(pluginData, (eventData.msg as Message).member, target)) {
|
||||
if (event.trigger.type === "command" && !canActOn(pluginData, eventData.msg.member, target)) {
|
||||
throw new ActionError("Missing permissions");
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ export async function moveToVoiceChannelAction(
|
|||
const target = await resolveMember(pluginData.client, pluginData.guild, targetId);
|
||||
if (!target) throw new ActionError("Unknown target member");
|
||||
|
||||
if (event.trigger.type === "command" && !canActOn(pluginData, (eventData.msg as Message).member, target)) {
|
||||
if (event.trigger.type === "command" && !canActOn(pluginData, eventData.msg.member, target)) {
|
||||
throw new ActionError("Missing permissions");
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import { DeleteFollowCmd, ListFollowCmd } from "./commands/ListFollowCmd";
|
|||
import { ChannelJoinAlertsEvt, ChannelLeaveAlertsEvt, ChannelSwitchAlertsEvt } from "./events/SendAlertsEvts";
|
||||
import { GuildBanRemoveAlertsEvt } from "./events/BanRemoveAlertsEvt";
|
||||
import { trimPluginDescription } from "../../utils";
|
||||
import Timeout = NodeJS.Timeout;
|
||||
|
||||
const defaultOptions: PluginOptions<LocateUserPluginType> = {
|
||||
config: {
|
||||
|
@ -70,7 +71,7 @@ export const LocateUserPlugin = zeppelinGuildPlugin<LocateUserPluginType>()("loc
|
|||
},
|
||||
|
||||
onUnload(pluginData) {
|
||||
clearTimeout(pluginData.state.outdatedAlertsTimeout);
|
||||
clearTimeout(pluginData.state.outdatedAlertsTimeout as Timeout);
|
||||
pluginData.state.unloaded = true;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -14,7 +14,6 @@ export const WhereCmd = locateUserCmd({
|
|||
},
|
||||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, args.member.id);
|
||||
sendWhere(pluginData, member, msg.channel, `${msg.member.mention} | `);
|
||||
sendWhere(pluginData, args.member, msg.channel, `${msg.member.mention} | `);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ export interface LocateUserPluginType extends BasePluginType {
|
|||
config: TConfigSchema;
|
||||
state: {
|
||||
alerts: GuildVCAlerts;
|
||||
outdatedAlertsTimeout: Timeout;
|
||||
outdatedAlertsTimeout: Timeout | null;
|
||||
usersWithAlerts: string[];
|
||||
unloaded: boolean;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import { moveMember } from "./moveMember";
|
|||
export async function sendAlerts(pluginData: GuildPluginData<LocateUserPluginType>, userId: string) {
|
||||
const triggeredAlerts = await pluginData.state.alerts.getAlertsByUserId(userId);
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, userId);
|
||||
if (!member) return;
|
||||
|
||||
triggeredAlerts.forEach(alert => {
|
||||
const prepend = `<@!${alert.requestor_id}>, an alert requested by you has triggered!\nReminder: \`${alert.body}\`\n`;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Member, TextableChannel, VoiceChannel } from "eris";
|
||||
import { Invite, Member, TextableChannel, VoiceChannel } from "eris";
|
||||
import { getInviteLink } from "knub/dist/helpers";
|
||||
import { createOrReuseInvite } from "./createOrReuseInvite";
|
||||
import { GuildPluginData } from "knub";
|
||||
|
@ -11,12 +11,14 @@ export async function sendWhere(
|
|||
channel: TextableChannel,
|
||||
prepend: string,
|
||||
) {
|
||||
const voice = pluginData.guild.channels.get(member.voiceState.channelID) as VoiceChannel;
|
||||
const voice = member.voiceState.channelID
|
||||
? (pluginData.guild.channels.get(member.voiceState.channelID) as VoiceChannel)
|
||||
: null;
|
||||
|
||||
if (voice == null) {
|
||||
channel.createMessage(prepend + "That user is not in a channel");
|
||||
} else {
|
||||
let invite = null;
|
||||
let invite: Invite;
|
||||
try {
|
||||
invite = await createOrReuseInvite(voice);
|
||||
} catch (e) {
|
||||
|
|
|
@ -28,11 +28,11 @@ export const LogsGuildMemberAddEvt = logsEvt({
|
|||
cases.sort((a, b) => (a.created_at > b.created_at ? -1 : 1));
|
||||
|
||||
if (cases.length) {
|
||||
const recentCaseLines = [];
|
||||
const recentCaseLines: string[] = [];
|
||||
const recentCases = cases.slice(0, 2);
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
for (const theCase of recentCases) {
|
||||
recentCaseLines.push(await casesPlugin.getCaseSummary(theCase));
|
||||
recentCaseLines.push((await casesPlugin.getCaseSummary(theCase))!);
|
||||
}
|
||||
|
||||
let recentCaseSummary = recentCaseLines.join("\n");
|
||||
|
|
|
@ -14,16 +14,17 @@ import { renderTemplate, TemplateParseError } from "../../../templateFormatter";
|
|||
import { logger } from "../../../logger";
|
||||
import moment from "moment-timezone";
|
||||
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
||||
import { MessageContent } from "eris";
|
||||
|
||||
export async function getLogMessage(
|
||||
pluginData: GuildPluginData<LogsPluginType>,
|
||||
type: LogType,
|
||||
data: any,
|
||||
opts?: Pick<TLogChannel, "format" | "timestamp_format" | "include_embed_timestamp">,
|
||||
): Promise<string> {
|
||||
): Promise<MessageContent | null> {
|
||||
const config = pluginData.config.get();
|
||||
const format = opts?.format?.[LogType[type]] || config.format[LogType[type]] || "";
|
||||
if (format === "" || format == null) return;
|
||||
if (format === "" || format == null) return null;
|
||||
|
||||
// See comment on FORMAT_NO_TIMESTAMP in types.ts
|
||||
const timestampFormat =
|
||||
|
@ -45,7 +46,7 @@ export async function getLogMessage(
|
|||
|
||||
const usersOrMembers = Array.isArray(inputUserOrMember) ? inputUserOrMember : [inputUserOrMember];
|
||||
|
||||
const mentions = [];
|
||||
const mentions: string[] = [];
|
||||
for (const userOrMember of usersOrMembers) {
|
||||
let user;
|
||||
let member;
|
||||
|
@ -91,7 +92,7 @@ export async function getLogMessage(
|
|||
} catch (e) {
|
||||
if (e instanceof TemplateParseError) {
|
||||
logger.error(`Error when parsing template:\nError: ${e.message}\nTemplate: ${format}`);
|
||||
return;
|
||||
return null;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -109,13 +109,13 @@ export async function log(pluginData: GuildPluginData<LogsPluginType>, type: Log
|
|||
if (!pluginData.state.batches.has(channel.id)) {
|
||||
pluginData.state.batches.set(channel.id, []);
|
||||
setTimeout(async () => {
|
||||
const batchedMessage = pluginData.state.batches.get(channel.id).join("\n");
|
||||
const batchedMessage = pluginData.state.batches.get(channel.id)!.join("\n");
|
||||
pluginData.state.batches.delete(channel.id);
|
||||
createChunkedMessage(channel, batchedMessage).catch(noop);
|
||||
}, batchTime);
|
||||
}
|
||||
|
||||
pluginData.state.batches.get(channel.id).push(message);
|
||||
pluginData.state.batches.get(channel.id)!.push(message);
|
||||
} else {
|
||||
// If we're not batching log messages, just send them immediately
|
||||
await createChunkedMessage(channel, message).catch(noop);
|
||||
|
|
|
@ -7,7 +7,7 @@ export async function saveMessagesToDB(
|
|||
channel: TextChannel,
|
||||
ids: string[],
|
||||
) {
|
||||
const failed = [];
|
||||
const failed: string[] = [];
|
||||
for (const id of ids) {
|
||||
const savedMessage = await pluginData.state.savedMessages.find(id);
|
||||
if (savedMessage) continue;
|
||||
|
|
|
@ -65,7 +65,7 @@ export const AddCaseCmd = modActionsCmd({
|
|||
modId: mod.id,
|
||||
type: CaseTypes[type],
|
||||
reason,
|
||||
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||
ppId: mod.id !== msg.author.id ? msg.author.id : undefined,
|
||||
});
|
||||
|
||||
if (user) {
|
||||
|
|
|
@ -78,7 +78,7 @@ export const BanCmd = modActionsCmd({
|
|||
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,
|
||||
},
|
||||
deleteMessageDays,
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import { LogsPlugin } from "../../Logs/LogsPlugin";
|
|||
import { LogType } from "../../../data/LogType";
|
||||
import moment from "moment-timezone";
|
||||
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
||||
import { Case } from "../../../data/entities/Case";
|
||||
|
||||
export const DeleteCaseCmd = modActionsCmd({
|
||||
trigger: ["delete_case", "deletecase"],
|
||||
|
@ -25,8 +26,8 @@ export const DeleteCaseCmd = modActionsCmd({
|
|||
},
|
||||
|
||||
async run({ pluginData, message, args }) {
|
||||
const failed = [];
|
||||
const validCases = [];
|
||||
const failed: number[] = [];
|
||||
const validCases: Case[] = [];
|
||||
let cancelled = 0;
|
||||
|
||||
for (const num of args.caseNumber) {
|
||||
|
|
|
@ -77,7 +77,7 @@ export const ForcebanCmd = modActionsCmd({
|
|||
modId: mod.id,
|
||||
type: CaseTypes.Ban,
|
||||
reason,
|
||||
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||
ppId: mod.id !== msg.author.id ? msg.author.id : undefined,
|
||||
});
|
||||
|
||||
// Confirm the action
|
||||
|
|
|
@ -14,7 +14,7 @@ export const HideCaseCmd = modActionsCmd({
|
|||
],
|
||||
|
||||
async run({ pluginData, message: msg, args }) {
|
||||
const failed = [];
|
||||
const failed: number[] = [];
|
||||
|
||||
for (const num of args.caseNum) {
|
||||
const theCase = await pluginData.state.cases.findByCaseNumber(num);
|
||||
|
|
|
@ -62,7 +62,7 @@ export const MassbanCmd = modActionsCmd({
|
|||
const loadingMsg = await msg.channel.createMessage("Banning...");
|
||||
|
||||
// Ban each user and count failed bans (if any)
|
||||
const failedBans = [];
|
||||
const failedBans: string[] = [];
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
for (const userId of args.userIds) {
|
||||
try {
|
||||
|
|
|
@ -62,7 +62,7 @@ export const MassmuteCmd = modActionsCmd({
|
|||
|
||||
// Mute everyone and count fails
|
||||
const modId = msg.author.id;
|
||||
const failedMutes = [];
|
||||
const failedMutes: string[] = [];
|
||||
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||
for (const userId of args.userIds) {
|
||||
try {
|
||||
|
|
|
@ -59,7 +59,7 @@ export const UnbanCmd = modActionsCmd({
|
|||
modId: mod.id,
|
||||
type: CaseTypes.Unban,
|
||||
reason,
|
||||
ppId: mod.id !== msg.author.id ? msg.author.id : null,
|
||||
ppId: mod.id !== msg.author.id ? msg.author.id : undefined,
|
||||
});
|
||||
|
||||
// Confirm the action
|
||||
|
|
|
@ -14,7 +14,7 @@ export const UnhideCaseCmd = modActionsCmd({
|
|||
],
|
||||
|
||||
async run({ pluginData, message: msg, args }) {
|
||||
const failed = [];
|
||||
const failed: number[] = [];
|
||||
|
||||
for (const num of args.caseNum) {
|
||||
const theCase = await pluginData.state.cases.findByCaseNumber(num);
|
||||
|
|
|
@ -24,7 +24,7 @@ export const UpdateCmd = modActionsCmd({
|
|||
],
|
||||
|
||||
async run({ pluginData, message: msg, args }) {
|
||||
let theCase: Case;
|
||||
let theCase: Case | undefined;
|
||||
if (args.caseNumber != null) {
|
||||
theCase = await pluginData.state.cases.findByCaseNumber(args.caseNumber);
|
||||
} else {
|
||||
|
|
|
@ -91,7 +91,7 @@ export const WarnCmd = modActionsCmd({
|
|||
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,
|
||||
reason,
|
||||
},
|
||||
retryPromptChannel: msg.channel as TextChannel,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { IgnoredEventType, modActionsEvt } from "../types";
|
||||
import { isEventIgnored } from "../functions/isEventIgnored";
|
||||
import { clearIgnoredEvents } from "../functions/clearIgnoredEvents";
|
||||
import { Constants as ErisConstants } from "eris";
|
||||
import { Constants as ErisConstants, User } from "eris";
|
||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||
import { CaseTypes } from "../../../data/CaseTypes";
|
||||
import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { stripObjectToScalars, resolveUser } from "../../../utils";
|
||||
import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils";
|
||||
|
||||
/**
|
||||
* Create a BAN case automatically when a user is banned manually.
|
||||
|
@ -29,27 +29,27 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt(
|
|||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
|
||||
let createdCase;
|
||||
let mod = null;
|
||||
let mod: User | UnknownUser | null = null;
|
||||
let reason = "";
|
||||
|
||||
if (relevantAuditLogEntry) {
|
||||
const modId = relevantAuditLogEntry.user.id;
|
||||
const auditLogId = relevantAuditLogEntry.id;
|
||||
|
||||
mod = resolveUser(pluginData.client, modId);
|
||||
reason = relevantAuditLogEntry.reason;
|
||||
mod = await resolveUser(pluginData.client, modId);
|
||||
reason = relevantAuditLogEntry.reason || "";
|
||||
createdCase = await casesPlugin.createCase({
|
||||
userId: user.id,
|
||||
modId,
|
||||
type: CaseTypes.Ban,
|
||||
auditLogId,
|
||||
reason,
|
||||
reason: reason || undefined,
|
||||
automatic: true,
|
||||
});
|
||||
} else {
|
||||
createdCase = await casesPlugin.createCase({
|
||||
userId: user.id,
|
||||
modId: null,
|
||||
modId: "0",
|
||||
type: CaseTypes.Ban,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt(
|
|||
modId: kickAuditLogEntry.user.id,
|
||||
type: CaseTypes.Kick,
|
||||
auditLogId: kickAuditLogEntry.id,
|
||||
reason: kickAuditLogEntry.reason,
|
||||
reason: kickAuditLogEntry.reason || undefined,
|
||||
automatic: true,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { IgnoredEventType, modActionsEvt } from "../types";
|
||||
import { isEventIgnored } from "../functions/isEventIgnored";
|
||||
import { clearIgnoredEvents } from "../functions/clearIgnoredEvents";
|
||||
import { Constants as ErisConstants } from "eris";
|
||||
import { Constants as ErisConstants, User } from "eris";
|
||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||
import { CaseTypes } from "../../../data/CaseTypes";
|
||||
import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry";
|
||||
import { stripObjectToScalars, resolveUser } from "../../../utils";
|
||||
import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
|
||||
/**
|
||||
|
@ -29,13 +29,13 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt(
|
|||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
|
||||
let createdCase;
|
||||
let mod = null;
|
||||
let mod: User | UnknownUser | null = null;
|
||||
|
||||
if (relevantAuditLogEntry) {
|
||||
const modId = relevantAuditLogEntry.user.id;
|
||||
const auditLogId = relevantAuditLogEntry.id;
|
||||
|
||||
mod = resolveUser(pluginData.client, modId);
|
||||
mod = await resolveUser(pluginData.client, modId);
|
||||
createdCase = await casesPlugin.createCase({
|
||||
userId: user.id,
|
||||
modId,
|
||||
|
@ -46,7 +46,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt(
|
|||
} else {
|
||||
createdCase = await casesPlugin.createCase({
|
||||
userId: user.id,
|
||||
modId: null,
|
||||
modId: "0",
|
||||
type: CaseTypes.Unban,
|
||||
automatic: true,
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
|||
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";
|
||||
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
||||
import { logger } from "../../../logger";
|
||||
import { GuildMessage } from "knub/dist/helpers";
|
||||
|
||||
/**
|
||||
* The actual function run by both !mute and !forcemute.
|
||||
|
@ -18,12 +19,12 @@ import { logger } from "../../../logger";
|
|||
export async function actualMuteUserCmd(
|
||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||
user: User | UnknownUser,
|
||||
msg: Message,
|
||||
msg: GuildMessage,
|
||||
args: { time?: number; reason?: string; mod: Member; notify?: string; "notify-channel"?: TextChannel },
|
||||
) {
|
||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||
let mod = msg.member;
|
||||
let pp = null;
|
||||
let mod: Member = msg.member;
|
||||
let pp: User | null = null;
|
||||
|
||||
if (args.mod) {
|
||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
||||
|
@ -36,7 +37,7 @@ export async function actualMuteUserCmd(
|
|||
}
|
||||
|
||||
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||
const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments) : undefined;
|
||||
|
||||
let muteResult: MuteResult;
|
||||
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||
|
@ -54,7 +55,7 @@ export async function actualMuteUserCmd(
|
|||
contactMethods,
|
||||
caseArgs: {
|
||||
modId: mod.id,
|
||||
ppId: pp && pp.id,
|
||||
ppId: pp ? pp.id : undefined,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
|
@ -15,7 +15,7 @@ export async function actualUnmuteCmd(
|
|||
) {
|
||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||
let mod = msg.author;
|
||||
let pp = null;
|
||||
let pp: User | null = null;
|
||||
|
||||
if (args.mod) {
|
||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
||||
|
@ -27,15 +27,20 @@ export async function actualUnmuteCmd(
|
|||
pp = msg.author;
|
||||
}
|
||||
|
||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
||||
const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments) : undefined;
|
||||
|
||||
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||
const result = await mutesPlugin.unmuteUser(user.id, args.time, {
|
||||
modId: mod.id,
|
||||
ppId: pp && pp.id,
|
||||
ppId: pp ? pp.id : undefined,
|
||||
reason,
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
sendErrorMessage(pluginData, msg.channel, "User is not muted!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Confirm the action to the moderator
|
||||
if (args.time) {
|
||||
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import { GuildPluginData } from "knub";
|
||||
import { BanOptions, BanResult, IgnoredEventType, ModActionsPluginType } from "../types";
|
||||
import { notifyUser, resolveUser, stripObjectToScalars, ucfirst, UserNotificationResult } from "../../../utils";
|
||||
import {
|
||||
createUserNotificationError,
|
||||
notifyUser,
|
||||
resolveUser,
|
||||
stripObjectToScalars,
|
||||
ucfirst,
|
||||
UserNotificationResult,
|
||||
} from "../../../utils";
|
||||
import { User } from "eris";
|
||||
import { renderTemplate } from "../../../templateFormatter";
|
||||
import { getDefaultContactMethods } from "./getDefaultContactMethods";
|
||||
|
@ -15,7 +22,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
|
|||
export async function banUserId(
|
||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||
userId: string,
|
||||
reason: string = null,
|
||||
reason?: string,
|
||||
banOptions: BanOptions = {},
|
||||
): Promise<BanResult> {
|
||||
const config = pluginData.config.get();
|
||||
|
@ -30,15 +37,22 @@ export async function banUserId(
|
|||
// Attempt to message the user *before* banning them, as doing it after may not be possible
|
||||
let notifyResult: UserNotificationResult = { method: null, success: true };
|
||||
if (reason && user instanceof User) {
|
||||
const banMessage = await renderTemplate(config.ban_message, {
|
||||
guildName: pluginData.guild.name,
|
||||
reason,
|
||||
});
|
||||
|
||||
const contactMethods = banOptions?.contactMethods
|
||||
? banOptions.contactMethods
|
||||
: getDefaultContactMethods(pluginData, "ban");
|
||||
notifyResult = await notifyUser(user, banMessage, contactMethods);
|
||||
|
||||
if (contactMethods.length) {
|
||||
if (config.ban_message) {
|
||||
const banMessage = await renderTemplate(config.ban_message, {
|
||||
guildName: pluginData.guild.name,
|
||||
reason,
|
||||
});
|
||||
|
||||
notifyResult = await notifyUser(user, banMessage, contactMethods);
|
||||
} else {
|
||||
notifyResult = createUserNotificationError("No ban message specified in config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (Try to) ban the user
|
||||
|
@ -59,18 +73,19 @@ export async function banUserId(
|
|||
}
|
||||
|
||||
// Create a case for this action
|
||||
const modId = banOptions.caseArgs?.modId || pluginData.client.user.id;
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
const createdCase = await casesPlugin.createCase({
|
||||
...(banOptions.caseArgs || {}),
|
||||
userId,
|
||||
modId: banOptions.caseArgs?.modId,
|
||||
modId,
|
||||
type: CaseTypes.Ban,
|
||||
reason,
|
||||
noteDetails: notifyResult.text ? [ucfirst(notifyResult.text)] : [],
|
||||
});
|
||||
|
||||
// Log the action
|
||||
const mod = await resolveUser(pluginData.client, banOptions.caseArgs?.modId);
|
||||
const mod = await resolveUser(pluginData.client, modId);
|
||||
pluginData.state.serverLogs.log(LogType.MEMBER_BAN, {
|
||||
mod: stripObjectToScalars(mod),
|
||||
user: stripObjectToScalars(user),
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
import { GuildPluginData } from "knub";
|
||||
import { IgnoredEventType, KickOptions, KickResult, ModActionsPluginType } from "../types";
|
||||
import { Member } from "eris";
|
||||
import { notifyUser, resolveUser, stripObjectToScalars, ucfirst, UserNotificationResult } from "../../../utils";
|
||||
import {
|
||||
createUserNotificationError,
|
||||
notifyUser,
|
||||
resolveUser,
|
||||
stripObjectToScalars,
|
||||
ucfirst,
|
||||
UserNotificationResult,
|
||||
} from "../../../utils";
|
||||
import { renderTemplate } from "../../../templateFormatter";
|
||||
import { getDefaultContactMethods } from "./getDefaultContactMethods";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
|
@ -15,7 +22,7 @@ import { CasesPlugin } from "../../Cases/CasesPlugin";
|
|||
export async function kickMember(
|
||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||
member: Member,
|
||||
reason: string = null,
|
||||
reason?: string,
|
||||
kickOptions: KickOptions = {},
|
||||
): Promise<KickResult> {
|
||||
const config = pluginData.config.get();
|
||||
|
@ -23,15 +30,22 @@ 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) {
|
||||
const kickMessage = await renderTemplate(config.kick_message, {
|
||||
guildName: pluginData.guild.name,
|
||||
reason,
|
||||
});
|
||||
|
||||
const contactMethods = kickOptions?.contactMethods
|
||||
? kickOptions.contactMethods
|
||||
: getDefaultContactMethods(pluginData, "kick");
|
||||
notifyResult = await notifyUser(member.user, kickMessage, contactMethods);
|
||||
|
||||
if (contactMethods.length) {
|
||||
if (config.kick_message) {
|
||||
const kickMessage = await renderTemplate(config.kick_message, {
|
||||
guildName: pluginData.guild.name,
|
||||
reason,
|
||||
});
|
||||
|
||||
notifyResult = await notifyUser(member.user, kickMessage, contactMethods);
|
||||
} else {
|
||||
notifyResult = createUserNotificationError("No kick message specified in the config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kick the user
|
||||
|
@ -46,19 +60,21 @@ export async function kickMember(
|
|||
};
|
||||
}
|
||||
|
||||
const modId = kickOptions.caseArgs?.modId || pluginData.client.user.id;
|
||||
|
||||
// Create a case for this action
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
const createdCase = await casesPlugin.createCase({
|
||||
...(kickOptions.caseArgs || {}),
|
||||
userId: member.id,
|
||||
modId: kickOptions.caseArgs?.modId,
|
||||
modId,
|
||||
type: CaseTypes.Kick,
|
||||
reason,
|
||||
noteDetails: notifyResult.text ? [ucfirst(notifyResult.text)] : [],
|
||||
});
|
||||
|
||||
// Log the action
|
||||
const mod = await resolveUser(pluginData.client, kickOptions.caseArgs?.modId);
|
||||
const mod = await resolveUser(pluginData.client, modId);
|
||||
pluginData.state.serverLogs.log(LogType.MEMBER_KICK, {
|
||||
mod: stripObjectToScalars(mod),
|
||||
user: stripObjectToScalars(member.user),
|
||||
|
|
|
@ -2,7 +2,14 @@ import { GuildPluginData } from "knub";
|
|||
import { ModActionsPluginType, WarnOptions, WarnResult } from "../types";
|
||||
import { Member } from "eris";
|
||||
import { getDefaultContactMethods } from "./getDefaultContactMethods";
|
||||
import { notifyUser, resolveUser, stripObjectToScalars, ucfirst } from "../../../utils";
|
||||
import {
|
||||
createUserNotificationError,
|
||||
notifyUser,
|
||||
resolveUser,
|
||||
stripObjectToScalars,
|
||||
ucfirst,
|
||||
UserNotificationResult,
|
||||
} from "../../../utils";
|
||||
import { waitForReaction } from "knub/dist/helpers";
|
||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||
import { CaseTypes } from "../../../data/CaseTypes";
|
||||
|
@ -13,14 +20,19 @@ export async function warnMember(
|
|||
member: Member,
|
||||
reason: string,
|
||||
warnOptions: WarnOptions = {},
|
||||
): Promise<WarnResult | null> {
|
||||
): Promise<WarnResult> {
|
||||
const config = pluginData.config.get();
|
||||
|
||||
const warnMessage = config.warn_message.replace("{guildName}", pluginData.guild.name).replace("{reason}", reason);
|
||||
const contactMethods = warnOptions?.contactMethods
|
||||
? warnOptions.contactMethods
|
||||
: getDefaultContactMethods(pluginData, "warn");
|
||||
const notifyResult = await notifyUser(member.user, warnMessage, contactMethods);
|
||||
let notifyResult: UserNotificationResult;
|
||||
if (config.warn_message) {
|
||||
const warnMessage = config.warn_message.replace("{guildName}", pluginData.guild.name).replace("{reason}", reason);
|
||||
const contactMethods = warnOptions?.contactMethods
|
||||
? warnOptions.contactMethods
|
||||
: getDefaultContactMethods(pluginData, "warn");
|
||||
notifyResult = await notifyUser(member.user, warnMessage, contactMethods);
|
||||
} else {
|
||||
notifyResult = createUserNotificationError("No warn message specified in config");
|
||||
}
|
||||
|
||||
if (!notifyResult.success) {
|
||||
if (warnOptions.retryPromptChannel && pluginData.guild.channels.has(warnOptions.retryPromptChannel.id)) {
|
||||
|
@ -43,17 +55,19 @@ export async function warnMember(
|
|||
}
|
||||
}
|
||||
|
||||
const modId = warnOptions.caseArgs?.modId ?? pluginData.client.user.id;
|
||||
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
const createdCase = await casesPlugin.createCase({
|
||||
...(warnOptions.caseArgs || {}),
|
||||
userId: member.id,
|
||||
modId: warnOptions.caseArgs?.modId,
|
||||
modId,
|
||||
type: CaseTypes.Warn,
|
||||
reason,
|
||||
noteDetails: notifyResult.text ? [ucfirst(notifyResult.text)] : [],
|
||||
});
|
||||
|
||||
const mod = await resolveUser(pluginData.client, warnOptions.caseArgs?.modId);
|
||||
const mod = await resolveUser(pluginData.client, modId);
|
||||
pluginData.state.serverLogs.log(LogType.MEMBER_WARN, {
|
||||
mod: stripObjectToScalars(mod),
|
||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||
|
|
|
@ -98,9 +98,9 @@ export type BanResult =
|
|||
export type WarnMemberNotifyRetryCallback = () => boolean | Promise<boolean>;
|
||||
|
||||
export interface WarnOptions {
|
||||
caseArgs?: Partial<CaseArgs>;
|
||||
contactMethods?: UserNotificationMethod[];
|
||||
retryPromptChannel?: TextChannel;
|
||||
caseArgs?: Partial<CaseArgs> | null;
|
||||
contactMethods?: UserNotificationMethod[] | null;
|
||||
retryPromptChannel?: TextChannel | null;
|
||||
}
|
||||
|
||||
export interface KickOptions {
|
||||
|
|
|
@ -17,6 +17,7 @@ import { CaseArgs } from "../Cases/types";
|
|||
import { Member } from "eris";
|
||||
import { ClearActiveMuteOnMemberBanEvt } from "./events/ClearActiveMuteOnMemberBanEvt";
|
||||
import { ReapplyActiveMuteOnJoinEvt } from "./events/ReapplyActiveMuteOnJoinEvt";
|
||||
import { mapToPublicFn } from "../../pluginUtils";
|
||||
|
||||
const defaultOptions = {
|
||||
config: {
|
||||
|
@ -82,19 +83,12 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()("mutes", {
|
|||
],
|
||||
|
||||
public: {
|
||||
muteUser(pluginData) {
|
||||
return (userId: string, muteTime: number = null, reason: string = null, muteOptions: 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);
|
||||
};
|
||||
},
|
||||
muteUser: mapToPublicFn(muteUser),
|
||||
unmuteUser: mapToPublicFn(unmuteUser),
|
||||
hasMutedRole(pluginData) {
|
||||
return (member: Member) => {
|
||||
return member.roles.includes(pluginData.config.get().mute_role);
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
return muteRole ? member.roles.includes(muteRole) : false;
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
@ -12,7 +12,7 @@ export const ClearMutesCmd = mutesCmd({
|
|||
},
|
||||
|
||||
async run({ pluginData, message: msg, args }) {
|
||||
const failed = [];
|
||||
const failed: string[] = [];
|
||||
for (const id of args.userIds) {
|
||||
const mute = await pluginData.state.mutes.findExistingMuteForUserId(id);
|
||||
if (!mute) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { DBDateFormat, isFullMessage, MINUTES, noop, resolveMember } from "../..
|
|||
import moment from "moment-timezone";
|
||||
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
||||
import { getBaseUrl } from "../../../pluginUtils";
|
||||
import { Member } from "eris";
|
||||
|
||||
export const MutesCmd = mutesCmd({
|
||||
trigger: "mutes",
|
||||
|
@ -31,7 +32,7 @@ export const MutesCmd = mutesCmd({
|
|||
let clearReactionsTimeout;
|
||||
const clearReactionsDebounce = 5 * MINUTES;
|
||||
|
||||
let lines = [];
|
||||
let lines: string[] = [];
|
||||
|
||||
// Active, logged mutes
|
||||
const activeMutes = await pluginData.state.mutes.getActiveMutes();
|
||||
|
@ -41,13 +42,13 @@ export const MutesCmd = mutesCmd({
|
|||
if (a.expires_at == null && b.expires_at == null) {
|
||||
return a.created_at > b.created_at ? -1 : 1;
|
||||
}
|
||||
return a.expires_at > b.expires_at ? 1 : -1;
|
||||
return a.expires_at! > b.expires_at! ? 1 : -1;
|
||||
});
|
||||
|
||||
if (args.manual) {
|
||||
// Show only manual mutes (i.e. "Muted" role added without a logged mute)
|
||||
const muteUserIds = new Set(activeMutes.map(m => m.user_id));
|
||||
const manuallyMutedMembers = [];
|
||||
const manuallyMutedMembers: Member[] = [];
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
|
||||
if (muteRole) {
|
||||
|
@ -65,7 +66,7 @@ export const MutesCmd = mutesCmd({
|
|||
} else {
|
||||
// Show filtered active mutes (but not manual mutes)
|
||||
let filteredMutes: IMuteWithDetails[] = activeMutes;
|
||||
let bannedIds: string[] = null;
|
||||
let bannedIds: string[] | null = null;
|
||||
|
||||
// Filter: mute age
|
||||
if (args.age) {
|
||||
|
|
|
@ -10,9 +10,11 @@ export const ReapplyActiveMuteOnJoinEvt = mutesEvt("guildMemberAdd", async ({ pl
|
|||
if (mute) {
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
|
||||
const memberRolesLock = await pluginData.locks.acquire(`member-roles-${member.id}`);
|
||||
await member.addRole(muteRole);
|
||||
memberRolesLock.unlock();
|
||||
if (muteRole) {
|
||||
const memberRolesLock = await pluginData.locks.acquire(`member-roles-${member.id}`);
|
||||
await member.addRole(muteRole);
|
||||
memberRolesLock.unlock();
|
||||
}
|
||||
|
||||
pluginData.state.serverLogs.log(LogType.MEMBER_MUTE_REJOIN, {
|
||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||
|
|
|
@ -10,7 +10,10 @@ export async function clearExpiredMutes(pluginData: GuildPluginData<MutesPluginT
|
|||
|
||||
if (member) {
|
||||
try {
|
||||
await member.removeRole(pluginData.config.get().mute_role);
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
if (muteRole) {
|
||||
await member.removeRole(muteRole);
|
||||
}
|
||||
} catch (e) {
|
||||
pluginData.state.serverLogs.log(LogType.BOT_ALERT, {
|
||||
body: `Failed to remove mute role from {userMention(member)}`,
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Member } from "eris";
|
|||
import { GuildPluginData } from "knub";
|
||||
import { MutesPluginType } from "../types";
|
||||
|
||||
export function memberHasMutedRole(pluginData: GuildPluginData<MutesPluginType>, member: Member) {
|
||||
return member.roles.includes(pluginData.config.get().mute_role);
|
||||
export function memberHasMutedRole(pluginData: GuildPluginData<MutesPluginType>, member: Member): boolean {
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
return muteRole ? member.roles.includes(muteRole) : false;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
ucfirst,
|
||||
UserNotificationResult,
|
||||
resolveMember,
|
||||
UserNotificationMethod,
|
||||
} from "../../../utils";
|
||||
import { renderTemplate } from "../../../templateFormatter";
|
||||
import { TextChannel, User } from "eris";
|
||||
|
@ -20,8 +21,8 @@ import { Case } from "../../../data/entities/Case";
|
|||
export async function muteUser(
|
||||
pluginData: GuildPluginData<MutesPluginType>,
|
||||
userId: string,
|
||||
muteTime: number = null,
|
||||
reason: string = null,
|
||||
muteTime?: number,
|
||||
reason?: string,
|
||||
muteOptions: MuteOptions = {},
|
||||
) {
|
||||
const lock = await pluginData.locks.acquire(`mute-${userId}`);
|
||||
|
@ -90,7 +91,7 @@ export async function muteUser(
|
|||
}));
|
||||
|
||||
if (muteMessage && user instanceof User) {
|
||||
let contactMethods = [];
|
||||
let contactMethods: UserNotificationMethod[] = [];
|
||||
|
||||
if (muteOptions?.contactMethods) {
|
||||
contactMethods = muteOptions.contactMethods;
|
||||
|
@ -112,18 +113,21 @@ export async function muteUser(
|
|||
|
||||
// Create/update a case
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
let theCase: Case;
|
||||
let theCase: Case | undefined =
|
||||
existingMute && existingMute.case_id ? await pluginData.state.cases.find(existingMute.case_id) : undefined;
|
||||
|
||||
if (existingMute && existingMute.case_id) {
|
||||
if (theCase) {
|
||||
// Update old case
|
||||
// Since mutes can often have multiple notes (extraNotes), we won't post each case note individually,
|
||||
// but instead we'll post the entire case afterwards
|
||||
theCase = await pluginData.state.cases.find(existingMute.case_id);
|
||||
const noteDetails = [`Mute updated to ${muteTime ? timeUntilUnmute : "indefinite"}`];
|
||||
const reasons = [reason, ...(muteOptions.caseArgs?.extraNotes || [])];
|
||||
const reasons = reason ? [reason] : [];
|
||||
if (muteOptions.caseArgs?.extraNotes) {
|
||||
reasons.push(...muteOptions.caseArgs.extraNotes);
|
||||
}
|
||||
for (const noteReason of reasons) {
|
||||
await casesPlugin.createCaseNote({
|
||||
caseId: existingMute.case_id,
|
||||
caseId: existingMute!.case_id,
|
||||
modId: muteOptions.caseArgs?.modId,
|
||||
body: noteReason,
|
||||
noteDetails,
|
||||
|
@ -132,7 +136,7 @@ export async function muteUser(
|
|||
}
|
||||
|
||||
if (muteOptions.caseArgs?.postInCaseLogOverride !== false) {
|
||||
casesPlugin.postCaseToCaseLogChannel(existingMute.case_id);
|
||||
casesPlugin.postCaseToCaseLogChannel(existingMute!.case_id);
|
||||
}
|
||||
} else {
|
||||
// Create new case
|
||||
|
|
|
@ -7,18 +7,20 @@ import humanizeDuration from "humanize-duration";
|
|||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||
import { CaseTypes } from "../../../data/CaseTypes";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { WithRequiredProps } from "../../../utils/typeUtils";
|
||||
|
||||
export async function unmuteUser(
|
||||
pluginData: GuildPluginData<MutesPluginType>,
|
||||
userId: string,
|
||||
unmuteTime: number = null,
|
||||
unmuteTime?: number,
|
||||
caseArgs: Partial<CaseArgs> = {},
|
||||
): Promise<UnmuteResult> {
|
||||
): Promise<UnmuteResult | null> {
|
||||
const existingMute = await pluginData.state.mutes.findExistingMuteForUserId(userId);
|
||||
const user = await resolveUser(pluginData.client, userId);
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, userId); // Grab the fresh member so we don't have stale role info
|
||||
const modId = caseArgs.modId || pluginData.client.user.id;
|
||||
|
||||
if (!existingMute && !memberHasMutedRole(pluginData, member)) return;
|
||||
if (!existingMute && member && !memberHasMutedRole(pluginData, member)) return null;
|
||||
|
||||
if (unmuteTime) {
|
||||
// Schedule timed unmute (= just set the mute's duration)
|
||||
|
@ -31,7 +33,7 @@ export async function unmuteUser(
|
|||
// Unmute immediately
|
||||
if (member) {
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
if (member.roles.includes(muteRole)) {
|
||||
if (muteRole && member.roles.includes(muteRole)) {
|
||||
await member.removeRole(muteRole);
|
||||
}
|
||||
} else {
|
||||
|
@ -47,7 +49,7 @@ export async function unmuteUser(
|
|||
const timeUntilUnmute = unmuteTime && humanizeDuration(unmuteTime);
|
||||
|
||||
// Create a case
|
||||
const noteDetails = [];
|
||||
const noteDetails: string[] = [];
|
||||
if (unmuteTime) {
|
||||
noteDetails.push(`Scheduled unmute in ${timeUntilUnmute}`);
|
||||
} else {
|
||||
|
@ -61,13 +63,13 @@ export async function unmuteUser(
|
|||
const createdCase = await casesPlugin.createCase({
|
||||
...caseArgs,
|
||||
userId,
|
||||
modId: caseArgs.modId,
|
||||
modId,
|
||||
type: CaseTypes.Unmute,
|
||||
noteDetails,
|
||||
});
|
||||
|
||||
// Log the action
|
||||
const mod = pluginData.client.users.get(caseArgs.modId);
|
||||
const mod = pluginData.client.users.get(modId);
|
||||
if (unmuteTime) {
|
||||
pluginData.state.serverLogs.log(LogType.MEMBER_TIMED_UNMUTE, {
|
||||
mod: stripObjectToScalars(mod),
|
||||
|
|
|
@ -13,6 +13,6 @@ export const MessageCreateEvt = nameHistoryEvt({
|
|||
event: "messageCreate",
|
||||
|
||||
async listener(meta) {
|
||||
meta.pluginData.state.updateQueue.add(() => updateNickname(meta.pluginData, meta.args.message.member));
|
||||
meta.pluginData.state.updateQueue.add(() => updateNickname(meta.pluginData, meta.args.message.member!));
|
||||
},
|
||||
});
|
||||
|
|
|
@ -27,10 +27,10 @@ export const LoadDataEvt = persistEvt({
|
|||
|
||||
const toRestore: MemberOptions = {};
|
||||
const config = pluginData.config.getForMember(member);
|
||||
const restoredData = [];
|
||||
const restoredData: string[] = [];
|
||||
|
||||
// Check permissions
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id);
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||
let requiredPermissions = 0;
|
||||
if (config.persist_nicknames) requiredPermissions |= p.manageNicknames;
|
||||
if (config.persisted_roles) requiredPermissions |= p.manageRoles;
|
||||
|
|
|
@ -10,5 +10,5 @@ export async function getPingableRolesForChannel(
|
|||
pluginData.state.cache.set(channelId, await pluginData.state.pingableRoles.getForChannel(channelId));
|
||||
}
|
||||
|
||||
return pluginData.state.cache.get(channelId);
|
||||
return pluginData.state.cache.get(channelId)!;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ export const EditEmbedCmd = postCmd({
|
|||
|
||||
const content = args.content || args.maincontent;
|
||||
|
||||
let color = null;
|
||||
let color: number | null = null;
|
||||
if (args.color) {
|
||||
const colorRgb = parseColor(args.color);
|
||||
if (colorRgb) {
|
||||
|
@ -42,8 +42,7 @@ export const EditEmbedCmd = postCmd({
|
|||
}
|
||||
}
|
||||
|
||||
const embed: Embed = savedMessage.data.embeds[0] as Embed;
|
||||
embed.type = "rich";
|
||||
const embed: Embed = savedMessage.data.embeds![0] as Embed;
|
||||
if (args.title) embed.title = args.title;
|
||||
if (content) embed.description = formatContent(content);
|
||||
if (color) embed.color = color;
|
||||
|
|
|
@ -35,7 +35,7 @@ export const PostEmbedCmd = postCmd({
|
|||
return;
|
||||
}
|
||||
|
||||
let color = null;
|
||||
let color: number | null = null;
|
||||
if (args.color) {
|
||||
const colorRgb = parseColor(args.color);
|
||||
if (colorRgb) {
|
||||
|
|
|
@ -39,7 +39,7 @@ export const ScheduledPostsListCmd = postCmd({
|
|||
|
||||
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
|
||||
const prettyPostAt = timeAndDate
|
||||
.inGuildTz(moment.utc(p.post_at, DBDateFormat))
|
||||
.inGuildTz(moment.utc(p.post_at!, DBDateFormat))
|
||||
.format(timeAndDate.getDateFormat("pretty_datetime"));
|
||||
const parts = [`\`#${i++}\` \`[${prettyPostAt}]\` ${previewText}${isTruncated ? "..." : ""}`];
|
||||
if (p.attachments.length) parts.push("*(with attachment)*");
|
||||
|
|
|
@ -19,13 +19,13 @@ export async function actualPostCmd(
|
|||
msg: Message,
|
||||
targetChannel: Channel,
|
||||
content: StrictMessageContent,
|
||||
opts?: {
|
||||
opts: {
|
||||
"enable-mentions"?: boolean;
|
||||
schedule?: string;
|
||||
repeat?: number;
|
||||
"repeat-until"?: string;
|
||||
"repeat-times"?: number;
|
||||
},
|
||||
} = {},
|
||||
) {
|
||||
if (!(targetChannel instanceof TextChannel)) {
|
||||
msg.channel.createMessage(errorMessage("Channel is not a text channel"));
|
||||
|
@ -63,9 +63,9 @@ export async function actualPostCmd(
|
|||
}
|
||||
|
||||
// For repeated posts, make sure repeat-until or repeat-times is specified
|
||||
let repeatUntil: moment.Moment = null;
|
||||
let repeatTimes: number = null;
|
||||
let repeatDetailsStr: string = null;
|
||||
let repeatUntil: moment.Moment | null = null;
|
||||
let repeatTimes: number | null = null;
|
||||
let repeatDetailsStr: string | null = null;
|
||||
|
||||
if (opts["repeat-until"]) {
|
||||
repeatUntil = await parseScheduleTime(pluginData, msg.author.id, opts["repeat-until"]);
|
||||
|
|
|
@ -8,7 +8,7 @@ export async function parseScheduleTime(
|
|||
pluginData: GuildPluginData<any>,
|
||||
memberId: string,
|
||||
str: string,
|
||||
): Promise<Moment> {
|
||||
): Promise<Moment | null> {
|
||||
const tz = await pluginData.getPlugin(TimeAndDatePlugin).getMemberTz(memberId);
|
||||
|
||||
const dt1 = moment.tz(str, "YYYY-MM-DD HH:mm:ss", tz);
|
||||
|
|
|
@ -111,7 +111,7 @@ export const InitReactionRolesCmd = reactionRolesCmd({
|
|||
reactionRoles,
|
||||
);
|
||||
|
||||
if (errors.length) {
|
||||
if (errors?.length) {
|
||||
sendErrorMessage(pluginData, msg.channel, `Errors while adding reaction roles:\n${errors.join("\n")}`);
|
||||
} else {
|
||||
sendSuccessMessage(pluginData, msg.channel, "Reaction roles added");
|
||||
|
|
|
@ -14,7 +14,7 @@ export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|||
export type RoleChangeMode = "+" | "-";
|
||||
|
||||
export type PendingMemberRoleChanges = {
|
||||
timeout: NodeJS.Timeout;
|
||||
timeout: NodeJS.Timeout | null;
|
||||
applyFn: () => void;
|
||||
changes: Array<{
|
||||
mode: RoleChangeMode;
|
||||
|
|
|
@ -48,7 +48,7 @@ export async function addMemberPendingRoleChange(
|
|||
pluginData.state.pendingRoleChanges.set(memberId, newPendingRoleChangeObj);
|
||||
}
|
||||
|
||||
const pendingRoleChangeObj = pluginData.state.pendingRoleChanges.get(memberId);
|
||||
const pendingRoleChangeObj = pluginData.state.pendingRoleChanges.get(memberId)!;
|
||||
pendingRoleChangeObj.changes.push({ mode, roleId });
|
||||
|
||||
if (pendingRoleChangeObj.timeout) clearTimeout(pendingRoleChangeObj.timeout);
|
||||
|
|
|
@ -17,11 +17,11 @@ export async function applyReactionRoleReactionsToMessage(
|
|||
channelId: string,
|
||||
messageId: string,
|
||||
reactionRoles: ReactionRole[],
|
||||
): Promise<string[]> {
|
||||
): Promise<string[] | undefined> {
|
||||
const channel = pluginData.guild.channels.get(channelId) as TextChannel;
|
||||
if (!channel) return;
|
||||
|
||||
const errors = [];
|
||||
const errors: string[] = [];
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
||||
|
||||
let targetMessage;
|
||||
|
|
|
@ -4,6 +4,7 @@ import { rolesCmd } from "../types";
|
|||
import { resolveMember, resolveRoleId, stripObjectToScalars, successMessage } from "../../../utils";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { logger } from "../../../logger";
|
||||
import { Member } from "eris";
|
||||
|
||||
export const MassAddRoleCmd = rolesCmd({
|
||||
trigger: "massaddrole",
|
||||
|
@ -17,8 +18,8 @@ export const MassAddRoleCmd = rolesCmd({
|
|||
async run({ message: msg, args, pluginData }) {
|
||||
msg.channel.createMessage(`Resolving members...`);
|
||||
|
||||
const members = [];
|
||||
const unknownMembers = [];
|
||||
const members: Member[] = [];
|
||||
const unknownMembers: string[] = [];
|
||||
for (const memberId of args.members) {
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||
if (member) members.push(member);
|
||||
|
@ -55,7 +56,7 @@ export const MassAddRoleCmd = rolesCmd({
|
|||
|
||||
const membersWithoutTheRole = members.filter(m => !m.roles.includes(roleId));
|
||||
let assigned = 0;
|
||||
const failed = [];
|
||||
const failed: string[] = [];
|
||||
const alreadyHadRole = members.length - membersWithoutTheRole.length;
|
||||
|
||||
msg.channel.createMessage(
|
||||
|
|
|
@ -4,6 +4,7 @@ import { rolesCmd } from "../types";
|
|||
import { resolveMember, stripObjectToScalars, successMessage, resolveRoleId } from "../../../utils";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { logger } from "../../../logger";
|
||||
import { Member } from "eris";
|
||||
|
||||
export const MassRemoveRoleCmd = rolesCmd({
|
||||
trigger: "massremoverole",
|
||||
|
@ -17,8 +18,8 @@ export const MassRemoveRoleCmd = rolesCmd({
|
|||
async run({ message: msg, args, pluginData }) {
|
||||
msg.channel.createMessage(`Resolving members...`);
|
||||
|
||||
const members = [];
|
||||
const unknownMembers = [];
|
||||
const members: Member[] = [];
|
||||
const unknownMembers: string[] = [];
|
||||
for (const memberId of args.members) {
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||
if (member) members.push(member);
|
||||
|
@ -55,7 +56,7 @@ export const MassRemoveRoleCmd = rolesCmd({
|
|||
|
||||
const membersWithTheRole = members.filter(m => m.roles.includes(roleId));
|
||||
let assigned = 0;
|
||||
const failed = [];
|
||||
const failed: string[] = [];
|
||||
const didNotHaveRole = members.length - membersWithTheRole.length;
|
||||
|
||||
msg.channel.createMessage(
|
||||
|
|
|
@ -30,7 +30,7 @@ export const RoleAddCmd = selfGrantableRolesCmd({
|
|||
const hasUnknownRoles = matchedRoleIds.length !== roleNames.length;
|
||||
|
||||
const rolesToAdd: Map<string, Role> = Array.from(matchedRoleIds.values())
|
||||
.map(id => pluginData.guild.roles.get(id))
|
||||
.map(id => pluginData.guild.roles.get(id)!)
|
||||
.filter(Boolean)
|
||||
.reduce((map, role) => {
|
||||
map.set(role.id, role);
|
||||
|
@ -68,9 +68,9 @@ export const RoleAddCmd = selfGrantableRolesCmd({
|
|||
rolesToAdd.delete(roleId);
|
||||
|
||||
if (msg.member.roles.includes(roleId)) {
|
||||
removed.add(pluginData.guild.roles.get(roleId));
|
||||
removed.add(pluginData.guild.roles.get(roleId)!);
|
||||
} else {
|
||||
skipped.add(pluginData.guild.roles.get(roleId));
|
||||
skipped.add(pluginData.guild.roles.get(roleId)!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ export const RoleAddCmd = selfGrantableRolesCmd({
|
|||
const addedRolesStr = Array.from(rolesToAdd.values()).map(r => (mentionRoles ? `<@&${r.id}>` : `**${r.name}**`));
|
||||
const addedRolesWord = rolesToAdd.size === 1 ? "role" : "roles";
|
||||
|
||||
const messageParts = [];
|
||||
const messageParts: string[] = [];
|
||||
messageParts.push(`Granted you the ${addedRolesStr.join(", ")} ${addedRolesWord}`);
|
||||
|
||||
if (skipped.size || removed.size) {
|
||||
|
|
|
@ -10,7 +10,7 @@ export const RoleHelpCmd = selfGrantableRolesCmd({
|
|||
const applyingEntries = getApplyingEntries(pluginData, msg);
|
||||
if (applyingEntries.length === 0) return;
|
||||
|
||||
const allPrimaryAliases = [];
|
||||
const allPrimaryAliases: string[] = [];
|
||||
for (const entry of applyingEntries) {
|
||||
for (const aliases of Object.values(entry.roles)) {
|
||||
if (aliases[0]) {
|
||||
|
|
|
@ -26,7 +26,7 @@ export const RoleRemoveCmd = selfGrantableRolesCmd({
|
|||
const roleNames = normalizeRoleNames(splitRoleNames(args.roleNames));
|
||||
const matchedRoleIds = findMatchingRoles(roleNames, applyingEntries);
|
||||
|
||||
const rolesToRemove = Array.from(matchedRoleIds.values()).map(id => pluginData.guild.roles.get(id));
|
||||
const rolesToRemove = Array.from(matchedRoleIds.values()).map(id => pluginData.guild.roles.get(id)!);
|
||||
const roleIdsToRemove = rolesToRemove.map(r => r.id);
|
||||
|
||||
// Remove the roles
|
||||
|
|
|
@ -25,7 +25,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
|
|||
return;
|
||||
}
|
||||
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id);
|
||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||
const missingPermissions = getMissingChannelPermissions(me, args.channel, BOT_SLOWMODE_CLEAR_PERMISSIONS);
|
||||
if (missingPermissions) {
|
||||
sendErrorMessage(
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue