From 8f7a6510eb6e6525a40b7eff540bfd8a4d86afa5 Mon Sep 17 00:00:00 2001 From: Dark <7890309+DarkView@users.noreply.github.com> Date: Mon, 31 May 2021 21:12:24 +0200 Subject: [PATCH] Pre-plugin moves --- backend/src/RecoverablePluginError.ts | 2 +- backend/src/commandTypes.ts | 6 ++-- backend/src/data/GuildArchives.ts | 4 +-- backend/src/data/GuildSavedMessages.ts | 16 +++++----- backend/src/data/entities/SavedMessage.ts | 4 +-- backend/src/data/entities/ScheduledPost.ts | 4 +-- backend/src/pluginUtils.ts | 35 +++++++++++---------- backend/src/types.ts | 1 - backend/src/utils/canAssignRole.ts | 12 +++---- backend/src/utils/canReadChannel.ts | 4 +-- backend/src/utils/createPaginatedMessage.ts | 15 +++++++-- backend/src/utils/hasDiscordPermissions.ts | 9 ++++-- backend/src/utils/messageHasContent.ts | 2 +- 13 files changed, 62 insertions(+), 52 deletions(-) diff --git a/backend/src/RecoverablePluginError.ts b/backend/src/RecoverablePluginError.ts index 3cb1c7ac..e34a2ab2 100644 --- a/backend/src/RecoverablePluginError.ts +++ b/backend/src/RecoverablePluginError.ts @@ -1,4 +1,4 @@ -import { Guild } from "eris"; +import { Guild } from "discord.js"; export enum ERRORS { NO_MUTE_ROLE_IN_CONFIG = 1, diff --git a/backend/src/commandTypes.ts b/backend/src/commandTypes.ts index cfebf1ac..647dde5c 100644 --- a/backend/src/commandTypes.ts +++ b/backend/src/commandTypes.ts @@ -3,7 +3,6 @@ import { convertDelayStringToMS, disableCodeBlocks, disableInlineCode, - isSnowflake, isValidSnowflake, resolveMember, resolveUser, @@ -11,13 +10,12 @@ import { roleMentionRegex, UnknownUser, } from "./utils"; -import { GuildChannel, Member, TextChannel, User } from "eris"; import { baseTypeConverters, baseCommandParameterTypeHelpers, CommandContext, TypeConversionError } from "knub"; import { createTypeHelper } from "knub-command-manager"; -import { getChannelIdFromMessageId } from "./data/getChannelIdFromMessageId"; import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget"; import { inputPatternToRegExp } from "./validatorUtils"; import { isValidTimezone } from "./utils/isValidTimezone"; +import { GuildChannel, GuildMember, User } from "discord.js"; export const commandTypes = { ...baseTypeConverters, @@ -112,7 +110,7 @@ export const commandTypeHelpers = { delay: createTypeHelper(commandTypes.delay), resolvedUser: createTypeHelper>(commandTypes.resolvedUser), resolvedUserLoose: createTypeHelper>(commandTypes.resolvedUserLoose), - resolvedMember: createTypeHelper>(commandTypes.resolvedMember), + resolvedMember: createTypeHelper>(commandTypes.resolvedMember), messageTarget: createTypeHelper>(commandTypes.messageTarget), anyId: createTypeHelper>(commandTypes.anyId), regex: createTypeHelper(commandTypes.regex), diff --git a/backend/src/data/GuildArchives.ts b/backend/src/data/GuildArchives.ts index a67048d5..9c1ea69c 100644 --- a/backend/src/data/GuildArchives.ts +++ b/backend/src/data/GuildArchives.ts @@ -4,8 +4,8 @@ import { getRepository, Repository } from "typeorm"; import { BaseGuildRepository } from "./BaseGuildRepository"; import { trimLines } from "../utils"; import { SavedMessage } from "./entities/SavedMessage"; -import { Guild } from "eris"; import { renderTemplate } from "../templateFormatter"; +import { Guild } from "discord.js"; const DEFAULT_EXPIRY_DAYS = 30; @@ -73,7 +73,7 @@ export class GuildArchives extends BaseGuildRepository { protected async renderLinesFromSavedMessages(savedMessages: SavedMessage[], guild: Guild) { const msgLines: string[] = []; for (const msg of savedMessages) { - const channel = guild.channels.get(msg.channel_id); + const channel = guild.channels.cache.get(msg.channel_id); const user = { ...msg.data.author, id: msg.user_id }; const line = await renderTemplate(MESSAGE_ARCHIVE_MESSAGE_FORMAT, { diff --git a/backend/src/data/GuildSavedMessages.ts b/backend/src/data/GuildSavedMessages.ts index 5653fb84..7bc4134d 100644 --- a/backend/src/data/GuildSavedMessages.ts +++ b/backend/src/data/GuildSavedMessages.ts @@ -2,11 +2,11 @@ import { getRepository, Repository } from "typeorm"; import { BaseGuildRepository } from "./BaseGuildRepository"; import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage"; import { QueuedEventEmitter } from "../QueuedEventEmitter"; -import { GuildChannel, Message, PossiblyUncachedTextableChannel } from "eris"; import moment from "moment-timezone"; import { MINUTES, SECONDS } from "../utils"; import { isAPI } from "../globals"; import { cleanupMessages } from "./cleanup/messages"; +import { GuildChannel, Message } from "discord.js"; if (!isAPI()) { const CLEANUP_INTERVAL = 5 * MINUTES; @@ -34,19 +34,19 @@ export class GuildSavedMessages extends BaseGuildRepository { this.toBePermanent = new Set(); } - public msgToSavedMessageData(msg: Message): ISavedMessageData { + public msgToSavedMessageData(msg: Message): ISavedMessageData { const data: ISavedMessageData = { author: { username: msg.author.username, discriminator: msg.author.discriminator, }, content: msg.content, - timestamp: msg.timestamp, + timestamp: msg.createdTimestamp, }; - if (msg.attachments.length) data.attachments = msg.attachments; + if (msg.attachments.size) data.attachments = msg.attachments.array(); if (msg.embeds.length) data.embeds = msg.embeds; - if (msg.stickers?.length) data.stickers = msg.stickers; + if (msg.stickers?.size) data.stickers = msg.stickers.array(); return data; } @@ -139,12 +139,12 @@ export class GuildSavedMessages extends BaseGuildRepository { this.events.emit(`create:${data.id}`, [inserted]); } - async createFromMsg(msg: Message, overrides = {}) { + async createFromMsg(msg: Message, overrides = {}) { const existingSavedMsg = await this.find(msg.id); if (existingSavedMsg) return; const savedMessageData = this.msgToSavedMessageData(msg); - const postedAt = moment.utc(msg.timestamp, "x").format("YYYY-MM-DD HH:mm:ss"); + const postedAt = moment.utc(msg.createdTimestamp, "x").format("YYYY-MM-DD HH:mm:ss"); const data = { id: msg.id, @@ -222,7 +222,7 @@ export class GuildSavedMessages extends BaseGuildRepository { this.events.emit(`update:${id}`, [newMessage, oldMessage]); } - async saveEditFromMsg(msg: Message) { + async saveEditFromMsg(msg: Message) { const newData = this.msgToSavedMessageData(msg); return this.saveEdit(msg.id, newData); } diff --git a/backend/src/data/entities/SavedMessage.ts b/backend/src/data/entities/SavedMessage.ts index ccccf7a2..77294366 100644 --- a/backend/src/data/entities/SavedMessage.ts +++ b/backend/src/data/entities/SavedMessage.ts @@ -1,9 +1,9 @@ +import { MessageAttachment, Sticker } from "discord.js"; import { Column, Entity, PrimaryColumn } from "typeorm"; import { createEncryptedJsonTransformer } from "../encryptedJsonTransformer"; -import { Attachment, Sticker } from "eris"; export interface ISavedMessageData { - attachments?: Attachment[]; + attachments?: MessageAttachment[]; author: { username: string; discriminator: string; diff --git a/backend/src/data/entities/ScheduledPost.ts b/backend/src/data/entities/ScheduledPost.ts index 0d136045..8b7d4088 100644 --- a/backend/src/data/entities/ScheduledPost.ts +++ b/backend/src/data/entities/ScheduledPost.ts @@ -1,5 +1,5 @@ +import { MessageAttachment } from "discord.js"; import { Column, Entity, PrimaryColumn } from "typeorm"; -import { Attachment } from "eris"; import { StrictMessageContent } from "../../utils"; @Entity("scheduled_posts") @@ -18,7 +18,7 @@ export class ScheduledPost { @Column("simple-json") content: StrictMessageContent; - @Column("simple-json") attachments: Attachment[]; + @Column("simple-json") attachments: MessageAttachment[]; @Column({ type: String, nullable: true }) post_at: string | null; diff --git a/backend/src/pluginUtils.ts b/backend/src/pluginUtils.ts index f1ea4616..23b21d0f 100644 --- a/backend/src/pluginUtils.ts +++ b/backend/src/pluginUtils.ts @@ -2,7 +2,6 @@ * @file Utility functions that are plugin-instance-specific (i.e. use PluginData) */ -import { AdvancedMessageContent, AllowedMentions, GuildTextableChannel, Member, Message, TextableChannel } from "eris"; import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub"; import { decodeAndValidateStrict, StrictValidationError, validate } from "./validatorUtils"; import { deepKeyIntersect, errorMessage, successMessage, tDeepPartial, tNullable } from "./utils"; @@ -14,11 +13,17 @@ import { Tail } from "./utils/typeUtils"; import { AnyPluginData } from "knub/dist/plugins/PluginData"; import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin"; import { logger } from "./logger"; +import { APIMessage, GuildMember, Message, MessageMentionOptions, MessageOptions, TextChannel, User } from "discord.js"; const { getMemberLevel } = helpers; -export function canActOn(pluginData: GuildPluginData, member1: Member, member2: Member, allowSameLevel = false) { - if (member2.id === pluginData.client.user.id) { +export function canActOn( + pluginData: GuildPluginData, + member1: GuildMember, + member2: GuildMember, + allowSameLevel = false, +) { + if (member2.id === pluginData.client.user!.id) { return false; } @@ -180,21 +185,19 @@ export function getPluginConfigPreprocessor( export function sendSuccessMessage( pluginData: AnyPluginData, - channel: TextableChannel, + channel: TextChannel, body: string, - allowedMentions?: AllowedMentions, + allowedMentions?: MessageMentionOptions, ): Promise { const emoji = pluginData.fullConfig.success_emoji || undefined; const formattedBody = successMessage(body, emoji); - const content: AdvancedMessageContent = allowedMentions + const content: MessageOptions = allowedMentions ? { content: formattedBody, allowedMentions } : { content: formattedBody }; return channel - .createMessage(content) // Force line break + .send({ content }) // Force line break .catch(err => { - const channelInfo = (channel as GuildTextableChannel).guild - ? `${channel.id} (${(channel as GuildTextableChannel).guild.id})` - : `${channel.id}`; + const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : `${channel.id}`; logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`); return undefined; }); @@ -202,21 +205,19 @@ export function sendSuccessMessage( export function sendErrorMessage( pluginData: AnyPluginData, - channel: TextableChannel, + channel: TextChannel, body: string, - allowedMentions?: AllowedMentions, + allowedMentions?: MessageMentionOptions, ): Promise { const emoji = pluginData.fullConfig.error_emoji || undefined; const formattedBody = errorMessage(body, emoji); - const content: AdvancedMessageContent = allowedMentions + const content: MessageOptions = allowedMentions ? { content: formattedBody, allowedMentions } : { content: formattedBody }; return channel - .createMessage(content) // Force line break + .send({ ...content, split: false }) // Force line break .catch(err => { - const channelInfo = (channel as GuildTextableChannel).guild - ? `${channel.id} (${(channel as GuildTextableChannel).guild.id})` - : `${channel.id}`; + const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : `${channel.id}`; logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`); return undefined; }); diff --git a/backend/src/types.ts b/backend/src/types.ts index 324817bb..6378ad27 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -1,6 +1,5 @@ import { BaseConfig, Knub } from "knub"; import * as t from "io-ts"; -import { Message } from "eris"; export interface ZeppelinGuildConfig extends BaseConfig { success_emoji?: string; diff --git a/backend/src/utils/canAssignRole.ts b/backend/src/utils/canAssignRole.ts index f42778bd..17de0e45 100644 --- a/backend/src/utils/canAssignRole.ts +++ b/backend/src/utils/canAssignRole.ts @@ -1,9 +1,9 @@ -import { Constants, Guild, Member, Role } from "eris"; +import { Guild, GuildMember, Permissions, Role } from "discord.js"; import { getMissingPermissions } from "./getMissingPermissions"; import { hasDiscordPermissions } from "./hasDiscordPermissions"; -export function canAssignRole(guild: Guild, member: Member, roleId: string) { - if (getMissingPermissions(member.permission, Constants.Permissions.manageRoles)) { +export function canAssignRole(guild: Guild, member: GuildMember, roleId: string) { + if (getMissingPermissions(member.permissions, Permissions.FLAGS.MANAGE_ROLES)) { return false; } @@ -11,14 +11,14 @@ export function canAssignRole(guild: Guild, member: Member, roleId: string) { return false; } - const targetRole = guild.roles.get(roleId); + const targetRole = guild.roles.cache.get(roleId); if (!targetRole) { return false; } - const memberRoles = member.roles.map(_roleId => guild.roles.get(_roleId)!); + const memberRoles = member.roles.cache; const highestRoleWithManageRoles = memberRoles.reduce((highest, role) => { - if (!hasDiscordPermissions(role.permissions, Constants.Permissions.manageRoles)) return highest; + if (!hasDiscordPermissions(role.permissions, Permissions.FLAGS.MANAGE_ROLES)) return highest; if (highest == null) return role; if (role.position > highest.position) return role; return highest; diff --git a/backend/src/utils/canReadChannel.ts b/backend/src/utils/canReadChannel.ts index fb14874a..6f1b3fe2 100644 --- a/backend/src/utils/canReadChannel.ts +++ b/backend/src/utils/canReadChannel.ts @@ -1,8 +1,8 @@ -import { Constants, GuildChannel, Member } from "eris"; import { readChannelPermissions } from "./readChannelPermissions"; import { getMissingChannelPermissions } from "./getMissingChannelPermissions"; +import { GuildChannel, GuildMember } from "discord.js"; -export function canReadChannel(channel: GuildChannel, member: Member) { +export function canReadChannel(channel: GuildChannel, member: GuildMember) { // Not missing permissions required to read the channel = can read channel return !getMissingChannelPermissions(member, channel, readChannelPermissions); } diff --git a/backend/src/utils/createPaginatedMessage.ts b/backend/src/utils/createPaginatedMessage.ts index e3289881..a398c8da 100644 --- a/backend/src/utils/createPaginatedMessage.ts +++ b/backend/src/utils/createPaginatedMessage.ts @@ -1,9 +1,18 @@ -import { APIMessage, Client, Message, MessageReaction, PartialUser, TextChannel, User } from "discord.js"; +import { + APIMessage, + Client, + Message, + MessageOptions, + MessageReaction, + PartialUser, + TextChannel, + User, +} from "discord.js"; import { Awaitable } from "knub/dist/utils"; import { MINUTES, noop } from "../utils"; import Timeout = NodeJS.Timeout; -export type LoadPageFn = (page: number) => Awaitable; +export type LoadPageFn = (page: number) => Awaitable; export interface PaginateMessageOpts { timeout: number; @@ -24,7 +33,7 @@ export async function createPaginatedMessage( ): Promise { const fullOpts = { ...defaultOpts, ...opts } as PaginateMessageOpts; const firstPageContent = await loadPageFn(1); - const message = await channel.send(firstPageContent); + const message = await channel.send({ content: firstPageContent }); let page = 1; let pageLoadId = 0; // Used to avoid race conditions when rapidly switching pages diff --git a/backend/src/utils/hasDiscordPermissions.ts b/backend/src/utils/hasDiscordPermissions.ts index 28391195..34b6d9e1 100644 --- a/backend/src/utils/hasDiscordPermissions.ts +++ b/backend/src/utils/hasDiscordPermissions.ts @@ -1,11 +1,14 @@ -import { PermissionOverwrites, Permissions } from "discord.js"; +import { Permissions } from "discord.js"; /** * @param resolvedPermissions A Permission object from e.g. GuildChannel#permissionsOf() or Member#permission * @param requiredPermissions Bitmask of required permissions */ -export function hasDiscordPermissions(resolvedPermissions: PermissionOverwrites, requiredPermissions: number | bigint) { - const allowedPermissions = BigInt(resolvedPermissions.allow); +export function hasDiscordPermissions( + resolvedPermissions: Permissions | Readonly, + requiredPermissions: number | bigint, +) { + const allowedPermissions = BigInt(resolvedPermissions); const nRequiredPermissions = BigInt(requiredPermissions); if (Boolean(allowedPermissions & BigInt(Permissions.FLAGS.ADMINISTRATOR))) { diff --git a/backend/src/utils/messageHasContent.ts b/backend/src/utils/messageHasContent.ts index 40aaca8e..e333f5c9 100644 --- a/backend/src/utils/messageHasContent.ts +++ b/backend/src/utils/messageHasContent.ts @@ -1,4 +1,4 @@ -import { APIMessage, MessageOptions } from "discord.js"; +import { MessageOptions } from "discord.js"; function embedHasContent(embed: any) { for (const [key, value] of Object.entries(embed)) {