From d0a1beb8093e0dc7e7487b7baf4dc29a4efb9846 Mon Sep 17 00:00:00 2001 From: Dark <7890309+DarkView@users.noreply.github.com> Date: Wed, 2 Jun 2021 04:07:50 +0200 Subject: [PATCH] Finish preliminary rework, ready to test --- .gitignore | 2 + backend/src/data/GuildSavedMessages.ts | 3 +- .../src/plugins/Automod/actions/addRoles.ts | 5 +- .../plugins/Automod/actions/removeRoles.ts | 5 +- .../functions/getTextMatchPartialSummary.ts | 6 +- .../plugins/Automod/triggers/memberJoin.ts | 2 +- .../commands/AddDashboardUserCmd.ts | 5 +- .../BotControl/commands/AllowServerCmd.ts | 9 +- .../BotControl/commands/DisallowServerCmd.ts | 10 ++- .../BotControl/commands/EligibleCmd.ts | 13 +-- .../BotControl/commands/LeaveServerCmd.ts | 13 +-- .../commands/ListDashboardPermsCmd.ts | 17 ++-- .../commands/ListDashboardUsersCmd.ts | 5 +- .../commands/ReloadGlobalPluginsCmd.ts | 3 +- .../BotControl/commands/ReloadServerCmd.ts | 11 +-- .../commands/RemoveDashboardUserCmd.ts | 5 +- .../plugins/BotControl/commands/ServersCmd.ts | 9 +- .../src/plugins/Censor/util/censorMessage.ts | 2 +- .../commands/ArchiveChannelCmd.ts | 11 ++- .../ChannelArchiver/rehostAttachment.ts | 5 +- .../functions/handleCompanionPermissions.ts | 8 +- .../Counters/commands/AddCounterCmd.ts | 8 +- .../CustomEvents/actions/addRoleAction.ts | 2 +- .../CustomEvents/actions/messageAction.ts | 3 +- .../actions/moveToVoiceChannelAction.ts | 5 +- .../actions/setChannelPermissionOverrides.ts | 7 +- .../CustomEvents/functions/runEvent.ts | 3 +- .../GuildAccessMonitorPlugin.ts | 5 +- .../plugins/LocateUser/commands/FollowCmd.ts | 4 +- .../LocateUser/events/SendAlertsEvts.ts | 6 +- .../plugins/LocateUser/utils/moveMember.ts | 2 +- .../Logs/events/LogsVoiceChannelEvts.ts | 7 +- .../MessageSaver/commands/SavePinsToDB.ts | 6 +- .../plugins/ModActions/ModActionsPlugin.ts | 5 +- .../plugins/ModActions/commands/AddCaseCmd.ts | 2 +- .../src/plugins/ModActions/commands/BanCmd.ts | 16 ++-- .../plugins/ModActions/commands/CaseCmd.ts | 2 +- .../ModActions/commands/CasesModCmd.ts | 5 +- .../ModActions/commands/CasesUserCmd.ts | 13 +-- .../ModActions/commands/DeleteCaseCmd.ts | 5 +- .../ModActions/commands/ForcebanCmd.ts | 7 +- .../plugins/ModActions/commands/MassBanCmd.ts | 12 ++- .../ModActions/commands/MassUnbanCmd.ts | 9 +- .../ModActions/commands/MassmuteCmd.ts | 7 +- .../plugins/ModActions/commands/MuteCmd.ts | 18 ++-- .../plugins/ModActions/commands/NoteCmd.ts | 4 +- .../ModActions/commands/SoftbanCommand.ts | 2 +- .../plugins/ModActions/commands/UnbanCmd.ts | 4 +- .../plugins/ModActions/commands/UnmuteCmd.ts | 7 +- .../plugins/ModActions/commands/WarnCmd.ts | 14 +-- .../events/CreateBanCaseOnManualBanEvt.ts | 8 +- .../events/CreateKickCaseOnManualKickEvt.ts | 7 +- .../events/CreateUnbanCaseOnManualUnbanEvt.ts | 8 +- .../events/PostAlertOnMemberJoinEvt.ts | 9 +- .../functions/actualKickMemberCmd.ts | 9 +- .../ModActions/functions/actualMuteUserCmd.ts | 21 ++--- .../functions/actualUnmuteUserCmd.ts | 13 +-- .../plugins/ModActions/functions/banUserId.ts | 12 +-- .../functions/formatReasonWithAttachments.ts | 4 +- .../functions/getDefaultContactMethods.ts | 1 + .../plugins/ModActions/functions/isBanned.ts | 5 +- .../ModActions/functions/kickMember.ts | 3 +- .../functions/outdatedTempbansLoop.ts | 2 +- .../functions/readContactMethodsFromArgs.ts | 1 + .../ModActions/functions/updateCase.ts | 11 +-- .../ModActions/functions/warnMember.ts | 12 +-- backend/src/plugins/ModActions/types.ts | 1 + backend/src/plugins/Mutes/MutesPlugin.ts | 5 +- .../Mutes/commands/ClearBannedMutesCmd.ts | 10 +-- .../commands/ClearMutesWithoutRoleCmd.ts | 4 +- .../src/plugins/Mutes/commands/MutesCmd.ts | 31 ++++--- .../events/ClearActiveMuteOnMemberBanEvt.ts | 6 +- .../events/ClearActiveMuteOnRoleRemovalEvt.ts | 2 +- .../events/ReapplyActiveMuteOnJoinEvt.ts | 2 +- .../Mutes/functions/clearExpiredMutes.ts | 18 ++-- .../Mutes/functions/memberHasMutedRole.ts | 5 +- .../src/plugins/Mutes/functions/muteUser.ts | 27 +++--- .../src/plugins/Mutes/functions/unmuteUser.ts | 21 +++-- backend/src/plugins/Mutes/types.ts | 3 +- .../plugins/NameHistory/commands/NamesCmd.ts | 2 +- .../NameHistory/events/UpdateNameEvts.ts | 9 +- .../src/plugins/NameHistory/updateNickname.ts | 9 +- .../src/plugins/Persist/events/LoadDataEvt.ts | 13 +-- .../plugins/Persist/events/StoreDataEvt.ts | 7 +- backend/src/plugins/Post/commands/EditCmd.ts | 5 +- .../src/plugins/Post/commands/EditEmbedCmd.ts | 9 +- .../src/plugins/Post/commands/PostEmbedCmd.ts | 5 +- .../Post/commands/ScheduledPostsListCmd.ts | 2 +- .../Post/commands/ScheduledPostsShowCmd.ts | 1 + .../src/plugins/Post/util/actualPostCmd.ts | 49 +++++++---- backend/src/plugins/Post/util/postMessage.ts | 13 ++- .../plugins/Post/util/scheduledPostLoop.ts | 3 +- .../commands/ClearReactionRolesCmd.ts | 7 +- .../commands/InitReactionRolesCmd.ts | 8 +- .../events/AddReactionRoleEvt.ts | 12 +-- .../util/addMemberPendingRoleChange.ts | 4 +- .../applyReactionRoleReactionsToMessage.ts | 3 +- .../Reminders/utils/postDueRemindersLoop.ts | 5 +- .../src/plugins/Roles/commands/AddRoleCmd.ts | 7 +- .../plugins/Roles/commands/MassAddRoleCmd.ts | 13 +-- .../Roles/commands/MassRemoveRoleCmd.ts | 13 +-- .../plugins/Roles/commands/RemoveRoleCmd.ts | 7 +- .../SelfGrantableRoles/commands/RoleAddCmd.ts | 5 +- .../commands/RoleHelpCmd.ts | 2 +- .../commands/RoleRemoveCmd.ts | 2 +- .../Slowmode/commands/SlowmodeGetCmd.ts | 5 +- .../Slowmode/commands/SlowmodeListCmd.ts | 5 +- .../Slowmode/commands/SlowmodeSetCmd.ts | 13 ++- .../plugins/Slowmode/requiredPermissions.ts | 12 +-- .../Slowmode/util/actualDisableSlowmodeCmd.ts | 11 +-- .../Slowmode/util/applyBotSlowmodeToUserId.ts | 13 ++- .../util/clearBotSlowmodeFromUserId.ts | 3 +- .../Slowmode/util/clearExpiredSlowmodes.ts | 3 +- .../util/disableBotSlowmodeForChannel.ts | 1 + .../plugins/Slowmode/util/onMessageCreate.ts | 3 +- backend/src/plugins/Spam/SpamPlugin.ts | 5 +- .../src/plugins/Spam/events/SpamVoiceEvt.ts | 34 ++------ .../Spam/util/logAndDetectMessageSpam.ts | 3 +- .../Starboard/commands/MigratePinsCmd.ts | 5 +- .../events/StarboardReactionAddEvt.ts | 17 ++-- .../events/StarboardReactionRemoveEvts.ts | 5 +- .../util/createStarboardEmbedFromMessage.ts | 13 +-- .../createStarboardPseudoFooterForMessage.ts | 2 + .../Starboard/util/saveMessageToStarboard.ts | 3 +- .../util/updateStarboardMessageStarCount.ts | 1 + backend/src/plugins/Tags/TagsPlugin.ts | 4 +- .../src/plugins/Tags/commands/TagEvalCmd.ts | 2 +- .../src/plugins/Tags/commands/TagListCmd.ts | 2 +- .../src/plugins/Tags/commands/TagSourceCmd.ts | 2 +- .../Tags/util/matchAndRenderTagFromString.ts | 3 +- .../src/plugins/Tags/util/onMessageCreate.ts | 8 +- .../src/plugins/Tags/util/onMessageDelete.ts | 5 +- .../plugins/Tags/util/renderTagFromString.ts | 3 +- .../TimeAndDate/commands/ViewTimezoneCmd.ts | 4 +- .../events/UpdateUsernameEvts.ts | 6 +- .../plugins/UsernameSaver/updateUsername.ts | 1 + .../src/plugins/Utility/commands/AboutCmd.ts | 16 ++-- .../src/plugins/Utility/commands/AvatarCmd.ts | 10 ++- .../Utility/commands/ChannelInfoCmd.ts | 2 +- .../src/plugins/Utility/commands/CleanCmd.ts | 9 +- .../plugins/Utility/commands/ContextCmd.ts | 10 ++- .../plugins/Utility/commands/EmojiInfoCmd.ts | 2 +- .../src/plugins/Utility/commands/HelpCmd.ts | 2 +- .../src/plugins/Utility/commands/InfoCmd.ts | 20 ++--- .../plugins/Utility/commands/InviteInfoCmd.ts | 2 +- .../src/plugins/Utility/commands/JumboCmd.ts | 2 +- .../src/plugins/Utility/commands/LevelCmd.ts | 4 +- .../Utility/commands/MessageInfoCmd.ts | 2 +- .../plugins/Utility/commands/NicknameCmd.ts | 8 +- .../Utility/commands/NicknameResetCmd.ts | 4 +- .../src/plugins/Utility/commands/PingCmd.ts | 19 ++--- .../Utility/commands/ReloadGuildCmd.ts | 3 +- .../plugins/Utility/commands/RoleInfoCmd.ts | 2 +- .../src/plugins/Utility/commands/RolesCmd.ts | 13 +-- .../plugins/Utility/commands/ServerInfoCmd.ts | 2 +- .../Utility/commands/SnowflakeInfoCmd.ts | 2 +- .../src/plugins/Utility/commands/SourceCmd.ts | 6 +- .../plugins/Utility/commands/UserInfoCmd.ts | 2 +- .../Utility/commands/VcdisconnectCmd.ts | 10 +-- .../src/plugins/Utility/commands/VcmoveCmd.ts | 25 +++--- .../Utility/functions/getChannelInfoEmbed.ts | 57 +++++++------ .../Utility/functions/getEmojiInfoEmbed.ts | 5 +- .../Utility/functions/getGuildPreview.ts | 3 +- .../Utility/functions/getInviteInfoEmbed.ts | 24 +++--- .../Utility/functions/getMessageInfoEmbed.ts | 40 +++++---- .../Utility/functions/getRoleInfoEmbed.ts | 9 +- .../Utility/functions/getServerInfoEmbed.ts | 47 +++++----- .../functions/getSnowflakeInfoEmbed.ts | 3 +- .../Utility/functions/getUserInfoEmbed.ts | 29 ++++--- backend/src/plugins/Utility/guildReloads.ts | 2 + backend/src/plugins/Utility/refreshMembers.ts | 3 +- backend/src/plugins/Utility/search.ts | 85 ++++++++++--------- .../events/SendWelcomeMessageEvt.ts | 3 +- backend/src/types.ts | 22 +++++ backend/src/utils.test.ts | 4 +- backend/src/utils.ts | 28 +++--- .../erisAllowedMentionsToDjsMentionOptions.ts | 8 +- 177 files changed, 854 insertions(+), 707 deletions(-) diff --git a/.gitignore b/.gitignore index 2d5e4afe..e3b71ab8 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,5 @@ npm-audit.txt # Debug files *.debug.ts *.debug.js + +.vscode/ diff --git a/backend/src/data/GuildSavedMessages.ts b/backend/src/data/GuildSavedMessages.ts index 7bc4134d..b5759fde 100644 --- a/backend/src/data/GuildSavedMessages.ts +++ b/backend/src/data/GuildSavedMessages.ts @@ -211,7 +211,8 @@ export class GuildSavedMessages extends BaseGuildRepository { const newMessage = { ...oldMessage, data: newData }; - await this.messages.update( + //@ts-ignore + await this.messages.update( // FIXME? { id }, { data: newData, diff --git a/backend/src/plugins/Automod/actions/addRoles.ts b/backend/src/plugins/Automod/actions/addRoles.ts index 39f59870..ea467446 100644 --- a/backend/src/plugins/Automod/actions/addRoles.ts +++ b/backend/src/plugins/Automod/actions/addRoles.ts @@ -53,13 +53,13 @@ export const AddRolesAction = automodAction({ await Promise.all( members.map(async member => { - const memberRoles = new Set(member.roles); + const memberRoles = new Set(member.roles.cache.keyArray()); for (const roleId of rolesToAssign) { memberRoles.add(roleId); ignoreRoleChange(pluginData, member.id, roleId); } - if (memberRoles.size === member.roles.length) { + if (memberRoles.size === member.roles.cache.size) { // No role changes return; } @@ -70,7 +70,6 @@ export const AddRolesAction = automodAction({ await member.edit({ roles: rolesArr, }); - member.roles = rolesArr; // Make sure we know of the new roles internally as well memberRoleLock.unlock(); }), diff --git a/backend/src/plugins/Automod/actions/removeRoles.ts b/backend/src/plugins/Automod/actions/removeRoles.ts index dcfbd9d3..79e22fae 100644 --- a/backend/src/plugins/Automod/actions/removeRoles.ts +++ b/backend/src/plugins/Automod/actions/removeRoles.ts @@ -57,13 +57,13 @@ export const RemoveRolesAction = automodAction({ await Promise.all( members.map(async member => { - const memberRoles = new Set(member.roles); + const memberRoles = new Set(member.roles.cache.keyArray()); for (const roleId of rolesToRemove) { memberRoles.delete(roleId); ignoreRoleChange(pluginData, member.id, roleId); } - if (memberRoles.size === member.roles.length) { + if (memberRoles.size === member.roles.cache.size) { // No role changes return; } @@ -74,7 +74,6 @@ export const RemoveRolesAction = automodAction({ await member.edit({ roles: rolesArr, }); - member.roles = rolesArr; // Make sure we know of the new roles internally as well memberRoleLock.unlock(); }), diff --git a/backend/src/plugins/Automod/functions/getTextMatchPartialSummary.ts b/backend/src/plugins/Automod/functions/getTextMatchPartialSummary.ts index 37a04fe4..99442b1e 100644 --- a/backend/src/plugins/Automod/functions/getTextMatchPartialSummary.ts +++ b/backend/src/plugins/Automod/functions/getTextMatchPartialSummary.ts @@ -23,11 +23,11 @@ export function getTextMatchPartialSummary( } else if (type === "username") { return `username: ${context.user!.username}`; } else if (type === "nickname") { - return `nickname: ${context.member!.nick}`; + return `nickname: ${context.member!.nickname}`; } else if (type === "visiblename") { - const visibleName = context.member?.nick || context.user!.username; + const visibleName = context.member?.nickname || context.user!.username; return `visible name: ${visibleName}`; } else if (type === "customstatus") { - return `custom status: ${context.member!.game!.state}`; + return `custom status: ${context.member!.presence.activities.find(a => a.type === "CUSTOM_STATUS")?.name}`; } } diff --git a/backend/src/plugins/Automod/triggers/memberJoin.ts b/backend/src/plugins/Automod/triggers/memberJoin.ts index 210cd8e5..a94b6b52 100644 --- a/backend/src/plugins/Automod/triggers/memberJoin.ts +++ b/backend/src/plugins/Automod/triggers/memberJoin.ts @@ -20,7 +20,7 @@ export const MemberJoinTrigger = automodTrigger()({ if (triggerConfig.only_new) { const threshold = Date.now() - convertDelayStringToMS(triggerConfig.new_threshold)!; - return context.member.createdAt >= threshold ? {} : null; + return context.member.user.createdTimestamp >= threshold ? {} : null; } return {}; diff --git a/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts b/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts index 5bda2423..3e207b1e 100644 --- a/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts +++ b/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts @@ -2,6 +2,7 @@ import { botControlCmd } from "../types"; import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { ApiPermissions } from "@shared/apiPermissions"; +import { TextChannel } from "discord.js"; export const AddDashboardUserCmd = botControlCmd({ trigger: ["add_dashboard_user"], @@ -18,7 +19,7 @@ export const AddDashboardUserCmd = botControlCmd({ async run({ pluginData, message: msg, args }) { const guild = await pluginData.state.allowedGuilds.find(args.guildId); if (!guild) { - sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin"); return; } @@ -39,7 +40,7 @@ export const AddDashboardUserCmd = botControlCmd({ ); sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `The following users were given dashboard access for **${guild.name}**:\n\n${userNameList}`, ); }, diff --git a/backend/src/plugins/BotControl/commands/AllowServerCmd.ts b/backend/src/plugins/BotControl/commands/AllowServerCmd.ts index 7d969f8f..751fdfcc 100644 --- a/backend/src/plugins/BotControl/commands/AllowServerCmd.ts +++ b/backend/src/plugins/BotControl/commands/AllowServerCmd.ts @@ -3,6 +3,7 @@ import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../.. import { commandTypeHelpers as ct } from "../../../commandTypes"; import { isSnowflake } from "../../../utils"; import { ApiPermissions } from "@shared/apiPermissions"; +import { TextChannel } from "discord.js"; export const AllowServerCmd = botControlCmd({ trigger: ["allow_server", "allowserver", "add_server", "addserver"], @@ -19,17 +20,17 @@ export const AllowServerCmd = botControlCmd({ async run({ pluginData, message: msg, args }) { const existing = await pluginData.state.allowedGuilds.find(args.guildId); if (existing) { - sendErrorMessage(pluginData, msg.channel, "Server is already allowed!"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is already allowed!"); return; } if (!isSnowflake(args.guildId)) { - sendErrorMessage(pluginData, msg.channel, "Invalid server ID!"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid server ID!"); return; } if (args.userId && !isSnowflake(args.userId)) { - sendErrorMessage(pluginData, msg.channel, "Invalid user ID!"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid user ID!"); return; } @@ -40,6 +41,6 @@ export const AllowServerCmd = botControlCmd({ await pluginData.state.apiPermissionAssignments.addUser(args.guildId, args.userId, [ApiPermissions.EditConfig]); } - sendSuccessMessage(pluginData, msg.channel, "Server is now allowed to use Zeppelin!"); + sendSuccessMessage(pluginData, msg.channel as TextChannel, "Server is now allowed to use Zeppelin!"); }, }); diff --git a/backend/src/plugins/BotControl/commands/DisallowServerCmd.ts b/backend/src/plugins/BotControl/commands/DisallowServerCmd.ts index fa882b8e..1fc4916e 100644 --- a/backend/src/plugins/BotControl/commands/DisallowServerCmd.ts +++ b/backend/src/plugins/BotControl/commands/DisallowServerCmd.ts @@ -2,6 +2,7 @@ import { botControlCmd } from "../types"; import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { noop } from "../../../utils"; +import { TextChannel } from "discord.js"; export const DisallowServerCmd = botControlCmd({ trigger: ["disallow_server", "disallowserver", "remove_server", "removeserver"], @@ -17,12 +18,15 @@ export const DisallowServerCmd = botControlCmd({ async run({ pluginData, message: msg, args }) { const existing = await pluginData.state.allowedGuilds.find(args.guildId); if (!existing) { - sendErrorMessage(pluginData, msg.channel, "That server is not allowed in the first place!"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "That server is not allowed in the first place!"); return; } await pluginData.state.allowedGuilds.remove(args.guildId); - await pluginData.client.leaveGuild(args.guildId).catch(noop); - sendSuccessMessage(pluginData, msg.channel, "Server removed!"); + await pluginData.client.guilds.cache + .get(args.guildId) + ?.leave() + .catch(noop); + sendSuccessMessage(pluginData, msg.channel as TextChannel, "Server removed!"); }, }); diff --git a/backend/src/plugins/BotControl/commands/EligibleCmd.ts b/backend/src/plugins/BotControl/commands/EligibleCmd.ts index 922b423b..ff68d1d8 100644 --- a/backend/src/plugins/BotControl/commands/EligibleCmd.ts +++ b/backend/src/plugins/BotControl/commands/EligibleCmd.ts @@ -2,6 +2,7 @@ import { botControlCmd } from "../types"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { resolveInvite, verboseUserMention } from "../../../utils"; +import { TextChannel } from "discord.js"; const REQUIRED_MEMBER_COUNT = 5000; @@ -18,7 +19,7 @@ export const EligibleCmd = botControlCmd({ if ((await pluginData.state.apiPermissionAssignments.getByUserId(args.user.id)).length) { sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `${verboseUserMention(args.user)} is an existing bot operator. They are eligible!`, ); return; @@ -26,17 +27,17 @@ export const EligibleCmd = botControlCmd({ const invite = await resolveInvite(pluginData.client, args.inviteCode, true); if (!invite || !invite.guild) { - sendErrorMessage(pluginData, msg.channel, "Could not resolve server from invite"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not resolve server from invite"); return; } if (invite.guild.features.includes("PARTNERED")) { - sendSuccessMessage(pluginData, msg.channel, `Server is partnered. It is eligible!`); + sendSuccessMessage(pluginData, msg.channel as TextChannel, `Server is partnered. It is eligible!`); return; } if (invite.guild.features.includes("VERIFIED")) { - sendSuccessMessage(pluginData, msg.channel, `Server is verified. It is eligible!`); + sendSuccessMessage(pluginData, msg.channel as TextChannel, `Server is verified. It is eligible!`); return; } @@ -44,7 +45,7 @@ export const EligibleCmd = botControlCmd({ if (memberCount >= REQUIRED_MEMBER_COUNT) { sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `Server has ${memberCount} members, which is equal or higher than the required ${REQUIRED_MEMBER_COUNT}. It is eligible!`, ); return; @@ -52,7 +53,7 @@ export const EligibleCmd = botControlCmd({ sendErrorMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `Server **${invite.guild.name}** (\`${invite.guild.id}\`) is not eligible`, ); }, diff --git a/backend/src/plugins/BotControl/commands/LeaveServerCmd.ts b/backend/src/plugins/BotControl/commands/LeaveServerCmd.ts index 51b47d1d..1d96eb96 100644 --- a/backend/src/plugins/BotControl/commands/LeaveServerCmd.ts +++ b/backend/src/plugins/BotControl/commands/LeaveServerCmd.ts @@ -1,6 +1,7 @@ import { botControlCmd } from "../types"; import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; +import { TextChannel } from "discord.js"; export const LeaveServerCmd = botControlCmd({ trigger: ["leave_server", "leave_guild"], @@ -14,21 +15,21 @@ export const LeaveServerCmd = botControlCmd({ }, async run({ pluginData, message: msg, args }) { - if (!pluginData.client.guilds.has(args.guildId)) { - sendErrorMessage(pluginData, msg.channel, "I am not in that guild"); + if (!pluginData.client.guilds.cache.has(args.guildId)) { + sendErrorMessage(pluginData, msg.channel as TextChannel, "I am not in that guild"); return; } - const guildToLeave = pluginData.client.guilds.get(args.guildId)!; + const guildToLeave = await pluginData.client.guilds.fetch(args.guildId)!; const guildName = guildToLeave.name; try { - await pluginData.client.leaveGuild(args.guildId); + await pluginData.client.guilds.cache.get(args.guildId)?.leave(); } catch (e) { - sendErrorMessage(pluginData, msg.channel, `Failed to leave guild: ${e.message}`); + sendErrorMessage(pluginData, msg.channel as TextChannel, `Failed to leave guild: ${e.message}`); return; } - sendSuccessMessage(pluginData, msg.channel, `Left guild **${guildName}**`); + sendSuccessMessage(pluginData, msg.channel as TextChannel, `Left guild **${guildName}**`); }, }); diff --git a/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts b/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts index aa047547..2933cf32 100644 --- a/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts +++ b/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts @@ -4,6 +4,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes"; import { createChunkedMessage, resolveUser } from "../../../utils"; import { AllowedGuild } from "../../../data/entities/AllowedGuild"; import { ApiPermissionAssignment } from "../../../data/entities/ApiPermissionAssignment"; +import { TextChannel } from "discord.js"; export const ListDashboardPermsCmd = botControlCmd({ trigger: ["list_dashboard_permissions", "list_dashboard_perms", "list_dash_permissionss", "list_dash_perms"], @@ -19,7 +20,7 @@ export const ListDashboardPermsCmd = botControlCmd({ async run({ pluginData, message: msg, args }) { if (!args.user && !args.guildId) { - sendErrorMessage(pluginData, msg.channel, "Must specify at least guildId, user, or both."); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Must specify at least guildId, user, or both."); return; } @@ -27,7 +28,7 @@ export const ListDashboardPermsCmd = botControlCmd({ if (args.guildId) { guild = await pluginData.state.allowedGuilds.find(args.guildId); if (!guild) { - sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin"); return; } } @@ -36,7 +37,7 @@ export const ListDashboardPermsCmd = botControlCmd({ if (args.user) { existingUserAssignment = await pluginData.state.apiPermissionAssignments.getByUserId(args.user.id); if (existingUserAssignment.length === 0) { - sendErrorMessage(pluginData, msg.channel, "The user has no assigned permissions."); + sendErrorMessage(pluginData, msg.channel as TextChannel, "The user has no assigned permissions."); return; } } @@ -59,7 +60,7 @@ export const ListDashboardPermsCmd = botControlCmd({ if (finalMessage === "") { sendErrorMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `The user ${userInfo} has no assigned permissions on the specified server.`, ); return; @@ -70,7 +71,11 @@ export const ListDashboardPermsCmd = botControlCmd({ const existingGuildAssignment = await pluginData.state.apiPermissionAssignments.getByGuildId(guild.id); if (existingGuildAssignment.length === 0) { - sendErrorMessage(pluginData, msg.channel, `The server ${guildInfo} has no assigned permissions.`); + sendErrorMessage( + pluginData, + msg.channel as TextChannel, + `The server ${guildInfo} has no assigned permissions.`, + ); return; } @@ -83,6 +88,6 @@ export const ListDashboardPermsCmd = botControlCmd({ } } - await sendSuccessMessage(pluginData, msg.channel, finalMessage.trim(), {}); + await sendSuccessMessage(pluginData, msg.channel as TextChannel, finalMessage.trim(), {}); }, }); diff --git a/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts b/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts index 5d65525b..107579b2 100644 --- a/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts +++ b/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts @@ -3,6 +3,7 @@ import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../.. import { commandTypeHelpers as ct } from "../../../commandTypes"; import { ApiPermissions } from "@shared/apiPermissions"; import { resolveUser, UnknownUser } from "../../../utils"; +import { TextChannel } from "discord.js"; export const ListDashboardUsersCmd = botControlCmd({ trigger: ["list_dashboard_users"], @@ -18,7 +19,7 @@ export const ListDashboardUsersCmd = botControlCmd({ async run({ pluginData, message: msg, args }) { const guild = await pluginData.state.allowedGuilds.find(args.guildId); if (!guild) { - sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin"); return; } @@ -30,7 +31,7 @@ export const ListDashboardUsersCmd = botControlCmd({ sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `The following users have dashboard access for **${guild.name}**:\n\n${userNameList}`, {}, ); diff --git a/backend/src/plugins/BotControl/commands/ReloadGlobalPluginsCmd.ts b/backend/src/plugins/BotControl/commands/ReloadGlobalPluginsCmd.ts index 1e341d00..8be32a5e 100644 --- a/backend/src/plugins/BotControl/commands/ReloadGlobalPluginsCmd.ts +++ b/backend/src/plugins/BotControl/commands/ReloadGlobalPluginsCmd.ts @@ -1,6 +1,7 @@ import { botControlCmd } from "../types"; import { isOwnerPreFilter } from "../../../pluginUtils"; import { getActiveReload, setActiveReload } from "../activeReload"; +import { TextChannel } from "discord.js"; export const ReloadGlobalPluginsCmd = botControlCmd({ trigger: "bot_reload_global_plugins", @@ -13,7 +14,7 @@ export const ReloadGlobalPluginsCmd = botControlCmd({ if (getActiveReload()) return; setActiveReload((message.channel as TextChannel).guild?.id, message.channel.id); - await message.channel.createMessage("Reloading global plugins..."); + await message.channel.send("Reloading global plugins..."); pluginData.getKnubInstance().reloadGlobalContext(); }, diff --git a/backend/src/plugins/BotControl/commands/ReloadServerCmd.ts b/backend/src/plugins/BotControl/commands/ReloadServerCmd.ts index 7c725e11..892ef744 100644 --- a/backend/src/plugins/BotControl/commands/ReloadServerCmd.ts +++ b/backend/src/plugins/BotControl/commands/ReloadServerCmd.ts @@ -1,6 +1,7 @@ import { botControlCmd } from "../types"; import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; +import { TextChannel } from "discord.js"; export const ReloadServerCmd = botControlCmd({ trigger: ["reload_server", "reload_guild"], @@ -14,19 +15,19 @@ export const ReloadServerCmd = botControlCmd({ }, async run({ pluginData, message: msg, args }) { - if (!pluginData.client.guilds.has(args.guildId)) { - sendErrorMessage(pluginData, msg.channel, "I am not in that guild"); + if (!pluginData.client.guilds.cache.has(args.guildId)) { + sendErrorMessage(pluginData, msg.channel as TextChannel, "I am not in that guild"); return; } try { await pluginData.getKnubInstance().reloadGuild(args.guildId); } catch (e) { - sendErrorMessage(pluginData, msg.channel, `Failed to reload guild: ${e.message}`); + sendErrorMessage(pluginData, msg.channel as TextChannel, `Failed to reload guild: ${e.message}`); return; } - const guild = pluginData.client.guilds.get(args.guildId); - sendSuccessMessage(pluginData, msg.channel, `Reloaded guild **${guild?.name || "???"}**`); + const guild = await pluginData.client.guilds.fetch(args.guildId); + sendSuccessMessage(pluginData, msg.channel as TextChannel, `Reloaded guild **${guild?.name || "???"}**`); }, }); diff --git a/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts b/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts index 078c189c..186e02a2 100644 --- a/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts +++ b/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts @@ -2,6 +2,7 @@ import { botControlCmd } from "../types"; import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { ApiPermissions } from "@shared/apiPermissions"; +import { TextChannel } from "discord.js"; export const RemoveDashboardUserCmd = botControlCmd({ trigger: ["remove_dashboard_user"], @@ -18,7 +19,7 @@ export const RemoveDashboardUserCmd = botControlCmd({ async run({ pluginData, message: msg, args }) { const guild = await pluginData.state.allowedGuilds.find(args.guildId); if (!guild) { - sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin"); return; } @@ -39,7 +40,7 @@ export const RemoveDashboardUserCmd = botControlCmd({ ); sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `The following users were removed from the dashboard for **${guild.name}**:\n\n${userNameList}`, ); }, diff --git a/backend/src/plugins/BotControl/commands/ServersCmd.ts b/backend/src/plugins/BotControl/commands/ServersCmd.ts index 7d4be31c..1d99230b 100644 --- a/backend/src/plugins/BotControl/commands/ServersCmd.ts +++ b/backend/src/plugins/BotControl/commands/ServersCmd.ts @@ -3,6 +3,7 @@ import { isOwnerPreFilter } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import escapeStringRegexp from "escape-string-regexp"; import { createChunkedMessage, getUser, sorter } from "../../../utils"; +import { TextChannel } from "discord.js"; export const ServersCmd = botControlCmd({ trigger: ["servers", "guilds"], @@ -23,7 +24,7 @@ export const ServersCmd = botControlCmd({ 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") : null; - const joinedGuilds = Array.from(pluginData.client.guilds.values()); + const joinedGuilds = Array.from(pluginData.client.guilds.cache.values()); const loadedGuilds = pluginData.getKnubInstance().getLoadedGuilds(); const loadedGuildsMap = loadedGuilds.reduce((map, guildData) => map.set(guildData.guildId, guildData), new Map()); @@ -50,16 +51,16 @@ export const ServersCmd = botControlCmd({ const owner = getUser(pluginData.client, g.ownerID); return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${owner.username}#${owner.discriminator}** \`${owner.id}\`)`; }); - createChunkedMessage(msg.channel, lines.join("\n")); + createChunkedMessage(msg.channel as TextChannel, lines.join("\n")); } else { - msg.channel.createMessage("No servers matched the filters"); + msg.channel.send("No servers matched the filters"); } } else { const total = joinedGuilds.length; const initialized = joinedGuilds.filter(g => loadedGuildsMap.has(g.id)).length; const unInitialized = total - initialized; - msg.channel.createMessage( + msg.channel.send( `I am on **${total} total servers**, of which **${initialized} are initialized** and **${unInitialized} are not initialized**`, ); } diff --git a/backend/src/plugins/Censor/util/censorMessage.ts b/backend/src/plugins/Censor/util/censorMessage.ts index 9591e81d..ad4c32ba 100644 --- a/backend/src/plugins/Censor/util/censorMessage.ts +++ b/backend/src/plugins/Censor/util/censorMessage.ts @@ -14,7 +14,7 @@ export async function censorMessage( pluginData.state.serverLogs.ignoreLog(LogType.MESSAGE_DELETE, savedMessage.id); try { - const channel = pluginData.guild.channels.resolve(savedMessage.channel_id) as TextChannel + const channel = pluginData.guild.channels.resolve(savedMessage.channel_id) as TextChannel; await channel.messages.delete(savedMessage.id); } catch { return; diff --git a/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts b/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts index b85aeb2f..faa67c18 100644 --- a/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts +++ b/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts @@ -104,6 +104,15 @@ export const ArchiveChannelCmd = channelArchiverCmd({ result += `\n\n${archiveLines.join("\n")}\n`; progressMsg.delete().catch(noop); - msg.channel.send({ content: "Archive created!", files: [{attachment: Buffer.from(result), name: `archive-${args.channel.name}-${moment.utc().format("YYYY-MM-DD-HH-mm-ss")}.txt`}], split: false }); + msg.channel.send({ + content: "Archive created!", + files: [ + { + attachment: Buffer.from(result), + name: `archive-${args.channel.name}-${moment.utc().format("YYYY-MM-DD-HH-mm-ss")}.txt`, + }, + ], + split: false, + }); }, }); diff --git a/backend/src/plugins/ChannelArchiver/rehostAttachment.ts b/backend/src/plugins/ChannelArchiver/rehostAttachment.ts index 56ef2924..bf05d122 100644 --- a/backend/src/plugins/ChannelArchiver/rehostAttachment.ts +++ b/backend/src/plugins/ChannelArchiver/rehostAttachment.ts @@ -18,7 +18,10 @@ export async function rehostAttachment(attachment: MessageAttachment, targetChan } try { - const content: MessageOptions = { content: `Rehost of attachment ${attachment.id}`, files: [{ name: attachment.name ? attachment.name : undefined, attachment: await fsp.readFile(downloaded.path)}]} + const content: MessageOptions = { + content: `Rehost of attachment ${attachment.id}`, + files: [{ name: attachment.name ? attachment.name : undefined, attachment: await fsp.readFile(downloaded.path) }], + }; const rehostMessage = await targetChannel.send({ content, split: false }); return rehostMessage.attachments.values()[0].url; } catch { diff --git a/backend/src/plugins/CompanionChannels/functions/handleCompanionPermissions.ts b/backend/src/plugins/CompanionChannels/functions/handleCompanionPermissions.ts index 022b01d7..1a338251 100644 --- a/backend/src/plugins/CompanionChannels/functions/handleCompanionPermissions.ts +++ b/backend/src/plugins/CompanionChannels/functions/handleCompanionPermissions.ts @@ -60,11 +60,9 @@ export async function handleCompanionPermissions( for (const [channelId, permissions] of permsToSet) { const channel = pluginData.guild.channels.cache.get(channelId); if (!channel || !(channel instanceof TextChannel)) continue; - await channel.updateOverwrite( - userId, - new Permissions(BigInt(permissions)).serialize(), - {reason: `Companion Channel for ${voiceChannel!.id} | User Joined`}, - ); + await channel.updateOverwrite(userId, new Permissions(BigInt(permissions)).serialize(), { + reason: `Companion Channel for ${voiceChannel!.id} | User Joined`, + }); } } catch (e) { if (isDiscordRESTError(e) && e.code === 50001) { diff --git a/backend/src/plugins/Counters/commands/AddCounterCmd.ts b/backend/src/plugins/Counters/commands/AddCounterCmd.ts index 26c4da25..779c83f0 100644 --- a/backend/src/plugins/Counters/commands/AddCounterCmd.ts +++ b/backend/src/plugins/Counters/commands/AddCounterCmd.ts @@ -128,13 +128,9 @@ export const AddCounterCmd = typedGuildCommand()({ `Added ${amount} to **${counterName}** for <@!${user.id}> in <#${channel.id}>. The value is now ${newValue}.`, ); } else if (channel) { - message.channel.send( - `Added ${amount} to **${counterName}** in <#${channel.id}>. The value is now ${newValue}.`, - ); + message.channel.send(`Added ${amount} to **${counterName}** in <#${channel.id}>. The value is now ${newValue}.`); } else if (user) { - message.channel.send( - `Added ${amount} to **${counterName}** for <@!${user.id}>. The value is now ${newValue}.`, - ); + message.channel.send(`Added ${amount} to **${counterName}** for <@!${user.id}>. The value is now ${newValue}.`); } else { message.channel.send(`Added ${amount} to **${counterName}**. The value is now ${newValue}.`); } diff --git a/backend/src/plugins/CustomEvents/actions/addRoleAction.ts b/backend/src/plugins/CustomEvents/actions/addRoleAction.ts index 1780ba60..f356e6f9 100644 --- a/backend/src/plugins/CustomEvents/actions/addRoleAction.ts +++ b/backend/src/plugins/CustomEvents/actions/addRoleAction.ts @@ -30,6 +30,6 @@ export async function addRoleAction( const rolesToAdd = Array.isArray(action.role) ? action.role : [action.role]; await target.edit({ - roles: Array.from(new Set([...target.roles, ...rolesToAdd])), + roles: Array.from(new Set([...target.roles.cache.array(), ...rolesToAdd])), }); } diff --git a/backend/src/plugins/CustomEvents/actions/messageAction.ts b/backend/src/plugins/CustomEvents/actions/messageAction.ts index bd4e6300..fe03eda0 100644 --- a/backend/src/plugins/CustomEvents/actions/messageAction.ts +++ b/backend/src/plugins/CustomEvents/actions/messageAction.ts @@ -3,6 +3,7 @@ import { CustomEventsPluginType } from "../types"; import * as t from "io-ts"; import { renderTemplate } from "../../../templateFormatter"; import { ActionError } from "../ActionError"; +import { TextChannel } from "discord.js"; export const MessageAction = t.type({ type: t.literal("message"), @@ -21,5 +22,5 @@ export async function messageAction( if (!targetChannel) throw new ActionError("Unknown target channel"); if (!(targetChannel instanceof TextChannel)) throw new ActionError("Target channel is not a text channel"); - await targetChannel.createMessage({ content: action.content }); + await targetChannel.send({ content: action.content }); } diff --git a/backend/src/plugins/CustomEvents/actions/moveToVoiceChannelAction.ts b/backend/src/plugins/CustomEvents/actions/moveToVoiceChannelAction.ts index 33636c5c..6d8f0731 100644 --- a/backend/src/plugins/CustomEvents/actions/moveToVoiceChannelAction.ts +++ b/backend/src/plugins/CustomEvents/actions/moveToVoiceChannelAction.ts @@ -5,6 +5,7 @@ import { renderTemplate } from "../../../templateFormatter"; import { resolveMember } from "../../../utils"; import { ActionError } from "../ActionError"; import { canActOn } from "../../../pluginUtils"; +import { VoiceChannel } from "discord.js"; export const MoveToVoiceChannelAction = t.type({ type: t.literal("move_to_vc"), @@ -33,8 +34,8 @@ export async function moveToVoiceChannelAction( if (!targetChannel) throw new ActionError("Unknown target channel"); if (!(targetChannel instanceof VoiceChannel)) throw new ActionError("Target channel is not a voice channel"); - if (!target.voiceState.channelID) return; + if (!target.voice.channelID) return; await target.edit({ - channelID: targetChannel.id, + channel: targetChannel.id, }); } diff --git a/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts b/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts index 48114ec0..24555c2e 100644 --- a/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts +++ b/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts @@ -30,11 +30,8 @@ export async function setChannelPermissionOverridesAction( } for (const override of action.overrides) { - await channel.editPermission( - override.id, - override.allow, - override.deny, - override.type, + await channel.overwritePermissions( + [{ id: override.id, allow: BigInt(override.allow), deny: BigInt(override.deny), type: override.type }], `Custom event: ${event.name}`, ); } diff --git a/backend/src/plugins/CustomEvents/functions/runEvent.ts b/backend/src/plugins/CustomEvents/functions/runEvent.ts index e6e909da..5a4121ac 100644 --- a/backend/src/plugins/CustomEvents/functions/runEvent.ts +++ b/backend/src/plugins/CustomEvents/functions/runEvent.ts @@ -10,6 +10,7 @@ import { messageAction } from "../actions/messageAction"; import { makeRoleMentionableAction } from "../actions/makeRoleMentionableAction"; import { makeRoleUnmentionableAction } from "../actions/makeRoleUnmentionableAction"; import { setChannelPermissionOverridesAction } from "../actions/setChannelPermissionOverrides"; +import { Message, TextChannel } from "discord.js"; export async function runEvent( pluginData: GuildPluginData, @@ -38,7 +39,7 @@ export async function runEvent( } catch (e) { if (e instanceof ActionError) { if (event.trigger.type === "command") { - sendErrorMessage(pluginData, (eventData.msg as Message).channel, e.message); + sendErrorMessage(pluginData, (eventData.msg as Message).channel as TextChannel, e.message); } else { // TODO: Where to log action errors from other kinds of triggers? } diff --git a/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts b/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts index 5689cd73..ca322168 100644 --- a/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts +++ b/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts @@ -2,6 +2,7 @@ import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint"; import { BasePluginType, typedGlobalEventListener, GlobalPluginData } from "knub"; import * as t from "io-ts"; import { AllowedGuilds } from "../../data/AllowedGuilds"; +import { Guild } from "discord.js"; interface GuildAccessMonitorPluginType extends BasePluginType { config: {}; @@ -27,7 +28,7 @@ export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin()({ - event: "guildAvailable", + event: "guildCreate", listener({ pluginData, args: { guild } }) { checkGuild(pluginData, guild); }, @@ -39,7 +40,7 @@ export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin joins or switches VC in the next ${humanizeDuration( - time, - )} i will notify you`, + `Every time <@${args.member.id}> joins or switches VC in the next ${humanizeDuration(time)} i will notify you`, ); } }, diff --git a/backend/src/plugins/LocateUser/events/SendAlertsEvts.ts b/backend/src/plugins/LocateUser/events/SendAlertsEvts.ts index f506069c..d1f5e18c 100644 --- a/backend/src/plugins/LocateUser/events/SendAlertsEvts.ts +++ b/backend/src/plugins/LocateUser/events/SendAlertsEvts.ts @@ -6,7 +6,7 @@ export const VoiceStateUpdateAlertEvt = locateUserEvt({ event: "voiceStateUpdate", async listener(meta) { - const memberId = meta.args.oldState.member ? meta.args.oldState.member.id : meta.args.newState.member!.id; + const memberId = meta.args.oldState.member ? meta.args.oldState.member.id : meta.args.newState.member!.id; if (meta.args.newState.channel != null) { if (meta.pluginData.state.usersWithAlerts.includes(memberId)) { @@ -20,8 +20,8 @@ export const VoiceStateUpdateAlertEvt = locateUserEvt({ const txtChannel = meta.pluginData.guild.channels.resolve(alert.channel_id) as TextChannel; txtChannel.send( `🔴 <@!${alert.requestor_id}> the user <@!${alert.user_id}> disconnected out of \`<#!${voiceChannel.id}>\``, - ); - }); + ); + }); } }, }); diff --git a/backend/src/plugins/LocateUser/utils/moveMember.ts b/backend/src/plugins/LocateUser/utils/moveMember.ts index 4289b2a1..6e74ae4b 100644 --- a/backend/src/plugins/LocateUser/utils/moveMember.ts +++ b/backend/src/plugins/LocateUser/utils/moveMember.ts @@ -13,7 +13,7 @@ export async function moveMember( if (modMember.voice.channelID != null) { try { await modMember.edit({ - channel: target.voice.channelID + channel: target.voice.channelID, }); } catch { sendErrorMessage(pluginData, errorChannel, "Failed to move you. Are you in a voice channel?"); diff --git a/backend/src/plugins/Logs/events/LogsVoiceChannelEvts.ts b/backend/src/plugins/Logs/events/LogsVoiceChannelEvts.ts index ef0ba7af..61ce1593 100644 --- a/backend/src/plugins/Logs/events/LogsVoiceChannelEvts.ts +++ b/backend/src/plugins/Logs/events/LogsVoiceChannelEvts.ts @@ -10,13 +10,15 @@ export const LogsVoiceStateUpdateEvt = logsEvt({ const newChannel = meta.args.newState.channel; const member = meta.args.newState.member ?? meta.args.oldState.member!; - if (!newChannel) { // Leave evt + if (!newChannel) { + // Leave evt meta.pluginData.state.guildLogs.log(LogType.VOICE_CHANNEL_LEAVE, { member: stripObjectToScalars(member, ["user", "roles"]), oldChannel: stripObjectToScalars(oldChannel), newChannel: stripObjectToScalars(newChannel), }); - } else if (!oldChannel) { // Join Evt + } else if (!oldChannel) { + // Join Evt meta.pluginData.state.guildLogs.log(LogType.VOICE_CHANNEL_JOIN, { member: stripObjectToScalars(member, ["user", "roles"]), oldChannel: stripObjectToScalars(oldChannel), @@ -29,6 +31,5 @@ export const LogsVoiceStateUpdateEvt = logsEvt({ newChannel: stripObjectToScalars(newChannel), }); } - }, }); diff --git a/backend/src/plugins/MessageSaver/commands/SavePinsToDB.ts b/backend/src/plugins/MessageSaver/commands/SavePinsToDB.ts index 5d9484ed..a159a642 100644 --- a/backend/src/plugins/MessageSaver/commands/SavePinsToDB.ts +++ b/backend/src/plugins/MessageSaver/commands/SavePinsToDB.ts @@ -16,11 +16,7 @@ export const SavePinsToDBCmd = messageSaverCmd({ await msg.channel.send(`Saving pins from <#${args.channel.id}>...`); const pins = await args.channel.messages.fetchPinned(); - const { savedCount, failed } = await saveMessagesToDB( - pluginData, - args.channel, - pins.keyArray(), - ); + const { savedCount, failed } = await saveMessagesToDB(pluginData, args.channel, pins.keyArray()); if (failed.length) { sendSuccessMessage( diff --git a/backend/src/plugins/ModActions/ModActionsPlugin.ts b/backend/src/plugins/ModActions/ModActionsPlugin.ts index 499f8176..f0a51c69 100644 --- a/backend/src/plugins/ModActions/ModActionsPlugin.ts +++ b/backend/src/plugins/ModActions/ModActionsPlugin.ts @@ -45,6 +45,7 @@ import { onModActionsEvent } from "./functions/onModActionsEvent"; import { offModActionsEvent } from "./functions/offModActionsEvent"; import { updateCase } from "./functions/updateCase"; import { Queue } from "../../Queue"; +import { GuildMember, Message } from "discord.js"; const defaultOptions = { config: { @@ -158,13 +159,13 @@ export const ModActionsPlugin = zeppelinGuildPlugin()({ public: { warnMember(pluginData) { - return (member: Member, reason: string, warnOptions?: WarnOptions) => { + return (member: GuildMember, reason: string, warnOptions?: WarnOptions) => { warnMember(pluginData, member, reason, warnOptions); }; }, kickMember(pluginData) { - return (member: Member, reason: string, kickOptions?: KickOptions) => { + return (member: GuildMember, reason: string, kickOptions?: KickOptions) => { kickMember(pluginData, member, reason, kickOptions); }; }, diff --git a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts index 6e0caf16..7f2a551d 100644 --- a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts +++ b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts @@ -59,7 +59,7 @@ export const AddCaseCmd = modActionsCmd({ return; } - const reason = formatReasonWithAttachments(args.reason, msg.attachments); + const reason = formatReasonWithAttachments(args.reason, msg.attachments.array()); // Create the case const casesPlugin = pluginData.getPlugin(CasesPlugin); diff --git a/backend/src/plugins/ModActions/commands/BanCmd.ts b/backend/src/plugins/ModActions/commands/BanCmd.ts index 71f61310..f8cb4ff9 100644 --- a/backend/src/plugins/ModActions/commands/BanCmd.ts +++ b/backend/src/plugins/ModActions/commands/BanCmd.ts @@ -6,7 +6,7 @@ import { isBanned } from "../functions/isBanned"; import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { banUserId } from "../functions/banUserId"; -import { getMemberLevel, waitForReaction } from "knub/dist/helpers"; +import { getMemberLevel } from "knub/dist/helpers"; import humanizeDuration from "humanize-duration"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { CaseTypes } from "../../../data/CaseTypes"; @@ -49,7 +49,7 @@ export const BanCmd = modActionsCmd({ } const time = args["time"] ? args["time"] : null; - const reason = formatReasonWithAttachments(args.reason, msg.attachments); + const reason = formatReasonWithAttachments(args.reason, msg.attachments.array()); const memberToBan = await resolveMember(pluginData.client, pluginData.guild, user.id); // The moderator who did the action is the message author or, if used, the specified -mod let mod = msg.member; @@ -76,11 +76,11 @@ export const BanCmd = modActionsCmd({ } // Ask the mod if we should update the existing ban - const alreadyBannedMsg = await msg.channel.createMessage("User is already banned, update ban?"); - const reply = await waitForReaction(pluginData.client, alreadyBannedMsg, ["✅", "❌"], msg.author.id); + const alreadyBannedMsg = await msg.channel.send("User is already banned, update ban?"); + const reply = false; // await waitForReaction(pluginData.client, alreadyBannedMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton alreadyBannedMsg.delete().catch(noop); - if (!reply || reply.name === "❌") { + if (!reply /* || reply.name === "❌"*/) { sendErrorMessage(pluginData, msg.channel, "User already banned, update cancelled by moderator"); lock.unlock(); return; @@ -124,11 +124,11 @@ export const BanCmd = modActionsCmd({ } } else { // Ask the mod if we should upgrade to a forceban as the user is not on the server - const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forceban instead?"); - const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); + const notOnServerMsg = await msg.channel.send("User not found on the server, forceban instead?"); + const reply = false; // await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); Waiting for waitForButton notOnServerMsg.delete().catch(noop); - if (!reply || reply.name === "❌") { + if (!reply /*|| reply.name === "❌"*/) { sendErrorMessage(pluginData, msg.channel, "User not on server, ban cancelled by moderator"); lock.unlock(); return; diff --git a/backend/src/plugins/ModActions/commands/CaseCmd.ts b/backend/src/plugins/ModActions/commands/CaseCmd.ts index ff5932c5..6c50d4c8 100644 --- a/backend/src/plugins/ModActions/commands/CaseCmd.ts +++ b/backend/src/plugins/ModActions/commands/CaseCmd.ts @@ -24,6 +24,6 @@ export const CaseCmd = modActionsCmd({ const casesPlugin = pluginData.getPlugin(CasesPlugin); const embed = await casesPlugin.getCaseEmbed(theCase.id, msg.author.id); - msg.channel.createMessage(embed); + msg.channel.send(embed); }, }); diff --git a/backend/src/plugins/ModActions/commands/CasesModCmd.ts b/backend/src/plugins/ModActions/commands/CasesModCmd.ts index 8a4d7d79..49bbc937 100644 --- a/backend/src/plugins/ModActions/commands/CasesModCmd.ts +++ b/backend/src/plugins/ModActions/commands/CasesModCmd.ts @@ -9,6 +9,7 @@ import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields"; import { getDefaultPrefix } from "knub/dist/commands/commandUtils"; import { getGuildPrefix } from "../../../utils/getGuildPrefix"; import { createPaginatedMessage } from "../../../utils/createPaginatedMessage"; +import { MessageEmbedOptions, User } from "discord.js"; const opts = { mod: ct.userId({ option: true }), @@ -55,10 +56,10 @@ export const CasesModCmd = modActionsCmd({ const lastCaseNum = page * casesPerPage; const title = `Most recent cases ${firstCaseNum}-${lastCaseNum} of ${totalCases} by ${modName}`; - const embed: EmbedOptions = { + const embed: MessageEmbedOptions = { author: { name: title, - icon_url: mod instanceof User ? mod.avatarURL || mod.defaultAvatarURL : undefined, + iconURL: mod instanceof User ? mod.avatarURL() || mod.defaultAvatarURL : undefined, }, fields: [ ...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")), diff --git a/backend/src/plugins/ModActions/commands/CasesUserCmd.ts b/backend/src/plugins/ModActions/commands/CasesUserCmd.ts index 8cfade7a..7fa4f499 100644 --- a/backend/src/plugins/ModActions/commands/CasesUserCmd.ts +++ b/backend/src/plugins/ModActions/commands/CasesUserCmd.ts @@ -16,6 +16,7 @@ import { getGuildPrefix } from "../../../utils/getGuildPrefix"; import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields"; import { asyncMap } from "../../../utils/async"; import { CaseTypes } from "../../../data/CaseTypes"; +import { MessageEmbedOptions, User } from "discord.js"; const opts = { expand: ct.bool({ option: true, isSwitch: true, shortcut: "e" }), @@ -75,13 +76,13 @@ export const CasesUserCmd = modActionsCmd({ : `${user.username}#${user.discriminator}`; if (cases.length === 0) { - msg.channel.createMessage(`No cases found for **${userName}**`); + msg.channel.send(`No cases found for **${userName}**`); } else { const casesToDisplay = args.hidden ? cases : normalCases; if (args.expand) { if (casesToDisplay.length > 8) { - msg.channel.createMessage("Too many cases for expanded view. Please use compact view instead."); + msg.channel.send("Too many cases for expanded view. Please use compact view instead."); return; } @@ -89,7 +90,7 @@ export const CasesUserCmd = modActionsCmd({ const casesPlugin = pluginData.getPlugin(CasesPlugin); for (const theCase of casesToDisplay) { const embed = await casesPlugin.getCaseEmbed(theCase.id); - msg.channel.createMessage(embed); + msg.channel.send(embed); } } else { // Compact view (= regular message with a preview of each case) @@ -121,13 +122,13 @@ export const CasesUserCmd = modActionsCmd({ const chunkStart = i * linesPerChunk + 1; const chunkEnd = Math.min((i + 1) * linesPerChunk, lines.length); - const embed: EmbedOptions = { + const embed: MessageEmbedOptions = { author: { name: lineChunks.length === 1 ? `Cases for ${userName} (${lines.length} total)` : `Cases ${chunkStart}–${chunkEnd} of ${lines.length} for ${userName}`, - icon_url: user instanceof User ? user.avatarURL || user.defaultAvatarURL : undefined, + icon_url: user instanceof User ? user.avatarURL() || user.defaultAvatarURL : undefined, }, fields: [ ...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")), @@ -135,7 +136,7 @@ export const CasesUserCmd = modActionsCmd({ ], }; - msg.channel.createMessage({ embed }); + msg.channel.send({ embed }); } } } diff --git a/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts b/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts index 1756b2b7..ecda9c25 100644 --- a/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts +++ b/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts @@ -10,6 +10,7 @@ import { LogType } from "../../../data/LogType"; import moment from "moment-timezone"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; import { Case } from "../../../data/entities/Case"; +import { TextChannel } from "discord.js"; export const DeleteCaseCmd = modActionsCmd({ trigger: ["delete_case", "deletecase"], @@ -49,7 +50,7 @@ export const DeleteCaseCmd = modActionsCmd({ if (!args.force) { const cases = pluginData.getPlugin(CasesPlugin); const embedContent = await cases.getCaseEmbed(theCase); - message.channel.createMessage({ + message.channel.send({ content: "Delete the following case? Answer 'Yes' to continue, 'No' to cancel.", embed: embedContent.embed, }); @@ -62,7 +63,7 @@ export const DeleteCaseCmd = modActionsCmd({ ); const normalizedReply = (reply?.content || "").toLowerCase().trim(); if (normalizedReply !== "yes" && normalizedReply !== "y") { - message.channel.createMessage("Cancelled. Case was not deleted."); + message.channel.send("Cancelled. Case was not deleted."); cancelled++; continue; } diff --git a/backend/src/plugins/ModActions/commands/ForcebanCmd.ts b/backend/src/plugins/ModActions/commands/ForcebanCmd.ts index cdbbbc97..6ba06b74 100644 --- a/backend/src/plugins/ModActions/commands/ForcebanCmd.ts +++ b/backend/src/plugins/ModActions/commands/ForcebanCmd.ts @@ -61,14 +61,17 @@ export const ForcebanCmd = modActionsCmd({ mod = args.mod; } - const reason = formatReasonWithAttachments(args.reason, msg.attachments); + const reason = formatReasonWithAttachments(args.reason, msg.attachments.array()); ignoreEvent(pluginData, IgnoredEventType.Ban, user.id); pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, user.id); try { // FIXME: Use banUserId()? - await pluginData.guild.banMember(user.id, 1, reason != null ? encodeURIComponent(reason) : undefined); + await pluginData.guild.bans.create(user.id, { + days: 1, + reason: reason != null ? encodeURIComponent(reason) : undefined, + }); } catch { sendErrorMessage(pluginData, msg.channel, "Failed to forceban member"); return; diff --git a/backend/src/plugins/ModActions/commands/MassBanCmd.ts b/backend/src/plugins/ModActions/commands/MassBanCmd.ts index 73b93174..758dd268 100644 --- a/backend/src/plugins/ModActions/commands/MassBanCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassBanCmd.ts @@ -15,6 +15,7 @@ import { LogType } from "../../../data/LogType"; import { performance } from "perf_hooks"; import { humanizeDurationShort } from "../../../humanizeDurationShort"; import { load } from "js-yaml"; +import { TextChannel } from "discord.js"; export const MassbanCmd = modActionsCmd({ trigger: "massban", @@ -35,14 +36,14 @@ export const MassbanCmd = modActionsCmd({ } // Ask for ban reason (cleaner this way instead of trying to cram it into the args) - msg.channel.createMessage("Ban reason? `cancel` to cancel"); + msg.channel.send("Ban reason? `cancel` to cancel"); const banReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id); if (!banReasonReply || !banReasonReply.content || banReasonReply.content.toLowerCase().trim() === "cancel") { sendErrorMessage(pluginData, msg.channel, "Cancelled"); return; } - const banReason = formatReasonWithAttachments(banReasonReply.content, msg.attachments); + const banReason = formatReasonWithAttachments(banReasonReply.content, msg.attachments.array()); // Verify we can act on each of the users specified for (const userId of args.userIds) { @@ -60,7 +61,7 @@ export const MassbanCmd = modActionsCmd({ pluginData.state.massbanQueue.length === 0 ? "Banning..." : `Massban queued. Waiting for previous massban to finish (max wait ${maxWaitTimeFormatted}).`; - const loadingMsg = await msg.channel.createMessage(initialLoadingText); + const loadingMsg = await msg.channel.send(initialLoadingText); const waitTimeStart = performance.now(); const waitingInterval = setInterval(() => { @@ -95,7 +96,10 @@ export const MassbanCmd = modActionsCmd({ ignoreEvent(pluginData, IgnoredEventType.Ban, userId, 120 * 1000); pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000); - await pluginData.guild.banMember(userId, 1, banReason != null ? encodeURIComponent(banReason) : undefined); + await pluginData.guild.bans.create(userId, { + days: 1, + reason: banReason != null ? encodeURIComponent(banReason) : undefined, + }); await casesPlugin.createCase({ userId, diff --git a/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts b/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts index ac0b3f39..d4673dbf 100644 --- a/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts @@ -10,6 +10,7 @@ import { waitForReply } from "knub/dist/helpers"; import { ignoreEvent } from "../functions/ignoreEvent"; import { CasesPlugin } from "../../Cases/CasesPlugin"; import { LogType } from "../../../data/LogType"; +import { TextChannel } from "discord.js"; export const MassunbanCmd = modActionsCmd({ trigger: "massunban", @@ -30,14 +31,14 @@ export const MassunbanCmd = modActionsCmd({ } // Ask for unban reason (cleaner this way instead of trying to cram it into the args) - msg.channel.createMessage("Unban reason? `cancel` to cancel"); + msg.channel.send("Unban reason? `cancel` to cancel"); const unbanReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id); if (!unbanReasonReply || !unbanReasonReply.content || unbanReasonReply.content.toLowerCase().trim() === "cancel") { sendErrorMessage(pluginData, msg.channel, "Cancelled"); return; } - const unbanReason = formatReasonWithAttachments(unbanReasonReply.content, msg.attachments); + const unbanReason = formatReasonWithAttachments(unbanReasonReply.content, msg.attachments.array()); // Ignore automatic unban cases and logs for these users // We'll create our own cases below and post a single "mass unbanned" log instead @@ -48,7 +49,7 @@ export const MassunbanCmd = modActionsCmd({ }); // Show a loading indicator since this can take a while - const loadingMsg = await msg.channel.createMessage("Unbanning..."); + const loadingMsg = await msg.channel.send("Unbanning..."); // Unban each user and count failed unbans (if any) const failedUnbans: Array<{ userId: string; reason: UnbanFailReasons }> = []; @@ -60,7 +61,7 @@ export const MassunbanCmd = modActionsCmd({ } try { - await pluginData.guild.unbanMember(userId, unbanReason != null ? encodeURIComponent(unbanReason) : undefined); + await pluginData.guild.bans.remove(userId, unbanReason != null ? encodeURIComponent(unbanReason) : undefined); await casesPlugin.createCase({ userId, diff --git a/backend/src/plugins/ModActions/commands/MassmuteCmd.ts b/backend/src/plugins/ModActions/commands/MassmuteCmd.ts index eeceabd3..15c2e90f 100644 --- a/backend/src/plugins/ModActions/commands/MassmuteCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassmuteCmd.ts @@ -8,6 +8,7 @@ import { waitForReply } from "knub/dist/helpers"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin"; +import { TextChannel } from "discord.js"; export const MassmuteCmd = modActionsCmd({ trigger: "massmute", @@ -28,7 +29,7 @@ export const MassmuteCmd = modActionsCmd({ } // Ask for mute reason - msg.channel.createMessage("Mute reason? `cancel` to cancel"); + msg.channel.send("Mute reason? `cancel` to cancel"); const muteReasonReceived = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id); if ( !muteReasonReceived || @@ -39,7 +40,7 @@ export const MassmuteCmd = modActionsCmd({ return; } - const muteReason = formatReasonWithAttachments(muteReasonReceived.content, msg.attachments); + const muteReason = formatReasonWithAttachments(muteReasonReceived.content, msg.attachments.array()); // Verify we can act upon all users for (const userId of args.userIds) { @@ -58,7 +59,7 @@ export const MassmuteCmd = modActionsCmd({ }); // Show loading indicator - const loadingMsg = await msg.channel.createMessage("Muting..."); + const loadingMsg = await msg.channel.send("Muting..."); // Mute everyone and count fails const modId = msg.author.id; diff --git a/backend/src/plugins/ModActions/commands/MuteCmd.ts b/backend/src/plugins/ModActions/commands/MuteCmd.ts index c8336aae..67f5ce71 100644 --- a/backend/src/plugins/ModActions/commands/MuteCmd.ts +++ b/backend/src/plugins/ModActions/commands/MuteCmd.ts @@ -1,16 +1,8 @@ import { modActionsCmd } from "../types"; import { commandTypeHelpers as ct } from "../../../commandTypes"; -import { Case } from "../../../data/entities/Case"; -import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; -import { CasesPlugin } from "../../Cases/CasesPlugin"; -import { LogType } from "../../../data/LogType"; -import { CaseTypes } from "../../../data/CaseTypes"; -import { errorMessage, noop, resolveMember, resolveUser, stripObjectToScalars } from "../../../utils"; +import { canActOn, sendErrorMessage } from "../../../pluginUtils"; +import { noop, resolveMember, resolveUser } from "../../../utils"; import { isBanned } from "../functions/isBanned"; -import { waitForReaction } from "knub/dist/helpers"; -import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs"; -import { warnMember } from "../functions/warnMember"; import { actualMuteUserCmd } from "../functions/actualMuteUserCmd"; @@ -62,11 +54,11 @@ export const MuteCmd = modActionsCmd({ return; } else { // Ask the mod if we should upgrade to a forcemute as the user is not on the server - const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forcemute instead?"); - const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); + const notOnServerMsg = await msg.channel.send("User not found on the server, forcemute instead?"); + const reply = false; // await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton notOnServerMsg.delete().catch(noop); - if (!reply || reply.name === "❌") { + if (!reply /*|| reply.name === "❌"*/) { sendErrorMessage(pluginData, msg.channel, "User not on server, mute cancelled by moderator"); return; } diff --git a/backend/src/plugins/ModActions/commands/NoteCmd.ts b/backend/src/plugins/ModActions/commands/NoteCmd.ts index af6a1298..4b31954d 100644 --- a/backend/src/plugins/ModActions/commands/NoteCmd.ts +++ b/backend/src/plugins/ModActions/commands/NoteCmd.ts @@ -25,13 +25,13 @@ export const NoteCmd = modActionsCmd({ return; } - if (!args.note && msg.attachments.length === 0) { + if (!args.note && msg.attachments.size === 0) { sendErrorMessage(pluginData, msg.channel, "Text or attachment required"); return; } const userName = `${user.username}#${user.discriminator}`; - const reason = formatReasonWithAttachments(args.note, msg.attachments); + const reason = formatReasonWithAttachments(args.note, msg.attachments.array()); const casesPlugin = pluginData.getPlugin(CasesPlugin); const createdCase = await casesPlugin.createCase({ diff --git a/backend/src/plugins/ModActions/commands/SoftbanCommand.ts b/backend/src/plugins/ModActions/commands/SoftbanCommand.ts index 8105aae3..ea768f09 100644 --- a/backend/src/plugins/ModActions/commands/SoftbanCommand.ts +++ b/backend/src/plugins/ModActions/commands/SoftbanCommand.ts @@ -28,7 +28,7 @@ export const SoftbanCmd = modActionsCmd({ async run({ pluginData, message: msg, args }) { await actualKickMemberCmd(pluginData, msg, { clean: true, ...args }); - await msg.channel.createMessage( + await msg.channel.send( "Softban will be removed in the future - please use the kick command with the `-clean` argument instead!", ); }, diff --git a/backend/src/plugins/ModActions/commands/UnbanCmd.ts b/backend/src/plugins/ModActions/commands/UnbanCmd.ts index c3016a9b..ada9c975 100644 --- a/backend/src/plugins/ModActions/commands/UnbanCmd.ts +++ b/backend/src/plugins/ModActions/commands/UnbanCmd.ts @@ -45,11 +45,11 @@ export const UnbanCmd = modActionsCmd({ } pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, user.id); - const reason = formatReasonWithAttachments(args.reason, msg.attachments); + const reason = formatReasonWithAttachments(args.reason, msg.attachments.array()); try { ignoreEvent(pluginData, IgnoredEventType.Unban, user.id); - await pluginData.guild.unbanMember(user.id, reason != null ? encodeURIComponent(reason) : undefined); + await pluginData.guild.bans.remove(user.id, reason != null ? encodeURIComponent(reason) : undefined); } catch { sendErrorMessage(pluginData, msg.channel, "Failed to unban member; are you sure they're banned?"); return; diff --git a/backend/src/plugins/ModActions/commands/UnmuteCmd.ts b/backend/src/plugins/ModActions/commands/UnmuteCmd.ts index c294517c..53cc6728 100644 --- a/backend/src/plugins/ModActions/commands/UnmuteCmd.ts +++ b/backend/src/plugins/ModActions/commands/UnmuteCmd.ts @@ -5,7 +5,6 @@ import { resolveUser, resolveMember, noop } from "../../../utils"; import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin"; import { actualUnmuteCmd } from "../functions/actualUnmuteUserCmd"; import { isBanned } from "../functions/isBanned"; -import { waitForReaction } from "knub/dist/helpers"; const opts = { mod: ct.member({ option: true }), @@ -61,11 +60,11 @@ export const UnmuteCmd = modActionsCmd({ return; } else { // Ask the mod if we should upgrade to a forceunmute as the user is not on the server - const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forceunmute instead?"); - const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); + const notOnServerMsg = await msg.channel.send("User not found on the server, forceunmute instead?"); + const reply = false; //await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton notOnServerMsg.delete().catch(noop); - if (!reply || reply.name === "❌") { + if (!reply /*|| reply.name === "❌"*/) { sendErrorMessage(pluginData, msg.channel, "User not on server, unmute cancelled by moderator"); return; } diff --git a/backend/src/plugins/ModActions/commands/WarnCmd.ts b/backend/src/plugins/ModActions/commands/WarnCmd.ts index 22e4e660..9f347c97 100644 --- a/backend/src/plugins/ModActions/commands/WarnCmd.ts +++ b/backend/src/plugins/ModActions/commands/WarnCmd.ts @@ -8,9 +8,9 @@ import { LogType } from "../../../data/LogType"; import { CaseTypes } from "../../../data/CaseTypes"; import { errorMessage, resolveMember, resolveUser, stripObjectToScalars } from "../../../utils"; import { isBanned } from "../functions/isBanned"; -import { waitForReaction } from "knub/dist/helpers"; import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs"; import { warnMember } from "../functions/warnMember"; +import { TextChannel } from "discord.js"; export const WarnCmd = modActionsCmd({ trigger: "warn", @@ -56,7 +56,7 @@ export const WarnCmd = modActionsCmd({ let mod = msg.member; if (args.mod) { if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) { - msg.channel.createMessage(errorMessage("You don't have permission to use -mod")); + msg.channel.send(errorMessage("You don't have permission to use -mod")); return; } @@ -64,19 +64,19 @@ export const WarnCmd = modActionsCmd({ } const config = pluginData.config.get(); - const reason = formatReasonWithAttachments(args.reason, msg.attachments); + const reason = formatReasonWithAttachments(args.reason, msg.attachments.array()); const casesPlugin = pluginData.getPlugin(CasesPlugin); const priorWarnAmount = await casesPlugin.getCaseTypeAmountForUserId(memberToWarn.id, CaseTypes.Warn); if (config.warn_notify_enabled && priorWarnAmount >= config.warn_notify_threshold) { - const tooManyWarningsMsg = await msg.channel.createMessage( + const tooManyWarningsMsg = await msg.channel.send( config.warn_notify_message.replace("{priorWarnings}", `${priorWarnAmount}`), ); - const reply = await waitForReaction(pluginData.client, tooManyWarningsMsg, ["✅", "❌"], msg.author.id); + const reply = false; //await waitForReaction(pluginData.client, tooManyWarningsMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton tooManyWarningsMsg.delete(); - if (!reply || reply.name === "❌") { - msg.channel.createMessage(errorMessage("Warn cancelled by moderator")); + if (!reply /*|| reply.name === "❌"*/) { + msg.channel.send(errorMessage("Warn cancelled by moderator")); return; } } diff --git a/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts b/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts index 1d206a7c..cc9b975c 100644 --- a/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts +++ b/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts @@ -8,6 +8,7 @@ import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAu import { LogType } from "../../../data/LogType"; import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils"; import { Case } from "../../../data/entities/Case"; +import { GuildAuditLogs, User } from "discord.js"; /** * Create a BAN case automatically when a user is banned manually. @@ -15,7 +16,8 @@ import { Case } from "../../../data/entities/Case"; */ export const CreateBanCaseOnManualBanEvt = modActionsEvt({ event: "guildBanAdd", - async listener({ pluginData, args: { guild, user } }) { + async listener({ pluginData, args: { ban } }) { + const user = ban.user; if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) { clearIgnoredEvents(pluginData, IgnoredEventType.Ban, user.id); return; @@ -23,7 +25,7 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt({ const relevantAuditLogEntry = await safeFindRelevantAuditLogEntry( pluginData, - ErisConstants.AuditLogActions.MEMBER_BAN_ADD, + GuildAuditLogs.Actions.MEMBER_BAN_ADD as number, user.id, ); @@ -34,7 +36,7 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt({ let reason = ""; if (relevantAuditLogEntry) { - const modId = relevantAuditLogEntry.user.id; + const modId = relevantAuditLogEntry.executor!.id; const auditLogId = relevantAuditLogEntry.id; mod = await resolveUser(pluginData.client, modId); diff --git a/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts b/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts index 07d9f01f..3229058d 100644 --- a/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts +++ b/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts @@ -9,6 +9,7 @@ import { LogType } from "../../../data/LogType"; import { resolveUser, stripObjectToScalars, UnknownUser } from "../../../utils"; import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry"; import { Case } from "../../../data/entities/Case"; +import { GuildAuditLogs, User } from "discord.js"; /** * Create a KICK case automatically when a user is kicked manually. @@ -24,7 +25,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({ const kickAuditLogEntry = await safeFindRelevantAuditLogEntry( pluginData, - ErisConstants.AuditLogActions.MEMBER_KICK, + GuildAuditLogs.Actions.MEMBER_KICK as number, member.id, ); @@ -40,7 +41,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({ `Tried to create duplicate case for audit log entry ${kickAuditLogEntry.id}, existing case id ${createdCase.id}`, ); } else { - mod = await resolveUser(pluginData.client, kickAuditLogEntry.user.id); + mod = await resolveUser(pluginData.client, kickAuditLogEntry.executor!.id); const config = mod instanceof UnknownUser ? pluginData.config.get() : await pluginData.config.getForUser(mod); @@ -48,7 +49,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({ const casesPlugin = pluginData.getPlugin(CasesPlugin); createdCase = await casesPlugin.createCase({ userId: member.id, - modId: kickAuditLogEntry.user.id, + modId: mod.id, type: CaseTypes.Kick, auditLogId: kickAuditLogEntry.id, reason: kickAuditLogEntry.reason || undefined, diff --git a/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts b/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts index 00d21ab2..5d684e97 100644 --- a/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts +++ b/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts @@ -8,6 +8,7 @@ import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAu import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils"; import { LogType } from "../../../data/LogType"; import { Case } from "../../../data/entities/Case"; +import { GuildAuditLogs, User } from "discord.js"; /** * Create an UNBAN case automatically when a user is unbanned manually. @@ -15,7 +16,8 @@ import { Case } from "../../../data/entities/Case"; */ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({ event: "guildBanRemove", - async listener({ pluginData, args: { guild, user } }) { + async listener({ pluginData, args: { ban } }) { + const user = ban.user; if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) { clearIgnoredEvents(pluginData, IgnoredEventType.Unban, user.id); return; @@ -23,7 +25,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({ const relevantAuditLogEntry = await safeFindRelevantAuditLogEntry( pluginData, - ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE, + GuildAuditLogs.Actions.MEMBER_BAN_REMOVE as number, user.id, ); @@ -33,7 +35,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({ let mod: User | UnknownUser | null = null; if (relevantAuditLogEntry) { - const modId = relevantAuditLogEntry.user.id; + const modId = relevantAuditLogEntry.executor!.id; const auditLogId = relevantAuditLogEntry.id; mod = await resolveUser(pluginData.client, modId); diff --git a/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts b/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts index cef6c2e5..d13ecef4 100644 --- a/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts +++ b/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts @@ -4,13 +4,14 @@ import { LogType } from "../../../data/LogType"; import { resolveMember } from "../../../utils"; import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions"; +import { TextChannel, Constants, Permissions } from "discord.js"; /** * Show an alert if a member with prior notes joins the server */ export const PostAlertOnMemberJoinEvt = modActionsEvt({ event: "guildMemberAdd", - async listener({ pluginData, args: { guild, member } }) { + async listener({ pluginData, args: { member } }) { const config = pluginData.config.get(); if (!config.alert_on_rejoin) return; @@ -38,15 +39,15 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt({ } const botMember = await resolveMember(pluginData.client, pluginData.guild, pluginData.client.user!.id); - const botPerms = alertChannel.permissionsOf(botMember ?? pluginData.client.user!.id); - if (!hasDiscordPermissions(botPerms, Constants.Permissions.sendMessages)) { + const botPerms = alertChannel.permissionsFor(botMember ?? pluginData.client.user!.id); + if (!hasDiscordPermissions(botPerms, Permissions.FLAGS.SEND_MESSAGES)) { logs.log(LogType.BOT_ALERT, { body: `Missing "Send Messages" permissions for the \`alert_channel\` configured in \`mod_actions\`: \`${alertChannelId}\``, }); return; } - await alertChannel.createMessage( + await alertChannel.send( `<@!${member.id}> (${member.user.username}#${member.user.discriminator} \`${member.id}\`) joined with ${actions.length} prior record(s)`, ); } diff --git a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts index 906cc375..290996b0 100644 --- a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts @@ -9,6 +9,7 @@ import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; import { kickMember } from "./kickMember"; import { ignoreEvent } from "./ignoreEvent"; import { isBanned } from "./isBanned"; +import { GuildMember, TextChannel } from "discord.js"; export async function actualKickMemberCmd( pluginData: GuildPluginData, @@ -16,7 +17,7 @@ export async function actualKickMemberCmd( args: { user: string; reason: string; - mod: Member; + mod: GuildMember; notify?: string; "notify-channel"?: TextChannel; clean?: boolean; @@ -81,7 +82,7 @@ export async function actualKickMemberCmd( ignoreEvent(pluginData, IgnoredEventType.Ban, memberToKick.id); try { - await memberToKick.ban(1, encodeURIComponent("kick -clean")); + await memberToKick.ban({ days: 1, reason: encodeURIComponent("kick -clean") }); } catch { sendErrorMessage(pluginData, msg.channel, "Failed to ban the user to clean messages (-clean)"); } @@ -90,14 +91,14 @@ export async function actualKickMemberCmd( ignoreEvent(pluginData, IgnoredEventType.Unban, memberToKick.id); try { - await pluginData.guild.unbanMember(memberToKick.id, encodeURIComponent("kick -clean")); + await pluginData.guild.bans.remove(memberToKick.id, encodeURIComponent("kick -clean")); } catch { sendErrorMessage(pluginData, msg.channel, "Failed to unban the user after banning them (-clean)"); } } if (kickResult.status === "failed") { - msg.channel.createMessage(errorMessage(`Failed to kick user`)); + msg.channel.send(errorMessage(`Failed to kick user`)); return; } diff --git a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts index bbf2ac99..203913b0 100644 --- a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts @@ -9,6 +9,7 @@ import { MutesPlugin } from "../../Mutes/MutesPlugin"; import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; import { logger } from "../../../logger"; +import { User, Message, TextChannel, GuildMember } from "discord.js"; /** * The actual function run by both !mute and !forcemute. @@ -17,16 +18,16 @@ import { logger } from "../../../logger"; export async function actualMuteUserCmd( pluginData: GuildPluginData, user: User | UnknownUser, - msg: Message, - args: { time?: number; reason?: string; mod: Member; notify?: string; "notify-channel"?: TextChannel }, + msg: Message, + args: { time?: number; reason?: string; mod: GuildMember; notify?: string; "notify-channel"?: TextChannel }, ) { // The moderator who did the action is the message author or, if used, the specified -mod - let mod: Member = msg.member; + let mod: GuildMember = msg.member!; let pp: User | null = null; if (args.mod) { if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) { - sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "You don't have permission to use -mod"); return; } @@ -35,7 +36,7 @@ export async function actualMuteUserCmd( } const timeUntilUnmute = args.time && humanizeDuration(args.time); - const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments) : undefined; + const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments.array()) : undefined; let muteResult: MuteResult; const mutesPlugin = pluginData.getPlugin(MutesPlugin); @@ -44,7 +45,7 @@ export async function actualMuteUserCmd( try { contactMethods = readContactMethodsFromArgs(args); } catch (e) { - sendErrorMessage(pluginData, msg.channel, e.message); + sendErrorMessage(pluginData, msg.channel as TextChannel, e.message); return; } @@ -58,16 +59,16 @@ export async function actualMuteUserCmd( }); } catch (e) { if (e instanceof RecoverablePluginError && e.code === ERRORS.NO_MUTE_ROLE_IN_CONFIG) { - sendErrorMessage(pluginData, msg.channel, "Could not mute the user: no mute role set in config"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not mute the user: no mute role set in config"); } else if (isDiscordRESTError(e) && e.code === 10007) { - sendErrorMessage(pluginData, msg.channel, "Could not mute the user: unknown member"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not mute the user: unknown member"); } else { logger.error(`Failed to mute user ${user.id}: ${e.stack}`); if (user.id == null) { // tslint-disable-next-line:no-console console.trace("[DEBUG] Null user.id for mute"); } - sendErrorMessage(pluginData, msg.channel, "Could not mute the user"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not mute the user"); } return; @@ -102,5 +103,5 @@ export async function actualMuteUserCmd( } if (muteResult.notifyResult.text) response += ` (${muteResult.notifyResult.text})`; - sendSuccessMessage(pluginData, msg.channel, response); + sendSuccessMessage(pluginData, msg.channel as TextChannel, response); } diff --git a/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts index badfccd5..72950b82 100644 --- a/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts @@ -6,12 +6,13 @@ import { sendErrorMessage, sendSuccessMessage, hasPermission } from "../../../pl import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin"; import humanizeDuration from "humanize-duration"; +import { User, Message, GuildMember, TextChannel } from "discord.js"; export async function actualUnmuteCmd( pluginData: GuildPluginData, user: User | UnknownUser, msg: Message, - args: { time?: number; reason?: string; mod?: Member }, + args: { time?: number; reason?: string; mod?: GuildMember }, ) { // The moderator who did the action is the message author or, if used, the specified -mod let mod = msg.author; @@ -19,7 +20,7 @@ export async function actualUnmuteCmd( if (args.mod) { if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id }))) { - sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "You don't have permission to use -mod"); return; } @@ -27,7 +28,7 @@ export async function actualUnmuteCmd( pp = msg.author; } - const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments) : undefined; + const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments.array()) : undefined; const mutesPlugin = pluginData.getPlugin(MutesPlugin); const result = await mutesPlugin.unmuteUser(user.id, args.time, { @@ -37,7 +38,7 @@ export async function actualUnmuteCmd( }); if (!result) { - sendErrorMessage(pluginData, msg.channel, "User is not muted!"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "User is not muted!"); return; } @@ -46,7 +47,7 @@ export async function actualUnmuteCmd( const timeUntilUnmute = args.time && humanizeDuration(args.time); sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, asSingleLine(` Unmuting **${user.username}#${user.discriminator}** in ${timeUntilUnmute} (Case #${result.case.case_number}) @@ -55,7 +56,7 @@ export async function actualUnmuteCmd( } else { sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, asSingleLine(` Unmuted **${user.username}#${user.discriminator}** (Case #${result.case.case_number}) diff --git a/backend/src/plugins/ModActions/functions/banUserId.ts b/backend/src/plugins/ModActions/functions/banUserId.ts index f259dca9..e1da2e2d 100644 --- a/backend/src/plugins/ModActions/functions/banUserId.ts +++ b/backend/src/plugins/ModActions/functions/banUserId.ts @@ -17,6 +17,7 @@ import { CasesPlugin } from "../../Cases/CasesPlugin"; import { CaseTypes } from "../../../data/CaseTypes"; import { logger } from "../../../logger"; import humanizeDuration from "humanize-duration"; +import { DiscordAPIError, User } from "discord.js"; /** * Ban the specified user id, whether or not they're actually on the server at the time. Generates a case. @@ -77,14 +78,13 @@ export async function banUserId( ignoreEvent(pluginData, IgnoredEventType.Ban, userId); try { const deleteMessageDays = Math.min(30, Math.max(0, banOptions.deleteMessageDays ?? 1)); - await pluginData.guild.banMember( - userId, - deleteMessageDays, - reason != null ? encodeURIComponent(reason) : undefined, - ); + await pluginData.guild.bans.create(userId, { + days: deleteMessageDays, + reason: reason != null ? encodeURIComponent(reason) : undefined, + }); } catch (e) { let errorMessage; - if (e instanceof DiscordRESTError) { + if (e instanceof DiscordAPIError) { errorMessage = `API error ${e.code}: ${e.message}`; } else { logger.warn(`Error applying ban to ${userId}: ${e}`); diff --git a/backend/src/plugins/ModActions/functions/formatReasonWithAttachments.ts b/backend/src/plugins/ModActions/functions/formatReasonWithAttachments.ts index abf820c6..809fe909 100644 --- a/backend/src/plugins/ModActions/functions/formatReasonWithAttachments.ts +++ b/backend/src/plugins/ModActions/functions/formatReasonWithAttachments.ts @@ -1,4 +1,6 @@ -export function formatReasonWithAttachments(reason: string, attachments: Attachment[]) { +import { MessageAttachment } from "discord.js"; + +export function formatReasonWithAttachments(reason: string, attachments: MessageAttachment[]) { const attachmentUrls = attachments.map(a => a.url); return ((reason || "") + " " + attachmentUrls.join(" ")).trim(); } diff --git a/backend/src/plugins/ModActions/functions/getDefaultContactMethods.ts b/backend/src/plugins/ModActions/functions/getDefaultContactMethods.ts index 1d2484c3..68078a88 100644 --- a/backend/src/plugins/ModActions/functions/getDefaultContactMethods.ts +++ b/backend/src/plugins/ModActions/functions/getDefaultContactMethods.ts @@ -1,6 +1,7 @@ import { GuildPluginData } from "knub"; import { ModActionsPluginType } from "../types"; import { UserNotificationMethod } from "../../../utils"; +import { TextChannel } from "discord.js"; export function getDefaultContactMethods( pluginData: GuildPluginData, diff --git a/backend/src/plugins/ModActions/functions/isBanned.ts b/backend/src/plugins/ModActions/functions/isBanned.ts index bac97e91..4496fe1a 100644 --- a/backend/src/plugins/ModActions/functions/isBanned.ts +++ b/backend/src/plugins/ModActions/functions/isBanned.ts @@ -4,6 +4,7 @@ import { isDiscordHTTPError, isDiscordRESTError, SECONDS, sleep } from "../../.. import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogType } from "../../../data/LogType"; import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions"; +import { Permissions } from "discord.js"; export async function isBanned( pluginData: GuildPluginData, @@ -11,7 +12,7 @@ export async function isBanned( timeout: number = 5 * SECONDS, ): Promise { const botMember = pluginData.guild.members.cache.get(pluginData.client.user!.id); - if (botMember && !hasDiscordPermissions(botMember.permissions, Constants.Permissions.banMembers)) { + if (botMember && !hasDiscordPermissions(botMember.permissions, Permissions.FLAGS.BAN_MEMBERS)) { pluginData.getPlugin(LogsPlugin).log(LogType.BOT_ALERT, { body: `Missing "Ban Members" permission to check for existing bans`, }); @@ -19,7 +20,7 @@ export async function isBanned( } try { - const potentialBan = await Promise.race([pluginData.guild.getBan(userId), sleep(timeout)]); + const potentialBan = await Promise.race([pluginData.guild.bans.fetch({ user: userId }), sleep(timeout)]); return potentialBan != null; } catch (e) { if (isDiscordRESTError(e) && e.code === 10026) { diff --git a/backend/src/plugins/ModActions/functions/kickMember.ts b/backend/src/plugins/ModActions/functions/kickMember.ts index eaaa2f69..175a480e 100644 --- a/backend/src/plugins/ModActions/functions/kickMember.ts +++ b/backend/src/plugins/ModActions/functions/kickMember.ts @@ -15,13 +15,14 @@ import { LogType } from "../../../data/LogType"; import { ignoreEvent } from "./ignoreEvent"; import { CaseTypes } from "../../../data/CaseTypes"; import { CasesPlugin } from "../../Cases/CasesPlugin"; +import { GuildMember } from "discord.js"; /** * Kick the specified server member. Generates a case. */ export async function kickMember( pluginData: GuildPluginData, - member: Member, + member: GuildMember, reason?: string, kickOptions: KickOptions = {}, ): Promise { diff --git a/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts b/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts index 0fc3749c..bb7fe336 100644 --- a/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts +++ b/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts @@ -30,7 +30,7 @@ export async function outdatedTempbansLoop(pluginData: GuildPluginData, - member: Member, + member: GuildMember, reason: string, warnOptions: WarnOptions = {}, ): Promise { @@ -42,13 +42,13 @@ export async function warnMember( } if (!notifyResult.success) { - if (warnOptions.retryPromptChannel && pluginData.guild.channels.has(warnOptions.retryPromptChannel.id)) { - const failedMsg = await warnOptions.retryPromptChannel.createMessage( + if (warnOptions.retryPromptChannel && pluginData.guild.channels.resolve(warnOptions.retryPromptChannel.id)) { + const failedMsg = await warnOptions.retryPromptChannel.send( "Failed to message the user. Log the warning anyway?", ); - const reply = await waitForReaction(pluginData.client, failedMsg, ["✅", "❌"]); + const reply = false; //await waitForReaction(pluginData.client, failedMsg, ["✅", "❌"]); FIXME waiting on waitForButton failedMsg.delete(); - if (!reply || reply.name === "❌") { + if (!reply /*|| reply.name === "❌"*/) { return { status: "failed", error: "Failed to message user", diff --git a/backend/src/plugins/ModActions/types.ts b/backend/src/plugins/ModActions/types.ts index 3ebeacec..08c1314a 100644 --- a/backend/src/plugins/ModActions/types.ts +++ b/backend/src/plugins/ModActions/types.ts @@ -11,6 +11,7 @@ import { GuildTempbans } from "../../data/GuildTempbans"; import Timeout = NodeJS.Timeout; import { EventEmitter } from "events"; import { Queue } from "../../Queue"; +import { TextChannel } from "discord.js"; export const ConfigSchema = t.type({ dm_on_warn: t.boolean, diff --git a/backend/src/plugins/Mutes/MutesPlugin.ts b/backend/src/plugins/Mutes/MutesPlugin.ts index 5e8c0045..acb16e44 100644 --- a/backend/src/plugins/Mutes/MutesPlugin.ts +++ b/backend/src/plugins/Mutes/MutesPlugin.ts @@ -20,6 +20,7 @@ import { mapToPublicFn } from "../../pluginUtils"; import { EventEmitter } from "events"; import { onMutesEvent } from "./functions/onMutesEvent"; import { offMutesEvent } from "./functions/offMutesEvent"; +import { GuildMember } from "discord.js"; const defaultOptions = { config: { @@ -92,9 +93,9 @@ export const MutesPlugin = zeppelinGuildPlugin()({ muteUser: mapToPublicFn(muteUser), unmuteUser: mapToPublicFn(unmuteUser), hasMutedRole(pluginData) { - return (member: Member) => { + return (member: GuildMember) => { const muteRole = pluginData.config.get().mute_role; - return muteRole ? member.roles.includes(muteRole) : false; + return muteRole ? member.roles.cache.has(muteRole) : false; }; }, diff --git a/backend/src/plugins/Mutes/commands/ClearBannedMutesCmd.ts b/backend/src/plugins/Mutes/commands/ClearBannedMutesCmd.ts index 37f78f6f..c2fbc844 100644 --- a/backend/src/plugins/Mutes/commands/ClearBannedMutesCmd.ts +++ b/backend/src/plugins/Mutes/commands/ClearBannedMutesCmd.ts @@ -1,6 +1,7 @@ import { mutesCmd } from "../types"; import { sendSuccessMessage } from "../../../pluginUtils"; +import { User } from "discord.js"; export const ClearBannedMutesCmd = mutesCmd({ trigger: "clear_banned_mutes", @@ -8,17 +9,14 @@ export const ClearBannedMutesCmd = mutesCmd({ description: "Clear dangling mutes for members who have been banned", async run({ pluginData, message: msg }) { - await msg.channel.createMessage("Clearing mutes from banned users..."); + await msg.channel.send("Clearing mutes from banned users..."); const activeMutes = await pluginData.state.mutes.getActiveMutes(); - // Mismatch in Eris docs and actual result here, based on Eris's code comments anyway - const bans: Array<{ reason: string; user: User }> = (await pluginData.guild.getBans()) as any; + const bans: Array<{ reason: string; user: User }> = (await pluginData.guild.bans.fetch({ cache: true })) as any; const bannedIds = bans.map(b => b.user.id); - await msg.channel.createMessage( - `Found ${activeMutes.length} mutes and ${bannedIds.length} bans, cross-referencing...`, - ); + await msg.channel.send(`Found ${activeMutes.length} mutes and ${bannedIds.length} bans, cross-referencing...`); let cleared = 0; for (const mute of activeMutes) { diff --git a/backend/src/plugins/Mutes/commands/ClearMutesWithoutRoleCmd.ts b/backend/src/plugins/Mutes/commands/ClearMutesWithoutRoleCmd.ts index f05b16cf..08aebe63 100644 --- a/backend/src/plugins/Mutes/commands/ClearMutesWithoutRoleCmd.ts +++ b/backend/src/plugins/Mutes/commands/ClearMutesWithoutRoleCmd.ts @@ -12,14 +12,14 @@ export const ClearMutesWithoutRoleCmd = mutesCmd({ const muteRole = pluginData.config.get().mute_role; if (!muteRole) return; - await msg.channel.createMessage("Clearing mutes from members that don't have the mute role..."); + await msg.channel.send("Clearing mutes from members that don't have the mute role..."); let cleared = 0; for (const mute of activeMutes) { const member = await resolveMember(pluginData.client, pluginData.guild, mute.user_id); if (!member) continue; - if (!member.roles.includes(muteRole)) { + if (!member.roles.cache.has(muteRole)) { await pluginData.state.mutes.clear(mute.user_id); cleared++; } diff --git a/backend/src/plugins/Mutes/commands/MutesCmd.ts b/backend/src/plugins/Mutes/commands/MutesCmd.ts index 7e52589a..276a6227 100644 --- a/backend/src/plugins/Mutes/commands/MutesCmd.ts +++ b/backend/src/plugins/Mutes/commands/MutesCmd.ts @@ -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 { GuildMember } from "discord.js"; export const MutesCmd = mutesCmd({ trigger: "mutes", @@ -21,7 +22,7 @@ export const MutesCmd = mutesCmd({ }, async run({ pluginData, message: msg, args }) { - const listMessagePromise = msg.channel.createMessage("Loading mutes..."); + const listMessagePromise = msg.channel.send("Loading mutes..."); const mutesPerPage = 10; let totalMutes = 0; let hasFilters = false; @@ -47,13 +48,13 @@ export const MutesCmd = mutesCmd({ 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: Member[] = []; + const manuallyMutedMembers: GuildMember[] = []; const muteRole = pluginData.config.get().mute_role; if (muteRole) { - pluginData.guild.members.forEach(member => { + pluginData.guild.members.cache.forEach(member => { if (muteUserIds.has(member.id)) return; - if (member.roles.includes(muteRole)) manuallyMutedMembers.push(member); + if (member.roles.cache.has(muteRole)) manuallyMutedMembers.push(member); }); } @@ -85,7 +86,7 @@ export const MutesCmd = mutesCmd({ if (!member) { if (!bannedIds) { - const bans = await pluginData.guild.getBans(); + const bans = await pluginData.guild.bans.fetch({ cache: true }); bannedIds = bans.map(u => u.user.id); } @@ -111,7 +112,7 @@ export const MutesCmd = mutesCmd({ const muteCasesById = muteCases.reduce((map, c) => map.set(c.id, c), new Map()); lines = filteredMutes.map(mute => { - const user = pluginData.client.user!.get(mute.user_id); + const user = pluginData.client.users.resolve(mute.user_id); const username = user ? `${user.username}#${user.discriminator}` : "Unknown#0000"; const theCase = muteCasesById.get(mute.case_id); const caseName = theCase ? `Case #${theCase.case_number}` : "No case"; @@ -194,29 +195,31 @@ export const MutesCmd = mutesCmd({ if (totalPages > 1) { hasReactions = true; - listMessage.addReaction("⬅"); - listMessage.addReaction("➡"); + listMessage.react("⬅"); + listMessage.react("➡"); const paginationReactionListener = pluginData.events.on( "messageReactionAdd", - ({ args: { message: rMsg, emoji, member } }) => { + async ({ args: { reaction, user } }) => { + const rMsg = reaction.message; + const member = await pluginData.guild.members.fetch(user.id); if (!isFullMessage(rMsg)) return; if (rMsg.id !== listMessage.id) return; if (member.id !== msg.author.id) return; - if (!["⬅", "➡"].includes(emoji.name)) return; + if (!["⬅", "➡"].includes(reaction.emoji.name!)) return; - if (emoji.name === "⬅" && currentPage > 1) { + if (reaction.emoji.name === "⬅" && currentPage > 1) { drawListPage(currentPage - 1); - } else if (emoji.name === "➡" && currentPage < totalPages) { + } else if (reaction.emoji.name === "➡" && currentPage < totalPages) { drawListPage(currentPage + 1); } - rMsg.removeReaction(emoji.name, member.id).catch(noop); + reaction.remove().catch(noop); }, ); clearReactionsFn = () => { - listMessage.removeReactions().catch(noop); + listMessage.reactions.removeAll().catch(noop); pluginData.events.off("messageReactionAdd", paginationReactionListener); }; bumpClearReactionsTimeout(); diff --git a/backend/src/plugins/Mutes/events/ClearActiveMuteOnMemberBanEvt.ts b/backend/src/plugins/Mutes/events/ClearActiveMuteOnMemberBanEvt.ts index 7a40b25e..94604dcd 100644 --- a/backend/src/plugins/Mutes/events/ClearActiveMuteOnMemberBanEvt.ts +++ b/backend/src/plugins/Mutes/events/ClearActiveMuteOnMemberBanEvt.ts @@ -5,10 +5,10 @@ import { mutesEvt } from "../types"; */ export const ClearActiveMuteOnMemberBanEvt = mutesEvt({ event: "guildBanAdd", - async listener({ pluginData, args: { user } }) { - const mute = await pluginData.state.mutes.findExistingMuteForUserId(user.id); + async listener({ pluginData, args: { ban } }) { + const mute = await pluginData.state.mutes.findExistingMuteForUserId(ban.user.id); if (mute) { - pluginData.state.mutes.clear(user.id); + pluginData.state.mutes.clear(ban.user.id); } }, }); diff --git a/backend/src/plugins/Mutes/events/ClearActiveMuteOnRoleRemovalEvt.ts b/backend/src/plugins/Mutes/events/ClearActiveMuteOnRoleRemovalEvt.ts index cba7f2a2..f3b4eeed 100644 --- a/backend/src/plugins/Mutes/events/ClearActiveMuteOnRoleRemovalEvt.ts +++ b/backend/src/plugins/Mutes/events/ClearActiveMuteOnRoleRemovalEvt.ts @@ -6,7 +6,7 @@ import { memberHasMutedRole } from "../functions/memberHasMutedRole"; */ export const ClearActiveMuteOnRoleRemovalEvt = mutesEvt({ event: "guildMemberUpdate", - async listener({ pluginData, args: { member } }) { + async listener({ pluginData, args: { oldMember, newMember: member } }) { const muteRole = pluginData.config.get().mute_role; if (!muteRole) return; diff --git a/backend/src/plugins/Mutes/events/ReapplyActiveMuteOnJoinEvt.ts b/backend/src/plugins/Mutes/events/ReapplyActiveMuteOnJoinEvt.ts index 2b149eb7..729392b8 100644 --- a/backend/src/plugins/Mutes/events/ReapplyActiveMuteOnJoinEvt.ts +++ b/backend/src/plugins/Mutes/events/ReapplyActiveMuteOnJoinEvt.ts @@ -15,7 +15,7 @@ export const ReapplyActiveMuteOnJoinEvt = mutesEvt({ if (muteRole) { const memberRoleLock = await pluginData.locks.acquire(memberRolesLock(member)); - await member.addRole(muteRole); + await member.roles.add(muteRole); memberRoleLock.unlock(); } diff --git a/backend/src/plugins/Mutes/functions/clearExpiredMutes.ts b/backend/src/plugins/Mutes/functions/clearExpiredMutes.ts index 65bd2b72..7db4e807 100644 --- a/backend/src/plugins/Mutes/functions/clearExpiredMutes.ts +++ b/backend/src/plugins/Mutes/functions/clearExpiredMutes.ts @@ -16,17 +16,17 @@ export async function clearExpiredMutes(pluginData: GuildPluginData r !== muteRole); + await member.roles.remove(muteRole); } if (mute.roles_to_restore) { - const memberOptions: MemberOptions = {}; - const guildRoles = pluginData.guild.roles; - memberOptions.roles = Array.from( - new Set([...mute.roles_to_restore, ...member.roles.filter(x => x !== muteRole && guildRoles.has(x))]), - ); - await member.edit(memberOptions); - member.roles = memberOptions.roles; + const guildRoles = pluginData.guild.roles.cache; + let newRoles: string[] = member.roles.cache.keyArray(); + newRoles = + muteRole && newRoles.includes(muteRole) ? newRoles.splice(newRoles.indexOf(muteRole), 1) : newRoles; + for (const toRestore of mute.roles_to_restore) { + if (guildRoles.has(toRestore) && toRestore !== muteRole) newRoles.push(toRestore); + } + await member.roles.set(newRoles); } lock.unlock(); diff --git a/backend/src/plugins/Mutes/functions/memberHasMutedRole.ts b/backend/src/plugins/Mutes/functions/memberHasMutedRole.ts index 8b296f19..70180dc9 100644 --- a/backend/src/plugins/Mutes/functions/memberHasMutedRole.ts +++ b/backend/src/plugins/Mutes/functions/memberHasMutedRole.ts @@ -1,7 +1,8 @@ +import { GuildMember } from "discord.js"; import { GuildPluginData } from "knub"; import { MutesPluginType } from "../types"; -export function memberHasMutedRole(pluginData: GuildPluginData, member: Member): boolean { +export function memberHasMutedRole(pluginData: GuildPluginData, member: GuildMember): boolean { const muteRole = pluginData.config.get().mute_role; - return muteRole ? member.roles.includes(muteRole) : false; + return muteRole ? member.roles.cache.has(muteRole) : false; } diff --git a/backend/src/plugins/Mutes/functions/muteUser.ts b/backend/src/plugins/Mutes/functions/muteUser.ts index 16ef5479..15bef04f 100644 --- a/backend/src/plugins/Mutes/functions/muteUser.ts +++ b/backend/src/plugins/Mutes/functions/muteUser.ts @@ -19,6 +19,7 @@ import { LogType } from "../../../data/LogType"; import { Case } from "../../../data/entities/Case"; import { LogsPlugin } from "../../../plugins/Logs/LogsPlugin"; import { muteLock } from "../../../utils/lockNameHelpers"; +import { TextChannel, User } from "discord.js"; export async function muteUser( pluginData: GuildPluginData, @@ -58,8 +59,8 @@ export async function muteUser( if (member) { const logs = pluginData.getPlugin(LogsPlugin); // remove and store any roles to be removed/restored - const currentUserRoles = member.roles; - const memberOptions: MemberOptions = {}; + const currentUserRoles = member.roles.cache.keyArray(); + let newRoles: string[] = currentUserRoles; const removeRoles = removeRolesOnMuteOverride ?? config.remove_roles_on_mute; const restoreRoles = restoreRolesOnMuteOverride ?? config.restore_roles_on_mute; @@ -67,13 +68,13 @@ export async function muteUser( if (!Array.isArray(removeRoles)) { if (removeRoles) { // exclude managed roles from being removed - const managedRoles = pluginData.guild.roles.filter(x => x.managed).map(y => y.id); - memberOptions.roles = managedRoles.filter(x => member.roles.includes(x)); - await member.edit(memberOptions); + const managedRoles = pluginData.guild.roles.cache.filter(x => x.managed).map(y => y.id); + newRoles = currentUserRoles.filter(r => !managedRoles.includes(r)); + await member.roles.set(newRoles); } } else { - memberOptions.roles = currentUserRoles.filter(x => !(removeRoles).includes(x)); - await member.edit(memberOptions); + newRoles = currentUserRoles.filter(x => !(removeRoles).includes(x)); + await member.roles.set(newRoles); } // set roles to be restored @@ -86,11 +87,11 @@ export async function muteUser( } // Apply mute role if it's missing - if (!member.roles.includes(muteRole)) { + if (!currentUserRoles.includes(muteRole)) { try { - await member.addRole(muteRole); + await member.roles.add(muteRole); } catch (e) { - const actualMuteRole = pluginData.guild.roles.find(x => x.id === muteRole); + const actualMuteRole = pluginData.guild.roles.cache.find(x => x.id === muteRole); if (!actualMuteRole) { lock.unlock(); logs.log(LogType.BOT_ALERT, { @@ -100,9 +101,9 @@ export async function muteUser( } const zep = await resolveMember(pluginData.client, pluginData.guild, pluginData.client.user!.id); - const zepRoles = pluginData.guild.roles.filter(x => zep!.roles.includes(x.id)); + const zepRoles = pluginData.guild.roles.cache.filter(x => zep!.roles.cache.has(x.id)); // If we have roles and one of them is above the muted role, throw generic error - if (zepRoles.length >= 0 && zepRoles.some(zepRole => zepRole.position > actualMuteRole.position)) { + if (zepRoles.size >= 0 && zepRoles.some(zepRole => zepRole.position > actualMuteRole.position)) { lock.unlock(); logs.log(LogType.BOT_ALERT, { body: `Cannot mute user ${member.id}: ${e}`, @@ -125,7 +126,7 @@ export async function muteUser( if (moveToVoiceChannel || cfg.kick_from_voice_channel) { // TODO: Add back the voiceState check once we figure out how to get voice state for guild members that are loaded on-demand try { - await member.edit({ channelID: moveToVoiceChannel }); + await member.edit({ channel: moveToVoiceChannel }); } catch {} // tslint:disable-line } } diff --git a/backend/src/plugins/Mutes/functions/unmuteUser.ts b/backend/src/plugins/Mutes/functions/unmuteUser.ts index c71096be..0fa81dcb 100644 --- a/backend/src/plugins/Mutes/functions/unmuteUser.ts +++ b/backend/src/plugins/Mutes/functions/unmuteUser.ts @@ -36,18 +36,17 @@ export async function unmuteUser( const lock = await pluginData.locks.acquire(memberRolesLock(member)); const muteRole = pluginData.config.get().mute_role; - if (muteRole && member.roles.includes(muteRole)) { - await member.removeRole(muteRole); - member.roles = member.roles.filter(r => r !== muteRole); + if (muteRole && member.roles.cache.has(muteRole)) { + await member.roles.remove(muteRole); } if (existingMute?.roles_to_restore) { - const memberOptions: MemberOptions = {}; - const guildRoles = pluginData.guild.roles; - memberOptions.roles = Array.from( - new Set([...existingMute.roles_to_restore, ...member.roles.filter(x => x !== muteRole && guildRoles.has(x))]), - ); - await member.edit(memberOptions); - member.roles = memberOptions.roles; + const guildRoles = pluginData.guild.roles.cache; + let newRoles: string[] = member.roles.cache.keyArray(); + newRoles = muteRole && newRoles.includes(muteRole) ? newRoles.splice(newRoles.indexOf(muteRole), 1) : newRoles; + for (const toRestore of existingMute.roles_to_restore) { + if (guildRoles.has(toRestore) && toRestore !== muteRole) newRoles.push(toRestore); + } + await member.roles.set(newRoles); } lock.unlock(); @@ -85,7 +84,7 @@ export async function unmuteUser( }); // Log the action - const mod = pluginData.client.user!.get(modId); + const mod = pluginData.client.users.fetch(modId); if (unmuteTime) { pluginData.state.serverLogs.log(LogType.MEMBER_TIMED_UNMUTE, { mod: stripObjectToScalars(mod), diff --git a/backend/src/plugins/Mutes/types.ts b/backend/src/plugins/Mutes/types.ts index e87e8a6e..9fc62f46 100644 --- a/backend/src/plugins/Mutes/types.ts +++ b/backend/src/plugins/Mutes/types.ts @@ -11,6 +11,7 @@ import { GuildMutes } from "../../data/GuildMutes"; import { CaseArgs } from "../Cases/types"; import Timeout = NodeJS.Timeout; import { EventEmitter } from "events"; +import { GuildMember } from "discord.js"; export const ConfigSchema = t.type({ mute_role: tNullable(t.string), @@ -58,7 +59,7 @@ export interface MutesPluginType extends BasePluginType { } export interface IMuteWithDetails extends Mute { - member?: Member; + member?: GuildMember; banned?: boolean; } diff --git a/backend/src/plugins/NameHistory/commands/NamesCmd.ts b/backend/src/plugins/NameHistory/commands/NamesCmd.ts index c47f1912..90cf80ee 100644 --- a/backend/src/plugins/NameHistory/commands/NamesCmd.ts +++ b/backend/src/plugins/NameHistory/commands/NamesCmd.ts @@ -29,7 +29,7 @@ export const NamesCmd = nameHistoryCmd({ ); const usernameRows = usernames.map(r => `\`[${r.timestamp}]\` **${disableCodeBlocks(r.username)}**`); - const user = pluginData.client.user!.get(args.userId); + const user = await pluginData.client.users.fetch(args.userId); const currentUsername = user ? `${user.username}#${user.discriminator}` : args.userId; const nicknameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS); diff --git a/backend/src/plugins/NameHistory/events/UpdateNameEvts.ts b/backend/src/plugins/NameHistory/events/UpdateNameEvts.ts index 66947b22..706c93cc 100644 --- a/backend/src/plugins/NameHistory/events/UpdateNameEvts.ts +++ b/backend/src/plugins/NameHistory/events/UpdateNameEvts.ts @@ -2,10 +2,15 @@ import { nameHistoryEvt } from "../types"; import { updateNickname } from "../updateNickname"; export const ChannelJoinEvt = nameHistoryEvt({ - event: "voiceChannelJoin", + event: "voiceStateUpdate", async listener(meta) { - meta.pluginData.state.updateQueue.add(() => updateNickname(meta.pluginData, meta.args.member)); + meta.pluginData.state.updateQueue.add(() => + updateNickname( + meta.pluginData, + meta.args.newState.member ? meta.args.newState.member : meta.args.oldState.member!, + ), + ); }, }); diff --git a/backend/src/plugins/NameHistory/updateNickname.ts b/backend/src/plugins/NameHistory/updateNickname.ts index 290ac4d1..e843ae3b 100644 --- a/backend/src/plugins/NameHistory/updateNickname.ts +++ b/backend/src/plugins/NameHistory/updateNickname.ts @@ -1,11 +1,12 @@ +import { GuildMember } from "discord.js"; import { GuildPluginData } from "knub"; import { NameHistoryPluginType } from "./types"; -export async function updateNickname(pluginData: GuildPluginData, member: Member) { +export async function updateNickname(pluginData: GuildPluginData, member: GuildMember) { if (!member) return; const latestEntry = await pluginData.state.nicknameHistory.getLastEntry(member.id); - if (!latestEntry || latestEntry.nickname !== member.nick) { - if (!latestEntry && member.nick == null) return; // No need to save "no nickname" if there's no previous data - await pluginData.state.nicknameHistory.addEntry(member.id, member.nick); + if (!latestEntry || latestEntry.nickname !== member.nickname) { + if (!latestEntry && member.nickname == null) return; // No need to save "no nickname" if there's no previous data + await pluginData.state.nicknameHistory.addEntry(member.id, member.nickname); } } diff --git a/backend/src/plugins/Persist/events/LoadDataEvt.ts b/backend/src/plugins/Persist/events/LoadDataEvt.ts index 76cf5366..96c63027 100644 --- a/backend/src/plugins/Persist/events/LoadDataEvt.ts +++ b/backend/src/plugins/Persist/events/LoadDataEvt.ts @@ -8,8 +8,9 @@ import { LogsPlugin } from "../../Logs/LogsPlugin"; import { missingPermissionError } from "../../../utils/missingPermissionError"; import { canAssignRole } from "../../../utils/canAssignRole"; import { memberRolesLock } from "../../../utils/lockNameHelpers"; +import { GuildMemberEditData, Permissions } from "discord.js"; -const p = Constants.Permissions; +const p = Permissions.FLAGS; export const LoadDataEvt = persistEvt({ event: "guildMemberAdd", @@ -26,16 +27,16 @@ export const LoadDataEvt = persistEvt({ return; } - const toRestore: MemberOptions = {}; + let toRestore: GuildMemberEditData = {}; const config = await pluginData.config.getForMember(member); const restoredData: string[] = []; // Check permissions const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!; let requiredPermissions = 0n; - if (config.persist_nicknames) requiredPermissions |= p.manageNicknames; - if (config.persisted_roles) requiredPermissions |= p.manageRoles; - const missingPermissions = getMissingPermissions(me.permission, requiredPermissions); + if (config.persist_nicknames) requiredPermissions |= p.MANAGE_NICKNAMES; + if (config.persisted_roles) requiredPermissions |= p.MANAGE_ROLES; + const missingPermissions = getMissingPermissions(me.permissions, requiredPermissions); if (missingPermissions) { pluginData.getPlugin(LogsPlugin).log(LogType.BOT_ALERT, { body: `Missing permissions for persist plugin: ${missingPermissionError(missingPermissions)}`, @@ -61,7 +62,7 @@ export const LoadDataEvt = persistEvt({ if (rolesToRestore.length) { restoredData.push("roles"); - toRestore.roles = Array.from(new Set([...rolesToRestore, ...member.roles])); + toRestore.roles = Array.from(new Set([...rolesToRestore, ...member.roles.cache])); } } diff --git a/backend/src/plugins/Persist/events/StoreDataEvt.ts b/backend/src/plugins/Persist/events/StoreDataEvt.ts index 2b9ded49..0bc95404 100644 --- a/backend/src/plugins/Persist/events/StoreDataEvt.ts +++ b/backend/src/plugins/Persist/events/StoreDataEvt.ts @@ -2,12 +2,13 @@ import { persistEvt } from "../types"; import { IPartialPersistData } from "../../../data/GuildPersistedData"; import intersection from "lodash.intersection"; +import { GuildMember } from "discord.js"; export const StoreDataEvt = persistEvt({ event: "guildMemberRemove", async listener(meta) { - const member = meta.args.member as Member; + const member = meta.args.member as GuildMember; const pluginData = meta.pluginData; let persist = false; @@ -23,9 +24,9 @@ export const StoreDataEvt = persistEvt({ } } - if (config.persist_nicknames && member.nick) { + if (config.persist_nicknames && member.nickname) { persist = true; - persistData.nickname = member.nick; + persistData.nickname = member.nickname; } if (persist) { diff --git a/backend/src/plugins/Post/commands/EditCmd.ts b/backend/src/plugins/Post/commands/EditCmd.ts index 9cac7d16..b0df9b4d 100644 --- a/backend/src/plugins/Post/commands/EditCmd.ts +++ b/backend/src/plugins/Post/commands/EditCmd.ts @@ -2,6 +2,7 @@ import { postCmd } from "../types"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { formatContent } from "../util/formatContent"; +import { TextChannel } from "discord.js"; export const EditCmd = postCmd({ trigger: "edit", @@ -24,7 +25,9 @@ export const EditCmd = postCmd({ return; } - await pluginData.client.editMessage(savedMessage.channel_id, savedMessage.id, formatContent(args.content)); + (pluginData.guild.channels.cache.get(savedMessage.channel_id) as TextChannel).messages.edit(savedMessage.id, { + content: formatContent(args.content), + }); sendSuccessMessage(pluginData, msg.channel, "Message edited"); }, }); diff --git a/backend/src/plugins/Post/commands/EditEmbedCmd.ts b/backend/src/plugins/Post/commands/EditEmbedCmd.ts index 64ec7e81..d832e8aa 100644 --- a/backend/src/plugins/Post/commands/EditEmbedCmd.ts +++ b/backend/src/plugins/Post/commands/EditEmbedCmd.ts @@ -6,6 +6,7 @@ import { trimLines } from "../../../utils"; import { formatContent } from "../util/formatContent"; import { parseColor } from "../../../utils/parseColor"; import { rgbToInt } from "../../../utils/rgbToInt"; +import { MessageEmbed, TextChannel } from "discord.js"; const COLOR_MATCH_REGEX = /^#?([0-9a-f]{6})$/; @@ -42,17 +43,19 @@ export const EditEmbedCmd = postCmd({ } } - const embed: Embed = savedMessage.data.embeds![0] as Embed; + const embed: MessageEmbed = savedMessage.data.embeds![0] as MessageEmbed; if (args.title) embed.title = args.title; if (content) embed.description = formatContent(content); if (color) embed.color = color; - await pluginData.client.editMessage(savedMessage.channel_id, savedMessage.id, { embed }); + (pluginData.guild.channels.cache.get(savedMessage.channel_id) as TextChannel).messages.edit(savedMessage.id, { + embed, + }); await sendSuccessMessage(pluginData, msg.channel, "Embed edited"); if (args.content) { const prefix = pluginData.fullConfig.prefix || "!"; - msg.channel.createMessage( + msg.channel.send( trimLines(` <@!${msg.author.id}> You can now specify an embed's content directly at the end of the command: \`${prefix}edit_embed -title "Some title" content goes here\` diff --git a/backend/src/plugins/Post/commands/PostEmbedCmd.ts b/backend/src/plugins/Post/commands/PostEmbedCmd.ts index 5868f2b8..344b9e17 100644 --- a/backend/src/plugins/Post/commands/PostEmbedCmd.ts +++ b/backend/src/plugins/Post/commands/PostEmbedCmd.ts @@ -7,6 +7,7 @@ import { isValidEmbed, trimLines } from "../../../utils"; import { formatContent } from "../util/formatContent"; import { parseColor } from "../../../utils/parseColor"; import { rgbToInt } from "../../../utils/rgbToInt"; +import { MessageEmbed, MessageEmbedOptions } from "discord.js"; export const PostEmbedCmd = postCmd({ trigger: "post_embed", @@ -46,7 +47,7 @@ export const PostEmbedCmd = postCmd({ } } - let embed: Embed = { type: "rich" }; + let embed: MessageEmbedOptions = {}; if (args.title) embed.title = args.title; if (color) embed.color = color; @@ -73,7 +74,7 @@ export const PostEmbedCmd = postCmd({ if (args.content) { const prefix = pluginData.fullConfig.prefix || "!"; - msg.channel.createMessage( + msg.channel.send( trimLines(` <@!${msg.author.id}> You can now specify an embed's content directly at the end of the command: \`${prefix}edit_embed -title "Some title" content goes here\` diff --git a/backend/src/plugins/Post/commands/ScheduledPostsListCmd.ts b/backend/src/plugins/Post/commands/ScheduledPostsListCmd.ts index bc61a4ba..3a3a3c8f 100644 --- a/backend/src/plugins/Post/commands/ScheduledPostsListCmd.ts +++ b/backend/src/plugins/Post/commands/ScheduledPostsListCmd.ts @@ -20,7 +20,7 @@ export const ScheduledPostsListCmd = postCmd({ async run({ message: msg, pluginData }) { const scheduledPosts = await pluginData.state.scheduledPosts.all(); if (scheduledPosts.length === 0) { - msg.channel.createMessage("No scheduled posts"); + msg.channel.send("No scheduled posts"); return; } diff --git a/backend/src/plugins/Post/commands/ScheduledPostsShowCmd.ts b/backend/src/plugins/Post/commands/ScheduledPostsShowCmd.ts index 6501f835..a94b8033 100644 --- a/backend/src/plugins/Post/commands/ScheduledPostsShowCmd.ts +++ b/backend/src/plugins/Post/commands/ScheduledPostsShowCmd.ts @@ -3,6 +3,7 @@ import { sorter } from "../../../utils"; import { sendErrorMessage } from "../../../pluginUtils"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { postMessage } from "../util/postMessage"; +import { TextChannel } from "discord.js"; export const ScheduledPostsShowCmd = postCmd({ trigger: ["scheduled_posts", "scheduled_posts show"], diff --git a/backend/src/plugins/Post/util/actualPostCmd.ts b/backend/src/plugins/Post/util/actualPostCmd.ts index 2adddad2..c814ae0b 100644 --- a/backend/src/plugins/Post/util/actualPostCmd.ts +++ b/backend/src/plugins/Post/util/actualPostCmd.ts @@ -8,6 +8,7 @@ import { PostPluginType } from "../types"; import { parseScheduleTime } from "./parseScheduleTime"; import { postMessage } from "./postMessage"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { Message, Channel, TextChannel } from "discord.js"; const MIN_REPEAT_TIME = 5 * MINUTES; const MAX_REPEAT_TIME = Math.pow(2, 32); @@ -27,22 +28,30 @@ export async function actualPostCmd( } = {}, ) { if (!(targetChannel instanceof TextChannel)) { - msg.channel.createMessage(errorMessage("Channel is not a text channel")); + msg.channel.send(errorMessage("Channel is not a text channel")); return; } - if (content == null && msg.attachments.length === 0) { - msg.channel.createMessage(errorMessage("Message content or attachment required")); + if (content == null && msg.attachments.size === 0) { + msg.channel.send(errorMessage("Message content or attachment required")); return; } if (opts.repeat) { if (opts.repeat < MIN_REPEAT_TIME) { - sendErrorMessage(pluginData, msg.channel, `Minimum time for -repeat is ${humanizeDuration(MIN_REPEAT_TIME)}`); + sendErrorMessage( + pluginData, + msg.channel as TextChannel, + `Minimum time for -repeat is ${humanizeDuration(MIN_REPEAT_TIME)}`, + ); return; } if (opts.repeat > MAX_REPEAT_TIME) { - sendErrorMessage(pluginData, msg.channel, `Max time for -repeat is ${humanizeDuration(MAX_REPEAT_TIME)}`); + sendErrorMessage( + pluginData, + msg.channel as TextChannel, + `Max time for -repeat is ${humanizeDuration(MAX_REPEAT_TIME)}`, + ); return; } } @@ -53,7 +62,7 @@ export async function actualPostCmd( // Schedule the post to be posted later postAt = await parseScheduleTime(pluginData, msg.author.id, opts.schedule); if (!postAt) { - sendErrorMessage(pluginData, msg.channel, "Invalid schedule time"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid schedule time"); return; } } else if (opts.repeat) { @@ -70,17 +79,17 @@ export async function actualPostCmd( // Invalid time if (!repeatUntil) { - sendErrorMessage(pluginData, msg.channel, "Invalid time specified for -repeat-until"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid time specified for -repeat-until"); return; } if (repeatUntil.isBefore(moment.utc())) { - sendErrorMessage(pluginData, msg.channel, "You can't set -repeat-until in the past"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "You can't set -repeat-until in the past"); return; } if (repeatUntil.isAfter(MAX_REPEAT_UNTIL)) { sendErrorMessage( pluginData, - msg.channel, + msg.channel as TextChannel, "Unfortunately, -repeat-until can only be at most 100 years into the future. Maybe 99 years would be enough?", ); return; @@ -88,18 +97,26 @@ export async function actualPostCmd( } else if (opts["repeat-times"]) { repeatTimes = opts["repeat-times"]; if (repeatTimes <= 0) { - sendErrorMessage(pluginData, msg.channel, "-repeat-times must be 1 or more"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "-repeat-times must be 1 or more"); return; } } if (repeatUntil && repeatTimes) { - sendErrorMessage(pluginData, msg.channel, "You can only use one of -repeat-until or -repeat-times at once"); + sendErrorMessage( + pluginData, + msg.channel as TextChannel, + "You can only use one of -repeat-until or -repeat-times at once", + ); return; } if (opts.repeat && !repeatUntil && !repeatTimes) { - sendErrorMessage(pluginData, msg.channel, "You must specify -repeat-until or -repeat-times for repeated messages"); + sendErrorMessage( + pluginData, + msg.channel as TextChannel, + "You must specify -repeat-until or -repeat-times for repeated messages", + ); return; } @@ -114,7 +131,7 @@ export async function actualPostCmd( // Save schedule/repeat information in DB if (postAt) { if (postAt < moment.utc()) { - sendErrorMessage(pluginData, msg.channel, "Post can't be scheduled to be posted in the past"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Post can't be scheduled to be posted in the past"); return; } @@ -123,7 +140,7 @@ export async function actualPostCmd( author_name: `${msg.author.username}#${msg.author.discriminator}`, channel_id: targetChannel.id, content, - attachments: msg.attachments, + attachments: msg.attachments.array(), post_at: postAt .clone() .tz("Etc/UTC") @@ -162,7 +179,7 @@ export async function actualPostCmd( // When the message isn't scheduled for later, post it immediately if (!opts.schedule) { - await postMessage(pluginData, targetChannel, content, msg.attachments, opts["enable-mentions"]); + await postMessage(pluginData, targetChannel, content, msg.attachments.array(), opts["enable-mentions"]); } if (opts.repeat) { @@ -197,6 +214,6 @@ export async function actualPostCmd( } if (targetChannel.id !== msg.channel.id || opts.schedule || opts.repeat) { - sendSuccessMessage(pluginData, msg.channel, successMessage); + sendSuccessMessage(pluginData, msg.channel as TextChannel, successMessage); } } diff --git a/backend/src/plugins/Post/util/postMessage.ts b/backend/src/plugins/Post/util/postMessage.ts index fc31b063..292fc6b3 100644 --- a/backend/src/plugins/Post/util/postMessage.ts +++ b/backend/src/plugins/Post/util/postMessage.ts @@ -4,14 +4,15 @@ import { PostPluginType } from "../types"; import { downloadFile } from "../../../utils"; import fs from "fs"; import { formatContent } from "./formatContent"; +import { TextChannel, Message, MessageOptions, MessageAttachment } from "discord.js"; const fsp = fs.promises; export async function postMessage( pluginData: GuildPluginData, channel: TextChannel, - content: MessageContent, - attachments: Attachment[] = [], + content: MessageOptions, + attachments: MessageAttachment[] = [], enableMentions: boolean = false, ): Promise { if (typeof content === "string") { @@ -27,20 +28,18 @@ export async function postMessage( if (attachments.length) { downloadedAttachment = await downloadFile(attachments[0].url); file = { - name: attachments[0].filename, + name: attachments[0].name, file: await fsp.readFile(downloadedAttachment.path), }; } if (enableMentions) { content.allowedMentions = { - everyone: true, - users: true, - roles: true, + parse: ["everyone", "roles", "users"], }; } - const createdMsg = await channel.createMessage(content, file); + const createdMsg = await channel.send(content, file); pluginData.state.savedMessages.setPermanent(createdMsg.id); if (downloadedAttachment) { diff --git a/backend/src/plugins/Post/util/scheduledPostLoop.ts b/backend/src/plugins/Post/util/scheduledPostLoop.ts index ac2f2519..d24f3ec6 100644 --- a/backend/src/plugins/Post/util/scheduledPostLoop.ts +++ b/backend/src/plugins/Post/util/scheduledPostLoop.ts @@ -6,6 +6,7 @@ import { LogType } from "../../../data/LogType"; import moment from "moment-timezone"; import { postMessage } from "./postMessage"; +import { TextChannel, User } from "discord.js"; const SCHEDULED_POST_CHECK_INTERVAL = 5 * SECONDS; @@ -15,7 +16,7 @@ export async function scheduledPostLoop(pluginData: GuildPluginData = pluginData.client.user!.get(post.author_id) || { + const author: User = (await pluginData.client.users.fetch(post.author_id)) || { id: post.author_id, username, discriminator, diff --git a/backend/src/plugins/ReactionRoles/commands/ClearReactionRolesCmd.ts b/backend/src/plugins/ReactionRoles/commands/ClearReactionRolesCmd.ts index 828ba54e..1b6bb197 100644 --- a/backend/src/plugins/ReactionRoles/commands/ClearReactionRolesCmd.ts +++ b/backend/src/plugins/ReactionRoles/commands/ClearReactionRolesCmd.ts @@ -3,6 +3,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { isDiscordRESTError } from "../../../utils"; +import { Message } from "discord.js"; export const ClearReactionRolesCmd = reactionRolesCmd({ trigger: "reaction_roles clear", @@ -21,9 +22,9 @@ export const ClearReactionRolesCmd = reactionRolesCmd({ pluginData.state.reactionRoles.removeFromMessage(args.message.messageId); - let targetMessage: Message; + let targetMessage: Message; try { - targetMessage = await args.message.channel.getMessage(args.message.messageId); + targetMessage = await args.message.channel.messages.fetch(args.message.messageId); } catch (err) { if (isDiscordRESTError(err) && err.code === 50001) { sendErrorMessage(pluginData, msg.channel, "Missing access to the specified message"); @@ -33,7 +34,7 @@ export const ClearReactionRolesCmd = reactionRolesCmd({ throw err; } - await targetMessage.removeReactions(); + await targetMessage.reactions.removeAll(); sendSuccessMessage(pluginData, msg.channel, "Reaction roles cleared"); }, diff --git a/backend/src/plugins/ReactionRoles/commands/InitReactionRolesCmd.ts b/backend/src/plugins/ReactionRoles/commands/InitReactionRolesCmd.ts index 8518518f..2434dde5 100644 --- a/backend/src/plugins/ReactionRoles/commands/InitReactionRolesCmd.ts +++ b/backend/src/plugins/ReactionRoles/commands/InitReactionRolesCmd.ts @@ -1,8 +1,6 @@ import { reactionRolesCmd, TReactionRolePair } from "../types"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; - -import { RecoverablePluginError, ERRORS } from "../../../RecoverablePluginError"; import { canUseEmoji, isDiscordRESTError, isValidEmoji, noop, trimPluginDescription } from "../../../utils"; import { applyReactionRoleReactionsToMessage } from "../util/applyReactionRoleReactionsToMessage"; import { canReadChannel } from "../../../utils/canReadChannel"; @@ -41,7 +39,7 @@ export const InitReactionRolesCmd = reactionRolesCmd({ let targetMessage; try { - targetMessage = await args.message.channel.getMessage(args.message.messageId).catch(noop); + targetMessage = await args.message.channel.messages.fetch(args.message.messageId).catch(noop); } catch (e) { if (isDiscordRESTError(e)) { sendErrorMessage(pluginData, msg.channel, `Error ${e.code} while getting message: ${e.message}`); @@ -96,13 +94,13 @@ export const InitReactionRolesCmd = reactionRolesCmd({ return; } - if (!pluginData.guild.roles.has(pair[1])) { + if (!pluginData.guild.roles.cache.has(pair[1])) { sendErrorMessage(pluginData, msg.channel, `Unknown role ${pair[1]}`); return; } } - const progressMessage = msg.channel.createMessage("Adding reaction roles..."); + const progressMessage = msg.channel.send("Adding reaction roles..."); // Save the new reaction roles to the database for (const pair of emojiRolePairs) { diff --git a/backend/src/plugins/ReactionRoles/events/AddReactionRoleEvt.ts b/backend/src/plugins/ReactionRoles/events/AddReactionRoleEvt.ts index 63fef94f..b8331cf5 100644 --- a/backend/src/plugins/ReactionRoles/events/AddReactionRoleEvt.ts +++ b/backend/src/plugins/ReactionRoles/events/AddReactionRoleEvt.ts @@ -4,6 +4,7 @@ import { addMemberPendingRoleChange } from "../util/addMemberPendingRoleChange"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogType } from "../../../data/LogType"; +import { Message } from "discord.js"; const CLEAR_ROLES_EMOJI = "❌"; @@ -12,9 +13,9 @@ export const AddReactionRoleEvt = reactionRolesEvt({ async listener(meta) { const pluginData = meta.pluginData; - const msg = meta.args.message as Message; - const emoji = meta.args.emoji; - const userId = meta.args.member.id; + const msg = meta.args.reaction.message as Message; + const emoji = meta.args.reaction.emoji; + const userId = meta.args.user.id; if (userId === pluginData.client.user!.id) { // Don't act on own reactions @@ -39,7 +40,7 @@ export const AddReactionRoleEvt = reactionRolesEvt({ // User reacted with a reaction role emoji -> add the role const matchingReactionRole = await pluginData.state.reactionRoles.getByMessageAndEmoji( msg.id, - emoji.id || emoji.name, + emoji.id || emoji.name!, ); if (!matchingReactionRole) return; @@ -59,9 +60,8 @@ export const AddReactionRoleEvt = reactionRolesEvt({ if (config.remove_user_reactions) { setTimeout(() => { pluginData.state.reactionRemoveQueue.add(async () => { - const reaction = emoji.id ? `${emoji.name}:${emoji.id}` : emoji.name; const wait = sleep(1500); - await msg.channel.removeMessageReaction(msg.id, reaction, userId).catch(noop); + await meta.args.reaction.remove().catch(noop); await wait; }); }, 1500); diff --git a/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts b/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts index 00ae6108..1bc5bf73 100644 --- a/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts +++ b/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts @@ -23,7 +23,7 @@ export async function addMemberPendingRoleChange( const member = await resolveMember(pluginData.client, pluginData.guild, memberId); if (member) { - const newRoleIds = new Set(member.roles); + const newRoleIds = new Set(member.roles.cache.keyArray()); for (const change of newPendingRoleChangeObj.changes) { if (change.mode === "+") newRoleIds.add(change.roleId); else newRoleIds.delete(change.roleId); @@ -38,7 +38,7 @@ export async function addMemberPendingRoleChange( ); } catch (e) { logger.warn( - `Failed to apply role changes to ${member.username}#${member.discriminator} (${member.id}): ${e.message}`, + `Failed to apply role changes to ${member.user.username}#${member.user.discriminator} (${member.id}): ${e.message}`, ); } } diff --git a/backend/src/plugins/ReactionRoles/util/applyReactionRoleReactionsToMessage.ts b/backend/src/plugins/ReactionRoles/util/applyReactionRoleReactionsToMessage.ts index 63421863..ea143838 100644 --- a/backend/src/plugins/ReactionRoles/util/applyReactionRoleReactionsToMessage.ts +++ b/backend/src/plugins/ReactionRoles/util/applyReactionRoleReactionsToMessage.ts @@ -6,6 +6,7 @@ import { isDiscordRESTError, sleep, isSnowflake } from "../../../utils"; import { logger } from "../../../logger"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogType } from "../../../data/LogType"; +import { TextChannel } from "discord.js"; const CLEAR_ROLES_EMOJI = "❌"; @@ -26,7 +27,7 @@ export async function applyReactionRoleReactionsToMessage( let targetMessage; try { - targetMessage = await channel.getMessage(messageId); + targetMessage = await channel.messages.fetch(messageId); } catch (e) { if (isDiscordRESTError(e)) { if (e.code === 10008) { diff --git a/backend/src/plugins/Reminders/utils/postDueRemindersLoop.ts b/backend/src/plugins/Reminders/utils/postDueRemindersLoop.ts index d0c4765d..7a5d447a 100644 --- a/backend/src/plugins/Reminders/utils/postDueRemindersLoop.ts +++ b/backend/src/plugins/Reminders/utils/postDueRemindersLoop.ts @@ -4,6 +4,7 @@ import moment from "moment-timezone"; import humanizeDuration from "humanize-duration"; import { disableLinkPreviews } from "knub/dist/helpers"; import { SECONDS } from "../../../utils"; +import { TextChannel } from "discord.js"; const REMINDER_LOOP_TIME = 10 * SECONDS; const MAX_TRIES = 3; @@ -19,7 +20,7 @@ export async function postDueRemindersLoop(pluginData: GuildPluginData: ${reminder.body} \n\`Set at ${reminder.created_at} (${result} ago)\``, ), @@ -28,7 +29,7 @@ export async function postDueRemindersLoop(pluginData: GuildPluginData: ${reminder.body}`), allowedMentions: { users: [reminder.user_id], diff --git a/backend/src/plugins/Roles/commands/AddRoleCmd.ts b/backend/src/plugins/Roles/commands/AddRoleCmd.ts index e49b6d7f..cc093d3e 100644 --- a/backend/src/plugins/Roles/commands/AddRoleCmd.ts +++ b/backend/src/plugins/Roles/commands/AddRoleCmd.ts @@ -3,6 +3,7 @@ import { sendErrorMessage, sendSuccessMessage, canActOn } from "../../../pluginU import { rolesCmd } from "../types"; import { resolveRoleId, stripObjectToScalars, verboseUserMention } from "../../../utils"; import { LogType } from "../../../data/LogType"; +import { GuildChannel } from "discord.js"; export const AddRoleCmd = rolesCmd({ trigger: "addrole", @@ -33,7 +34,7 @@ export const AddRoleCmd = rolesCmd({ } // Sanity check: make sure the role is configured properly - const role = (msg.channel as GuildChannel).guild.roles.get(roleId); + const role = (msg.channel as GuildChannel).guild.roles.cache.get(roleId); if (!role) { pluginData.state.logs.log(LogType.BOT_ALERT, { body: `Unknown role configured for 'roles' plugin: ${roleId}`, @@ -42,14 +43,14 @@ export const AddRoleCmd = rolesCmd({ return; } - if (args.member.roles.includes(roleId)) { + if (args.member.roles.cache.has(roleId)) { sendErrorMessage(pluginData, msg.channel, "Member already has that role"); return; } pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, args.member.id); - await args.member.addRole(roleId); + await args.member.roles.add(roleId); pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, { member: stripObjectToScalars(args.member, ["user", "roles"]), diff --git a/backend/src/plugins/Roles/commands/MassAddRoleCmd.ts b/backend/src/plugins/Roles/commands/MassAddRoleCmd.ts index 32b953a7..f2f0532d 100644 --- a/backend/src/plugins/Roles/commands/MassAddRoleCmd.ts +++ b/backend/src/plugins/Roles/commands/MassAddRoleCmd.ts @@ -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 { GuildMember } from "discord.js"; export const MassAddRoleCmd = rolesCmd({ trigger: "massaddrole", @@ -15,9 +16,9 @@ export const MassAddRoleCmd = rolesCmd({ }, async run({ message: msg, args, pluginData }) { - msg.channel.createMessage(`Resolving members...`); + msg.channel.send(`Resolving members...`); - const members: Member[] = []; + const members: GuildMember[] = []; const unknownMembers: string[] = []; for (const memberId of args.members) { const member = await resolveMember(pluginData.client, pluginData.guild, memberId); @@ -57,12 +58,12 @@ export const MassAddRoleCmd = rolesCmd({ return; } - const membersWithoutTheRole = members.filter(m => !m.roles.includes(roleId)); + const membersWithoutTheRole = members.filter(m => !m.roles.cache.has(roleId)); let assigned = 0; const failed: string[] = []; const alreadyHadRole = members.length - membersWithoutTheRole.length; - msg.channel.createMessage( + msg.channel.send( `Adding role **${role.name}** to ${membersWithoutTheRole.length} ${ membersWithoutTheRole.length === 1 ? "member" : "members" }...`, @@ -71,7 +72,7 @@ export const MassAddRoleCmd = rolesCmd({ for (const member of membersWithoutTheRole) { try { pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, member.id); - await member.addRole(roleId); + await member.roles.add(roleId); pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, { member: stripObjectToScalars(member, ["user", "roles"]), roles: role.name, @@ -97,6 +98,6 @@ export const MassAddRoleCmd = rolesCmd({ resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`; } - msg.channel.createMessage(successMessage(resultMessage)); + msg.channel.send(successMessage(resultMessage)); }, }); diff --git a/backend/src/plugins/Roles/commands/MassRemoveRoleCmd.ts b/backend/src/plugins/Roles/commands/MassRemoveRoleCmd.ts index b9d085f1..42240164 100644 --- a/backend/src/plugins/Roles/commands/MassRemoveRoleCmd.ts +++ b/backend/src/plugins/Roles/commands/MassRemoveRoleCmd.ts @@ -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 { GuildMember } from "discord.js"; export const MassRemoveRoleCmd = rolesCmd({ trigger: "massremoverole", @@ -15,9 +16,9 @@ export const MassRemoveRoleCmd = rolesCmd({ }, async run({ message: msg, args, pluginData }) { - msg.channel.createMessage(`Resolving members...`); + msg.channel.send(`Resolving members...`); - const members: Member[] = []; + const members: GuildMember[] = []; const unknownMembers: string[] = []; for (const memberId of args.members) { const member = await resolveMember(pluginData.client, pluginData.guild, memberId); @@ -57,12 +58,12 @@ export const MassRemoveRoleCmd = rolesCmd({ return; } - const membersWithTheRole = members.filter(m => m.roles.includes(roleId)); + const membersWithTheRole = members.filter(m => m.roles.cache.has(roleId)); let assigned = 0; const failed: string[] = []; const didNotHaveRole = members.length - membersWithTheRole.length; - msg.channel.createMessage( + msg.channel.send( `Removing role **${role.name}** from ${membersWithTheRole.length} ${ membersWithTheRole.length === 1 ? "member" : "members" }...`, @@ -71,7 +72,7 @@ export const MassRemoveRoleCmd = rolesCmd({ for (const member of membersWithTheRole) { try { pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, member.id); - await member.removeRole(roleId); + await member.roles.remove(roleId); pluginData.state.logs.log(LogType.MEMBER_ROLE_REMOVE, { member: stripObjectToScalars(member, ["user", "roles"]), roles: role.name, @@ -97,6 +98,6 @@ export const MassRemoveRoleCmd = rolesCmd({ resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`; } - msg.channel.createMessage(successMessage(resultMessage)); + msg.channel.send(successMessage(resultMessage)); }, }); diff --git a/backend/src/plugins/Roles/commands/RemoveRoleCmd.ts b/backend/src/plugins/Roles/commands/RemoveRoleCmd.ts index 12f5b640..b160bff3 100644 --- a/backend/src/plugins/Roles/commands/RemoveRoleCmd.ts +++ b/backend/src/plugins/Roles/commands/RemoveRoleCmd.ts @@ -4,6 +4,7 @@ import { rolesCmd } from "../types"; import { LogType } from "../../../data/LogType"; import { stripObjectToScalars, verboseUserMention, resolveRoleId } from "../../../utils"; +import { GuildChannel } from "discord.js"; export const RemoveRoleCmd = rolesCmd({ trigger: "removerole", @@ -34,7 +35,7 @@ export const RemoveRoleCmd = rolesCmd({ } // Sanity check: make sure the role is configured properly - const role = (msg.channel as GuildChannel).guild.roles.get(roleId); + const role = (msg.channel as GuildChannel).guild.roles.cache.get(roleId); if (!role) { pluginData.state.logs.log(LogType.BOT_ALERT, { body: `Unknown role configured for 'roles' plugin: ${roleId}`, @@ -43,14 +44,14 @@ export const RemoveRoleCmd = rolesCmd({ return; } - if (!args.member.roles.includes(roleId)) { + if (!args.member.roles.cache.has(roleId)) { sendErrorMessage(pluginData, msg.channel, "Member doesn't have that role"); return; } pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, args.member.id); - await args.member.removeRole(roleId); + await args.member.roles.remove(roleId); pluginData.state.logs.log(LogType.MEMBER_ROLE_REMOVE, { member: stripObjectToScalars(args.member, ["user", "roles"]), diff --git a/backend/src/plugins/SelfGrantableRoles/commands/RoleAddCmd.ts b/backend/src/plugins/SelfGrantableRoles/commands/RoleAddCmd.ts index 3f165e4e..cf3d9c84 100644 --- a/backend/src/plugins/SelfGrantableRoles/commands/RoleAddCmd.ts +++ b/backend/src/plugins/SelfGrantableRoles/commands/RoleAddCmd.ts @@ -7,6 +7,7 @@ import { normalizeRoleNames } from "../util/normalizeRoleNames"; import { findMatchingRoles } from "../util/findMatchingRoles"; import { memberRolesLock } from "../../../utils/lockNameHelpers"; +import { Role } from "discord.js"; export const RoleAddCmd = selfGrantableRolesCmd({ trigger: ["role", "role add"], @@ -49,7 +50,7 @@ export const RoleAddCmd = selfGrantableRolesCmd({ } // Grant the roles - const newRoleIds = new Set([...rolesToAdd.keys(), ...msg.member.roles]); + const newRoleIds = new Set([...rolesToAdd.keys(), ...msg.member.roles.cache.keys()]); // Remove extra roles (max_roles) for each entry const skipped: Set = new Set(); @@ -68,7 +69,7 @@ export const RoleAddCmd = selfGrantableRolesCmd({ newRoleIds.delete(roleId); rolesToAdd.delete(roleId); - if (msg.member.roles.includes(roleId)) { + if (msg.member.roles.cache.has(roleId)) { removed.add(pluginData.guild.roles.cache.get(roleId)!); } else { skipped.add(pluginData.guild.roles.cache.get(roleId)!); diff --git a/backend/src/plugins/SelfGrantableRoles/commands/RoleHelpCmd.ts b/backend/src/plugins/SelfGrantableRoles/commands/RoleHelpCmd.ts index 41d96d55..2969ac0b 100644 --- a/backend/src/plugins/SelfGrantableRoles/commands/RoleHelpCmd.ts +++ b/backend/src/plugins/SelfGrantableRoles/commands/RoleHelpCmd.ts @@ -47,6 +47,6 @@ export const RoleHelpCmd = selfGrantableRolesCmd({ color: parseInt("42bff4", 16), }; - msg.channel.createMessage({ embed: helpEmbed }); + msg.channel.send({ embed: helpEmbed }); }, }); diff --git a/backend/src/plugins/SelfGrantableRoles/commands/RoleRemoveCmd.ts b/backend/src/plugins/SelfGrantableRoles/commands/RoleRemoveCmd.ts index ba4240f6..5d41e639 100644 --- a/backend/src/plugins/SelfGrantableRoles/commands/RoleRemoveCmd.ts +++ b/backend/src/plugins/SelfGrantableRoles/commands/RoleRemoveCmd.ts @@ -32,7 +32,7 @@ export const RoleRemoveCmd = selfGrantableRolesCmd({ // Remove the roles if (rolesToRemove.length) { - const newRoleIds = msg.member.roles.filter(roleId => !roleIdsToRemove.includes(roleId)); + const newRoleIds = msg.member.roles.cache.filter(role => !roleIdsToRemove.includes(role.id)); try { await msg.member.edit({ diff --git a/backend/src/plugins/Slowmode/commands/SlowmodeGetCmd.ts b/backend/src/plugins/Slowmode/commands/SlowmodeGetCmd.ts index 567a2da9..276e28e9 100644 --- a/backend/src/plugins/Slowmode/commands/SlowmodeGetCmd.ts +++ b/backend/src/plugins/Slowmode/commands/SlowmodeGetCmd.ts @@ -2,6 +2,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes"; import { slowmodeCmd } from "../types"; import humanizeDuration from "humanize-duration"; +import { TextChannel } from "discord.js"; export const SlowmodeGetCmd = slowmodeCmd({ trigger: "slowmode", @@ -29,9 +30,9 @@ export const SlowmodeGetCmd = slowmodeCmd({ if (currentSlowmode) { const humanized = humanizeDuration(channel.rateLimitPerUser * 1000); const slowmodeType = isNative ? "native" : "bot-maintained"; - msg.channel.createMessage(`The current slowmode of <#${channel.id}> is **${humanized}** (${slowmodeType})`); + msg.channel.send(`The current slowmode of <#${channel.id}> is **${humanized}** (${slowmodeType})`); } else { - msg.channel.createMessage("Channel is not on slowmode"); + msg.channel.send("Channel is not on slowmode"); } }, }); diff --git a/backend/src/plugins/Slowmode/commands/SlowmodeListCmd.ts b/backend/src/plugins/Slowmode/commands/SlowmodeListCmd.ts index 7571b358..0ea52e9f 100644 --- a/backend/src/plugins/Slowmode/commands/SlowmodeListCmd.ts +++ b/backend/src/plugins/Slowmode/commands/SlowmodeListCmd.ts @@ -3,6 +3,7 @@ import { slowmodeCmd } from "../types"; import { createChunkedMessage } from "knub/dist/helpers"; import { errorMessage } from "../../../utils"; import humanizeDuration from "humanize-duration"; +import { GuildChannel, TextChannel } from "discord.js"; export const SlowmodeListCmd = slowmodeCmd({ trigger: ["slowmode list", "slowmode l", "slowmodes"], @@ -12,7 +13,7 @@ export const SlowmodeListCmd = slowmodeCmd({ const channels = pluginData.guild.channels; const slowmodes: Array<{ channel: GuildChannel; seconds: number; native: boolean }> = []; - for (const channel of channels.values()) { + for (const channel of channels.cache.values()) { if (!(channel instanceof TextChannel)) continue; // Bot slowmode @@ -40,7 +41,7 @@ export const SlowmodeListCmd = slowmodeCmd({ createChunkedMessage(msg.channel, lines.join("\n")); } else { - msg.channel.createMessage(errorMessage("No active slowmodes!")); + msg.channel.send(errorMessage("No active slowmodes!")); } }, }); diff --git a/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts b/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts index aeebeb35..633e77c6 100644 --- a/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts +++ b/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts @@ -9,6 +9,7 @@ import { actualDisableSlowmodeCmd } from "../util/actualDisableSlowmodeCmd"; import { getMissingPermissions } from "../../../utils/getMissingPermissions"; import { missingPermissionError } from "../../../utils/missingPermissionError"; import { BOT_SLOWMODE_PERMISSIONS, NATIVE_SLOWMODE_PERMISSIONS } from "../requiredPermissions"; +import { Permissions, TextChannel } from "discord.js"; const MAX_NATIVE_SLOWMODE = 6 * HOURS; // 6 hours const MAX_BOT_SLOWMODE = DAYS * 365 * 100; // 100 years @@ -84,10 +85,13 @@ export const SlowmodeSetCmd = slowmodeCmd({ } // Verify permissions - const channelPermissions = channel.permissionsOf(pluginData.client.user!.id); + const channelPermissions = channel.permissionsFor(pluginData.client.user!.id); if (mode === "native") { - const missingPermissions = getMissingPermissions(channelPermissions, NATIVE_SLOWMODE_PERMISSIONS); + const missingPermissions = getMissingPermissions( + channelPermissions ? channelPermissions : new Permissions(), + NATIVE_SLOWMODE_PERMISSIONS, + ); if (missingPermissions) { sendErrorMessage( pluginData, @@ -99,7 +103,10 @@ export const SlowmodeSetCmd = slowmodeCmd({ } if (mode === "bot") { - const missingPermissions = getMissingPermissions(channelPermissions, BOT_SLOWMODE_PERMISSIONS); + const missingPermissions = getMissingPermissions( + channelPermissions ? channelPermissions : new Permissions(), + BOT_SLOWMODE_PERMISSIONS, + ); if (missingPermissions) { sendErrorMessage( pluginData, diff --git a/backend/src/plugins/Slowmode/requiredPermissions.ts b/backend/src/plugins/Slowmode/requiredPermissions.ts index bee1a4bc..ea9065be 100644 --- a/backend/src/plugins/Slowmode/requiredPermissions.ts +++ b/backend/src/plugins/Slowmode/requiredPermissions.ts @@ -1,6 +1,8 @@ -const p = Constants.Permissions; +import { Permissions } from "discord.js"; -export const NATIVE_SLOWMODE_PERMISSIONS = p.readMessages | p.manageChannels; -export const BOT_SLOWMODE_PERMISSIONS = p.readMessages | p.manageRoles | p.manageMessages; -export const BOT_SLOWMODE_CLEAR_PERMISSIONS = p.readMessages | p.manageRoles; -export const BOT_SLOWMODE_DISABLE_PERMISSIONS = p.readMessages | p.manageRoles; +const p = Permissions.FLAGS; + +export const NATIVE_SLOWMODE_PERMISSIONS = p.VIEW_CHANNEL | p.MANAGE_CHANNELS; +export const BOT_SLOWMODE_PERMISSIONS = p.VIEW_CHANNEL | p.MANAGE_ROLES | p.MANAGE_MESSAGES; +export const BOT_SLOWMODE_CLEAR_PERMISSIONS = p.VIEW_CHANNEL | p.MANAGE_ROLES; +export const BOT_SLOWMODE_DISABLE_PERMISSIONS = p.VIEW_CHANNEL | p.MANAGE_ROLES; diff --git a/backend/src/plugins/Slowmode/util/actualDisableSlowmodeCmd.ts b/backend/src/plugins/Slowmode/util/actualDisableSlowmodeCmd.ts index 41e5660e..4d02cf09 100644 --- a/backend/src/plugins/Slowmode/util/actualDisableSlowmodeCmd.ts +++ b/backend/src/plugins/Slowmode/util/actualDisableSlowmodeCmd.ts @@ -4,13 +4,14 @@ import { noop } from "../../../utils"; import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions"; import { BOT_SLOWMODE_DISABLE_PERMISSIONS } from "../requiredPermissions"; import { missingPermissionError } from "../../../utils/missingPermissionError"; +import { Message, TextChannel } from "discord.js"; export async function actualDisableSlowmodeCmd(msg: Message, args, pluginData) { const botSlowmode = await pluginData.state.slowmodes.getChannelSlowmode(args.channel.id); const hasNativeSlowmode = args.channel.rateLimitPerUser; if (!botSlowmode && hasNativeSlowmode === 0) { - sendErrorMessage(pluginData, msg.channel, "Channel is not on slowmode!"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "Channel is not on slowmode!"); return; } @@ -19,13 +20,13 @@ export async function actualDisableSlowmodeCmd(msg: Message, args, pluginData) { if (missingPermissions) { sendErrorMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `Unable to disable slowmode. ${missingPermissionError(missingPermissions)}`, ); return; } - const initMsg = await msg.channel.createMessage("Disabling slowmode..."); + const initMsg = await msg.channel.send("Disabling slowmode..."); // Disable bot-maintained slowmode let failedUsers: string[] = []; @@ -42,11 +43,11 @@ export async function actualDisableSlowmodeCmd(msg: Message, args, pluginData) { if (failedUsers.length) { sendSuccessMessage( pluginData, - msg.channel, + msg.channel as TextChannel, `Slowmode disabled! Failed to clear slowmode from the following users:\n\n<@!${failedUsers.join(">\n<@!")}>`, ); } else { - sendSuccessMessage(pluginData, msg.channel, "Slowmode disabled!"); + sendSuccessMessage(pluginData, msg.channel as TextChannel, "Slowmode disabled!"); initMsg.delete().catch(noop); } } diff --git a/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts b/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts index 775a29a3..02f465ec 100644 --- a/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts +++ b/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts @@ -4,6 +4,7 @@ import { GuildPluginData } from "knub"; import { isDiscordRESTError, stripObjectToScalars, UnknownUser } from "../../../utils"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; +import { GuildChannel, TextChannel, Permissions } from "discord.js"; export async function applyBotSlowmodeToUserId( pluginData: GuildPluginData, @@ -12,13 +13,17 @@ export async function applyBotSlowmodeToUserId( ) { // Deny sendMessage permission from the user. If there are existing permission overwrites, take those into account. const existingOverride = channel.permissionOverwrites.get(userId); - const newDeniedPermissions = (existingOverride ? existingOverride.deny : 0n) | Constants.Permissions.sendMessages; - const newAllowedPermissions = (existingOverride ? existingOverride.allow : 0n) & ~Constants.Permissions.sendMessages; + const newDeniedPermissions = + (existingOverride ? existingOverride.deny.bitfield : 0n) | Permissions.FLAGS.SEND_MESSAGES; + const newAllowedPermissions = + (existingOverride ? existingOverride.allow.bitfield : 0n) & ~Permissions.FLAGS.SEND_MESSAGES; try { - await channel.editPermission(userId, newAllowedPermissions, newDeniedPermissions, "member"); + await channel.overwritePermissions([ + { id: userId, allow: newAllowedPermissions, deny: newDeniedPermissions, type: "member" }, + ]); } catch (e) { - const user = pluginData.client.user!.get(userId) || new UnknownUser({ id: userId }); + const user = pluginData.client.users.fetch(userId) || new UnknownUser({ id: userId }); if (isDiscordRESTError(e) && e.code === 50013) { logger.warn( diff --git a/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts b/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts index c44e1754..4f7cb4c6 100644 --- a/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts +++ b/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts @@ -1,3 +1,4 @@ +import { GuildChannel, TextChannel } from "discord.js"; import { GuildPluginData } from "knub"; import { SlowmodePluginType } from "../types"; @@ -12,7 +13,7 @@ export async function clearBotSlowmodeFromUserId( // Previously we diffed the overrides so we could clear the "send messages" override without touching other // overrides. Unfortunately, it seems that was a bit buggy - we didn't always receive the event for the changed // overrides and then we also couldn't diff against them. For consistency's sake, we just delete the override now. - await channel.deletePermission(userId); + await channel.permissionOverwrites.get(userId)?.delete(); } catch (e) { if (!force) { throw e; diff --git a/backend/src/plugins/Slowmode/util/clearExpiredSlowmodes.ts b/backend/src/plugins/Slowmode/util/clearExpiredSlowmodes.ts index 51764846..66357446 100644 --- a/backend/src/plugins/Slowmode/util/clearExpiredSlowmodes.ts +++ b/backend/src/plugins/Slowmode/util/clearExpiredSlowmodes.ts @@ -5,6 +5,7 @@ import { logger } from "../../../logger"; import { stripObjectToScalars, UnknownUser } from "../../../utils"; import { clearBotSlowmodeFromUserId } from "./clearBotSlowmodeFromUserId"; +import { GuildChannel, TextChannel } from "discord.js"; export async function clearExpiredSlowmodes(pluginData: GuildPluginData) { const expiredSlowmodeUsers = await pluginData.state.slowmodes.getExpiredSlowmodeUsers(); @@ -20,7 +21,7 @@ export async function clearExpiredSlowmodes(pluginData: GuildPluginData, msg: SavedMessage) { if (msg.is_bot) return; @@ -49,7 +50,7 @@ export async function onMessageCreate(pluginData: GuildPluginData()({ // prettier-ignore events: [ - SpamVoiceJoinEvt, - SpamVoiceSwitchEvt, + SpamVoiceStateUpdateEvt, ], beforeLoad(pluginData) { diff --git a/backend/src/plugins/Spam/events/SpamVoiceEvt.ts b/backend/src/plugins/Spam/events/SpamVoiceEvt.ts index ab99afd4..2b553e06 100644 --- a/backend/src/plugins/Spam/events/SpamVoiceEvt.ts +++ b/backend/src/plugins/Spam/events/SpamVoiceEvt.ts @@ -1,37 +1,13 @@ import { spamEvt, RecentActionType } from "../types"; import { logAndDetectOtherSpam } from "../util/logAndDetectOtherSpam"; -export const SpamVoiceJoinEvt = spamEvt({ - event: "voiceChannelJoin", +export const SpamVoiceStateUpdateEvt = spamEvt({ + event: "voiceStateUpdate", async listener(meta) { - const member = meta.args.member; - const channel = meta.args.newChannel; - - const config = await meta.pluginData.config.getMatchingConfig({ member, channelId: channel.id }); - const maxVoiceMoves = config.max_voice_moves; - if (maxVoiceMoves) { - logAndDetectOtherSpam( - meta.pluginData, - RecentActionType.VoiceChannelMove, - maxVoiceMoves, - member.id, - 1, - "0", - Date.now(), - null, - "too many voice channel moves", - ); - } - }, -}); - -export const SpamVoiceSwitchEvt = spamEvt({ - event: "voiceChannelSwitch", - - async listener(meta) { - const member = meta.args.member; - const channel = meta.args.newChannel; + const member = meta.args.newState.member; + if (!member) return; + const channel = meta.args.newState.channel!; const config = await meta.pluginData.config.getMatchingConfig({ member, channelId: channel.id }); const maxVoiceMoves = config.max_voice_moves; diff --git a/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts b/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts index 29e5f0b7..0ce54e7f 100644 --- a/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts +++ b/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts @@ -23,6 +23,7 @@ import { clearRecentUserActions } from "./clearRecentUserActions"; import { saveSpamArchives } from "./saveSpamArchives"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; +import { TextChannel } from "discord.js"; export async function logAndDetectMessageSpam( pluginData: GuildPluginData, @@ -122,7 +123,7 @@ export async function logAndDetectMessageSpam( // Then, if enabled, remove the spam messages if (spamConfig.clean !== false) { msgIds.forEach(id => pluginData.state.logs.ignoreLog(LogType.MESSAGE_DELETE, id)); - pluginData.client.deleteMessages(savedMessage.channel_id, msgIds).catch(noop); + (pluginData.guild.channels.cache.get(savedMessage.channel_id)! as TextChannel).bulkDelete(msgIds).catch(noop); } // Store the ID of the last handled message diff --git a/backend/src/plugins/Starboard/commands/MigratePinsCmd.ts b/backend/src/plugins/Starboard/commands/MigratePinsCmd.ts index 990ccd06..27b08d4d 100644 --- a/backend/src/plugins/Starboard/commands/MigratePinsCmd.ts +++ b/backend/src/plugins/Starboard/commands/MigratePinsCmd.ts @@ -3,6 +3,7 @@ import { starboardCmd } from "../types"; import { sendSuccessMessage, sendErrorMessage } from "../../../pluginUtils"; import { saveMessageToStarboard } from "../util/saveMessageToStarboard"; +import { TextChannel } from "discord.js"; export const MigratePinsCmd = starboardCmd({ trigger: "starboard migrate_pins", @@ -29,9 +30,9 @@ export const MigratePinsCmd = starboardCmd({ return; } - msg.channel.createMessage(`Migrating pins from <#${args.pinChannel.id}> to <#${starboardChannel.id}>...`); + msg.channel.send(`Migrating pins from <#${args.pinChannel.id}> to <#${starboardChannel.id}>...`); - const pins = await args.pinChannel.getPins(); + const pins = (await args.pinChannel.messages.fetchPinned()).array(); pins.reverse(); // Migrate pins starting from the oldest message for (const pin of pins) { diff --git a/backend/src/plugins/Starboard/events/StarboardReactionAddEvt.ts b/backend/src/plugins/Starboard/events/StarboardReactionAddEvt.ts index 4356a1f8..ddcdb925 100644 --- a/backend/src/plugins/Starboard/events/StarboardReactionAddEvt.ts +++ b/backend/src/plugins/Starboard/events/StarboardReactionAddEvt.ts @@ -4,6 +4,7 @@ import { UnknownUser, resolveMember, noop, resolveUser } from "../../../utils"; import { saveMessageToStarboard } from "../util/saveMessageToStarboard"; import { updateStarboardMessageStarCount } from "../util/updateStarboardMessageStarCount"; import { allStarboardsLock } from "../../../utils/lockNameHelpers"; +import { Message, TextChannel } from "discord.js"; export const StarboardReactionAddEvt = starboardEvt({ event: "messageReactionAdd", @@ -11,14 +12,14 @@ export const StarboardReactionAddEvt = starboardEvt({ async listener(meta) { const pluginData = meta.pluginData; - let msg = meta.args.message as Message; - const userId = meta.args.member.id; - const emoji = meta.args.emoji; + let msg = meta.args.reaction.message as Message; + const userId = meta.args.user.id; + const emoji = meta.args.reaction.emoji; if (!msg.author) { // Message is not cached, fetch it try { - msg = await msg.channel.getMessage(msg.id); + msg = await msg.channel.messages.fetch(msg.id); } catch { // Sometimes we get this event for messages we can't fetch with getMessage; ignore silently return; @@ -29,7 +30,7 @@ export const StarboardReactionAddEvt = starboardEvt({ if (msg.author.id === userId) return; const member = await resolveMember(pluginData.client, pluginData.guild, userId); - if (!member || member.bot) return; + if (!member || member.user.bot) return; const config = await pluginData.config.getMatchingConfig({ member, @@ -76,10 +77,8 @@ export const StarboardReactionAddEvt = starboardEvt({ // If the message has already been posted to this starboard, update star counts if (starboard.show_star_count) { for (const starboardMessage of starboardMessages) { - const realStarboardMessage = await pluginData.client.getMessage( - starboardMessage.starboard_channel_id, - starboardMessage.starboard_message_id, - ); + const channel = pluginData.guild.channels.cache.get(starboardMessage.starboard_channel_id) as TextChannel; + const realStarboardMessage = await channel.messages.fetch(starboardMessage.starboard_message_id); await updateStarboardMessageStarCount( starboard, msg, diff --git a/backend/src/plugins/Starboard/events/StarboardReactionRemoveEvts.ts b/backend/src/plugins/Starboard/events/StarboardReactionRemoveEvts.ts index bc4bfae4..203c4bde 100644 --- a/backend/src/plugins/Starboard/events/StarboardReactionRemoveEvts.ts +++ b/backend/src/plugins/Starboard/events/StarboardReactionRemoveEvts.ts @@ -6,7 +6,10 @@ export const StarboardReactionRemoveEvt = starboardEvt({ async listener(meta) { const boardLock = await meta.pluginData.locks.acquire(allStarboardsLock()); - await meta.pluginData.state.starboardReactions.deleteStarboardReaction(meta.args.message.id, meta.args.userID); + await meta.pluginData.state.starboardReactions.deleteStarboardReaction( + meta.args.reaction.message.id, + meta.args.user.id, + ); boardLock.unlock(); }, }); diff --git a/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts b/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts index 304bb410..7c47e846 100644 --- a/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts +++ b/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts @@ -1,6 +1,7 @@ import { EmbedWith, EMPTY_CHAR, messageLink } from "../../../utils"; import path from "path"; +import { Message, GuildChannel } from "discord.js"; const imageAttachmentExtensions = ["jpeg", "jpg", "png", "gif", "webp"]; const audioAttachmentExtensions = ["wav", "mp3", "m4a"]; @@ -21,15 +22,15 @@ export function createStarboardEmbedFromMessage( name: `${msg.author.username}#${msg.author.discriminator}`, }, fields: [], - timestamp: new Date(msg.timestamp).toISOString(), + timestamp: msg.createdAt, }; if (color != null) { embed.color = color; } - if (msg.author.avatarURL) { - embed.author.icon_url = msg.author.avatarURL; + if (msg.author.avatarURL()) { + embed.author.icon_url = msg.author.avatarURL()!; } // The second condition here checks for messages with only an image link that is then embedded. @@ -59,15 +60,15 @@ export function createStarboardEmbedFromMessage( } // If there are no embeds, add the first image attachment explicitly - else if (msg.attachments.length) { + else if (msg.attachments.size) { for (const attachment of msg.attachments) { const ext = path - .extname(attachment.filename) + .extname(attachment[1].name!) .slice(1) .toLowerCase(); if (imageAttachmentExtensions.includes(ext)) { - embed.image = { url: attachment.url }; + embed.image = { url: attachment[1].url }; break; } diff --git a/backend/src/plugins/Starboard/util/createStarboardPseudoFooterForMessage.ts b/backend/src/plugins/Starboard/util/createStarboardPseudoFooterForMessage.ts index d33413c0..04f32806 100644 --- a/backend/src/plugins/Starboard/util/createStarboardPseudoFooterForMessage.ts +++ b/backend/src/plugins/Starboard/util/createStarboardPseudoFooterForMessage.ts @@ -1,3 +1,4 @@ +import { Message, EmbedField } from "discord.js"; import { EMPTY_CHAR, messageLink } from "../../../utils"; import { TStarboardOpts } from "../types"; @@ -22,5 +23,6 @@ export function createStarboardPseudoFooterForMessage( return { name: EMPTY_CHAR, value: content, + inline: false, }; } diff --git a/backend/src/plugins/Starboard/util/saveMessageToStarboard.ts b/backend/src/plugins/Starboard/util/saveMessageToStarboard.ts index 99c74ad0..88f6023b 100644 --- a/backend/src/plugins/Starboard/util/saveMessageToStarboard.ts +++ b/backend/src/plugins/Starboard/util/saveMessageToStarboard.ts @@ -6,6 +6,7 @@ import { EmbedWith, EMPTY_CHAR, messageLink } from "../../../utils"; import path from "path"; import { createStarboardEmbedFromMessage } from "./createStarboardEmbedFromMessage"; import { createStarboardPseudoFooterForMessage } from "./createStarboardPseudoFooterForMessage"; +import { Message, TextChannel } from "discord.js"; export async function saveMessageToStarboard( pluginData: GuildPluginData, @@ -19,6 +20,6 @@ export async function saveMessageToStarboard( const embed = createStarboardEmbedFromMessage(msg, Boolean(starboard.copy_full_embed), starboard.color); embed.fields!.push(createStarboardPseudoFooterForMessage(starboard, msg, starboard.star_emoji![0], starCount)); - const starboardMessage = await (channel as TextChannel).createMessage({ embed }); + const starboardMessage = await (channel as TextChannel).send(embed); await pluginData.state.starboardMessages.createStarboardMessage(channel.id, msg.id, starboardMessage.id); } diff --git a/backend/src/plugins/Starboard/util/updateStarboardMessageStarCount.ts b/backend/src/plugins/Starboard/util/updateStarboardMessageStarCount.ts index 0d26f7c1..3cccbd37 100644 --- a/backend/src/plugins/Starboard/util/updateStarboardMessageStarCount.ts +++ b/backend/src/plugins/Starboard/util/updateStarboardMessageStarCount.ts @@ -2,6 +2,7 @@ import { noop } from "../../../utils"; import { createStarboardPseudoFooterForMessage } from "./createStarboardPseudoFooterForMessage"; import { TStarboardOpts } from "../types"; import Timeout = NodeJS.Timeout; +import { Message } from "discord.js"; const DEBOUNCE_DELAY = 1000; const debouncedUpdates: Record = {}; diff --git a/backend/src/plugins/Tags/TagsPlugin.ts b/backend/src/plugins/Tags/TagsPlugin.ts index a17f9345..889c92b2 100644 --- a/backend/src/plugins/Tags/TagsPlugin.ts +++ b/backend/src/plugins/Tags/TagsPlugin.ts @@ -214,11 +214,11 @@ export const TagsPlugin = zeppelinGuildPlugin()({ return input; } - if (pluginData.guild.members.has(input) || pluginData.client.user!.has(input)) { + if (pluginData.guild.members.cache.has(input) || pluginData.client.users.resolve(input)) { return `<@!${input}>`; } - if (pluginData.guild.channels.has(input) || pluginData.client.channelGuildMap[input]) { + if (pluginData.guild.channels.cache.has(input)) { return `<#${input}>`; } diff --git a/backend/src/plugins/Tags/commands/TagEvalCmd.ts b/backend/src/plugins/Tags/commands/TagEvalCmd.ts index 1569aeed..7d47b8be 100644 --- a/backend/src/plugins/Tags/commands/TagEvalCmd.ts +++ b/backend/src/plugins/Tags/commands/TagEvalCmd.ts @@ -32,7 +32,7 @@ export const TagEvalCmd = tagsCmd({ return; } - msg.channel.createMessage(rendered); + msg.channel.send(rendered); } catch (e) { if (e instanceof TemplateParseError) { sendErrorMessage(pluginData, msg.channel, `Failed to render tag: ${e.message}`); diff --git a/backend/src/plugins/Tags/commands/TagListCmd.ts b/backend/src/plugins/Tags/commands/TagListCmd.ts index 9e10892e..8ab8d8de 100644 --- a/backend/src/plugins/Tags/commands/TagListCmd.ts +++ b/backend/src/plugins/Tags/commands/TagListCmd.ts @@ -8,7 +8,7 @@ export const TagListCmd = tagsCmd({ async run({ message: msg, pluginData }) { const tags = await pluginData.state.tags.all(); if (tags.length === 0) { - msg.channel.createMessage(`No tags created yet! Use \`tag create\` command to create one.`); + msg.channel.send(`No tags created yet! Use \`tag create\` command to create one.`); return; } diff --git a/backend/src/plugins/Tags/commands/TagSourceCmd.ts b/backend/src/plugins/Tags/commands/TagSourceCmd.ts index ed3fde87..08847b00 100644 --- a/backend/src/plugins/Tags/commands/TagSourceCmd.ts +++ b/backend/src/plugins/Tags/commands/TagSourceCmd.ts @@ -35,6 +35,6 @@ export const TagSourceCmd = tagsCmd({ const archiveId = await pluginData.state.archives.create(tag.body, moment.utc().add(10, "minutes")); const url = pluginData.state.archives.getUrl(getBaseUrl(pluginData), archiveId); - msg.channel.createMessage(`Tag source:\n${url}`); + msg.channel.send(`Tag source:\n${url}`); }, }); diff --git a/backend/src/plugins/Tags/util/matchAndRenderTagFromString.ts b/backend/src/plugins/Tags/util/matchAndRenderTagFromString.ts index d44415fc..968fc1e7 100644 --- a/backend/src/plugins/Tags/util/matchAndRenderTagFromString.ts +++ b/backend/src/plugins/Tags/util/matchAndRenderTagFromString.ts @@ -4,6 +4,7 @@ import { TagsPluginType, TTagCategory } from "../types"; import { renderTagFromString } from "./renderTagFromString"; import { convertDelayStringToMS, StrictMessageContent } from "../../../utils"; import escapeStringRegexp from "escape-string-regexp"; +import { GuildMember } from "discord.js"; interface BaseResult { renderedContent: StrictMessageContent; @@ -25,7 +26,7 @@ type Result = ResultWithCategory | ResultWithoutCategory; export async function matchAndRenderTagFromString( pluginData: GuildPluginData, str: string, - member: Member, + member: GuildMember, extraMatchParams: ExtendedMatchParams = {}, ): Promise { const config = await pluginData.config.getMatchingConfig({ diff --git a/backend/src/plugins/Tags/util/onMessageCreate.ts b/backend/src/plugins/Tags/util/onMessageCreate.ts index 1171216c..e6169eb5 100644 --- a/backend/src/plugins/Tags/util/onMessageCreate.ts +++ b/backend/src/plugins/Tags/util/onMessageCreate.ts @@ -7,6 +7,8 @@ import { LogType } from "../../../data/LogType"; import { matchAndRenderTagFromString } from "./matchAndRenderTagFromString"; import { messageIsEmpty } from "../../../utils/messageIsEmpty"; +import { TextChannel } from "discord.js"; +import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions"; export async function onMessageCreate(pluginData: GuildPluginData, msg: SavedMessage) { if (msg.is_bot) return; @@ -100,9 +102,9 @@ export async function onMessageCreate(pluginData: GuildPluginData, msg: SavedMessage) { // Command message was deleted -> delete the response as well @@ -12,7 +13,7 @@ export async function onMessageDelete(pluginData: GuildPluginData, @@ -16,7 +17,7 @@ export async function renderTagFromString( prefix: string, tagName: string, tagBody: t.TypeOf, - member: Member, + member: GuildMember, ): Promise { const variableStr = str.slice(prefix.length + tagName.length).trim(); const tagArgs = parseArguments(variableStr).map(v => v.value); diff --git a/backend/src/plugins/TimeAndDate/commands/ViewTimezoneCmd.ts b/backend/src/plugins/TimeAndDate/commands/ViewTimezoneCmd.ts index 292f46de..d1d41694 100644 --- a/backend/src/plugins/TimeAndDate/commands/ViewTimezoneCmd.ts +++ b/backend/src/plugins/TimeAndDate/commands/ViewTimezoneCmd.ts @@ -13,11 +13,11 @@ export const ViewTimezoneCmd = timeAndDateCmd({ async run({ pluginData, message, args }) { const memberTimezone = await pluginData.state.memberTimezones.get(message.author.id); if (memberTimezone) { - message.channel.createMessage(`Your timezone is currently set to **${memberTimezone.timezone}**`); + message.channel.send(`Your timezone is currently set to **${memberTimezone.timezone}**`); return; } const serverTimezone = getGuildTz(pluginData); - message.channel.createMessage(`Your timezone is currently set to **${serverTimezone}** (server default)`); + message.channel.send(`Your timezone is currently set to **${serverTimezone}** (server default)`); }, }); diff --git a/backend/src/plugins/UsernameSaver/events/UpdateUsernameEvts.ts b/backend/src/plugins/UsernameSaver/events/UpdateUsernameEvts.ts index 9165952e..10e134b9 100644 --- a/backend/src/plugins/UsernameSaver/events/UpdateUsernameEvts.ts +++ b/backend/src/plugins/UsernameSaver/events/UpdateUsernameEvts.ts @@ -11,10 +11,10 @@ export const MessageCreateUpdateUsernameEvt = usernameSaverEvt({ }); export const VoiceChannelJoinUpdateUsernameEvt = usernameSaverEvt({ - event: "voiceChannelJoin", + event: "voiceStateUpdate", async listener(meta) { - if (meta.args.member.bot) return; - meta.pluginData.state.updateQueue.add(() => updateUsername(meta.pluginData, meta.args.member.user)); + if (meta.args.newState.member?.user.bot) return; + meta.pluginData.state.updateQueue.add(() => updateUsername(meta.pluginData, meta.args.newState.member!.user)); }, }); diff --git a/backend/src/plugins/UsernameSaver/updateUsername.ts b/backend/src/plugins/UsernameSaver/updateUsername.ts index f29ed600..56debeac 100644 --- a/backend/src/plugins/UsernameSaver/updateUsername.ts +++ b/backend/src/plugins/UsernameSaver/updateUsername.ts @@ -1,3 +1,4 @@ +import { User } from "discord.js"; import { GuildPluginData } from "knub"; import { UsernameSaverPluginType } from "./types"; diff --git a/backend/src/plugins/Utility/commands/AboutCmd.ts b/backend/src/plugins/Utility/commands/AboutCmd.ts index 264723b8..ad1d2bbf 100644 --- a/backend/src/plugins/Utility/commands/AboutCmd.ts +++ b/backend/src/plugins/Utility/commands/AboutCmd.ts @@ -1,7 +1,6 @@ import { utilityCmd } from "../types"; import { EmbedWith, multiSorter, resolveMember, sorter } from "../../../utils"; - import { getCurrentUptime } from "../../../uptime"; import humanizeDuration from "humanize-duration"; import LCL from "last-commit-log"; @@ -9,6 +8,7 @@ import path from "path"; import moment from "moment-timezone"; import { rootDir } from "../../../paths"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { GuildChannel, MessageOptions } from "discord.js"; export const AboutCmd = utilityCmd({ trigger: "about", @@ -41,7 +41,7 @@ export const AboutCmd = utilityCmd({ version = "?"; } - const shard = pluginData.client.shards.get(pluginData.client.guildShardMap[pluginData.guild.id])!; + //const shard = pluginData.client.shards.get(pluginData.client.guildShardMap[pluginData.guild.id])!; FIXME Sharding stuff const lastReload = humanizeDuration(Date.now() - pluginData.state.lastReload, { largest: 2, @@ -53,7 +53,7 @@ export const AboutCmd = utilityCmd({ ["Last reload", `${lastReload} ago`], ["Last update", lastUpdate], ["Version", version], - ["API latency", `${shard.latency}ms`], + // ["API latency", `${shard.latency}ms`], ["Server timezone", timeAndDate.getGuildTz()], ]; @@ -65,7 +65,7 @@ export const AboutCmd = utilityCmd({ ); loadedPlugins.sort(); - const aboutContent: MessageContent & { embed: EmbedWith<"title" | "fields"> } = { + const aboutContent: MessageOptions & { embed: EmbedWith<"title" | "fields"> } = { embed: { title: `About ${pluginData.client.user!.username}`, fields: [ @@ -102,7 +102,7 @@ export const AboutCmd = utilityCmd({ // For the embed color, find the highest colored role the bot has - this is their color on the server as well const botMember = await resolveMember(pluginData.client, pluginData.guild, pluginData.client.user!.id); - let botRoles = botMember?.roles.map(r => (msg.channel as GuildChannel).guild.roles.get(r)!) || []; + let botRoles = botMember?.roles.cache.map(r => (msg.channel as GuildChannel).guild.roles.cache.get(r.id)!) || []; botRoles = botRoles.filter(r => !!r); // Drop any unknown roles botRoles = botRoles.filter(r => r.color); // Filter to those with a color botRoles.sort(sorter("position", "DESC")); // Sort by position (highest first) @@ -111,10 +111,10 @@ export const AboutCmd = utilityCmd({ } // Use the bot avatar as the embed image - if (pluginData.client.user!avatarURL) { - aboutContent.embed.thumbnail = { url: pluginData.client.user!.avatarURL }; + if (pluginData.client.user!.avatarURL()) { + aboutContent.embed.thumbnail = { url: pluginData.client.user!.avatarURL()! }; } - msg.channel.createMessage(aboutContent); + msg.channel.send(aboutContent); }, }); diff --git a/backend/src/plugins/Utility/commands/AvatarCmd.ts b/backend/src/plugins/Utility/commands/AvatarCmd.ts index 51814d9e..c267afff 100644 --- a/backend/src/plugins/Utility/commands/AvatarCmd.ts +++ b/backend/src/plugins/Utility/commands/AvatarCmd.ts @@ -2,6 +2,7 @@ import { utilityCmd } from "../types"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { UnknownUser } from "../../../utils"; import { sendErrorMessage } from "../../../pluginUtils"; +import { MessageEmbedOptions } from "discord.js"; export const AvatarCmd = utilityCmd({ trigger: ["avatar", "av"], @@ -15,15 +16,16 @@ export const AvatarCmd = utilityCmd({ async run({ message: msg, args, pluginData }) { const user = args.user || msg.author; if (!(user instanceof UnknownUser)) { - let extension = user.avatarURL.slice(user.avatarURL.lastIndexOf("."), user.avatarURL.lastIndexOf("?")); + const avatar = user.avatarURL() || user.defaultAvatarURL; + let extension = avatar.slice(avatar.lastIndexOf("."), avatar.lastIndexOf("?")); // Some pngs can have the .jpg extention for some reason, so we always use .png for static images extension = extension === ".gif" ? extension : ".png"; - const avatarUrl = user.avatarURL.slice(0, user.avatarURL.lastIndexOf(".")); - const embed: EmbedOptions = { + const avatarUrl = avatar.slice(0, avatar.lastIndexOf(".")); + const embed: MessageEmbedOptions = { image: { url: avatarUrl + `${extension}?size=2048` }, }; embed.title = `Avatar of ${user.username}#${user.discriminator}:`; - msg.channel.createMessage({ embed }); + msg.channel.send({ embed }); } else { sendErrorMessage(pluginData, msg.channel, "Invalid user ID"); } diff --git a/backend/src/plugins/Utility/commands/ChannelInfoCmd.ts b/backend/src/plugins/Utility/commands/ChannelInfoCmd.ts index 044ba63d..dece87b7 100644 --- a/backend/src/plugins/Utility/commands/ChannelInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/ChannelInfoCmd.ts @@ -20,6 +20,6 @@ export const ChannelInfoCmd = utilityCmd({ return; } - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/CleanCmd.ts b/backend/src/plugins/Utility/commands/CleanCmd.ts index 72287c56..44db25b6 100644 --- a/backend/src/plugins/Utility/commands/CleanCmd.ts +++ b/backend/src/plugins/Utility/commands/CleanCmd.ts @@ -9,6 +9,7 @@ import { SavedMessage } from "../../../data/entities/SavedMessage"; import { LogType } from "../../../data/LogType"; import { allowTimeout } from "../../../RegExpRunner"; import { ModActionsPlugin } from "../../../plugins/ModActions/ModActionsPlugin"; +import { TextChannel, User, Message } from "discord.js"; const MAX_CLEAN_COUNT = 150; const MAX_CLEAN_TIME = 1 * DAYS; @@ -32,7 +33,7 @@ async function cleanMessages( pluginData.state.logs.ignoreLog(LogType.MESSAGE_DELETE_BULK, idsToDelete[0]); // Actually delete the messages - await pluginData.client.deleteMessages(channel.id, idsToDelete); + (pluginData.guild.channels.cache.get(channel.id) as TextChannel).bulkDelete(idsToDelete); await pluginData.state.savedMessages.markBulkAsDeleted(idsToDelete); // Create an archive @@ -106,18 +107,18 @@ export const CleanCmd = utilityCmd({ } } - const cleaningMessage = msg.channel.createMessage("Cleaning..."); + const cleaningMessage = msg.channel.send("Cleaning..."); const messagesToClean: SavedMessage[] = []; let beforeId = msg.id; - const timeCutoff = msg.timestamp - MAX_CLEAN_TIME; + const timeCutoff = msg.createdTimestamp - MAX_CLEAN_TIME; const upToMsgId = args["to-id"]; let foundId = false; const deletePins = args["delete-pins"] != null ? args["delete-pins"] : false; let pins: Message[] = []; if (!deletePins) { - pins = await msg.channel.getPins(); + pins = (await msg.channel.messages.fetchPinned()).array(); } while (messagesToClean.length < args.count) { diff --git a/backend/src/plugins/Utility/commands/ContextCmd.ts b/backend/src/plugins/Utility/commands/ContextCmd.ts index 1ab2269d..9a11df10 100644 --- a/backend/src/plugins/Utility/commands/ContextCmd.ts +++ b/backend/src/plugins/Utility/commands/ContextCmd.ts @@ -4,6 +4,7 @@ import { messageLink } from "../../../utils"; import { sendErrorMessage } from "../../../pluginUtils"; import { canReadChannel } from "../../../utils/canReadChannel"; +import { TextChannel } from "discord.js"; export const ContextCmd = utilityCmd({ trigger: "context", @@ -35,12 +36,17 @@ export const ContextCmd = utilityCmd({ return; } - const previousMessage = (await pluginData.client.getMessages(channel.id, 1, messageId))[0]; + const previousMessage = ( + await (pluginData.guild.channels.cache.get(channel.id) as TextChannel).messages.fetch({ + limit: 1, + before: messageId, + }) + )[0]; if (!previousMessage) { sendErrorMessage(pluginData, msg.channel, "Message context not found"); return; } - msg.channel.createMessage(messageLink(pluginData.guild.id, previousMessage.channel.id, previousMessage.id)); + msg.channel.send(messageLink(pluginData.guild.id, previousMessage.channel.id, previousMessage.id)); }, }); diff --git a/backend/src/plugins/Utility/commands/EmojiInfoCmd.ts b/backend/src/plugins/Utility/commands/EmojiInfoCmd.ts index 41889509..90d272d6 100644 --- a/backend/src/plugins/Utility/commands/EmojiInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/EmojiInfoCmd.ts @@ -27,6 +27,6 @@ export const EmojiInfoCmd = utilityCmd({ return; } - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/HelpCmd.ts b/backend/src/plugins/Utility/commands/HelpCmd.ts index 8d4af9cc..f677f7d2 100644 --- a/backend/src/plugins/Utility/commands/HelpCmd.ts +++ b/backend/src/plugins/Utility/commands/HelpCmd.ts @@ -71,7 +71,7 @@ export const HelpCmd = utilityCmd({ }); if (totalResults === 0) { - msg.channel.createMessage("No matching commands found!"); + msg.channel.send("No matching commands found!"); return; } diff --git a/backend/src/plugins/Utility/commands/InfoCmd.ts b/backend/src/plugins/Utility/commands/InfoCmd.ts index 19870f25..5a13fbed 100644 --- a/backend/src/plugins/Utility/commands/InfoCmd.ts +++ b/backend/src/plugins/Utility/commands/InfoCmd.ts @@ -42,7 +42,7 @@ export const InfoCmd = utilityCmd({ if (channel) { const embed = await getChannelInfoEmbed(pluginData, channelId!, message.author.id); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -50,11 +50,11 @@ export const InfoCmd = utilityCmd({ // 2. Server if (userCfg.can_server) { - const guild = pluginData.client.guilds.get(value); + const guild = pluginData.client.guilds.fetch(value); if (guild) { const embed = await getServerInfoEmbed(pluginData, value, message.author.id); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -66,7 +66,7 @@ export const InfoCmd = utilityCmd({ if (user && userCfg.can_userinfo) { const embed = await getUserInfoEmbed(pluginData, user.id, Boolean(args.compact), message.author.id); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -84,7 +84,7 @@ export const InfoCmd = utilityCmd({ message.author.id, ); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -99,7 +99,7 @@ export const InfoCmd = utilityCmd({ if (invite) { const embed = await getInviteInfoEmbed(pluginData, inviteCode); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -112,7 +112,7 @@ export const InfoCmd = utilityCmd({ if (serverPreview) { const embed = await getServerInfoEmbed(pluginData, value, message.author.id); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -124,7 +124,7 @@ export const InfoCmd = utilityCmd({ const role = roleId && pluginData.guild.roles.cache.get(roleId); if (role) { const embed = await getRoleInfoEmbed(pluginData, role, message.author.id); - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -135,7 +135,7 @@ export const InfoCmd = utilityCmd({ if (emojiIdMatch?.[2]) { const embed = await getEmojiInfoEmbed(pluginData, emojiIdMatch[2]); if (embed) { - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } } @@ -144,7 +144,7 @@ export const InfoCmd = utilityCmd({ // 9. Arbitrary ID if (isValidSnowflake(value) && userCfg.can_snowflake) { const embed = await getSnowflakeInfoEmbed(pluginData, value, true, message.author.id); - message.channel.createMessage({ embed }); + message.channel.send({ embed }); return; } diff --git a/backend/src/plugins/Utility/commands/InviteInfoCmd.ts b/backend/src/plugins/Utility/commands/InviteInfoCmd.ts index ee876026..a5c7fd9f 100644 --- a/backend/src/plugins/Utility/commands/InviteInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/InviteInfoCmd.ts @@ -22,6 +22,6 @@ export const InviteInfoCmd = utilityCmd({ return; } - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/JumboCmd.ts b/backend/src/plugins/Utility/commands/JumboCmd.ts index d31e2dcb..276fa257 100644 --- a/backend/src/plugins/Utility/commands/JumboCmd.ts +++ b/backend/src/plugins/Utility/commands/JumboCmd.ts @@ -83,6 +83,6 @@ export const JumboCmd = utilityCmd({ }; } - msg.channel.createMessage("", file); + msg.channel.send("", file); }, }); diff --git a/backend/src/plugins/Utility/commands/LevelCmd.ts b/backend/src/plugins/Utility/commands/LevelCmd.ts index 4ad4ce5c..70b6ceae 100644 --- a/backend/src/plugins/Utility/commands/LevelCmd.ts +++ b/backend/src/plugins/Utility/commands/LevelCmd.ts @@ -17,6 +17,8 @@ export const LevelCmd = utilityCmd({ run({ message, args, pluginData }) { const member = args.member || message.member; const level = getMemberLevel(pluginData, member); - message.channel.createMessage(`The permission level of ${member.username}#${member.discriminator} is **${level}**`); + message.channel.send( + `The permission level of ${member.user.username}#${member.user.discriminator} is **${level}**`, + ); }, }); diff --git a/backend/src/plugins/Utility/commands/MessageInfoCmd.ts b/backend/src/plugins/Utility/commands/MessageInfoCmd.ts index 4681fd2e..e46dbc3a 100644 --- a/backend/src/plugins/Utility/commands/MessageInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/MessageInfoCmd.ts @@ -31,6 +31,6 @@ export const MessageInfoCmd = utilityCmd({ return; } - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/NicknameCmd.ts b/backend/src/plugins/Utility/commands/NicknameCmd.ts index 4df752e8..b2da21cf 100644 --- a/backend/src/plugins/Utility/commands/NicknameCmd.ts +++ b/backend/src/plugins/Utility/commands/NicknameCmd.ts @@ -16,24 +16,24 @@ export const NicknameCmd = utilityCmd({ async run({ message: msg, args, pluginData }) { if (msg.member.id !== args.member.id && !canActOn(pluginData, msg.member, args.member)) { - msg.channel.createMessage(errorMessage("Cannot change nickname: insufficient permissions")); + msg.channel.send(errorMessage("Cannot change nickname: insufficient permissions")); return; } const nicknameLength = [...args.nickname].length; if (nicknameLength < 2 || nicknameLength > 32) { - msg.channel.createMessage(errorMessage("Nickname must be between 2 and 32 characters long")); + msg.channel.send(errorMessage("Nickname must be between 2 and 32 characters long")); return; } - const oldNickname = args.member.nick || ""; + const oldNickname = args.member.nickname || ""; try { await args.member.edit({ nick: args.nickname, }); } catch { - msg.channel.createMessage(errorMessage("Failed to change nickname")); + msg.channel.send(errorMessage("Failed to change nickname")); return; } diff --git a/backend/src/plugins/Utility/commands/NicknameResetCmd.ts b/backend/src/plugins/Utility/commands/NicknameResetCmd.ts index 33085053..e2e5db00 100644 --- a/backend/src/plugins/Utility/commands/NicknameResetCmd.ts +++ b/backend/src/plugins/Utility/commands/NicknameResetCmd.ts @@ -15,7 +15,7 @@ export const NicknameResetCmd = utilityCmd({ async run({ message: msg, args, pluginData }) { if (msg.member.id !== args.member.id && !canActOn(pluginData, msg.member, args.member)) { - msg.channel.createMessage(errorMessage("Cannot reset nickname: insufficient permissions")); + msg.channel.send(errorMessage("Cannot reset nickname: insufficient permissions")); return; } @@ -24,7 +24,7 @@ export const NicknameResetCmd = utilityCmd({ nick: "", }); } catch { - msg.channel.createMessage(errorMessage("Failed to reset nickname")); + msg.channel.send(errorMessage("Failed to reset nickname")); return; } diff --git a/backend/src/plugins/Utility/commands/PingCmd.ts b/backend/src/plugins/Utility/commands/PingCmd.ts index 0bf671bc..08030f77 100644 --- a/backend/src/plugins/Utility/commands/PingCmd.ts +++ b/backend/src/plugins/Utility/commands/PingCmd.ts @@ -1,5 +1,6 @@ import { utilityCmd } from "../types"; import { noop, trimLines } from "../../../utils"; +import { Message } from "discord.js"; const { performance } = require("perf_hooks"); @@ -15,12 +16,12 @@ export const PingCmd = utilityCmd({ for (let i = 0; i < 4; i++) { const start = performance.now(); - const message = await msg.channel.createMessage(`Calculating ping... ${i + 1}`); + const message = await msg.channel.send(`Calculating ping... ${i + 1}`); times.push(performance.now() - start); messages.push(message); if (msgToMsgDelay === undefined) { - msgToMsgDelay = message.timestamp - msg.timestamp; + msgToMsgDelay = message.createdTimestamp - msg.createdTimestamp; } } @@ -28,25 +29,19 @@ export const PingCmd = utilityCmd({ const lowest = Math.round(Math.min(...times)); const mean = Math.round(times.reduce((total, ms) => total + ms, 0) / times.length); - const shard = pluginData.client.shards.get(pluginData.client.guildShardMap[pluginData.guild.id])!; + // const shard = pluginData.client.shards.get(pluginData.client.guildShardMap[pluginData.guild.id])!; FIXME sharding stuff - msg.channel.createMessage( + msg.channel.send( trimLines(` **Ping:** Lowest: **${lowest}ms** Highest: **${highest}ms** Mean: **${mean}ms** Time between ping command and first reply: **${msgToMsgDelay!}ms** - Shard latency: **${shard.latency}ms** - `), + `), // Omitted line: Shard latency: **${shard.latency}ms** ); // Clean up test messages - pluginData.client - .deleteMessages( - messages[0].channel.id, - messages.map(m => m.id), - ) - .catch(noop); + msg.channel.bulkDelete(messages).catch(noop); }, }); diff --git a/backend/src/plugins/Utility/commands/ReloadGuildCmd.ts b/backend/src/plugins/Utility/commands/ReloadGuildCmd.ts index d7abeac8..1fc824e6 100644 --- a/backend/src/plugins/Utility/commands/ReloadGuildCmd.ts +++ b/backend/src/plugins/Utility/commands/ReloadGuildCmd.ts @@ -1,6 +1,7 @@ import { utilityCmd } from "../types"; import { activeReloads } from "../guildReloads"; +import { TextChannel } from "discord.js"; export const ReloadGuildCmd = utilityCmd({ trigger: "reload_guild", @@ -11,7 +12,7 @@ export const ReloadGuildCmd = utilityCmd({ if (activeReloads.has(pluginData.guild.id)) return; activeReloads.set(pluginData.guild.id, msg.channel as TextChannel); - msg.channel.createMessage("Reloading..."); + msg.channel.send("Reloading..."); pluginData.getKnubInstance().reloadGuild(pluginData.guild.id); }, }); diff --git a/backend/src/plugins/Utility/commands/RoleInfoCmd.ts b/backend/src/plugins/Utility/commands/RoleInfoCmd.ts index 1b04bf9b..48406cb3 100644 --- a/backend/src/plugins/Utility/commands/RoleInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/RoleInfoCmd.ts @@ -15,6 +15,6 @@ export const RoleInfoCmd = utilityCmd({ async run({ message, args, pluginData }) { const embed = await getRoleInfoEmbed(pluginData, args.role, message.author.id); - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/RolesCmd.ts b/backend/src/plugins/Utility/commands/RolesCmd.ts index e98c46e7..ea6ab800 100644 --- a/backend/src/plugins/Utility/commands/RolesCmd.ts +++ b/backend/src/plugins/Utility/commands/RolesCmd.ts @@ -4,6 +4,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes"; import { chunkArray, sorter, trimLines } from "../../../utils"; import { refreshMembersIfNeeded } from "../refreshMembers"; import { sendErrorMessage } from "../../../pluginUtils"; +import { Role, TextChannel } from "discord.js"; export const RolesCmd = utilityCmd({ trigger: "roles", @@ -21,7 +22,9 @@ export const RolesCmd = utilityCmd({ async run({ message: msg, args, pluginData }) { const { guild } = pluginData; - let roles: Array<{ _memberCount?: number } & Role> = Array.from((msg.channel as TextChannel).guild.roles.values()); + let roles: Array<{ _memberCount?: number } & Role> = Array.from( + (msg.channel as TextChannel).guild.roles.cache.values(), + ); let sort = args.sort; if (args.search) { @@ -33,8 +36,8 @@ export const RolesCmd = utilityCmd({ await refreshMembersIfNeeded(guild); // If the user requested role member counts as well, calculate them and sort the roles by their member count - const roleCounts: Map = Array.from(guild.members.values()).reduce((map, member) => { - for (const roleId of member.roles) { + const roleCounts: Map = Array.from(guild.members.cache.values()).reduce((map, member) => { + for (const roleId of member.roles.cache) { if (!map.has(roleId)) map.set(roleId, 0); map.set(roleId, map.get(roleId) + 1); } @@ -97,14 +100,14 @@ export const RolesCmd = utilityCmd({ }); if (i === 0) { - msg.channel.createMessage( + msg.channel.send( trimLines(` ${args.search ? "Total roles found" : "Total roles"}: ${roles.length} \`\`\`py\n${roleLines.join("\n")}\`\`\` `), ); } else { - msg.channel.createMessage("```py\n" + roleLines.join("\n") + "```"); + msg.channel.send("```py\n" + roleLines.join("\n") + "```"); } } }, diff --git a/backend/src/plugins/Utility/commands/ServerInfoCmd.ts b/backend/src/plugins/Utility/commands/ServerInfoCmd.ts index 97a5d06a..aaf74c57 100644 --- a/backend/src/plugins/Utility/commands/ServerInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/ServerInfoCmd.ts @@ -21,6 +21,6 @@ export const ServerInfoCmd = utilityCmd({ return; } - message.channel.createMessage({ embed: serverInfoEmbed }); + message.channel.send({ embed: serverInfoEmbed }); }, }); diff --git a/backend/src/plugins/Utility/commands/SnowflakeInfoCmd.ts b/backend/src/plugins/Utility/commands/SnowflakeInfoCmd.ts index ee03044e..b2f5bb30 100644 --- a/backend/src/plugins/Utility/commands/SnowflakeInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/SnowflakeInfoCmd.ts @@ -16,6 +16,6 @@ export const SnowflakeInfoCmd = utilityCmd({ async run({ message, args, pluginData }) { const embed = await getSnowflakeInfoEmbed(pluginData, args.id, false, message.author.id); - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/SourceCmd.ts b/backend/src/plugins/Utility/commands/SourceCmd.ts index 83e76e15..5a5d0c28 100644 --- a/backend/src/plugins/Utility/commands/SourceCmd.ts +++ b/backend/src/plugins/Utility/commands/SourceCmd.ts @@ -22,9 +22,7 @@ export const SourceCmd = utilityCmd({ return; } - const message = await pluginData.client - .getMessage(args.message.channel.id, args.message.messageId) - .catch(() => null); + const message = await args.message.channel.messages.fetch(args.message.messageId).catch(() => null); if (!message) { sendErrorMessage(pluginData, cmdMessage.channel, "Unknown message"); return; @@ -44,6 +42,6 @@ export const SourceCmd = utilityCmd({ const archiveId = await pluginData.state.archives.create(source, moment.utc().add(1, "hour")); const baseUrl = getBaseUrl(pluginData); const url = pluginData.state.archives.getUrl(baseUrl, archiveId); - cmdMessage.channel.createMessage(`Message source: ${url}`); + cmdMessage.channel.send(`Message source: ${url}`); }, }); diff --git a/backend/src/plugins/Utility/commands/UserInfoCmd.ts b/backend/src/plugins/Utility/commands/UserInfoCmd.ts index dca35e24..b7ceba39 100644 --- a/backend/src/plugins/Utility/commands/UserInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/UserInfoCmd.ts @@ -23,6 +23,6 @@ export const UserInfoCmd = utilityCmd({ return; } - message.channel.createMessage({ embed }); + message.channel.send({ embed }); }, }); diff --git a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts index c0e0cf63..d69c0fad 100644 --- a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts +++ b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts @@ -10,7 +10,7 @@ import { import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { LogType } from "../../../data/LogType"; -import { resolveChannel } from "knub/dist/helpers"; +import { VoiceChannel } from "discord.js"; export const VcdisconnectCmd = utilityCmd({ trigger: ["vcdisconnect", "vcdisc", "vcdc", "vckick", "vck"], @@ -28,16 +28,14 @@ export const VcdisconnectCmd = utilityCmd({ return; } - if (!args.member.voiceState || !args.member.voiceState.channelID) { + if (!args.member.voice || !args.member.voice.channelID) { sendErrorMessage(pluginData, msg.channel, "Member is not in a voice channel"); return; } - const channel = (await resolveChannel(pluginData.guild, args.member.voiceState.channelID)) as VoiceChannel; + const channel = pluginData.guild.channels.cache.get(args.member.voice.channelID) as VoiceChannel; try { - await args.member.edit({ - channelID: null, - }); + await args.member.voice.kick(); } catch { sendErrorMessage(pluginData, msg.channel, "Failed to disconnect member"); return; diff --git a/backend/src/plugins/Utility/commands/VcmoveCmd.ts b/backend/src/plugins/Utility/commands/VcmoveCmd.ts index ae28f873..87c2ef74 100644 --- a/backend/src/plugins/Utility/commands/VcmoveCmd.ts +++ b/backend/src/plugins/Utility/commands/VcmoveCmd.ts @@ -11,6 +11,7 @@ import { import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { LogType } from "../../../data/LogType"; +import { VoiceChannel } from "discord.js"; export const VcmoveCmd = utilityCmd({ trigger: "vcmove", @@ -47,7 +48,7 @@ export const VcmoveCmd = utilityCmd({ channel = potentialChannel; } else { // Search string -> find closest matching voice channel name - const voiceChannels = pluginData.guild.channels.filter(theChannel => { + const voiceChannels = pluginData.guild.channels.cache.array().filter(theChannel => { return theChannel instanceof VoiceChannel; }) as VoiceChannel[]; const closestMatch = simpleClosestStringMatch(args.channel, voiceChannels, ch => ch.name); @@ -59,21 +60,21 @@ export const VcmoveCmd = utilityCmd({ channel = closestMatch; } - if (!args.member.voiceState || !args.member.voiceState.channelID) { + if (!args.member.voice || !args.member.voice.channelID) { sendErrorMessage(pluginData, msg.channel, "Member is not in a voice channel"); return; } - if (args.member.voiceState.channelID === channel.id) { + if (args.member.voice.channelID === channel.id) { sendErrorMessage(pluginData, msg.channel, "Member is already on that channel!"); return; } - const oldVoiceChannel = pluginData.guild.channels.cache.get(args.member.voiceState.channelID); + const oldVoiceChannel = pluginData.guild.channels.cache.get(args.member.voice.channelID); try { await args.member.edit({ - channelID: channel.id, + channel: channel.id, }); } catch { sendErrorMessage(pluginData, msg.channel, "Failed to move member"); @@ -130,7 +131,7 @@ export const VcmoveAllCmd = utilityCmd({ channel = potentialChannel; } else { // Search string -> find closest matching voice channel name - const voiceChannels = pluginData.guild.channels.filter(theChannel => { + const voiceChannels = pluginData.guild.channels.cache.array().filter(theChannel => { return theChannel instanceof VoiceChannel; }) as VoiceChannel[]; const closestMatch = simpleClosestStringMatch(args.channel, voiceChannels, ch => ch.name); @@ -142,7 +143,7 @@ export const VcmoveAllCmd = utilityCmd({ channel = closestMatch; } - if (args.oldChannel.voiceMembers.size === 0) { + if (args.oldChannel.members.size === 0) { sendErrorMessage(pluginData, msg.channel, "Voice channel is empty"); return; } @@ -154,9 +155,9 @@ export const VcmoveAllCmd = utilityCmd({ // Cant leave null, otherwise we get an assignment error in the catch let currMember = msg.member; - const moveAmt = args.oldChannel.voiceMembers.size; + const moveAmt = args.oldChannel.members.size; let errAmt = 0; - for (const memberWithId of args.oldChannel.voiceMembers) { + for (const memberWithId of args.oldChannel.members) { currMember = memberWithId[1]; // Check for permissions but allow self-moves @@ -164,7 +165,7 @@ export const VcmoveAllCmd = utilityCmd({ sendErrorMessage( pluginData, msg.channel, - `Failed to move ${currMember.username}#${currMember.discriminator} (${currMember.id}): You cannot act on this member`, + `Failed to move ${currMember.user.username}#${currMember.user.discriminator} (${currMember.id}): You cannot act on this member`, ); errAmt++; continue; @@ -172,7 +173,7 @@ export const VcmoveAllCmd = utilityCmd({ try { currMember.edit({ - channelID: channel.id, + channel: channel.id, }); } catch { if (msg.member.id === currMember.id) { @@ -182,7 +183,7 @@ export const VcmoveAllCmd = utilityCmd({ sendErrorMessage( pluginData, msg.channel, - `Failed to move ${currMember.username}#${currMember.discriminator} (${currMember.id})`, + `Failed to move ${currMember.user.username}#${currMember.user.discriminator} (${currMember.id})`, ); errAmt++; continue; diff --git a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts index 45756642..69b3d10c 100644 --- a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts @@ -5,6 +5,8 @@ import moment from "moment-timezone"; import humanizeDuration from "humanize-duration"; import { EmbedWith, formatNumber, preEmbedPadding, trimLines } from "../../../utils"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { MessageEmbedOptions, Constants, VoiceChannel, StageChannel } from "discord.js"; +import { ChannelTypeStrings } from "src/types"; const TEXT_CHANNEL_ICON = "https://cdn.discordapp.com/attachments/740650744830623756/740656843545772062/text-channel.png"; @@ -19,7 +21,7 @@ export async function getChannelInfoEmbed( pluginData: GuildPluginData, channelId: string, requestMemberId?: string, -): Promise { +): Promise { const channel = pluginData.guild.channels.cache.get(channelId); if (!channel) { return null; @@ -30,22 +32,22 @@ export async function getChannelInfoEmbed( }; let icon = TEXT_CHANNEL_ICON; - if (channel.type === Constants.ChannelTypes.GUILD_VOICE) { + if (channel.type === ChannelTypeStrings.VOICE) { icon = VOICE_CHANNEL_ICON; - } else if (channel.type === Constants.ChannelTypes.GUILD_NEWS) { + } else if (channel.type === ChannelTypeStrings.NEWS) { icon = ANNOUNCEMENT_CHANNEL_ICON; - } else if (channel.type === Constants.ChannelTypes.GUILD_STAGE) { + } else if (channel.type === ChannelTypeStrings.STAGE) { icon = STAGE_CHANNEL_ICON; } const channelType = { - [Constants.ChannelTypes.GUILD_TEXT]: "Text channel", - [Constants.ChannelTypes.GUILD_VOICE]: "Voice channel", - [Constants.ChannelTypes.GUILD_CATEGORY]: "Category", - [Constants.ChannelTypes.GUILD_NEWS]: "Announcement channel", - [Constants.ChannelTypes.GUILD_STORE]: "Store channel", - [Constants.ChannelTypes.GUILD_STAGE]: "Stage channel", + [ChannelTypeStrings.TEXT]: "Text channel", + [ChannelTypeStrings.VOICE]: "Voice channel", + [ChannelTypeStrings.CATEGORY]: "Category", + [ChannelTypeStrings.NEWS]: "Announcement channel", + [ChannelTypeStrings.STORE]: "Store channel", + [ChannelTypeStrings.STAGE]: "Stage channel", }[channel.type] || "Channel"; embed.author = { @@ -55,9 +57,9 @@ export async function getChannelInfoEmbed( let channelName = `#${channel.name}`; if ( - channel.type === Constants.ChannelTypes.GUILD_VOICE || - channel.type === Constants.ChannelTypes.GUILD_CATEGORY || - channel.type === Constants.ChannelTypes.GUILD_STAGE + channel.type === ChannelTypeStrings.VOICE || + channel.type === ChannelTypeStrings.CATEGORY || + channel.type === ChannelTypeStrings.STAGE ) { channelName = channel.name; } @@ -68,12 +70,12 @@ export async function getChannelInfoEmbed( ? await timeAndDate.inMemberTz(requestMemberId, createdAt) : timeAndDate.inGuildTz(createdAt); const prettyCreatedAt = tzCreatedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const channelAge = humanizeDuration(Date.now() - channel.createdAt, { + const channelAge = humanizeDuration(Date.now() - channel.createdTimestamp, { largest: 2, round: true, }); - const showMention = channel.type !== Constants.ChannelTypes.GUILD_CATEGORY; + const showMention = channel.type !== ChannelTypeStrings.CATEGORY; embed.fields.push({ name: preEmbedPadding + "Channel information", @@ -86,11 +88,11 @@ export async function getChannelInfoEmbed( `), }); - if (channel.type === Constants.ChannelTypes.GUILD_VOICE || channel.type === Constants.ChannelTypes.GUILD_STAGE) { - const voiceMembers = Array.from(channel.voiceMembers.values()); - const muted = voiceMembers.filter(vm => vm.voiceState.mute || vm.voiceState.selfMute); - const deafened = voiceMembers.filter(vm => vm.voiceState.deaf || vm.voiceState.selfDeaf); - const voiceOrStage = channel.type === Constants.ChannelTypes.GUILD_VOICE ? "Voice" : "Stage"; + if (channel.type === ChannelTypeStrings.VOICE || channel.type === ChannelTypeStrings.STAGE) { + const voiceMembers = Array.from((channel as VoiceChannel | StageChannel).members.values()); + const muted = voiceMembers.filter(vm => vm.voice.mute || vm.voice.selfMute); + const deafened = voiceMembers.filter(vm => vm.voice.deaf || vm.voice.selfDeaf); + const voiceOrStage = channel.type === ChannelTypeStrings.VOICE ? "Voice" : "Stage"; embed.fields.push({ name: preEmbedPadding + `${voiceOrStage} information`, @@ -102,21 +104,20 @@ export async function getChannelInfoEmbed( }); } - if (channel.type === Constants.ChannelTypes.GUILD_CATEGORY) { - const textChannels = pluginData.guild.channels.filter( - ch => ch.parentID === channel.id && ch.type !== Constants.ChannelTypes.GUILD_VOICE, + if (channel.type === ChannelTypeStrings.CATEGORY) { + const textChannels = pluginData.guild.channels.cache.filter( + ch => ch.parentID === channel.id && ch.type !== ChannelTypeStrings.VOICE, ); - const voiceChannels = pluginData.guild.channels.filter( + const voiceChannels = pluginData.guild.channels.cache.filter( ch => - ch.parentID === channel.id && - (ch.type === Constants.ChannelTypes.GUILD_VOICE || ch.type === Constants.ChannelTypes.GUILD_STAGE), + ch.parentID === channel.id && (ch.type === ChannelTypeStrings.VOICE || ch.type === ChannelTypeStrings.STAGE), ); embed.fields.push({ name: preEmbedPadding + "Category information", value: trimLines(` - Text channels: **${textChannels.length}** - Voice channels: **${voiceChannels.length}** + Text channels: **${textChannels.size}** + Voice channels: **${voiceChannels.size}** `), }); } diff --git a/backend/src/plugins/Utility/functions/getEmojiInfoEmbed.ts b/backend/src/plugins/Utility/functions/getEmojiInfoEmbed.ts index b1e8297e..46ce8ab7 100644 --- a/backend/src/plugins/Utility/functions/getEmojiInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getEmojiInfoEmbed.ts @@ -1,12 +1,13 @@ import { GuildPluginData } from "knub"; import { UtilityPluginType } from "../types"; import { trimLines, preEmbedPadding, EmbedWith } from "../../../utils"; +import { MessageEmbedOptions } from "discord.js"; export async function getEmojiInfoEmbed( pluginData: GuildPluginData, emojiId: string, -): Promise { - const emoji = pluginData.guild.emojis.find(e => e.id === emojiId); +): Promise { + const emoji = pluginData.guild.emojis.cache.find(e => e.id === emojiId); if (!emoji) { return null; } diff --git a/backend/src/plugins/Utility/functions/getGuildPreview.ts b/backend/src/plugins/Utility/functions/getGuildPreview.ts index 34d7f73c..3da2c823 100644 --- a/backend/src/plugins/Utility/functions/getGuildPreview.ts +++ b/backend/src/plugins/Utility/functions/getGuildPreview.ts @@ -1,8 +1,9 @@ +import { Client, GuildPreview } from "discord.js"; import { memoize, MINUTES } from "../../../utils"; /** * Memoized getGuildPreview */ export function getGuildPreview(client: Client, guildId: string): Promise { - return memoize(() => client.getGuildPreview(guildId).catch(() => null), `getGuildPreview_${guildId}`, 10 * MINUTES); + return memoize(() => client.fetchGuildPreview(guildId).catch(() => null), `getGuildPreview_${guildId}`, 10 * MINUTES); } diff --git a/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts b/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts index dff670b5..78be9002 100644 --- a/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts @@ -9,6 +9,7 @@ import { EmbedWith, emptyEmbedValue, formatNumber, + GroupDMInvite, inviteHasCounts, isGroupDMInvite, isGuildInvite, @@ -16,12 +17,14 @@ import { resolveInvite, trimLines, } from "../../../utils"; +import { MessageEmbedOptions, Constants, Invite } from "discord.js"; +import { ChannelTypeStrings } from "src/types"; export async function getInviteInfoEmbed( pluginData: GuildPluginData, inviteCode: string, -): Promise { - const invite = await resolveInvite(pluginData.client, inviteCode, true); +): Promise { + let invite = await resolveInvite(pluginData.client, inviteCode, true); if (!invite) { return null; } @@ -67,9 +70,7 @@ export async function getInviteInfoEmbed( }); const channelName = - invite.channel.type === Constants.ChannelTypes.GUILD_VOICE - ? `🔉 ${invite.channel.name}` - : `#${invite.channel.name}`; + invite.channel.type === ChannelTypeStrings.VOICE ? `🔉 ${invite.channel.name}` : `#${invite.channel.name}`; const channelCreatedAtTimestamp = snowflakeToTimestamp(invite.channel.id); const channelCreatedAt = moment.utc(channelCreatedAtTimestamp, "x"); @@ -84,7 +85,7 @@ export async function getInviteInfoEmbed( Created: **${channelAge} ago** `); - if (invite.channel.type !== Constants.ChannelTypes.GUILD_VOICE) { + if (invite.channel.type !== ChannelTypeStrings.VOICE) { channelInfo += `\nMention: <#${invite.channel.id}>`; } @@ -113,16 +114,17 @@ export async function getInviteInfoEmbed( fields: [], }; + invite = invite as GroupDMInvite; embed.author = { name: invite.channel.name ? `Group DM invite: ${invite.channel.name}` : `Group DM invite`, url: `https://discord.gg/${invite.code}`, - }; + }; // FIXME pending invite re-think - if (invite.channel.icon) { + /*if (invite.channel.icon) { embed.author.icon_url = `https://cdn.discordapp.com/channel-icons/${invite.channel.id}/${invite.channel.icon}.png?size=256`; - } - - const channelCreatedAtTimestamp = snowflakeToTimestamp(invite.channel.id); + }*/ const channelCreatedAtTimestamp = snowflakeToTimestamp( + invite.channel.id, + ); const channelCreatedAt = moment.utc(channelCreatedAtTimestamp, "x"); const channelAge = humanizeDuration(Date.now() - channelCreatedAtTimestamp, { largest: 2, diff --git a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts index 798ec63a..2b3ad188 100644 --- a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts @@ -6,6 +6,8 @@ import humanizeDuration from "humanize-duration"; import { chunkMessageLines, EmbedWith, messageLink, preEmbedPadding, trimEmptyLines, trimLines } from "../../../utils"; import { getDefaultPrefix } from "knub/dist/commands/commandUtils"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { MessageEmbedOptions, Constants, TextChannel } from "discord.js"; +import { MessageTypeStrings } from "src/types"; const MESSAGE_ICON = "https://cdn.discordapp.com/attachments/740650744830623756/740685652152025088/message.png"; @@ -14,8 +16,10 @@ export async function getMessageInfoEmbed( channelId: string, messageId: string, requestMemberId?: string, -): Promise { - const message = await pluginData.client.getMessage(channelId, messageId).catch(() => null); +): Promise { + const message = await (pluginData.guild.channels.resolve(channelId) as TextChannel).messages + .fetch(messageId) + .catch(() => null); if (!message) { return null; } @@ -36,12 +40,12 @@ export async function getMessageInfoEmbed( ? await timeAndDate.inMemberTz(requestMemberId, createdAt) : timeAndDate.inGuildTz(createdAt); const prettyCreatedAt = tzCreatedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const messageAge = humanizeDuration(Date.now() - message.createdAt, { + const messageAge = humanizeDuration(Date.now() - message.createdTimestamp, { largest: 2, round: true, }); - const editedAt = message.editedTimestamp && moment.utc(message.editedTimestamp, "x"); + const editedAt = message.editedTimestamp ? moment.utc(message.editedTimestamp!, "x") : undefined; const tzEditedAt = requestMemberId ? await timeAndDate.inMemberTz(requestMemberId, editedAt) : timeAndDate.inGuildTz(editedAt); @@ -55,16 +59,16 @@ export async function getMessageInfoEmbed( const type = { - [Constants.MessageTypes.DEFAULT]: "Regular message", - [Constants.MessageTypes.CHANNEL_PINNED_MESSAGE]: "System message", - [Constants.MessageTypes.GUILD_MEMBER_JOIN]: "System message", - [Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION]: "System message", - [Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1]: "System message", - [Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2]: "System message", - [Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3]: "System message", - [Constants.MessageTypes.CHANNEL_FOLLOW_ADD]: "System message", - [Constants.MessageTypes.GUILD_DISCOVERY_DISQUALIFIED]: "System message", - [Constants.MessageTypes.GUILD_DISCOVERY_REQUALIFIED]: "System message", + [MessageTypeStrings.DEFAULT]: "Regular message", + [MessageTypeStrings.PINS_ADD]: "System message", + [MessageTypeStrings.GUILD_MEMBER_JOIN]: "System message", + [MessageTypeStrings.USER_PREMIUM_GUILD_SUBSCRIPTION]: "System message", + [MessageTypeStrings.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1]: "System message", + [MessageTypeStrings.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2]: "System message", + [MessageTypeStrings.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3]: "System message", + [MessageTypeStrings.CHANNEL_FOLLOW_ADD]: "System message", + [MessageTypeStrings.GUILD_DISCOVERY_DISQUALIFIED]: "System message", + [MessageTypeStrings.GUILD_DISCOVERY_REQUALIFIED]: "System message", }[message.type] || "Unknown"; embed.fields.push({ @@ -87,12 +91,12 @@ export async function getMessageInfoEmbed( ? await timeAndDate.inMemberTz(requestMemberId, authorCreatedAt) : timeAndDate.inGuildTz(authorCreatedAt); const prettyAuthorCreatedAt = tzAuthorCreatedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const authorAccountAge = humanizeDuration(Date.now() - message.author.createdAt, { + const authorAccountAge = humanizeDuration(Date.now() - message.author.createdTimestamp, { largest: 2, round: true, }); - const authorJoinedAt = message.member && moment.utc(message.member.joinedAt, "x"); + const authorJoinedAt = message.member && moment.utc(message.member.joinedTimestamp!, "x"); const tzAuthorJoinedAt = authorJoinedAt ? requestMemberId ? await timeAndDate.inMemberTz(requestMemberId, authorJoinedAt) @@ -101,7 +105,7 @@ export async function getMessageInfoEmbed( const prettyAuthorJoinedAt = tzAuthorJoinedAt?.format(timeAndDate.getDateFormat("pretty_datetime")); const authorServerAge = message.member && - humanizeDuration(Date.now() - message.member.joinedAt, { + humanizeDuration(Date.now() - message.member.joinedTimestamp!, { largest: 2, round: true, }); @@ -126,7 +130,7 @@ export async function getMessageInfoEmbed( }); } - if (message.attachments.length) { + if (message.attachments.size) { embed.fields.push({ name: preEmbedPadding + "Attachments", value: message.attachments[0].url, diff --git a/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts b/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts index e5dff015..6bf58c3e 100644 --- a/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts @@ -4,6 +4,7 @@ import { trimLines, preEmbedPadding, EmbedWith } from "../../../utils"; import moment from "moment-timezone"; import humanizeDuration from "humanize-duration"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { Role, MessageEmbedOptions } from "discord.js"; const MENTION_ICON = "https://cdn.discordapp.com/attachments/705009450855039042/839284872152481792/mention.png"; @@ -11,7 +12,7 @@ export async function getRoleInfoEmbed( pluginData: GuildPluginData, role: Role, requestMemberId?: string, -): Promise { +): Promise { const embed: EmbedWith<"fields"> = { fields: [], }; @@ -29,12 +30,12 @@ export async function getRoleInfoEmbed( ? await timeAndDate.inMemberTz(requestMemberId, createdAt) : timeAndDate.inGuildTz(createdAt); const prettyCreatedAt = tzCreatedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const roleAge = humanizeDuration(Date.now() - role.createdAt, { + const roleAge = humanizeDuration(Date.now() - role.createdTimestamp, { largest: 2, round: true, }); - const rolePerms = Object.keys(role.permissions.json).map(p => + const rolePerms = Object.keys(role.permissions.toJSON()).map(p => p // Voice channel related permission names start with 'voice' .replace(/^voice/i, "") @@ -44,7 +45,7 @@ export async function getRoleInfoEmbed( ); // -1 because of the @everyone role - const totalGuildRoles = pluginData.guild.roles.size - 1; + const totalGuildRoles = pluginData.guild.roles.cache.size - 1; embed.fields.push({ name: preEmbedPadding + "Role information", diff --git a/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts b/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts index a49deea6..fdbd3d66 100644 --- a/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts @@ -17,16 +17,17 @@ import moment from "moment-timezone"; import humanizeDuration from "humanize-duration"; import { getGuildPreview } from "./getGuildPreview"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { MessageEmbedOptions, CategoryChannel, TextChannel, VoiceChannel } from "discord.js"; export async function getServerInfoEmbed( pluginData: GuildPluginData, serverId: string, requestMemberId?: string, -): Promise { +): Promise { const thisServer = serverId === pluginData.guild.id ? pluginData.guild : null; const [restGuild, guildPreview] = await Promise.all([ thisServer - ? memoize(() => pluginData.client.getRESTGuild(serverId), `getRESTGuild_${serverId}`, 10 * MINUTES) + ? memoize(() => pluginData.client.guilds.fetch(serverId), `getRESTGuild_${serverId}`, 10 * MINUTES) : null, getGuildPreview(pluginData.client, serverId), ]); @@ -46,12 +47,12 @@ export async function getServerInfoEmbed( embed.author = { name: `Server: ${(guildPreview || restGuild)!.name}`, - icon_url: (guildPreview || restGuild)!.iconURL ?? undefined, + iconURL: (guildPreview || restGuild)!.iconURL() ?? undefined, }; // BASIC INFORMATION const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin); - const createdAt = moment.utc((guildPreview || restGuild)!.createdAt, "x"); + const createdAt = moment.utc((guildPreview || restGuild)!.id, "x"); // FIXME ID -> Timestamp const tzCreatedAt = requestMemberId ? await timeAndDate.inMemberTz(requestMemberId, createdAt) : timeAndDate.inGuildTz(createdAt); @@ -86,7 +87,7 @@ export async function getServerInfoEmbed( const bannerUrl = restGuild?.bannerURL ? `[Link](${restGuild.bannerURL})` : "None"; const splashUrl = (restGuild || guildPreview)!.splashURL != null - ? `[Link](${(restGuild || guildPreview)!.splashURL?.replace("size=128", "size=2048")})` + ? `[Link](${(restGuild || guildPreview)!.splashURL()?.replace("size=128", "size=2048")})` : "None"; embed.fields.push( @@ -113,33 +114,33 @@ export async function getServerInfoEmbed( restGuild?.approximateMemberCount || restGuild?.memberCount || thisServer?.memberCount || - thisServer?.members.size || + thisServer?.members.cache.size || 0; let onlineMemberCount = (guildPreview?.approximatePresenceCount || restGuild?.approximatePresenceCount)!; - if (onlineMemberCount == null && restGuild?.vanityURL) { + if (onlineMemberCount == null && restGuild?.vanityURLCode) { // For servers with a vanity URL, we can also use the numbers from the invite for online count - const invite = await resolveInvite(pluginData.client, restGuild.vanityURL!, true); + const invite = await resolveInvite(pluginData.client, restGuild.vanityURLCode!, true); if (invite && inviteHasCounts(invite)) { onlineMemberCount = invite.presenceCount; } } if (!onlineMemberCount && thisServer) { - onlineMemberCount = thisServer.members.filter(m => m.status !== "offline").length; // Extremely inaccurate fallback + onlineMemberCount = thisServer.members.cache.filter(m => m.presence.status !== "offline").size; // Extremely inaccurate fallback } const offlineMemberCount = totalMembers - onlineMemberCount; let memberCountTotalLines = `Total: **${formatNumber(totalMembers)}**`; - if (restGuild?.maxMembers) { - memberCountTotalLines += `\nMax: **${formatNumber(restGuild.maxMembers)}**`; + if (restGuild?.maximumMembers) { + memberCountTotalLines += `\nMax: **${formatNumber(restGuild.maximumMembers)}**`; } let memberCountOnlineLines = `Online: **${formatNumber(onlineMemberCount)}**`; - if (restGuild?.maxPresences) { - memberCountOnlineLines += `\nMax online: **${formatNumber(restGuild.maxPresences)}**`; + if (restGuild?.maximumPresences) { + memberCountOnlineLines += `\nMax online: **${formatNumber(restGuild.maximumPresences)}**`; } embed.fields.push({ @@ -154,19 +155,19 @@ export async function getServerInfoEmbed( // CHANNEL COUNTS if (thisServer) { - const totalChannels = thisServer.channels.size; - const categories = thisServer.channels.filter(channel => channel instanceof CategoryChannel); - const textChannels = thisServer.channels.filter(channel => channel instanceof TextChannel); - const voiceChannels = thisServer.channels.filter(channel => channel instanceof VoiceChannel); + const totalChannels = thisServer.channels.cache.size; + const categories = thisServer.channels.cache.filter(channel => channel instanceof CategoryChannel); + const textChannels = thisServer.channels.cache.filter(channel => channel instanceof TextChannel); + const voiceChannels = thisServer.channels.cache.filter(channel => channel instanceof VoiceChannel); embed.fields.push({ name: preEmbedPadding + "Channels", inline: true, value: trimLines(` Total: **${totalChannels}** / 500 - Categories: **${categories.length}** - Text: **${textChannels.length}** - Voice: **${voiceChannels.length}** + Categories: **${categories.size}** + Text: **${textChannels.size}** + Voice: **${voiceChannels.size}** `), }); } @@ -175,7 +176,7 @@ export async function getServerInfoEmbed( const otherStats: string[] = []; if (thisServer) { - otherStats.push(`Roles: **${thisServer.roles.size}** / 250`); + otherStats.push(`Roles: **${thisServer.roles.cache.size}** / 250`); } if (restGuild) { @@ -186,9 +187,9 @@ export async function getServerInfoEmbed( 2: 150, 3: 250, }[restGuild.premiumTier] || 50; - otherStats.push(`Emojis: **${restGuild.emojis.length}** / ${maxEmojis * 2}`); + otherStats.push(`Emojis: **${restGuild.emojis.cache.size}** / ${maxEmojis * 2}`); } else { - otherStats.push(`Emojis: **${guildPreview!.emojis.length}**`); + otherStats.push(`Emojis: **${guildPreview!.emojis.size}**`); } if (thisServer) { diff --git a/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts b/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts index bd0e39fc..0cec52bd 100644 --- a/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts @@ -14,6 +14,7 @@ import { CaseTypes } from "../../../data/CaseTypes"; import humanizeDuration from "humanize-duration"; import { snowflakeToTimestamp } from "../../../utils/snowflakeToTimestamp"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { MessageEmbedOptions } from "discord.js"; const SNOWFLAKE_ICON = "https://cdn.discordapp.com/attachments/740650744830623756/742020790471491668/snowflake.png"; @@ -22,7 +23,7 @@ export async function getSnowflakeInfoEmbed( snowflake: string, showUnknownWarning = false, requestMemberId?: string, -): Promise { +): Promise { const embed: EmbedWith<"fields"> = { fields: [], }; diff --git a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts index d6c2a0be..09c2fc59 100644 --- a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts @@ -15,13 +15,14 @@ import moment from "moment-timezone"; import { CaseTypes } from "../../../data/CaseTypes"; import humanizeDuration from "humanize-duration"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; +import { MessageEmbedOptions, Role } from "discord.js"; export async function getUserInfoEmbed( pluginData: GuildPluginData, userId: string, compact = false, requestMemberId?: string, -): Promise { +): Promise { const user = await resolveUser(pluginData.client, userId); if (!user || user instanceof UnknownUser) { return null; @@ -39,7 +40,7 @@ export async function getUserInfoEmbed( name: `User: ${user.username}#${user.discriminator}`, }; - const avatarURL = user.avatarURL || user.defaultAvatarURL; + const avatarURL = user.avatarURL() || user.defaultAvatarURL; embed.author.icon_url = avatarURL; const createdAt = moment.utc(user.createdAt, "x"); @@ -47,7 +48,7 @@ export async function getUserInfoEmbed( ? await timeAndDate.inMemberTz(requestMemberId, createdAt) : timeAndDate.inGuildTz(createdAt); const prettyCreatedAt = tzCreatedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const accountAge = humanizeDuration(moment.utc().valueOf() - user.createdAt, { + const accountAge = humanizeDuration(moment.utc().valueOf() - user.createdTimestamp, { largest: 2, round: true, }); @@ -61,12 +62,12 @@ export async function getUserInfoEmbed( `), }); if (member) { - const joinedAt = moment.utc(member.joinedAt, "x"); + const joinedAt = moment.utc(member.joinedTimestamp!, "x"); const tzJoinedAt = requestMemberId ? await timeAndDate.inMemberTz(requestMemberId, joinedAt) : timeAndDate.inGuildTz(joinedAt); const prettyJoinedAt = tzJoinedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const joinAge = humanizeDuration(moment.utc().valueOf() - member.joinedAt, { + const joinAge = humanizeDuration(moment.utc().valueOf() - member.joinedTimestamp!, { largest: 2, round: true, }); @@ -92,16 +93,18 @@ export async function getUserInfoEmbed( }); if (member) { - const joinedAt = moment.utc(member.joinedAt, "x"); + const joinedAt = moment.utc(member.joinedTimestamp!, "x"); const tzJoinedAt = requestMemberId ? await timeAndDate.inMemberTz(requestMemberId, joinedAt) : timeAndDate.inGuildTz(joinedAt); const prettyJoinedAt = tzJoinedAt.format(timeAndDate.getDateFormat("pretty_datetime")); - const joinAge = humanizeDuration(moment.utc().valueOf() - member.joinedAt, { + const joinAge = humanizeDuration(moment.utc().valueOf() - member.joinedTimestamp!, { largest: 2, round: true, }); - const roles = member.roles.map(id => pluginData.guild.roles.cache.get(id)).filter(r => r != null) as Role[]; + const roles = member.roles.cache + .map(role => pluginData.guild.roles.cache.get(role.id)) + .filter(r => r != null) as Role[]; roles.sort(sorter("position", "DESC")); embed.fields.push({ @@ -112,16 +115,14 @@ export async function getUserInfoEmbed( `), }); - const voiceChannel = member.voiceState.channelID - ? pluginData.guild.channels.cache.get(member.voiceState.channelID) - : null; - if (voiceChannel || member.voiceState.mute || member.voiceState.deaf) { + const voiceChannel = member.voice.channelID ? pluginData.guild.channels.cache.get(member.voice.channelID) : null; + if (voiceChannel || member.voice.mute || member.voice.deaf) { embed.fields.push({ name: preEmbedPadding + "Voice information", value: trimLines(` ${voiceChannel ? `Current voice channel: **${voiceChannel ? voiceChannel.name : "None"}**` : ""} - ${member.voiceState.mute ? "Server voice muted: **Yes**" : ""} - ${member.voiceState.deaf ? "Server voice deafened: **Yes**" : ""} + ${member.voice.mute ? "Server voice muted: **Yes**" : ""} + ${member.voice.deaf ? "Server voice deafened: **Yes**" : ""} `), }); } diff --git a/backend/src/plugins/Utility/guildReloads.ts b/backend/src/plugins/Utility/guildReloads.ts index a44b514d..b5cb292b 100644 --- a/backend/src/plugins/Utility/guildReloads.ts +++ b/backend/src/plugins/Utility/guildReloads.ts @@ -1 +1,3 @@ +import { TextChannel } from "discord.js"; + export const activeReloads: Map = new Map(); diff --git a/backend/src/plugins/Utility/refreshMembers.ts b/backend/src/plugins/Utility/refreshMembers.ts index a0ffc09f..aa4920d6 100644 --- a/backend/src/plugins/Utility/refreshMembers.ts +++ b/backend/src/plugins/Utility/refreshMembers.ts @@ -1,3 +1,4 @@ +import { Guild } from "discord.js"; import { HOURS, noop } from "../../utils"; const MEMBER_REFRESH_FREQUENCY = 1 * HOURS; // How often to do a full member refresh when using commands that need it @@ -9,7 +10,7 @@ export async function refreshMembersIfNeeded(guild: Guild) { return lastRefresh.promise; } - const loadPromise = guild.fetchAllMembers().then(noop); + const loadPromise = guild.members.fetch().then(noop); memberRefreshLog.set(guild.id, { time: Date.now(), promise: loadPromise, diff --git a/backend/src/plugins/Utility/search.ts b/backend/src/plugins/Utility/search.ts index 4900d0ce..75c8dbce 100644 --- a/backend/src/plugins/Utility/search.ts +++ b/backend/src/plugins/Utility/search.ts @@ -14,6 +14,7 @@ import { inputPatternToRegExp, InvalidRegexError } from "../../validatorUtils"; import { asyncFilter } from "../../utils/async"; import Timeout = NodeJS.Timeout; import { hasDiscordPermissions } from "../../utils/hasDiscordPermissions"; +import { Message, User, Constants, TextChannel, GuildMember, Permissions } from "discord.js"; const SEARCH_RESULTS_PER_PAGE = 15; const SEARCH_ID_RESULTS_PER_PAGE = 50; @@ -90,7 +91,7 @@ export async function displaySearch( if (originalSearchMsg) { searchMsgPromise = originalSearchMsg.edit("Searching..."); } else { - searchMsgPromise = msg.channel.createMessage("Searching..."); + searchMsgPromise = msg.channel.send("Searching..."); searchMsgPromise.then(m => (originalSearchMsg = m)); } @@ -106,12 +107,12 @@ export async function displaySearch( } } catch (e) { if (e instanceof SearchError) { - sendErrorMessage(pluginData, msg.channel, e.message); + sendErrorMessage(pluginData, msg.channel as TextChannel, e.message); return; } if (e instanceof InvalidRegexError) { - sendErrorMessage(pluginData, msg.channel, e.message); + sendErrorMessage(pluginData, msg.channel as TextChannel, e.message); return; } @@ -119,7 +120,7 @@ export async function displaySearch( } if (searchResult.totalResults === 0) { - sendErrorMessage(pluginData, msg.channel, "No results found"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "No results found"); return; } @@ -149,7 +150,7 @@ export async function displaySearch( const embed = await getUserInfoEmbed(pluginData, searchResult.results[0].id, false); if (embed) { searchMsg.edit("Only one result:"); - msg.channel.createMessage({ embed }); + msg.channel.send({ embed }); return; } } @@ -160,30 +161,32 @@ export async function displaySearch( if (searchResult.totalResults > perPage) { if (!hasReactions) { hasReactions = true; - searchMsg.addReaction("⬅"); - searchMsg.addReaction("➡"); - searchMsg.addReaction("🔄"); + searchMsg.react("⬅"); + searchMsg.react("➡"); + searchMsg.react("🔄"); - const listenerFn = pluginData.events.on("messageReactionAdd", ({ args: { message: rMsg, emoji, member } }) => { + const listenerFn = pluginData.events.on("messageReactionAdd", async ({ args: { reaction, user } }) => { + const rMsg = reaction.message; + const member = await pluginData.guild.members.fetch(user.id); if (rMsg.id !== searchMsg.id) return; - if (member.id !== msg.author.id) return; - if (!["⬅", "➡", "🔄"].includes(emoji.name)) return; + if (member.user.id !== msg.author.id) return; + if (!["⬅", "➡", "🔄"].includes(reaction.emoji.name!)) return; - if (emoji.name === "⬅" && currentPage > 1) { + if (reaction.emoji.name === "⬅" && currentPage > 1) { loadSearchPage(currentPage - 1); - } else if (emoji.name === "➡" && currentPage < searchResult.lastPage) { + } else if (reaction.emoji.name === "➡" && currentPage < searchResult.lastPage) { loadSearchPage(currentPage + 1); - } else if (emoji.name === "🔄") { + } else if (reaction.emoji.name === "🔄") { loadSearchPage(currentPage); } if (isFullMessage(rMsg)) { - rMsg.removeReaction(emoji.name, member.id); + reaction.remove(); } }); clearReactionsFn = async () => { - searchMsg.removeReactions().catch(noop); + searchMsg.reactions.removeAll().catch(noop); pluginData.events.off("messageReactionAdd", listenerFn); }; } @@ -229,12 +232,12 @@ export async function archiveSearch( } } catch (e) { if (e instanceof SearchError) { - sendErrorMessage(pluginData, msg.channel, e.message); + sendErrorMessage(pluginData, msg.channel as TextChannel, e.message); return; } if (e instanceof InvalidRegexError) { - sendErrorMessage(pluginData, msg.channel, e.message); + sendErrorMessage(pluginData, msg.channel as TextChannel, e.message); return; } @@ -242,7 +245,7 @@ export async function archiveSearch( } if (results.totalResults === 0) { - sendErrorMessage(pluginData, msg.channel, "No results found"); + sendErrorMessage(pluginData, msg.channel as TextChannel, "No results found"); return; } @@ -260,7 +263,7 @@ export async function archiveSearch( const baseUrl = getBaseUrl(pluginData); const url = await pluginData.state.archives.getUrl(baseUrl, archiveId); - await msg.channel.createMessage(`Exported search results: ${url}`); + await msg.channel.send(`Exported search results: ${url}`); } async function performMemberSearch( @@ -268,16 +271,16 @@ async function performMemberSearch( args: MemberSearchParams, page = 1, perPage = SEARCH_RESULTS_PER_PAGE, -): Promise<{ results: Member[]; totalResults: number; page: number; lastPage: number; from: number; to: number }> { +): Promise<{ results: GuildMember[]; totalResults: number; page: number; lastPage: number; from: number; to: number }> { await refreshMembersIfNeeded(pluginData.guild); - let matchingMembers = Array.from(pluginData.guild.members.values()); + let matchingMembers = Array.from(pluginData.guild.members.cache.values()); if (args.role) { const roleIds = args.role.split(","); matchingMembers = matchingMembers.filter(member => { for (const role of roleIds) { - if (!member.roles.includes(role)) return false; + if (!member.roles.cache.has(role)) return false; } return true; @@ -285,11 +288,11 @@ async function performMemberSearch( } if (args.voice) { - matchingMembers = matchingMembers.filter(m => m.voiceState.channelID != null); + matchingMembers = matchingMembers.filter(m => m.voice.channelID != null); } if (args.bot) { - matchingMembers = matchingMembers.filter(m => m.bot); + matchingMembers = matchingMembers.filter(m => m.user.bot); } if (args.query) { @@ -306,6 +309,7 @@ async function performMemberSearch( const execRegExp = getOptimizedRegExpRunner(pluginData, isSafeRegex); + /** FIXME if we ever get the intent for this again if (args["status-search"]) { matchingMembers = await asyncFilter(matchingMembers, async member => { if (member.game) { @@ -344,17 +348,18 @@ async function performMemberSearch( return false; }); } else { - matchingMembers = await asyncFilter(matchingMembers, async member => { - if (member.nick && (await execRegExp(queryRegex, member.nick).catch(allowTimeout))) { - return true; - } + */ + matchingMembers = await asyncFilter(matchingMembers, async member => { + if (member.nickname && (await execRegExp(queryRegex, member.nickname).catch(allowTimeout))) { + return true; + } - const fullUsername = `${member.user.username}#${member.user.discriminator}`; - if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true; + const fullUsername = `${member.user.username}#${member.user.discriminator}`; + if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true; - return false; - }); - } + return false; + }); + // } FIXME in conjunction with above comment } const [, sortDir, sortBy] = (args.sort && args.sort.match(/^(-?)(.*)$/)) ?? [null, "ASC", "name"]; @@ -396,11 +401,11 @@ async function performBanSearch( perPage = SEARCH_RESULTS_PER_PAGE, ): Promise<{ results: User[]; totalResults: number; page: number; lastPage: number; from: number; to: number }> { const member = pluginData.guild.members.cache.get(pluginData.client.user!.id); - if (member && !hasDiscordPermissions(member.permissions, Constants.Permissions.banMembers)) { + if (member && !hasDiscordPermissions(member.permissions, Permissions.FLAGS.BAN_MEMBERS)) { throw new SearchError(`Unable to search bans: missing "Ban Members" permission`); } - let matchingBans = (await pluginData.guild.getBans()).map(x => x.user); + let matchingBans = (await pluginData.guild.bans.fetch({ cache: false })).map(x => x.user); if (args.query) { let isSafeRegex = true; @@ -454,14 +459,14 @@ async function performBanSearch( }; } -function formatSearchResultList(members: Array): string { +function formatSearchResultList(members: Array): string { const longestId = members.reduce((longest, member) => Math.max(longest, member.id.length), 0); const lines = members.map(member => { const paddedId = member.id.padEnd(longestId, " "); let line; - if (member instanceof Member) { + if (member instanceof GuildMember) { line = `${paddedId} ${member.user.username}#${member.user.discriminator}`; - if (member.nick) line += ` (${member.nick})`; + if (member.nickname) line += ` (${member.nickname})`; } else { line = `${paddedId} ${member.username}#${member.discriminator}`; } @@ -470,6 +475,6 @@ function formatSearchResultList(members: Array): string { return lines.join("\n"); } -function formatSearchResultIdList(members: Array): string { +function formatSearchResultIdList(members: Array): string { return members.map(m => m.id).join(" "); } diff --git a/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts b/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts index 7317aaac..50d54b94 100644 --- a/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts +++ b/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts @@ -4,6 +4,7 @@ import { createChunkedMessage, stripObjectToScalars } from "../../../utils"; import { LogType } from "../../../data/LogType"; import { sendDM } from "../../../utils/sendDM"; +import { TextChannel } from "discord.js"; export const SendWelcomeMessageEvt = welcomeMessageEvt({ event: "guildMemberAdd", @@ -55,7 +56,7 @@ export const SendWelcomeMessageEvt = welcomeMessageEvt({ } if (config.send_to_channel) { - const channel = meta.args.guild.channels.cache.get(config.send_to_channel); + const channel = meta.args.member.guild.channels.cache.get(config.send_to_channel); if (!channel || !(channel instanceof TextChannel)) return; try { diff --git a/backend/src/types.ts b/backend/src/types.ts index 6378ad27..add1d061 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -75,3 +75,25 @@ export enum ChannelTypeStrings { STAGE = "stage", UNKNOWN = "unknown", } + +export enum MessageTypeStrings { + "DEFAULT", + "RECIPIENT_ADD", + "RECIPIENT_REMOVE", + "CALL", + "CHANNEL_NAME_CHANGE", + "CHANNEL_ICON_CHANGE", + "PINS_ADD", + "GUILD_MEMBER_JOIN", + "USER_PREMIUM_GUILD_SUBSCRIPTION", + "USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1", + "USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2", + "USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3", + "CHANNEL_FOLLOW_ADD", + "GUILD_DISCOVERY_DISQUALIFIED", + "GUILD_DISCOVERY_REQUALIFIED", + "GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING", + "GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING", + "REPLY", + "APPLICATION_COMMAND", +} diff --git a/backend/src/utils.test.ts b/backend/src/utils.test.ts index 9d72ce0f..ba1da55e 100644 --- a/backend/src/utils.test.ts +++ b/backend/src/utils.test.ts @@ -2,7 +2,7 @@ import * as ioTs from "io-ts"; import { convertDelayStringToMS, convertMSToDelayString, getUrlsInString, tAllowedMentions } from "./utils"; import test from "ava"; -import { AllowedMentions as ErisAllowedMentions } from "eris"; +import { erisAllowedMentionFormat } from "./utils/erisAllowedMentionsToDjsMentionOptions"; type AssertEquals = TActual extends TExpected ? true : false; @@ -52,6 +52,6 @@ test("delay strings: reverse conversion (conservative)", t => { test("tAllowedMentions matches Eris's AllowedMentions", t => { type TAllowedMentions = ioTs.TypeOf; - const typeTest: AssertEquals = true; + const typeTest: AssertEquals = true; t.pass(); }); diff --git a/backend/src/utils.ts b/backend/src/utils.ts index 549ebdd1..cfd33bf3 100644 --- a/backend/src/utils.ts +++ b/backend/src/utils.ts @@ -34,6 +34,8 @@ import { MessageEmbedOptions, MessageMentionOptions, MessageOptions, + PartialChannelData, + PartialMessage, StringResolvable, TextChannel, User, @@ -200,9 +202,9 @@ export function nonNullish(v: V): v is NonNullable { } export type InviteOpts = "withMetadata" | "withCount" | "withoutCount"; -export type GuildInvite = Invite & { guild: Guild }; -export type GroupDMInvite = Invite & { - channel: InvitePartialChannel; +export type GuildInvite = Invite & { guild: Guild }; +export type GroupDMInvite = Invite & { + channel: PartialChannelData; type: typeof Constants.ChannelTypes.GROUP; }; @@ -486,7 +488,7 @@ export async function findRelevantAuditLogEntry( } } - const entries = auditLogs ? auditLogs.entries : []; + const entries = auditLogs ? auditLogs.entries.array() : []; entries.sort((a, b) => { if (a.createdAt > b.createdAt) return -1; @@ -497,7 +499,7 @@ export async function findRelevantAuditLogEntry( const cutoffTS = Date.now() - 1000 * 60 * 2; const relevantEntry = entries.find(entry => { - return entry.targetID === userId && entry.createdAt >= cutoffTS; + return (entry.target as { id }).id === userId && entry.createdTimestamp >= cutoffTS; }); if (relevantEntry) { @@ -1119,7 +1121,7 @@ export function resolveUserId(bot: Client, value: string) { // A non-mention, full username? const usernameMatch = value.match(/^@?([^#]+)#(\d{4})$/); if (usernameMatch) { - const user = bot.users.find(u => u.username === usernameMatch[1] && u.discriminator === usernameMatch[2]); + const user = bot.users.cache.find(u => u.username === usernameMatch[1] && u.discriminator === usernameMatch[2]); if (user) return user.id; } @@ -1250,9 +1252,7 @@ export async function resolveRoleId(bot: Client, guildId: string, value: string) const inviteCache = new SimpleCache>(10 * MINUTES, 200); -type ResolveInviteReturnType = Promise< - (T extends true ? Invite<"withCount" | "withMetadata"> : Invite<"withMetadata">) | null ->; +type ResolveInviteReturnType = Promise; export async function resolveInvite( client: Client, code: string, @@ -1278,7 +1278,7 @@ export async function confirm( content: StringResolvable | MessageOptions, ) { const msg = await channel.send(content); - const reply = await helpers.waitForReaction(bot, msg, ["✅", "❌"], userId); + const reply: any = {}; // await helpers.waitForReaction(bot, msg, ["✅", "❌"], userId); FIXME waiting on waitForButton msg.delete().catch(noop); return reply && reply.name === "✅"; } @@ -1436,19 +1436,19 @@ export function trimMultilineString(str) { } export const trimPluginDescription = trimMultilineString; -export function isFullMessage(msg: PossiblyUncachedMessage): msg is Message { +export function isFullMessage(msg: Message | PartialMessage): msg is Message { return (msg as Message).createdAt != null; } -export function isGuildInvite(invite: Invite): invite is GuildInvite { +export function isGuildInvite(invite: Invite): invite is GuildInvite { return invite.guild != null; } -export function isGroupDMInvite(invite: Invite): invite is GroupDMInvite { +export function isGroupDMInvite(invite: Invite): invite is GroupDMInvite { return invite.guild == null && invite.channel?.type === "group"; } -export function inviteHasCounts(invite: Invite): invite is Invite<"withCount"> { +export function inviteHasCounts(invite: Invite): invite is Invite { return invite.memberCount != null; } diff --git a/backend/src/utils/erisAllowedMentionsToDjsMentionOptions.ts b/backend/src/utils/erisAllowedMentionsToDjsMentionOptions.ts index 776871d4..c12cec79 100644 --- a/backend/src/utils/erisAllowedMentionsToDjsMentionOptions.ts +++ b/backend/src/utils/erisAllowedMentionsToDjsMentionOptions.ts @@ -36,8 +36,8 @@ export function erisAllowedMentionsToDjsMentionOptions( } export interface erisAllowedMentionFormat { - everyone: boolean | undefined; - users: boolean | string[] | undefined; - roles: boolean | string[] | undefined; - repliedUser: boolean | undefined; + everyone?: boolean | undefined; + users?: boolean | string[] | undefined; + roles?: boolean | string[] | undefined; + repliedUser?: boolean | undefined; }