diff --git a/backend/package-lock.json b/backend/package-lock.json index 984a6020..1ec24d2c 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -14,7 +14,7 @@ "cors": "^2.8.5", "cross-env": "^5.2.0", "deep-diff": "^1.0.2", - "discord.js": "^13.0.0-dev.2e078e4.1625529824", + "discord.js": "^13.0.0-dev.07017a9.1626869177", "dotenv": "^4.0.0", "emoji-regex": "^8.0.0", "erlpack": "github:discord/erlpack", @@ -81,8 +81,8 @@ "version": "30.0.0-beta.38", "license": "MIT", "dependencies": { - "discord-api-types": "^0.18.1", - "discord.js": "^13.0.0-dev.2e078e4.1625529824", + "discord-api-types": "^0.19.0-next.836e8fb.1625574825", + "discord.js": "^13.0.0-dev.07017a9.1626869177", "knub-command-manager": "^9.1.0", "ts-essentials": "^6.0.7" }, @@ -2159,9 +2159,9 @@ } }, "node_modules/discord.js": { - "version": "13.0.0-dev.2e078e4.1625529824", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.0.0-dev.2e078e4.1625529824.tgz", - "integrity": "sha512-NKNnoEmh3+4eCG44BOIBjlJS0bKQEH8OgWoEjdJ9K53MYa5lfqbSho4NKXe5+hVpMr+U43wJ8ByUvw96ogqu8w==", + "version": "13.0.0-dev.07017a9.1626869177", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.0.0-dev.07017a9.1626869177.tgz", + "integrity": "sha512-awnE/59Sy6tnoAZUP7/f8tudcDT68WXxK0pgZZpA7WTGfyR5+IokWsFmkbS49dDll7OZQbi+L8iRt8ahYo3PGQ==", "dependencies": { "@discordjs/builders": "^0.2.0", "@discordjs/collection": "^0.1.6", @@ -2169,7 +2169,7 @@ "@sapphire/async-queue": "^1.1.4", "@types/ws": "^7.4.5", "abort-controller": "^3.0.0", - "discord-api-types": "^0.19.0-next.f393ba520d7d6d2aacaca7b3ca5d355fab614f6e", + "discord-api-types": "^0.19.0", "node-fetch": "^2.6.1", "ws": "^7.5.1" }, @@ -2179,9 +2179,9 @@ } }, "node_modules/discord.js/node_modules/discord-api-types": { - "version": "0.19.0-next.f393ba520d7d6d2aacaca7b3ca5d355fab614f6e", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.19.0-next.f393ba520d7d6d2aacaca7b3ca5d355fab614f6e.tgz", - "integrity": "sha512-ttRA/8e/WKHDbGFfED5WlS7gID+kalmNr6iMiWBCvkphQ7kFHiTOVbnj/zX9ksaRaYXp/I38SCQ+qZvLu8DJZg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.19.0.tgz", + "integrity": "sha512-t2HKLd43Lbe+rf+ffYfKVv9Kk5f6p7sFqvO6CMV55ZB0PgZv8WigCkt9FoJciYo5S3Q6CGYK+WnE/ZG+6vkBDQ==", "engines": { "node": ">=12" } @@ -8034,9 +8034,9 @@ "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==" }, "discord.js": { - "version": "13.0.0-dev.2e078e4.1625529824", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.0.0-dev.2e078e4.1625529824.tgz", - "integrity": "sha512-NKNnoEmh3+4eCG44BOIBjlJS0bKQEH8OgWoEjdJ9K53MYa5lfqbSho4NKXe5+hVpMr+U43wJ8ByUvw96ogqu8w==", + "version": "13.0.0-dev.07017a9.1626869177", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.0.0-dev.07017a9.1626869177.tgz", + "integrity": "sha512-awnE/59Sy6tnoAZUP7/f8tudcDT68WXxK0pgZZpA7WTGfyR5+IokWsFmkbS49dDll7OZQbi+L8iRt8ahYo3PGQ==", "requires": { "@discordjs/builders": "^0.2.0", "@discordjs/collection": "^0.1.6", @@ -8044,15 +8044,15 @@ "@sapphire/async-queue": "^1.1.4", "@types/ws": "^7.4.5", "abort-controller": "^3.0.0", - "discord-api-types": "^0.19.0-next.f393ba520d7d6d2aacaca7b3ca5d355fab614f6e", + "discord-api-types": "^0.19.0", "node-fetch": "^2.6.1", "ws": "^7.5.1" }, "dependencies": { "discord-api-types": { - "version": "0.19.0-next.f393ba520d7d6d2aacaca7b3ca5d355fab614f6e", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.19.0-next.f393ba520d7d6d2aacaca7b3ca5d355fab614f6e.tgz", - "integrity": "sha512-ttRA/8e/WKHDbGFfED5WlS7gID+kalmNr6iMiWBCvkphQ7kFHiTOVbnj/zX9ksaRaYXp/I38SCQ+qZvLu8DJZg==" + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.19.0.tgz", + "integrity": "sha512-t2HKLd43Lbe+rf+ffYfKVv9Kk5f6p7sFqvO6CMV55ZB0PgZv8WigCkt9FoJciYo5S3Q6CGYK+WnE/ZG+6vkBDQ==" } } }, @@ -8877,8 +8877,8 @@ "@typescript-eslint/eslint-plugin": "^4.23.0", "@typescript-eslint/parser": "^4.23.0", "chai": "^4.3.4", - "discord-api-types": "^0.18.1", - "discord.js": "^13.0.0-dev.2e078e4.1625529824", + "discord-api-types": "^0.19.0-next.836e8fb.1625574825", + "discord.js": "^13.0.0-dev.07017a9.1626869177", "eslint": "^7.2.0", "husky": "^4.3.8", "knub-command-manager": "^9.1.0", diff --git a/backend/package.json b/backend/package.json index 792d8126..7751262b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -29,7 +29,7 @@ "cors": "^2.8.5", "cross-env": "^5.2.0", "deep-diff": "^1.0.2", - "discord.js": "^13.0.0-dev.2e078e4.1625529824", + "discord.js": "^13.0.0-dev.07017a9.1626869177", "dotenv": "^4.0.0", "emoji-regex": "^8.0.0", "erlpack": "github:discord/erlpack", diff --git a/backend/src/data/GuildArchives.ts b/backend/src/data/GuildArchives.ts index df69e6c1..e55ac905 100644 --- a/backend/src/data/GuildArchives.ts +++ b/backend/src/data/GuildArchives.ts @@ -1,5 +1,6 @@ import { Guild, Snowflake } from "discord.js"; import moment from "moment-timezone"; +import { isDefaultSticker } from "src/utils/isDefaultSticker"; import { getRepository, Repository } from "typeorm"; import { renderTemplate } from "../templateFormatter"; import { trimLines } from "../utils"; @@ -13,7 +14,7 @@ const MESSAGE_ARCHIVE_HEADER_FORMAT = trimLines(` Server: {guild.name} ({guild.id}) `); const MESSAGE_ARCHIVE_MESSAGE_FORMAT = - "[#{channel.name}] [{user.id}] [{timestamp}] {user.username}#{user.discriminator}: {content}{attachments}"; + "[#{channel.name}] [{user.id}] [{timestamp}] {user.username}#{user.discriminator}: {content}{attachments}{stickers}"; export class GuildArchives extends BaseGuildRepository { protected archives: Repository; @@ -80,6 +81,12 @@ export class GuildArchives extends BaseGuildRepository { id: msg.id, timestamp: moment.utc(msg.posted_at).format("YYYY-MM-DD HH:mm:ss"), content: msg.data.content, + attachments: msg.data.attachments?.map(att => { + return JSON.stringify({ name: att.name, url: att.url, type: att.contentType }); + }), + stickers: msg.data.stickers?.map(sti => { + return JSON.stringify({ name: sti.name, id: sti.id, isDefault: isDefaultSticker(sti.id) }); + }), user, channel, }); diff --git a/backend/src/data/GuildSavedMessages.ts b/backend/src/data/GuildSavedMessages.ts index 0ede8e83..7fbcb120 100644 --- a/backend/src/data/GuildSavedMessages.ts +++ b/backend/src/data/GuildSavedMessages.ts @@ -1,6 +1,7 @@ import { GuildChannel, Message } from "discord.js"; import moment from "moment-timezone"; import { getRepository, Repository } from "typeorm"; +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; import { isAPI } from "../globals"; import { QueuedEventEmitter } from "../QueuedEventEmitter"; import { MINUTES, SECONDS } from "../utils"; @@ -222,7 +223,7 @@ export class GuildSavedMessages extends BaseGuildRepository { // FIXME? { id }, { - data: newData, + data: newData as QueryDeepPartialEntity, }, ); diff --git a/backend/src/index.ts b/backend/src/index.ts index 83146fe2..52d555b3 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,4 +1,4 @@ -import { Client, Intents, TextChannel } from "discord.js"; +import { Client, Collection, Intents, Options, TextChannel } from "discord.js"; import fs from "fs"; import yaml from "js-yaml"; import { Knub, PluginError } from "knub"; @@ -166,7 +166,7 @@ connect().then(async () => { // Regular Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.GUILD_BANS, - Intents.FLAGS.GUILD_EMOJIS, + Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS, Intents.FLAGS.GUILD_INVITES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.GUILD_MESSAGES, diff --git a/backend/src/plugins/AutoDelete/util/deleteNextItem.ts b/backend/src/plugins/AutoDelete/util/deleteNextItem.ts index e18b8feb..0016a793 100644 --- a/backend/src/plugins/AutoDelete/util/deleteNextItem.ts +++ b/backend/src/plugins/AutoDelete/util/deleteNextItem.ts @@ -1,9 +1,10 @@ -import { Permissions, Snowflake, TextChannel } from "discord.js"; +import { Permissions, Snowflake, TextChannel, User } from "discord.js"; import { GuildPluginData } from "knub"; import moment from "moment-timezone"; +import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; -import { resolveUser, stripObjectToScalars, verboseChannelMention } from "../../../utils"; +import { resolveUser, verboseChannelMention } from "../../../utils"; import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; @@ -60,8 +61,8 @@ export async function deleteNextItem(pluginData: GuildPluginData renderTemplate(str, { - user: stripObjectToScalars(user), + user: userToConfigAccessibleUser(user), }); const formatted = typeof actionConfig === "string" diff --git a/backend/src/plugins/Automod/functions/setAntiraidLevel.ts b/backend/src/plugins/Automod/functions/setAntiraidLevel.ts index 328a8772..a9f086be 100644 --- a/backend/src/plugins/Automod/functions/setAntiraidLevel.ts +++ b/backend/src/plugins/Automod/functions/setAntiraidLevel.ts @@ -1,7 +1,7 @@ import { User } from "discord.js"; import { GuildPluginData } from "knub"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { LogType } from "../../../data/LogType"; -import { stripObjectToScalars } from "../../../utils"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { runAutomodOnAntiraidLevel } from "../events/runAutomodOnAntiraidLevel"; import { AutomodPluginType } from "../types"; @@ -21,7 +21,7 @@ export async function setAntiraidLevel( if (user) { logs.log(LogType.SET_ANTIRAID_USER, { level: newLevel ?? "off", - user: stripObjectToScalars(user), + user: userToConfigAccessibleUser(user), }); } else { logs.log(LogType.SET_ANTIRAID_AUTO, { diff --git a/backend/src/plugins/Censor/util/censorMessage.ts b/backend/src/plugins/Censor/util/censorMessage.ts index 29704425..bec20326 100644 --- a/backend/src/plugins/Censor/util/censorMessage.ts +++ b/backend/src/plugins/Censor/util/censorMessage.ts @@ -1,9 +1,10 @@ -import { Snowflake, TextChannel } from "discord.js"; +import { Snowflake, TextChannel, User } from "discord.js"; import { GuildPluginData } from "knub"; import { deactivateMentions, disableCodeBlocks } from "knub/dist/helpers"; +import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { SavedMessage } from "../../../data/entities/SavedMessage"; import { LogType } from "../../../data/LogType"; -import { resolveUser, stripObjectToScalars } from "../../../utils"; +import { resolveUser } from "../../../utils"; import { CensorPluginType } from "../types"; export async function censorMessage( @@ -21,11 +22,11 @@ export async function censorMessage( } const user = await resolveUser(pluginData.client, savedMessage.user_id); - const channel = pluginData.guild.channels.cache.get(savedMessage.channel_id as Snowflake); + const channel = pluginData.guild.channels.resolve(savedMessage.channel_id as Snowflake)!; pluginData.state.serverLogs.log(LogType.CENSOR, { - user: stripObjectToScalars(user), - channel: stripObjectToScalars(channel), + user: userToConfigAccessibleUser(user), + channel: channelToConfigAccessibleChannel(channel), reason, message: savedMessage, messageText: disableCodeBlocks(deactivateMentions(savedMessage.data.content)), diff --git a/backend/src/plugins/ChannelArchiver/rehostAttachment.ts b/backend/src/plugins/ChannelArchiver/rehostAttachment.ts index 13b65cfc..9f5c6423 100644 --- a/backend/src/plugins/ChannelArchiver/rehostAttachment.ts +++ b/backend/src/plugins/ChannelArchiver/rehostAttachment.ts @@ -1,11 +1,14 @@ -import { MessageAttachment, MessageOptions, TextChannel } from "discord.js"; +import { MessageAttachment, MessageOptions, TextChannel, ThreadChannel } from "discord.js"; import fs from "fs"; import { downloadFile } from "../../utils"; const fsp = fs.promises; const MAX_ATTACHMENT_REHOST_SIZE = 1024 * 1024 * 8; -export async function rehostAttachment(attachment: MessageAttachment, targetChannel: TextChannel): Promise { +export async function rehostAttachment( + attachment: MessageAttachment, + targetChannel: TextChannel | ThreadChannel, +): Promise { if (attachment.size > MAX_ATTACHMENT_REHOST_SIZE) { return "Attachment too big to rehost"; } diff --git a/backend/src/plugins/CompanionChannels/CompanionChannelsPlugin.ts b/backend/src/plugins/CompanionChannels/CompanionChannelsPlugin.ts index 8565c67b..54196d78 100644 --- a/backend/src/plugins/CompanionChannels/CompanionChannelsPlugin.ts +++ b/backend/src/plugins/CompanionChannels/CompanionChannelsPlugin.ts @@ -1,5 +1,5 @@ import { CooldownManager } from "knub"; -import { GuildLogs } from "../../../data/GuildLogs"; +import { GuildLogs } from "../../data/GuildLogs"; import { trimPluginDescription } from "../../utils"; import { LogsPlugin } from "../Logs/LogsPlugin"; import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint"; diff --git a/backend/src/plugins/Logs/events/LogsGuildMemberAddEvt.ts b/backend/src/plugins/Logs/events/LogsGuildMemberAddEvt.ts index ff814dee..801229fd 100644 --- a/backend/src/plugins/Logs/events/LogsGuildMemberAddEvt.ts +++ b/backend/src/plugins/Logs/events/LogsGuildMemberAddEvt.ts @@ -2,7 +2,6 @@ import humanizeDuration from "humanize-duration"; import moment from "moment-timezone"; import { memberToConfigAccessibleMember } from "../../../utils/configAccessibleObjects"; import { LogType } from "../../../data/LogType"; -import { stripObjectToScalars } from "../../../utils"; import { CasesPlugin } from "../../Cases/CasesPlugin"; import { logsEvt } from "../types"; @@ -20,7 +19,7 @@ export const LogsGuildMemberAddEvt = logsEvt({ }); pluginData.state.guildLogs.log(LogType.MEMBER_JOIN, { - member: stripObjectToScalars(member, ["user", "roles"]), + member: memberToConfigAccessibleMember(member), new: member.user.createdTimestamp >= newThreshold ? " :new:" : "", account_age: accountAge, }); diff --git a/backend/src/plugins/Logs/events/LogsUserUpdateEvts.ts b/backend/src/plugins/Logs/events/LogsUserUpdateEvts.ts index eff1bd68..aa997913 100644 --- a/backend/src/plugins/Logs/events/LogsUserUpdateEvts.ts +++ b/backend/src/plugins/Logs/events/LogsUserUpdateEvts.ts @@ -27,8 +27,8 @@ export const LogsGuildMemberUpdateEvt = logsEvt({ } if (!isEqual(oldMember.roles, member.roles)) { - const addedRoles = diff(member.roles, oldMember.roles); - const removedRoles = diff(oldMember.roles, member.roles); + const addedRoles = diff(member.roles.cache.keyArray(), oldMember.roles.cache.keyArray()); + const removedRoles = diff(oldMember.roles.cache.keyArray(), member.roles.cache.keyArray()); let skip = false; if ( diff --git a/backend/src/plugins/Logs/util/onMessageDelete.ts b/backend/src/plugins/Logs/util/onMessageDelete.ts index 637e6cd3..bcb10d14 100644 --- a/backend/src/plugins/Logs/util/onMessageDelete.ts +++ b/backend/src/plugins/Logs/util/onMessageDelete.ts @@ -1,15 +1,16 @@ -import { MessageAttachment, Snowflake } from "discord.js"; +import { MessageAttachment, Snowflake, User } from "discord.js"; import { GuildPluginData } from "knub"; import moment from "moment-timezone"; +import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { SavedMessage } from "../../../data/entities/SavedMessage"; import { LogType } from "../../../data/LogType"; -import { resolveUser, stripObjectToScalars, useMediaUrls } from "../../../utils"; +import { resolveUser, useMediaUrls } from "../../../utils"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; import { FORMAT_NO_TIMESTAMP, LogsPluginType } from "../types"; export async function onMessageDelete(pluginData: GuildPluginData, savedMessage: SavedMessage) { const user = await resolveUser(pluginData.client, savedMessage.user_id); - const channel = pluginData.guild.channels.cache.get(savedMessage.channel_id as Snowflake); + const channel = pluginData.guild.channels.resolve(savedMessage.channel_id as Snowflake)!; if (user) { // Replace attachment URLs with media URLs @@ -27,8 +28,8 @@ export async function onMessageDelete(pluginData: GuildPluginData, - channel: TextChannel, + channel: TextChannel | ThreadChannel, ids: string[], ) { const failed: string[] = []; diff --git a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts index 6dbfb67d..794e96ed 100644 --- a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts +++ b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts @@ -1,10 +1,11 @@ +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { Case } from "../../../data/entities/Case"; import { LogType } from "../../../data/LogType"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { resolveMember, resolveUser, stripObjectToScalars } from "../../../utils"; +import { resolveMember, resolveUser } from "../../../utils"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { modActionsCmd } from "../types"; @@ -83,7 +84,7 @@ export const AddCaseCmd = modActionsCmd({ // Log the action pluginData.state.serverLogs.log(LogType.CASE_CREATE, { - mod: stripObjectToScalars(mod.user), + mod: userToConfigAccessibleUser(mod.user), userId: user.id, caseNum: theCase.case_number, caseType: type.toUpperCase(), diff --git a/backend/src/plugins/ModActions/commands/BanCmd.ts b/backend/src/plugins/ModActions/commands/BanCmd.ts index 8ebc8e2a..34a18e36 100644 --- a/backend/src/plugins/ModActions/commands/BanCmd.ts +++ b/backend/src/plugins/ModActions/commands/BanCmd.ts @@ -1,11 +1,13 @@ +import { User } from "discord.js"; import humanizeDuration from "humanize-duration"; import { getMemberLevel } from "knub/dist/helpers"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { resolveMember, resolveUser, stripObjectToScalars } from "../../../utils"; +import { resolveMember, resolveUser } from "../../../utils"; import { banLock } from "../../../utils/lockNameHelpers"; import { waitForButtonConfirm } from "../../../utils/waitForInteraction"; import { banUserId } from "../functions/banUserId"; @@ -109,8 +111,8 @@ export const BanCmd = modActionsCmd({ }); const logtype = time ? LogType.MEMBER_TIMED_BAN : LogType.MEMBER_BAN; pluginData.state.serverLogs.log(logtype, { - mod: stripObjectToScalars(mod.user), - user: stripObjectToScalars(user), + mod: userToConfigAccessibleUser(mod.user), + user: userToConfigAccessibleUser(user), caseNumber: createdCase.case_number, reason, banTime: time ? humanizeDuration(time) : null, diff --git a/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts b/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts index 931ce82c..0550942f 100644 --- a/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts +++ b/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts @@ -1,5 +1,6 @@ import { TextChannel } from "discord.js"; import { helpers } from "knub"; +import { memberToConfigAccessibleMember } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { Case } from "../../../data/entities/Case"; import { LogType } from "../../../data/LogType"; @@ -81,7 +82,7 @@ export const DeleteCaseCmd = modActionsCmd({ const logs = pluginData.getPlugin(LogsPlugin); logs.log(LogType.CASE_DELETE, { - mod: stripObjectToScalars(message.member, ["user", "roles"]), + mod: memberToConfigAccessibleMember(message.member), case: stripObjectToScalars(theCase), }); } diff --git a/backend/src/plugins/ModActions/commands/ForcebanCmd.ts b/backend/src/plugins/ModActions/commands/ForcebanCmd.ts index b84c2283..d14b15a4 100644 --- a/backend/src/plugins/ModActions/commands/ForcebanCmd.ts +++ b/backend/src/plugins/ModActions/commands/ForcebanCmd.ts @@ -1,10 +1,11 @@ import { Snowflake } from "discord.js"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { resolveMember, resolveUser, stripObjectToScalars } from "../../../utils"; +import { resolveMember, resolveUser } from "../../../utils"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { ignoreEvent } from "../functions/ignoreEvent"; import { isBanned } from "../functions/isBanned"; @@ -91,7 +92,7 @@ export const ForcebanCmd = modActionsCmd({ // Log the action pluginData.state.serverLogs.log(LogType.MEMBER_FORCEBAN, { - mod: stripObjectToScalars(mod.user), + mod: userToConfigAccessibleUser(mod.user), userId: user.id, caseNumber: createdCase.case_number, reason, diff --git a/backend/src/plugins/ModActions/commands/MassBanCmd.ts b/backend/src/plugins/ModActions/commands/MassBanCmd.ts index dc1e0855..bc737349 100644 --- a/backend/src/plugins/ModActions/commands/MassBanCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassBanCmd.ts @@ -1,6 +1,7 @@ import { Snowflake, TextChannel } from "discord.js"; import { waitForReply } from "knub/dist/helpers"; import { performance } from "perf_hooks"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; @@ -80,6 +81,7 @@ export const MassbanCmd = modActionsCmd({ const startTime = performance.now(); const failedBans: string[] = []; const casesPlugin = pluginData.getPlugin(CasesPlugin); + const deleteDays = (await pluginData.config.getForMessage(msg)).ban_delete_message_days; for (const [i, userId] of args.userIds.entries()) { if (pluginData.state.unloaded) { break; @@ -92,7 +94,7 @@ export const MassbanCmd = modActionsCmd({ pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000); await pluginData.guild.bans.create(userId as Snowflake, { - days: 1, + days: deleteDays, reason: banReason != null ? encodeURIComponent(banReason) : undefined, }); @@ -128,7 +130,7 @@ export const MassbanCmd = modActionsCmd({ } else { // Some or all bans were successful. Create a log entry for the mass ban and notify the user. pluginData.state.serverLogs.log(LogType.MASSBAN, { - mod: stripObjectToScalars(msg.author), + mod: userToConfigAccessibleUser(msg.author), count: successfulBanCount, reason: banReason, }); diff --git a/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts b/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts index 1d6ec0c7..9913ceac 100644 --- a/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts @@ -1,5 +1,6 @@ import { Snowflake, TextChannel } from "discord.js"; import { waitForReply } from "knub/dist/helpers"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; @@ -87,7 +88,7 @@ export const MassunbanCmd = modActionsCmd({ } else { // Some or all unbans were successful. Create a log entry for the mass unban and notify the user. pluginData.state.serverLogs.log(LogType.MASSUNBAN, { - mod: stripObjectToScalars(msg.author), + mod: userToConfigAccessibleUser(msg.author), count: successfulUnbanCount, reason: unbanReason, }); diff --git a/backend/src/plugins/ModActions/commands/MassmuteCmd.ts b/backend/src/plugins/ModActions/commands/MassmuteCmd.ts index a2c1faf2..bd26f471 100644 --- a/backend/src/plugins/ModActions/commands/MassmuteCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassmuteCmd.ts @@ -1,5 +1,6 @@ import { Snowflake, TextChannel } from "discord.js"; import { waitForReply } from "knub/dist/helpers"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; @@ -87,7 +88,7 @@ export const MassmuteCmd = modActionsCmd({ } else { // Success on all or some mutes pluginData.state.serverLogs.log(LogType.MASSMUTE, { - mod: stripObjectToScalars(msg.author), + mod: userToConfigAccessibleUser(msg.author), count: successfulMuteCount, }); diff --git a/backend/src/plugins/ModActions/commands/NoteCmd.ts b/backend/src/plugins/ModActions/commands/NoteCmd.ts index c5cd7679..195f10ae 100644 --- a/backend/src/plugins/ModActions/commands/NoteCmd.ts +++ b/backend/src/plugins/ModActions/commands/NoteCmd.ts @@ -1,8 +1,10 @@ +import { User } from "discord.js"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { resolveUser, stripObjectToScalars } from "../../../utils"; +import { resolveUser } from "../../../utils"; import { CasesPlugin } from "../../Cases/CasesPlugin"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { modActionsCmd } from "../types"; @@ -41,8 +43,8 @@ export const NoteCmd = modActionsCmd({ }); pluginData.state.serverLogs.log(LogType.MEMBER_NOTE, { - mod: stripObjectToScalars(msg.author), - user: stripObjectToScalars(user, ["user", "roles"]), + mod: userToConfigAccessibleUser(msg.author), + user: userToConfigAccessibleUser(user), caseNumber: createdCase.case_number, reason, }); diff --git a/backend/src/plugins/ModActions/commands/UnbanCmd.ts b/backend/src/plugins/ModActions/commands/UnbanCmd.ts index 5a9be476..5b4407f1 100644 --- a/backend/src/plugins/ModActions/commands/UnbanCmd.ts +++ b/backend/src/plugins/ModActions/commands/UnbanCmd.ts @@ -1,10 +1,11 @@ import { Snowflake } from "discord.js"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; -import { resolveUser, stripObjectToScalars } from "../../../utils"; +import { resolveUser } from "../../../utils"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { ignoreEvent } from "../functions/ignoreEvent"; import { IgnoredEventType, modActionsCmd } from "../types"; @@ -73,7 +74,7 @@ export const UnbanCmd = modActionsCmd({ // Log the action pluginData.state.serverLogs.log(LogType.MEMBER_UNBAN, { - mod: stripObjectToScalars(mod.user), + mod: userToConfigAccessibleUser(mod.user), userId: user.id, caseNumber: createdCase.case_number, reason, diff --git a/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts b/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts index 850ed2c0..0638dcf9 100644 --- a/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts +++ b/backend/src/plugins/ModActions/events/CreateBanCaseOnManualBanEvt.ts @@ -1,4 +1,5 @@ import { GuildAuditLogs, User } from "discord.js"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { Case } from "../../../data/entities/Case"; import { LogType } from "../../../data/LogType"; @@ -65,8 +66,8 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt({ } pluginData.state.serverLogs.log(LogType.MEMBER_BAN, { - mod: mod ? stripObjectToScalars(mod, ["user"]) : null, - user: stripObjectToScalars(user, ["user"]), + mod: mod ? userToConfigAccessibleUser(mod) : null, + user: userToConfigAccessibleUser(user), caseNumber: createdCase?.case_number ?? 0, reason, }); diff --git a/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts b/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts index 9bc6baf5..24c89e8d 100644 --- a/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts +++ b/backend/src/plugins/ModActions/events/CreateKickCaseOnManualKickEvt.ts @@ -1,9 +1,10 @@ import { GuildAuditLogs, User } from "discord.js"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { Case } from "../../../data/entities/Case"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; -import { resolveUser, stripObjectToScalars, UnknownUser } from "../../../utils"; +import { resolveUser, UnknownUser } from "../../../utils"; import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry"; import { CasesPlugin } from "../../Cases/CasesPlugin"; import { clearIgnoredEvents } from "../functions/clearIgnoredEvents"; @@ -58,8 +59,8 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({ } pluginData.state.serverLogs.log(LogType.MEMBER_KICK, { - user: stripObjectToScalars(member.user), - mod: mod ? stripObjectToScalars(mod) : null, + user: userToConfigAccessibleUser(member.user!), + mod: mod ? userToConfigAccessibleUser(mod) : null, caseNumber: createdCase?.case_number ?? 0, reason: kickAuditLogEntry.reason || "", }); diff --git a/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts b/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts index 7bec3cb7..5e788df5 100644 --- a/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts +++ b/backend/src/plugins/ModActions/events/CreateUnbanCaseOnManualUnbanEvt.ts @@ -1,8 +1,9 @@ import { GuildAuditLogs, User } from "discord.js"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { Case } from "../../../data/entities/Case"; import { LogType } from "../../../data/LogType"; -import { resolveUser, stripObjectToScalars, UnknownUser } from "../../../utils"; +import { resolveUser, UnknownUser } from "../../../utils"; import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry"; import { CasesPlugin } from "../../Cases/CasesPlugin"; import { clearIgnoredEvents } from "../functions/clearIgnoredEvents"; @@ -63,7 +64,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({ } pluginData.state.serverLogs.log(LogType.MEMBER_UNBAN, { - mod: mod ? stripObjectToScalars(mod, ["user"]) : null, + mod: mod ? userToConfigAccessibleUser(mod) : null, userId: user.id, caseNumber: createdCase?.case_number ?? 0, }); diff --git a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts index 06820890..a957696c 100644 --- a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts @@ -1,4 +1,4 @@ -import { GuildMember, TextChannel } from "discord.js"; +import { GuildMember, TextChannel, ThreadChannel } from "discord.js"; import { GuildPluginData } from "knub"; import { hasPermission } from "knub/dist/helpers"; import { LogType } from "../../../data/LogType"; @@ -19,7 +19,7 @@ export async function actualKickMemberCmd( reason: string; mod: GuildMember; notify?: string; - "notify-channel"?: TextChannel; + "notify-channel"?: TextChannel | ThreadChannel; clean?: boolean; }, ) { diff --git a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts index 57b0f249..4dc16209 100644 --- a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts @@ -1,4 +1,4 @@ -import { GuildMember, Message, TextChannel, User } from "discord.js"; +import { GuildMember, Message, TextChannel, ThreadChannel, User } from "discord.js"; import humanizeDuration from "humanize-duration"; import { GuildPluginData } from "knub"; import { logger } from "../../../logger"; @@ -19,7 +19,13 @@ export async function actualMuteUserCmd( pluginData: GuildPluginData, user: User | UnknownUser, msg: Message, - args: { time?: number; reason?: string; mod: GuildMember; notify?: string; "notify-channel"?: TextChannel }, + args: { + time?: number; + reason?: string; + mod: GuildMember; + notify?: string; + "notify-channel"?: TextChannel | ThreadChannel; + }, ) { // The moderator who did the action is the message author or, if used, the specified -mod let mod: GuildMember = msg.member!; diff --git a/backend/src/plugins/ModActions/functions/banUserId.ts b/backend/src/plugins/ModActions/functions/banUserId.ts index 101014b9..f9b37678 100644 --- a/backend/src/plugins/ModActions/functions/banUserId.ts +++ b/backend/src/plugins/ModActions/functions/banUserId.ts @@ -1,6 +1,7 @@ import { DiscordAPIError, Snowflake, User } from "discord.js"; import humanizeDuration from "humanize-duration"; import { GuildPluginData } from "knub"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; @@ -129,8 +130,8 @@ export async function banUserId( const mod = await resolveUser(pluginData.client, modId); const logtype = banTime ? LogType.MEMBER_TIMED_BAN : LogType.MEMBER_BAN; pluginData.state.serverLogs.log(logtype, { - mod: stripObjectToScalars(mod), - user: stripObjectToScalars(user), + mod: userToConfigAccessibleUser(mod), + user: userToConfigAccessibleUser(user), caseNumber: createdCase.case_number, reason, banTime: banTime ? humanizeDuration(banTime) : null, diff --git a/backend/src/plugins/ModActions/functions/kickMember.ts b/backend/src/plugins/ModActions/functions/kickMember.ts index d676e9aa..8c7d1563 100644 --- a/backend/src/plugins/ModActions/functions/kickMember.ts +++ b/backend/src/plugins/ModActions/functions/kickMember.ts @@ -1,5 +1,6 @@ import { GuildMember } from "discord.js"; import { GuildPluginData } from "knub"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { renderTemplate } from "../../../templateFormatter"; @@ -40,7 +41,7 @@ export async function kickMember( guildName: pluginData.guild.name, reason, moderator: kickOptions.caseArgs?.modId - ? stripObjectToScalars(await resolveUser(pluginData.client, kickOptions.caseArgs.modId)) + ? userToConfigAccessibleUser(await resolveUser(pluginData.client, kickOptions.caseArgs.modId)) : {}, }); @@ -79,8 +80,8 @@ export async function kickMember( // Log the action const mod = await resolveUser(pluginData.client, modId); pluginData.state.serverLogs.log(LogType.MEMBER_KICK, { - mod: stripObjectToScalars(mod), - user: stripObjectToScalars(member.user), + mod: userToConfigAccessibleUser(mod), + user: userToConfigAccessibleUser(member.user), caseNumber: createdCase.case_number, reason, }); diff --git a/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts b/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts index f983dd3b..bf6f0ab4 100644 --- a/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts +++ b/backend/src/plugins/ModActions/functions/outdatedTempbansLoop.ts @@ -4,6 +4,7 @@ import { GuildPluginData } from "knub"; import moment from "moment-timezone"; import { LogType } from "src/data/LogType"; import { logger } from "src/logger"; +import { userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { resolveUser, SECONDS, stripObjectToScalars } from "../../../utils"; import { CasesPlugin } from "../../Cases/CasesPlugin"; @@ -57,7 +58,7 @@ export async function outdatedTempbansLoop(pluginData: GuildPluginData: + Threads cannot have Bot Slowmode + `), + ); + return; + } } catch (e) { sendErrorMessage( pluginData, diff --git a/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts b/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts index 5f9ec9a4..ce4894e0 100644 --- a/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts +++ b/backend/src/plugins/Slowmode/commands/SlowmodeSetCmd.ts @@ -1,5 +1,6 @@ -import { Permissions, TextChannel } from "discord.js"; +import { Permissions, TextChannel, ThreadChannel } from "discord.js"; import humanizeDuration from "humanize-duration"; +import { ChannelTypeStrings } from "src/types"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { asSingleLine, DAYS, disableInlineCode, HOURS, MINUTES } from "../../../utils"; @@ -38,7 +39,7 @@ export const SlowmodeSetCmd = slowmodeCmd({ ], async run({ message: msg, args, pluginData }) { - const channel: TextChannel = args.channel || msg.channel; + const channel: TextChannel | ThreadChannel = args.channel || msg.channel; if (args.time === 0) { // Workaround until we can call SlowmodeDisableCmd from here @@ -122,7 +123,7 @@ export const SlowmodeSetCmd = slowmodeCmd({ if (mode === "native") { // If there is an existing bot-maintained slowmode, disable that first const existingBotSlowmode = await pluginData.state.slowmodes.getChannelSlowmode(channel.id); - if (existingBotSlowmode) { + if (existingBotSlowmode && channel.type === ChannelTypeStrings.TEXT) { await disableBotSlowmodeForChannel(pluginData, channel); } diff --git a/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts b/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts index 2bcb7c9d..6e180a36 100644 --- a/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts +++ b/backend/src/plugins/Slowmode/util/applyBotSlowmodeToUserId.ts @@ -1,5 +1,6 @@ import { GuildChannel, Permissions, Snowflake, TextChannel } from "discord.js"; import { GuildPluginData } from "knub"; +import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; import { isDiscordAPIError, stripObjectToScalars, UnknownUser } from "../../../utils"; @@ -20,7 +21,7 @@ export async function applyBotSlowmodeToUserId( await channel.permissionOverwrites.create(userId as Snowflake, { SEND_MESSAGES: false }, { type: 1 }); } } catch (e) { - const user = pluginData.client.users.fetch(userId as Snowflake) || new UnknownUser({ id: userId }); + const user = (await pluginData.client.users.fetch(userId as Snowflake)) || new UnknownUser({ id: userId }); if (isDiscordAPIError(e) && e.code === 50013) { logger.warn( @@ -28,14 +29,14 @@ export async function applyBotSlowmodeToUserId( ); pluginData.state.logs.log(LogType.BOT_ALERT, { body: `Missing permissions to apply bot slowmode to {userMention(user)} in {channelMention(channel)}`, - user: stripObjectToScalars(user), - channel: stripObjectToScalars(channel), + user: userToConfigAccessibleUser(user), + channel: channelToConfigAccessibleChannel(channel), }); } else { pluginData.state.logs.log(LogType.BOT_ALERT, { body: `Failed to apply bot slowmode to {userMention(user)} in {channelMention(channel)}`, - user: stripObjectToScalars(user), - channel: stripObjectToScalars(channel), + user: userToConfigAccessibleUser(user), + channel: channelToConfigAccessibleChannel(channel), }); throw e; } diff --git a/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts b/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts index 381fa930..5c59aaf3 100644 --- a/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts +++ b/backend/src/plugins/Slowmode/util/clearBotSlowmodeFromUserId.ts @@ -1,11 +1,11 @@ -import { GuildChannel, Snowflake, TextChannel } from "discord.js"; +import { GuildChannel, Snowflake, TextChannel, ThreadChannel } from "discord.js"; import { GuildPluginData } from "knub"; import { LogType } from "../../../data/LogType"; import { SlowmodePluginType } from "../types"; export async function clearBotSlowmodeFromUserId( pluginData: GuildPluginData, - channel: GuildChannel & TextChannel, + channel: TextChannel, userId: string, force = false, ) { diff --git a/backend/src/plugins/Slowmode/util/disableBotSlowmodeForChannel.ts b/backend/src/plugins/Slowmode/util/disableBotSlowmodeForChannel.ts index d1d40e0b..a6b06364 100644 --- a/backend/src/plugins/Slowmode/util/disableBotSlowmodeForChannel.ts +++ b/backend/src/plugins/Slowmode/util/disableBotSlowmodeForChannel.ts @@ -1,11 +1,11 @@ -import { GuildChannel, TextChannel } from "discord.js"; +import { GuildChannel, TextChannel, ThreadChannel } from "discord.js"; import { GuildPluginData } from "knub"; import { SlowmodePluginType } from "../types"; import { clearBotSlowmodeFromUserId } from "./clearBotSlowmodeFromUserId"; export async function disableBotSlowmodeForChannel( pluginData: GuildPluginData, - channel: GuildChannel & TextChannel, + channel: TextChannel, ) { // Disable channel slowmode await pluginData.state.slowmodes.deleteChannelSlowmode(channel.id); diff --git a/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts b/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts index bd09847a..e3b67ed1 100644 --- a/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts +++ b/backend/src/plugins/Spam/util/logAndDetectMessageSpam.ts @@ -1,6 +1,7 @@ import { Snowflake, TextChannel } from "discord.js"; import { GuildPluginData } from "knub"; import moment from "moment-timezone"; +import { channelToConfigAccessibleChannel, memberToConfigAccessibleMember } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { SavedMessage } from "../../../data/entities/SavedMessage"; import { LogType } from "../../../data/LogType"; @@ -185,8 +186,8 @@ export async function logAndDetectMessageSpam( // Create a log entry logs.log(LogType.MESSAGE_SPAM_DETECTED, { - member: stripObjectToScalars(member, ["user", "roles"]), - channel: stripObjectToScalars(channel), + member: memberToConfigAccessibleMember(member!), + channel: channelToConfigAccessibleChannel(channel!), description, limit: spamConfig.count, interval: spamConfig.interval, diff --git a/backend/src/plugins/Spam/util/logAndDetectOtherSpam.ts b/backend/src/plugins/Spam/util/logAndDetectOtherSpam.ts index 7e1b3c60..107cb45e 100644 --- a/backend/src/plugins/Spam/util/logAndDetectOtherSpam.ts +++ b/backend/src/plugins/Spam/util/logAndDetectOtherSpam.ts @@ -1,4 +1,5 @@ import { GuildPluginData } from "knub"; +import { memberToConfigAccessibleMember } from "src/utils/configAccessibleObjects"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; @@ -78,7 +79,7 @@ export async function logAndDetectOtherSpam( clearRecentUserActions(pluginData, RecentActionType.VoiceChannelMove, userId, actionGroupId); logs.log(LogType.OTHER_SPAM_DETECTED, { - member: stripObjectToScalars(member, ["user", "roles"]), + member: memberToConfigAccessibleMember(member!), description, limit: spamConfig.count, interval: spamConfig.interval, diff --git a/backend/src/plugins/Tags/commands/TagEvalCmd.ts b/backend/src/plugins/Tags/commands/TagEvalCmd.ts index e117983b..abf4a86c 100644 --- a/backend/src/plugins/Tags/commands/TagEvalCmd.ts +++ b/backend/src/plugins/Tags/commands/TagEvalCmd.ts @@ -1,3 +1,4 @@ +import { memberToConfigAccessibleMember, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { sendErrorMessage } from "../../../pluginUtils"; import { TemplateParseError } from "../../../templateFormatter"; @@ -20,8 +21,8 @@ export const TagEvalCmd = tagsCmd({ args.body, [], { - member: stripObjectToScalars(msg.member, ["user"]), - user: stripObjectToScalars(msg.member.user), + member: memberToConfigAccessibleMember(msg.member), + user: userToConfigAccessibleUser(msg.member.user), }, { member: msg.member }, ); diff --git a/backend/src/plugins/Tags/util/renderTagFromString.ts b/backend/src/plugins/Tags/util/renderTagFromString.ts index 930a70a5..4461f4a4 100644 --- a/backend/src/plugins/Tags/util/renderTagFromString.ts +++ b/backend/src/plugins/Tags/util/renderTagFromString.ts @@ -2,6 +2,7 @@ import { GuildMember } from "discord.js"; import * as t from "io-ts"; import { GuildPluginData } from "knub"; import { parseArguments } from "knub-command-manager"; +import { memberToConfigAccessibleMember, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { LogType } from "../../../data/LogType"; import { TemplateParseError } from "../../../templateFormatter"; import { StrictMessageContent, stripObjectToScalars } from "../../../utils"; @@ -27,8 +28,8 @@ export async function renderTagFromString( tagBody, tagArgs, { - member: stripObjectToScalars(member, ["user"]), - user: stripObjectToScalars(member.user), + member: memberToConfigAccessibleMember(member), + user: userToConfigAccessibleUser(member.user), }, { member }, ); diff --git a/backend/src/plugins/Utility/commands/CleanCmd.ts b/backend/src/plugins/Utility/commands/CleanCmd.ts index 9186e3c8..cfdaec88 100644 --- a/backend/src/plugins/Utility/commands/CleanCmd.ts +++ b/backend/src/plugins/Utility/commands/CleanCmd.ts @@ -1,6 +1,7 @@ import { Message, Snowflake, TextChannel, User } from "discord.js"; import { GuildPluginData } from "knub"; import moment from "moment-timezone"; +import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { SavedMessage } from "../../../data/entities/SavedMessage"; import { LogType } from "../../../data/LogType"; @@ -41,8 +42,8 @@ async function cleanMessages( const archiveUrl = pluginData.state.archives.getUrl(baseUrl, archiveId); pluginData.state.logs.log(LogType.CLEAN, { - mod: stripObjectToScalars(mod), - channel: stripObjectToScalars(channel), + mod: userToConfigAccessibleUser(mod), + channel: channelToConfigAccessibleChannel(channel), count: savedMessages.length, archiveUrl, }); @@ -172,7 +173,7 @@ export const CleanCmd = utilityCmd({ let responseText = `Cleaned ${messagesToClean.length} ${messagesToClean.length === 1 ? "message" : "messages"}`; if (targetChannel.id !== msg.channel.id) { - responseText += ` in <#${targetChannel.id}>\n${cleanResult.archiveUrl}`; + responseText += ` in <#${targetChannel.id}>: ${cleanResult.archiveUrl}`; } if (args.update) { diff --git a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts index d749b9c7..169da88e 100644 --- a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts +++ b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts @@ -1,4 +1,9 @@ import { VoiceChannel } from "discord.js"; +import { + channelToConfigAccessibleChannel, + memberToConfigAccessibleMember, + userToConfigAccessibleUser, +} from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { LogType } from "../../../data/LogType"; import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; @@ -35,9 +40,9 @@ export const VcdisconnectCmd = utilityCmd({ } pluginData.state.logs.log(LogType.VOICE_CHANNEL_FORCE_DISCONNECT, { - mod: stripObjectToScalars(msg.author), - member: stripObjectToScalars(args.member, ["user", "roles"]), - oldChannel: stripObjectToScalars(channel), + mod: userToConfigAccessibleUser(msg.author), + member: memberToConfigAccessibleMember(args.member), + oldChannel: channelToConfigAccessibleChannel(channel), }); sendSuccessMessage( diff --git a/backend/src/plugins/Utility/commands/VcmoveCmd.ts b/backend/src/plugins/Utility/commands/VcmoveCmd.ts index 784c5f4c..76eb2161 100644 --- a/backend/src/plugins/Utility/commands/VcmoveCmd.ts +++ b/backend/src/plugins/Utility/commands/VcmoveCmd.ts @@ -1,4 +1,9 @@ import { Snowflake, VoiceChannel } from "discord.js"; +import { + channelToConfigAccessibleChannel, + memberToConfigAccessibleMember, + userToConfigAccessibleUser, +} from "src/utils/configAccessibleObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { LogType } from "../../../data/LogType"; import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; @@ -74,10 +79,10 @@ export const VcmoveCmd = utilityCmd({ } pluginData.state.logs.log(LogType.VOICE_CHANNEL_FORCE_MOVE, { - mod: stripObjectToScalars(msg.author), - member: stripObjectToScalars(args.member, ["user", "roles"]), - oldChannel: stripObjectToScalars(oldVoiceChannel), - newChannel: stripObjectToScalars(channel), + mod: userToConfigAccessibleUser(msg.author), + member: memberToConfigAccessibleMember(args.member), + oldChannel: channelToConfigAccessibleChannel(oldVoiceChannel!), + newChannel: channelToConfigAccessibleChannel(channel), }); sendSuccessMessage( @@ -182,10 +187,10 @@ export const VcmoveAllCmd = utilityCmd({ } pluginData.state.logs.log(LogType.VOICE_CHANNEL_FORCE_MOVE, { - mod: stripObjectToScalars(msg.author), - member: stripObjectToScalars(currMember, ["user", "roles"]), - oldChannel: stripObjectToScalars(args.oldChannel), - newChannel: stripObjectToScalars(channel), + mod: userToConfigAccessibleUser(msg.author), + member: memberToConfigAccessibleMember(currMember), + oldChannel: channelToConfigAccessibleChannel(args.oldChannel), + newChannel: channelToConfigAccessibleChannel(channel), }); } diff --git a/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts b/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts index 2cfa6e53..ce1bf066 100644 --- a/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts +++ b/backend/src/plugins/WelcomeMessage/events/SendWelcomeMessageEvt.ts @@ -1,4 +1,9 @@ import { Snowflake, TextChannel } from "discord.js"; +import { + channelToConfigAccessibleChannel, + memberToConfigAccessibleMember, + userToConfigAccessibleUser, +} from "src/utils/configAccessibleObjects"; import { LogType } from "../../../data/LogType"; import { renderTemplate, TemplateParseError } from "../../../templateFormatter"; import { createChunkedMessage, stripObjectToScalars } from "../../../utils"; @@ -49,7 +54,7 @@ export const SendWelcomeMessageEvt = welcomeMessageEvt({ } catch { pluginData.state.logs.log(LogType.DM_FAILED, { source: "welcome message", - user: stripObjectToScalars(member.user), + user: userToConfigAccessibleUser(member.user), }); } } @@ -63,8 +68,8 @@ export const SendWelcomeMessageEvt = welcomeMessageEvt({ } catch { pluginData.state.logs.log(LogType.BOT_ALERT, { body: `Failed send a welcome message for {userMention(member)} to {channelMention(channel)}`, - member: stripObjectToScalars(member), - channel: stripObjectToScalars(channel), + member: memberToConfigAccessibleMember(member), + channel: channelToConfigAccessibleChannel(channel), }); } } diff --git a/backend/src/types.ts b/backend/src/types.ts index 27286147..9f9c1a53 100644 --- a/backend/src/types.ts +++ b/backend/src/types.ts @@ -65,15 +65,18 @@ export interface CommandInfo { } export enum ChannelTypeStrings { - TEXT = "text", - DM = "dm", - VOICE = "voice", - GROUP = "group", - CATEGORY = "category", - NEWS = "news", - STORE = "store", - STAGE = "stage", - UNKNOWN = "unknown", + TEXT = "GUILD_TEXT", + DM = "DM", + VOICE = "GUILD_VOICE", + GROUP = "GROUP_DM", + CATEGORY = "GUILD_CATEGORY", + NEWS = "GUILD_NEWS", + STORE = "GUILD_STORE", + NEWS_THREAD = "GUILD_NEWS_THREAD", + PUBLIC_THREAD = "GUILD_PUBLIC_THREAD", + PRIVATE_THREAD = "GUILD_PRIVATE_THREAD", + STAGE = "GUILD_STAGE_VOICE", + UNKNOWN = "UNKNOWN", } export enum MessageTypeStrings { diff --git a/backend/src/utils.ts b/backend/src/utils.ts index be9c6767..5a22c12d 100644 --- a/backend/src/utils.ts +++ b/backend/src/utils.ts @@ -8,6 +8,7 @@ import { GuildChannel, GuildMember, Invite, + LimitedCollection, Message, MessageAttachment, MessageEmbed, @@ -17,7 +18,9 @@ import { PartialChannelData, PartialMessage, Snowflake, + Sticker, TextChannel, + ThreadChannel, User, } from "discord.js"; import emojiRegex from "emoji-regex"; @@ -37,6 +40,7 @@ import { waitForButtonConfirm } from "./utils/waitForInteraction"; import { decodeAndValidateStrict, StrictValidationError } from "./validatorUtils"; import { isEqual } from "lodash"; import humanizeDuration from "humanize-duration"; +import { ChannelTypeStrings } from "./types"; const fsp = fs.promises; @@ -247,7 +251,7 @@ export type InviteOpts = "withMetadata" | "withCount" | "withoutCount"; export type GuildInvite = Invite & { guild: Guild }; export type GroupDMInvite = Invite & { channel: PartialChannelData; - type: typeof Constants.ChannelTypes.GROUP; + type: typeof Constants.ChannelTypes.GROUP_DM; }; /** @@ -1015,7 +1019,7 @@ export type CustomEmoji = { id: string; } & Emoji; -export type UserNotificationMethod = { type: "dm" } | { type: "channel"; channel: TextChannel }; +export type UserNotificationMethod = { type: "dm" } | { type: "channel"; channel: TextChannel | ThreadChannel }; export const disableUserNotificationStrings = ["no", "none", "off"]; @@ -1312,6 +1316,18 @@ export async function resolveInvite( return promise as ResolveInviteReturnType; } +const internalStickerCache: LimitedCollection = new LimitedCollection(500); + +export async function resolveStickerId(bot: Client, id: Snowflake): Promise { + const cachedSticker = internalStickerCache.get(id); + if (cachedSticker) return cachedSticker; + + const fetchedSticker = await bot.fetchSticker(id).catch(undefined); + internalStickerCache.set(id, fetchedSticker); + + return fetchedSticker; +} + export async function confirm(channel: TextChannel, userId: string, content: MessageOptions): Promise { return waitForButtonConfirm(channel, content, { restrictToId: userId }); } @@ -1352,7 +1368,10 @@ export function verboseUserName(user: User | UnknownUser): string { } export function verboseChannelMention(channel: GuildChannel): string { - const plainTextName = channel.type === "voice" || channel.type === "stage" ? channel.name : `#${channel.name}`; + const plainTextName = + channel.type === ChannelTypeStrings.VOICE || channel.type === ChannelTypeStrings.STAGE + ? channel.name + : `#${channel.name}`; return `<#${channel.id}> (**${plainTextName}**, \`${channel.id}\`)`; } @@ -1478,7 +1497,7 @@ export function isGuildInvite(invite: Invite): invite is } export function isGroupDMInvite(invite: Invite): invite is GroupDMInvite { - return invite.guild == null && invite.channel?.type === "group"; + return invite.guild == null && invite.channel?.type === ChannelTypeStrings.GROUP; } export function inviteHasCounts(invite: Invite): invite is Invite { diff --git a/backend/src/utils/configAccessibleObjects.ts b/backend/src/utils/configAccessibleObjects.ts index 92dc17c0..1c281ed6 100644 --- a/backend/src/utils/configAccessibleObjects.ts +++ b/backend/src/utils/configAccessibleObjects.ts @@ -8,15 +8,16 @@ import { ThreadChannel, User, } from "discord.js"; +import { UnknownUser } from "src/utils"; export interface IConfigAccessibleUser { - id: Snowflake; + id: Snowflake | string; username: string; discriminator: string; mention: string; - avatarURL: string; - bot: boolean; - createdAt: number; + avatarURL?: string; + bot?: boolean; + createdAt?: number; } export interface IConfigAccessibleRole { @@ -36,15 +37,27 @@ export interface IConfigAccessibleMember extends IConfigAccessibleUser { guildName: string; } -export function userToConfigAccessibleUser(user: User): IConfigAccessibleUser { +export function userToConfigAccessibleUser(user: User | UnknownUser): IConfigAccessibleUser { + if (`${user.username}#${user.discriminator}` === "Unknown#0000") { + const toReturnPartial: IConfigAccessibleUser = { + id: user.id, + username: "Unknown", + discriminator: "0000", + mention: `<@${user.id}>`, + }; + + return toReturnPartial; + } + + const properUser = user as User; const toReturn: IConfigAccessibleUser = { - id: user.id, - username: user.username, - discriminator: user.discriminator, - mention: `<@${user.id}>`, - avatarURL: user.displayAvatarURL({ dynamic: true }), - bot: user.bot, - createdAt: user.createdTimestamp, + id: properUser.id, + username: properUser.username, + discriminator: properUser.discriminator, + mention: `<@${properUser.id}>`, + avatarURL: properUser.displayAvatarURL({ dynamic: true }), + bot: properUser.bot, + createdAt: properUser.createdTimestamp, }; return toReturn; diff --git a/backend/src/utils/createPaginatedMessage.ts b/backend/src/utils/createPaginatedMessage.ts index 6bd6aae0..e711c620 100644 --- a/backend/src/utils/createPaginatedMessage.ts +++ b/backend/src/utils/createPaginatedMessage.ts @@ -4,6 +4,7 @@ import { MessageEditOptions, MessageOptions, MessageReaction, + PartialMessageReaction, PartialUser, TextChannel, User, @@ -37,7 +38,10 @@ export async function createPaginatedMessage( let page = 1; let pageLoadId = 0; // Used to avoid race conditions when rapidly switching pages - const reactionListener = async (reactionMessage: MessageReaction, reactor: User | PartialUser) => { + const reactionListener = async ( + reactionMessage: MessageReaction | PartialMessageReaction, + reactor: User | PartialUser, + ) => { if (reactionMessage.message.id !== message.id) { return; } diff --git a/backend/src/utils/getMissingChannelPermissions.ts b/backend/src/utils/getMissingChannelPermissions.ts index 0d224887..a1a7be9a 100644 --- a/backend/src/utils/getMissingChannelPermissions.ts +++ b/backend/src/utils/getMissingChannelPermissions.ts @@ -1,4 +1,4 @@ -import { GuildChannel, GuildMember } from "discord.js"; +import { GuildChannel, GuildMember, ThreadChannel } from "discord.js"; import { getMissingPermissions } from "./getMissingPermissions"; /** @@ -7,7 +7,7 @@ import { getMissingPermissions } from "./getMissingPermissions"; */ export function getMissingChannelPermissions( member: GuildMember, - channel: GuildChannel, + channel: GuildChannel | ThreadChannel, requiredPermissions: number | bigint, ): bigint { const memberChannelPermissions = channel.permissionsFor(member.id); diff --git a/backend/src/utils/isDefaultSticker.ts b/backend/src/utils/isDefaultSticker.ts new file mode 100644 index 00000000..85e3e974 --- /dev/null +++ b/backend/src/utils/isDefaultSticker.ts @@ -0,0 +1,306 @@ +const defaultStickerIds = [ + "749044136589393960", + "749045492352155769", + "749045743976710154", + "749046077629399122", + "749046696482439188", + "749047112028651530", + "749049128012742676", + "749051158542417980", + "749051341325729913", + "749051517964648458", + "749051844663181383", + "749052011751932006", + "749052505308266645", + "749052707536371812", + "749052944682582036", + "749053210760577245", + "749053441527251087", + "749053689419006003", + "749053927907131433", + "749054120345993216", + "749054292937277450", + "749054660769218631", + "749054894585151518", + "749055120263872532", + "754112474868875294", + "755244355563815073", + "755244428305760266", + "755244598799892490", + "755244649655959615", + "755490897143136446", + "781291131828699156", + "781291442961383434", + "781291606493495306", + "781321379546398740", + "781321702805340200", + "781321874650562560", + "781321970301796372", + "781322427820277791", + "781322566060343296", + "781322673527193620", + "781322765641973770", + "781322967127818240", + "781323072102858782", + "781323157239103548", + "781323249505927198", + "781323366921404426", + "781323471249604648", + "781323560756707328", + "781323628267962408", + "781323712640974858", + "781323769960202280", + "781323880723251220", + "781324010952458270", + "781324114685329417", + "781324245468315668", + "781324376884248596", + "781324451014246460", + "781324562905432064", + "781324642736144424", + "781324722394103808", + "813950454420471818", + "813950661292064808", + "813950759296172092", + "813950952436531213", + "813951067557462106", + "813951129544818708", + "813951478803857408", + "813951723822645278", + "813951924604895242", + "813952523408113694", + "813952588650381332", + "813952646083772486", + "813952751200763934", + "813952825520291902", + "813952903064584202", + "809207198856904764", + "809207265092698112", + "809207315822936064", + "809207399054442526", + "809207795999572038", + "809207857773936710", + "809207919115239525", + "809208197235343410", + "809208263987953694", + "809208353884471376", + "809208424419426344", + "809208728251138088", + "809208771834019850", + "809209078261874688", + "809209146846871562", + "809209216966852628", + "809209266556764241", + "809209320494333952", + "809209482902503444", + "809209627450671114", + "809209856321650698", + "809209923765272586", + "809210027524620328", + "809210129978228766", + "809210201033932891", + "809210344311619584", + "809210578433736724", + "809210750702583868", + "809210904263917618", + "809211336633614346", + "818596923887583302", + "818596976521248819", + "818597244017049652", + "818597355619483688", + "818597454483161098", + "818597555608092722", + "818597623397220362", + "818597707132043285", + "818597810047680532", + "818597885671243776", + "818598022798770186", + "818598125077266432", + "818598371324592218", + "818598476883165194", + "818599312882794506", + "754104467573571584", + "754106820079124480", + "754107009720385556", + "754107496884338698", + "754107539200671765", + "754107634172297306", + "754108691493683221", + "754108771852222564", + "754108811354046554", + "754108835895181322", + "754108890559283200", + "754108923509997568", + "754108948356792320", + "754108992195919903", + "754109038693974057", + "754109076933443614", + "754109137830281297", + "754109419821727885", + "754109474691612782", + "754109519113617478", + "754109542526091434", + "754109580069437481", + "754109748999225374", + "754109772449710080", + "754109815877402634", + "754109869325549638", + "754109908995276810", + "754109937872928857", + "754109983108497468", + "754110021574328400", + "823973720266899506", + "823973812748025937", + "823974092700254238", + "823974203929526292", + "823974288897343518", + "823974429834477578", + "823974530686648440", + "823974669748666418", + "823974764057722910", + "823974837156446208", + "823974930399232020", + "823975146263412786", + "823976022025306152", + "823976102976290866", + "823976251269054494", + "751604756748959874", + "751605093065031760", + "751605170818777108", + "751605236476543086", + "751605353585836101", + "751605453842022562", + "751605541687787550", + "751605606070091887", + "751605670654246972", + "751605738270359592", + "751605803932319754", + "751605873083678802", + "751605941375598672", + "751606014054236261", + "751606065447305216", + "751606120493350982", + "751606190383038604", + "751606254073544784", + "751606317936017458", + "751606379340365864", + "751606441315401848", + "751606491542192200", + "751606539600527410", + "751606636698927157", + "751606719611928586", + "751606808837357608", + "751606868115193948", + "751606917494734959", + "751606992849862706", + "751607061762277396", + "819128604311027752", + "819129296374595614", + "819130301702995968", + "819131032259133440", + "819131232642007062", + "819131655738228796", + "819131835635466280", + "819131978401316864", + "819132831023628298", + "819139462373310494", + "819139728128344064", + "819140386551365642", + "819140940018352178", + "819141435474706472", + "819145601031733269", + "772963467622744075", + "772963523630071828", + "772963562553081886", + "772970847232458782", + "772972089963577354", + "772973760457605182", + "772974139053047829", + "772974519786799114", + "772975031487168582", + "772975484874522674", + "772975929998835722", + "772976230718111764", + "772976562831097906", + "772976718939160606", + "772976899152543745", + "773897032485175296", + "773898515990315028", + "773899933131604008", + "773901313578369044", + "773902656442728488", + "773903221272870973", + "773903633951490098", + "773904449440579624", + "773909554005540894", + "773911171987144754", + "773912319839043625", + "773912616425881630", + "773914273075429387", + "773914595756081172", + "773914892800622612", + "776241800930787349", + "776241838813216788", + "776241877862187048", + "776241909374910534", + "776242510334525460", + "776242536820899861", + "776242590148198400", + "776242614663512095", + "776242643717455882", + "776242672562077696", + "776242703834284132", + "776242899662405712", + "776242924542492672", + "776242962072993792", + "776243107654008872", + "776243140750606366", + "776243172258611200", + "776243957259698226", + "776243988038025287", + "776244033244627004", + "776244136725970974", + "776244212806713344", + "776244240753098752", + "776244473184256000", + "776244492948209674", + "776244520928542731", + "776244545096122379", + "776244577509179412", + "776244610917335070", + "776244640239452200", + "816086581509095424", + "816086770541396028", + "816086882823831613", + "816086934266839040", + "816087074310193162", + "816087132447178774", + "816087220753924096", + "816087273548415006", + "816087483640709131", + "816087668630618152", + "816087792291282944", + "816087883252760617", + "816087973053464606", + "816088051121258596", + "816088135334494267", + "831569193391489054", + "831569335696228352", + "831569414746144798", + "831569534459576381", + "831569719814914108", + "831569909288140832", + "831570117057970176", + "831570479415689309", + "831570715471380550", + "831571053569769492", + "831571151535996988", + "831571320377835540", + "831571470824112138", + "831571594055778304", + "831571726223540294", +]; + +export function isDefaultSticker(id: string): boolean { + return defaultStickerIds.includes(id); +}