From b0c1009d5ab0ca7a64ace1e78a2f147b9629fe5f Mon Sep 17 00:00:00 2001 From: Rigidity <35380458+Rigidity@users.noreply.github.com> Date: Mon, 3 Jun 2024 10:04:35 -0400 Subject: [PATCH] Update ping command and some config and formatting cleanup (#147) --- .prettierrc | 18 ++--- package.json | 62 ++++++++--------- renovate.json | 4 +- src/commands/ping.ts | 60 ++++++++++++++++ src/commands/reping.ts | 38 ----------- src/commands/thread.ts | 35 +++++++--- src/commands/threads.ts | 9 ++- src/config.ts | 114 +++++++++++++++---------------- src/events/messageCreate.ts | 2 +- src/events/messageCreateForum.ts | 78 ++++++++++++++------- src/events/ready.ts | 8 +-- src/events/threadUpdate.ts | 99 +++++++++++++++++++-------- src/healthcheck.ts | 34 +++++---- src/index.ts | 9 ++- src/utils/reactionHandler.ts | 6 +- tsconfig.json | 25 +++---- 16 files changed, 357 insertions(+), 244 deletions(-) create mode 100644 src/commands/ping.ts delete mode 100644 src/commands/reping.ts diff --git a/.prettierrc b/.prettierrc index 92b1951..232501d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,10 +1,10 @@ { - "singleQuote": true, - "quoteProps": "as-needed", - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "always", - "semi": true, - "useTabs": false, - "tabWidth": 4 -} \ No newline at end of file + "singleQuote": true, + "quoteProps": "as-needed", + "trailingComma": "all", + "bracketSpacing": true, + "arrowParens": "always", + "semi": true, + "useTabs": false, + "tabWidth": 4 +} diff --git a/package.json b/package.json index 4c7cfa5..d231bda 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,33 @@ { - "name": "tauri-discord-bot", - "private": true, - "version": "0.0.0", - "main": "src/index.ts", - "type": "module", - "scripts": { - "dev": "nodemon --ext ts,js,mjs,json --legacy-watch --loader tsm .", - "start": "tsm ." - }, - "license": "MIT", - "engines": { - "node": "20.x" - }, - "dependencies": { - "discord.js": "14.15.2", - "dotenv": "16.4.5", - "express": "4.19.2", - "jellycommands": "1.0.0-next.43", - "ts-node": "10.9.2", - "tsm": "2.3.0", - "unfurl.js": "6.3.1", - "url-regex-safe": "3.0.0" - }, - "devDependencies": { - "@types/express": "4.17.21", - "@types/node": "20.12.12", - "@types/url-regex-safe": "1.0.2", - "nodemon": "3.1.1", - "prettier": "3.2.5", - "typescript": "5.4.5" - } + "name": "tauri-discord-bot", + "private": true, + "version": "0.0.0", + "main": "src/index.ts", + "type": "module", + "scripts": { + "dev": "nodemon --ext ts,js,mjs,json --legacy-watch --loader tsm .", + "start": "tsm ." + }, + "license": "MIT", + "engines": { + "node": ">=20.x" + }, + "dependencies": { + "discord.js": "14.15.2", + "dotenv": "16.4.5", + "express": "4.19.2", + "jellycommands": "1.0.0-next.43", + "ts-node": "10.9.2", + "tsm": "2.3.0", + "unfurl.js": "6.3.1", + "url-regex-safe": "3.0.0" + }, + "devDependencies": { + "@types/express": "4.17.21", + "@types/node": "20.12.12", + "@types/url-regex-safe": "1.0.2", + "nodemon": "3.1.1", + "prettier": "3.2.5", + "typescript": "5.4.5" + } } diff --git a/renovate.json b/renovate.json index f45d8f1..5682475 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,3 @@ { - "extends": [ - "config:base" - ] + "extends": ["config:base"] } diff --git a/src/commands/ping.ts b/src/commands/ping.ts new file mode 100644 index 0000000..1213e78 --- /dev/null +++ b/src/commands/ping.ts @@ -0,0 +1,60 @@ +import { APIRole, Role, roleMention } from 'discord.js'; +import { command } from 'jellycommands'; + +export default command({ + name: 'ping', + description: 'Ping a role', + global: true, + options: [ + { + name: 'role', + description: 'The role you want to ping', + type: 'Role', + required: true, + }, + ], + run: async ({ interaction }) => { + // Fetch the role and make sure it's pingable. + const role = interaction.options.getRole('role', true); + + // Fetch the member, since the interaction member might not be fully resolved. + const member = await interaction.guild.members.fetch( + interaction.user.id, + ); + + // Check if the role is pingable or the member has permission to ping everyone anyways. + let pingable = member.permissions.has('MentionEveryone', true) + ? 'yes' + : pingableStatus(role); + + if (pingable === 'no') { + return await interaction.reply({ + content: 'This role is not pingable.', + ephemeral: true, + }); + } + + // The user has to have the role to ping it in some circumstances. + if (pingable === 'self') { + if (!member.roles.cache.has(role.id)) { + return await interaction.reply({ + content: 'You do not have permission to ping this role.', + ephemeral: true, + }); + } + } + + // Ping the role in a reply so that you can see the original sender of the command. + await interaction.reply(`${roleMention(role.id)}`); + }, +}); + +function pingableStatus(role: Role | APIRole): 'yes' | 'no' | 'self' { + if (role.name === 'working-group' || role.name.startsWith('wg-')) { + return 'self'; + } else if (['mod', 'moderator'].includes(role.name)) { + return 'yes'; + } else { + return 'no'; + } +} diff --git a/src/commands/reping.ts b/src/commands/reping.ts deleted file mode 100644 index 6ccbb73..0000000 --- a/src/commands/reping.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { command } from 'jellycommands'; -import { wrap_in_embed } from '../utils/embed_helpers'; -import { GuildMemberRoleManager } from 'discord.js'; - -export default command({ - name: 'reping', - description: 'Ping a role', - - global: true, - - options: [ - { - name: 'role', - description: 'The role you want to ping', - type: 'Role', - required: true, - }, - ], - - run: async ({ interaction }) => { - // Find the desired role - const role = interaction.options.getRole('role', true); - // Check if the user has the role - let hasRole = ( - interaction.member.roles as GuildMemberRoleManager - ).cache.find((val) => val.id === role.id); - // Exit if the user doesn't have the role - if (!hasRole) return; - // Send the ping message - interaction.channel.send(`<@&${role.id}>`); - // Follow up the interaction - await interaction.reply(wrap_in_embed('Role pinged')); - // Delete the reply after 3 seconds - setTimeout(async () => { - await interaction.deleteReply(); - }, 3000); - }, -}); diff --git a/src/commands/thread.ts b/src/commands/thread.ts index eea276d..b1e1f68 100644 --- a/src/commands/thread.ts +++ b/src/commands/thread.ts @@ -141,7 +141,8 @@ export default command({ ); // Successfully solved the thread // Get the first message in the thread - const start_message = await thread.fetchStarterMessage(); + const start_message = + await thread.fetchStarterMessage(); // Get the first 2 messages after the start message const messages = await thread.messages.fetch({ limit: 2, @@ -167,7 +168,9 @@ export default command({ msg.components = [row]; await bot_message.edit(msg); // Commands require a reply - await interaction.followUp(wrap_in_embed('Thread solved.')); + await interaction.followUp( + wrap_in_embed('Thread solved.'), + ); // Delete the reply after 10 seconds setTimeout(async () => { await interaction.deleteReply(); @@ -177,21 +180,33 @@ export default command({ if (!(thread.parent instanceof ForumChannel)) throw new Error("Can't solve a non-help channel"); // Parent forum channel - const solveChannel = thread.guild.channels.cache.get(thread.parentId) as ForumChannel + const solveChannel = thread.guild.channels.cache.get( + thread.parentId, + ) as ForumChannel; // Solve tag - const solveTag = solveChannel.availableTags.find(tag => tag.name === SOLVED_TAG).id + const solveTag = solveChannel.availableTags.find( + (tag) => tag.name === SOLVED_TAG, + ).id; // Unsolve tag - const unsolveTag = solveChannel.availableTags.find(tag => tag.name === UNSOLVED_TAG).id + const unsolveTag = solveChannel.availableTags.find( + (tag) => tag.name === UNSOLVED_TAG, + ).id; // If this is a ThreadChannel - let tags = thread.appliedTags.filter(tag => tag !== solveTag && tag !== unsolveTag).splice(0, 4) + let tags = thread.appliedTags + .filter((tag) => tag !== solveTag && tag !== unsolveTag) + .splice(0, 4); // Add the solved tag - tags.unshift(solveTag) + tags.unshift(solveTag); // If neither tag is going to exist in the channel, add unsolved - if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) tags.unshift(unsolveTag) + if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) + tags.unshift(unsolveTag); // Ensure no duplicates are in the array - tags = [...new Set(tags)].sort() + tags = [...new Set(tags)].sort(); // Apply tags - if (tags.toString() !== thread.appliedTags.sort().toString()) thread.setAppliedTags(tags) + if ( + tags.toString() !== thread.appliedTags.sort().toString() + ) + thread.setAppliedTags(tags); // Commands require a reply await interaction.followUp(wrap_in_embed('Thread solved.')); // Delete the reply after 10 seconds diff --git a/src/commands/threads.ts b/src/commands/threads.ts index aab585d..e23f433 100644 --- a/src/commands/threads.ts +++ b/src/commands/threads.ts @@ -28,11 +28,10 @@ export default command({ await interaction.guild.channels.fetchActiveThreads() ).threads .map((x) => x) - .filter( - (thread) => - thread - .permissionsFor(interaction.user) - .has(['ReadMessageHistory', 'ViewChannel']), + .filter((thread) => + thread + .permissionsFor(interaction.user) + .has(['ReadMessageHistory', 'ViewChannel']), ); switch (subcommand) { diff --git a/src/config.ts b/src/config.ts index ffebb47..049fda7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,8 +1,8 @@ export const DEV_MODE = process.env.NODE_ENV !== 'production'; export const GUILD_ID = DEV_MODE - ? process.env.DEV_GUILD_ID - : '616186924390023171'; + ? process.env.DEV_GUILD_ID + : '616186924390023171'; export const DISCORD_TOKEN = process.env.DISCORD_TOKEN; @@ -10,29 +10,29 @@ export const TAURI_BLUE = 0x67d6ed; // people const ADMIN_ROLES = DEV_MODE - ? [process.env.DEV_ADMIN_ROLE] - : [ - // admin - '985400380663935088', - // core - '616187491715907585', - // working-group - '761977421305610241', - ]; + ? [process.env.DEV_ADMIN_ROLE] + : [ + // admin + '985400380663935088', + // core + '616187491715907585', + // working-group + '761977421305610241', + ]; // list of support roles without admin rights export const HELPER_ROLES = DEV_MODE - ? [process.env.DEV_HELPER_ROLE] - : [ - // Helping Hand - '995034988699455609', - ]; + ? [process.env.DEV_HELPER_ROLE] + : [ + // Helping Hand + '995034988699455609', + ]; export const BOT_DEVS = [ - // LorenzoLewis - '402698003569180674', - // Simon - // '329752097530839041', + // LorenzoLewis + '402698003569180674', + // Simon + // '329752097530839041', ]; // list of roles/user IDs other than the creator allowed to modify threads @@ -40,55 +40,55 @@ export const THREAD_ADMIN_IDS = [...ADMIN_ROLES, ...BOT_DEVS]; // auto thread channels with the issue handling feature export const HELP_THREAD_CHANNELS = DEV_MODE - ? [process.env.DEV_HELP_CHANNEL] - : [ - // #help-triage - '625037620996734986', - ]; + ? [process.env.DEV_HELP_CHANNEL] + : [ + // #help-triage + '625037620996734986', + ]; // channels that will be automatically threaded when a message is created export const AUTO_THREAD_CHANNELS = DEV_MODE - ? [process.env.DEV_DID_A_THING_CHANNEL, ...HELP_THREAD_CHANNELS] - : [ - // #did-a-thing - '616234029842300930', - ...HELP_THREAD_CHANNELS, - ]; + ? [process.env.DEV_DID_A_THING_CHANNEL, ...HELP_THREAD_CHANNELS] + : [ + // #did-a-thing + '616234029842300930', + ...HELP_THREAD_CHANNELS, + ]; export const MESSAGE_READ = '✅'; export const REACTION_ROLE: { - emojiName: string; - emojiId: string; - roleId: string; - description: string; + emojiName: string; + emojiId: string; + roleId: string; + description: string; }[] = DEV_MODE - ? [ - { - emojiName: 'sausageroll', - emojiId: '995712110925451324', - roleId: process.env.DEV_REACTION_ROLE, - description: - 'Join the conversation in the contributors channels (you can still view without this role)', - }, - ] - : [ - { - emojiName: 'tauri', - emojiId: '876938722266972210', - roleId: '986176820187631616', - description: - 'Join the conversation in the contributors channels (you can still view without this role)', - }, - ]; + ? [ + { + emojiName: 'sausageroll', + emojiId: '995712110925451324', + roleId: process.env.DEV_REACTION_ROLE, + description: + 'Join the conversation in the contributors channels (you can still view without this role)', + }, + ] + : [ + { + emojiName: 'tauri', + emojiId: '876938722266972210', + roleId: '986176820187631616', + description: + 'Join the conversation in the contributors channels (you can still view without this role)', + }, + ]; export const REACTION_ROLE_CHANNEL = DEV_MODE - ? process.env.DEV_REACTION_ROLE_CHANNEL - : '616210923354456064'; + ? process.env.DEV_REACTION_ROLE_CHANNEL + : '616210923354456064'; export const SUPPORT_FORUM = DEV_MODE - ? process.env.DEV_SUPPORT_FORUM_CHANNEL - : '1047150269156294677'; + ? process.env.DEV_SUPPORT_FORUM_CHANNEL + : '1047150269156294677'; export const SOLVABLE_FORUMS = [SUPPORT_FORUM]; export const UNSOLVED_TAG = 'unsolved'; export const SOLVED_TAG = 'solved'; diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index c13c32f..ae8435b 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -14,7 +14,7 @@ import { add_thread_prefix } from '../utils/threads'; export default event({ name: 'messageCreate', - run: async ({ }, message) => { + run: async ({}, message) => { // Rules for whether or not the message should be dealt with by the bot const should_ignore = message.author.bot || diff --git a/src/events/messageCreateForum.ts b/src/events/messageCreateForum.ts index dcfaeaa..18119c6 100644 --- a/src/events/messageCreateForum.ts +++ b/src/events/messageCreateForum.ts @@ -1,47 +1,76 @@ -import { - ThreadChannel, - ChannelType, - ForumChannel, -} from 'discord.js'; +import { ThreadChannel, ChannelType, ForumChannel } from 'discord.js'; import { event } from 'jellycommands'; import { wrap_in_embed } from '../utils/embed_helpers'; -import { SOLVABLE_FORUMS, UNSOLVED_TAG, SOLVED_TAG, MESSAGE_READ, SUPPORT_FORUM } from '../config'; +import { + SOLVABLE_FORUMS, + UNSOLVED_TAG, + SOLVED_TAG, + MESSAGE_READ, + SUPPORT_FORUM, +} from '../config'; export default event({ name: 'messageCreate', - run: async ({ }, message) => { + run: async ({}, message) => { // Rules for whether or not the message should be dealt with by the bot - const should_ignore = message.author.bot || !(message.channel.type === ChannelType.PublicThread) + const should_ignore = + message.author.bot || + !(message.channel.type === ChannelType.PublicThread); // If the message should be ignored, return without further processing if (should_ignore) return; // If this is posted in a solvable forum channel - if (message.channel instanceof ThreadChannel && SOLVABLE_FORUMS.includes(message.channel.parentId)) { + if ( + message.channel instanceof ThreadChannel && + SOLVABLE_FORUMS.includes(message.channel.parentId) + ) { // Parent forum channel - const solveChannel = message.guild.channels.cache.get(message.channel.parentId) as ForumChannel + const solveChannel = message.guild.channels.cache.get( + message.channel.parentId, + ) as ForumChannel; // Solve tag - const solveTag = solveChannel.availableTags.find(tag => tag.name === SOLVED_TAG).id + const solveTag = solveChannel.availableTags.find( + (tag) => tag.name === SOLVED_TAG, + ).id; // Unsolve tag - const unsolveTag = solveChannel.availableTags.find(tag => tag.name === UNSOLVED_TAG).id + const unsolveTag = solveChannel.availableTags.find( + (tag) => tag.name === UNSOLVED_TAG, + ).id; // The channel will have one of the tags, no further action required - if (message.channel.appliedTags.filter(tag => tag === unsolveTag || tag === solveTag).length === 1) return + if ( + message.channel.appliedTags.filter( + (tag) => tag === unsolveTag || tag === solveTag, + ).length === 1 + ) + return; // Tags to apply, without solve or unsolved, maximum 4 entries - let tags = message.channel.appliedTags.filter(tag => tag !== solveTag && tag !== unsolveTag).splice(0, 4) + let tags = message.channel.appliedTags + .filter((tag) => tag !== solveTag && tag !== unsolveTag) + .splice(0, 4); // Marked as both solved and unsolved - if (message.channel.appliedTags.includes(solveTag) && message.channel.appliedTags.includes(unsolveTag)) { + if ( + message.channel.appliedTags.includes(solveTag) && + message.channel.appliedTags.includes(unsolveTag) + ) { // Add the solved tag - tags.unshift(solveTag) + tags.unshift(solveTag); } // If neither tag is going to exist in the channel, add unsolved - if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) tags.unshift(unsolveTag) + if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) + tags.unshift(unsolveTag); // Ensure no duplicates are in the array - tags = [...new Set(tags)].sort() + tags = [...new Set(tags)].sort(); // Apply tags - if (tags.toString() !== message.channel.appliedTags.sort().toString()) message.channel.setAppliedTags(tags) + if ( + tags.toString() !== + message.channel.appliedTags.sort().toString() + ) + message.channel.setAppliedTags(tags); // If this is a new post and not just a regular message // Disabled for now due to the fact that nobody reads the message if (!message.nonce && message.position === 0 && false) { - const msg = await message.channel.send(wrap_in_embed( - `Thank you for your message! + const msg = await message.channel.send( + wrap_in_embed( + `Thank you for your message! 1. Search the <#${SUPPORT_FORUM}> forum for existing posts 2. Search Github issues to see if this is a known issue @@ -49,9 +78,10 @@ export default event({ 4. Provide reproduction steps for your issue 5. Be polite and remember to follow the [Tauri Code of Conduct](https://github.com/tauri-apps/governance-and-guidance/blob/main/CODE_OF_CONDUCT.md) - Once you've read this and taken the appropriate steps, react to this message` - )) - await msg.react(MESSAGE_READ) + Once you've read this and taken the appropriate steps, react to this message`, + ), + ); + await msg.react(MESSAGE_READ); } } }, diff --git a/src/events/ready.ts b/src/events/ready.ts index 767b705..e447071 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -10,11 +10,11 @@ export default event({ // Send the message for role reactions sendReactionRoleMessage(client); // Update the cache so that the bot can properly react to messages sent before it went live - updateCache(client) + updateCache(client); // Run a task in the background every 60 minutes setInterval(async () => { // Update the cache so that old messages can be reacted to - updateCache(client) - }, 60_000 * 60) // Every 60 minutes + updateCache(client); + }, 60_000 * 60); // Every 60 minutes }, -}); \ No newline at end of file +}); diff --git a/src/events/threadUpdate.ts b/src/events/threadUpdate.ts index 59febd8..b6751b8 100644 --- a/src/events/threadUpdate.ts +++ b/src/events/threadUpdate.ts @@ -1,54 +1,99 @@ -import { - ThreadChannel, - ChannelType, - ForumChannel, -} from 'discord.js'; +import { ThreadChannel, ChannelType, ForumChannel } from 'discord.js'; import { event } from 'jellycommands'; import { SOLVABLE_FORUMS, UNSOLVED_TAG, SOLVED_TAG } from '../config'; export default event({ name: 'threadUpdate', - run: async ({ }, oldChannel, newChannel) => { + run: async ({}, oldChannel, newChannel) => { if (newChannel instanceof ThreadChannel) { // If newChannel is a solvable channel if (SOLVABLE_FORUMS.includes(newChannel.parentId)) { // Parent forum channel - const solveChannel = newChannel.guild.channels.cache.get(newChannel.parentId) as ForumChannel + const solveChannel = newChannel.guild.channels.cache.get( + newChannel.parentId, + ) as ForumChannel; // Solve tag - const solveTag = solveChannel.availableTags.find(tag => tag.name === SOLVED_TAG).id + const solveTag = solveChannel.availableTags.find( + (tag) => tag.name === SOLVED_TAG, + ).id; // Unsolve tag - const unsolveTag = solveChannel.availableTags.find(tag => tag.name === UNSOLVED_TAG).id + const unsolveTag = solveChannel.availableTags.find( + (tag) => tag.name === UNSOLVED_TAG, + ).id; // The new channel will only have one of the tags, no further action required - if (newChannel.appliedTags.filter(tag => tag === unsolveTag || tag === solveTag).length === 1) return + if ( + newChannel.appliedTags.filter( + (tag) => tag === unsolveTag || tag === solveTag, + ).length === 1 + ) + return; // Detect if this was a Bot interaction by checking the combination of solved/unsolved in the old and new channels - if (oldChannel.appliedTags.includes(unsolveTag) && oldChannel.appliedTags.includes(solveTag) && (!newChannel.appliedTags.includes(solveTag) || !newChannel.appliedTags.includes(unsolveTag))) return; + if ( + oldChannel.appliedTags.includes(unsolveTag) && + oldChannel.appliedTags.includes(solveTag) && + (!newChannel.appliedTags.includes(solveTag) || + !newChannel.appliedTags.includes(unsolveTag)) + ) + return; // Tags to apply, without solve or unsolved, maximum 4 entries - let tags = newChannel.appliedTags.filter(tag => tag !== solveTag && tag !== unsolveTag).splice(0, 4) + let tags = newChannel.appliedTags + .filter((tag) => tag !== solveTag && tag !== unsolveTag) + .splice(0, 4); // solved !unsolved > !solved !unsolved : user removed solved, set unsolved - if ((oldChannel.appliedTags.includes(solveTag) && !oldChannel.appliedTags.includes(unsolveTag)) && (!newChannel.appliedTags.includes(solveTag) && !newChannel.appliedTags.includes(unsolveTag))) { - tags.unshift(unsolveTag) + if ( + oldChannel.appliedTags.includes(solveTag) && + !oldChannel.appliedTags.includes(unsolveTag) && + !newChannel.appliedTags.includes(solveTag) && + !newChannel.appliedTags.includes(unsolveTag) + ) { + tags.unshift(unsolveTag); // !solved unsolved > !solved !unsolved : user removed unsolved, set solved - } else if ((oldChannel.appliedTags.includes(unsolveTag) && !oldChannel.appliedTags.includes(solveTag)) && (!newChannel.appliedTags.includes(solveTag) && !newChannel.appliedTags.includes(unsolveTag))) { - tags.unshift(solveTag) + } else if ( + oldChannel.appliedTags.includes(unsolveTag) && + !oldChannel.appliedTags.includes(solveTag) && + !newChannel.appliedTags.includes(solveTag) && + !newChannel.appliedTags.includes(unsolveTag) + ) { + tags.unshift(solveTag); // solved !unsolved > solved unsolved : user marked already solved as unsolved, set unsolved - } else if ((oldChannel.appliedTags.includes(solveTag) && !oldChannel.appliedTags.includes(unsolveTag)) && (newChannel.appliedTags.includes(solveTag) && newChannel.appliedTags.includes(unsolveTag))) { - tags.unshift(unsolveTag) + } else if ( + oldChannel.appliedTags.includes(solveTag) && + !oldChannel.appliedTags.includes(unsolveTag) && + newChannel.appliedTags.includes(solveTag) && + newChannel.appliedTags.includes(unsolveTag) + ) { + tags.unshift(unsolveTag); // !solved unsolved > solved unsolved : user marked already unsolved as solved, set solved - } else if ((oldChannel.appliedTags.includes(unsolveTag) && !oldChannel.appliedTags.includes(solveTag)) && (newChannel.appliedTags.includes(solveTag) && newChannel.appliedTags.includes(unsolveTag))) { - tags.unshift(solveTag) + } else if ( + oldChannel.appliedTags.includes(unsolveTag) && + !oldChannel.appliedTags.includes(solveTag) && + newChannel.appliedTags.includes(solveTag) && + newChannel.appliedTags.includes(unsolveTag) + ) { + tags.unshift(solveTag); // > unsolved solved : post was going to be marked as both, assume solved is intended - } else if (newChannel.appliedTags.includes(unsolveTag) && newChannel.appliedTags.includes(solveTag)) { - tags.unshift(solveTag) + } else if ( + newChannel.appliedTags.includes(unsolveTag) && + newChannel.appliedTags.includes(solveTag) + ) { + tags.unshift(solveTag); // > !unsolved !unsolved : post was going to be marked as neither, assume unsolved is intended - } else if (!newChannel.appliedTags.includes(unsolveTag) && !newChannel.appliedTags.includes(solveTag)) { - tags.unshift(unsolveTag) + } else if ( + !newChannel.appliedTags.includes(unsolveTag) && + !newChannel.appliedTags.includes(solveTag) + ) { + tags.unshift(unsolveTag); } // If neither tag is going to exist for any reason, add unsolved - if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) tags.unshift(unsolveTag) + if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) + tags.unshift(unsolveTag); // Ensure no duplicates are in the array - tags = [...new Set(tags)].sort() + tags = [...new Set(tags)].sort(); // Apply tags if they are different from what's already being applied - if (tags.toString() !== newChannel.appliedTags.sort().toString()) newChannel.setAppliedTags(tags) + if ( + tags.toString() !== newChannel.appliedTags.sort().toString() + ) + newChannel.setAppliedTags(tags); } } }, diff --git a/src/healthcheck.ts b/src/healthcheck.ts index ff86b80..69f7706 100644 --- a/src/healthcheck.ts +++ b/src/healthcheck.ts @@ -4,24 +4,30 @@ import http from 'http'; const app = express(); const router = express.Router(); -router.use((req: express.Request, res: express.Response, next: express.NextFunction) => { - res.header('Access-Control-Allow-Methods', 'GET'); - const status = app.locals.getStatus() - if (status === 200) { - next(); - } else { - res.status(status).send({ error: 'Something failed!' }) - } -}); +router.use( + ( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ) => { + res.header('Access-Control-Allow-Methods', 'GET'); + const status = app.locals.getStatus(); + if (status === 200) { + next(); + } else { + res.status(status).send({ error: 'Something failed!' }); + } + }, +); -router.get('/health', (req: express.Request, res: express.Response) => { - res.status(200).send('Ok'); +router.get('/health', (req: express.Request, res: express.Response) => { + res.status(200).send('Ok'); }); app.use('/api/v1', router); export default function (callback: any) { - app.locals.getStatus = callback - const server = http.createServer(app); - return server.listen(3000); + app.locals.getStatus = callback; + const server = http.createServer(app); + return server.listen(3000); } diff --git a/src/index.ts b/src/index.ts index e778b2d..61383cd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,7 @@ const client = new JellyCommands({ GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildMessages + GatewayIntentBits.GuildMessages, ], }, @@ -33,12 +33,11 @@ const client = new JellyCommands({ }); function health() { - if (!client.isReady()) - return 502 - return 200 + if (!client.isReady()) return 502; + return 200; } healthcheck(health); // Auto reads the DISCORD_TOKEN environment variable -await client.login() +await client.login(); diff --git a/src/utils/reactionHandler.ts b/src/utils/reactionHandler.ts index 7af8701..808eacc 100644 --- a/src/utils/reactionHandler.ts +++ b/src/utils/reactionHandler.ts @@ -75,7 +75,7 @@ export async function sendReactionRoleMessage(client: Client) { ); messageArray.push('\n**<#879007560429088800>**'); messageArray.push( - "Get involved with Tauri development and browse the different projects.", + 'Get involved with Tauri development and browse the different projects.', ); let messageBody = messageArray.join('\n'); @@ -98,7 +98,9 @@ export async function sendReactionRoleMessage(client: Client) { console.debug('Message edited'); } else { // Delete old messages from the bot - messages.filter((item) => item.author.id == item.client.user.id).forEach((item) => item.delete()) + messages + .filter((item) => item.author.id == item.client.user.id) + .forEach((item) => item.delete()); console.debug('Attempting to send message...'); // Send the message message = await channel.send(messageBody); diff --git a/tsconfig.json b/tsconfig.json index 6a308b6..0efbdd4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,13 @@ { - "compilerOptions": { - "module": "Node16", - "esModuleInterop": true, - "target": "ES2022", - "noImplicitAny": true, - "moduleResolution": "node", - "sourceMap": true, - "outDir": "dist", - "skipLibCheck": true, - "lib": [ - "ES2021.String" - ] - }, - "include": ["src"] + "compilerOptions": { + "module": "ESNext", + "esModuleInterop": true, + "target": "ESNext", + "noImplicitAny": true, + "moduleResolution": "Node", + "sourceMap": true, + "outDir": "dist", + "skipLibCheck": true + }, + "include": ["src"] }