Update ping command and some config and formatting cleanup (#147)

This commit is contained in:
Rigidity
2024-06-03 10:04:35 -04:00
committed by GitHub
parent ea79d283fe
commit b0c1009d5a
16 changed files with 357 additions and 244 deletions

View File

@@ -1,10 +1,10 @@
{ {
"singleQuote": true, "singleQuote": true,
"quoteProps": "as-needed", "quoteProps": "as-needed",
"trailingComma": "all", "trailingComma": "all",
"bracketSpacing": true, "bracketSpacing": true,
"arrowParens": "always", "arrowParens": "always",
"semi": true, "semi": true,
"useTabs": false, "useTabs": false,
"tabWidth": 4 "tabWidth": 4
} }

View File

@@ -1,33 +1,33 @@
{ {
"name": "tauri-discord-bot", "name": "tauri-discord-bot",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"main": "src/index.ts", "main": "src/index.ts",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "nodemon --ext ts,js,mjs,json --legacy-watch --loader tsm .", "dev": "nodemon --ext ts,js,mjs,json --legacy-watch --loader tsm .",
"start": "tsm ." "start": "tsm ."
}, },
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "20.x" "node": ">=20.x"
}, },
"dependencies": { "dependencies": {
"discord.js": "14.15.2", "discord.js": "14.15.2",
"dotenv": "16.4.5", "dotenv": "16.4.5",
"express": "4.19.2", "express": "4.19.2",
"jellycommands": "1.0.0-next.43", "jellycommands": "1.0.0-next.43",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"tsm": "2.3.0", "tsm": "2.3.0",
"unfurl.js": "6.3.1", "unfurl.js": "6.3.1",
"url-regex-safe": "3.0.0" "url-regex-safe": "3.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/express": "4.17.21", "@types/express": "4.17.21",
"@types/node": "20.12.12", "@types/node": "20.12.12",
"@types/url-regex-safe": "1.0.2", "@types/url-regex-safe": "1.0.2",
"nodemon": "3.1.1", "nodemon": "3.1.1",
"prettier": "3.2.5", "prettier": "3.2.5",
"typescript": "5.4.5" "typescript": "5.4.5"
} }
} }

View File

@@ -1,5 +1,3 @@
{ {
"extends": [ "extends": ["config:base"]
"config:base"
]
} }

60
src/commands/ping.ts Normal file
View File

@@ -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';
}
}

View File

@@ -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);
},
});

View File

@@ -141,7 +141,8 @@ export default command({
); );
// Successfully solved the thread // Successfully solved the thread
// Get the first message in 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 // Get the first 2 messages after the start message
const messages = await thread.messages.fetch({ const messages = await thread.messages.fetch({
limit: 2, limit: 2,
@@ -167,7 +168,9 @@ export default command({
msg.components = [row]; msg.components = [row];
await bot_message.edit(msg); await bot_message.edit(msg);
// Commands require a reply // 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 // Delete the reply after 10 seconds
setTimeout(async () => { setTimeout(async () => {
await interaction.deleteReply(); await interaction.deleteReply();
@@ -177,21 +180,33 @@ export default command({
if (!(thread.parent instanceof ForumChannel)) if (!(thread.parent instanceof ForumChannel))
throw new Error("Can't solve a non-help channel"); throw new Error("Can't solve a non-help channel");
// Parent forum 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 // 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 // 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 // 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 // Add the solved tag
tags.unshift(solveTag) tags.unshift(solveTag);
// If neither tag is going to exist in the channel, add unsolved // 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 // Ensure no duplicates are in the array
tags = [...new Set(tags)].sort() tags = [...new Set(tags)].sort();
// Apply tags // 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 // 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 // Delete the reply after 10 seconds

View File

@@ -28,11 +28,10 @@ export default command({
await interaction.guild.channels.fetchActiveThreads() await interaction.guild.channels.fetchActiveThreads()
).threads ).threads
.map((x) => x) .map((x) => x)
.filter( .filter((thread) =>
(thread) => thread
thread .permissionsFor(interaction.user)
.permissionsFor(interaction.user) .has(['ReadMessageHistory', 'ViewChannel']),
.has(['ReadMessageHistory', 'ViewChannel']),
); );
switch (subcommand) { switch (subcommand) {

View File

@@ -1,8 +1,8 @@
export const DEV_MODE = process.env.NODE_ENV !== 'production'; export const DEV_MODE = process.env.NODE_ENV !== 'production';
export const GUILD_ID = DEV_MODE export const GUILD_ID = DEV_MODE
? process.env.DEV_GUILD_ID ? process.env.DEV_GUILD_ID
: '616186924390023171'; : '616186924390023171';
export const DISCORD_TOKEN = process.env.DISCORD_TOKEN; export const DISCORD_TOKEN = process.env.DISCORD_TOKEN;
@@ -10,29 +10,29 @@ export const TAURI_BLUE = 0x67d6ed;
// people // people
const ADMIN_ROLES = DEV_MODE const ADMIN_ROLES = DEV_MODE
? [process.env.DEV_ADMIN_ROLE] ? [process.env.DEV_ADMIN_ROLE]
: [ : [
// admin // admin
'985400380663935088', '985400380663935088',
// core // core
'616187491715907585', '616187491715907585',
// working-group // working-group
'761977421305610241', '761977421305610241',
]; ];
// list of support roles without admin rights // list of support roles without admin rights
export const HELPER_ROLES = DEV_MODE export const HELPER_ROLES = DEV_MODE
? [process.env.DEV_HELPER_ROLE] ? [process.env.DEV_HELPER_ROLE]
: [ : [
// Helping Hand // Helping Hand
'995034988699455609', '995034988699455609',
]; ];
export const BOT_DEVS = [ export const BOT_DEVS = [
// LorenzoLewis // LorenzoLewis
'402698003569180674', '402698003569180674',
// Simon // Simon
// '329752097530839041', // '329752097530839041',
]; ];
// list of roles/user IDs other than the creator allowed to modify threads // 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 // auto thread channels with the issue handling feature
export const HELP_THREAD_CHANNELS = DEV_MODE export const HELP_THREAD_CHANNELS = DEV_MODE
? [process.env.DEV_HELP_CHANNEL] ? [process.env.DEV_HELP_CHANNEL]
: [ : [
// #help-triage // #help-triage
'625037620996734986', '625037620996734986',
]; ];
// channels that will be automatically threaded when a message is created // channels that will be automatically threaded when a message is created
export const AUTO_THREAD_CHANNELS = DEV_MODE export const AUTO_THREAD_CHANNELS = DEV_MODE
? [process.env.DEV_DID_A_THING_CHANNEL, ...HELP_THREAD_CHANNELS] ? [process.env.DEV_DID_A_THING_CHANNEL, ...HELP_THREAD_CHANNELS]
: [ : [
// #did-a-thing // #did-a-thing
'616234029842300930', '616234029842300930',
...HELP_THREAD_CHANNELS, ...HELP_THREAD_CHANNELS,
]; ];
export const MESSAGE_READ = '✅'; export const MESSAGE_READ = '✅';
export const REACTION_ROLE: { export const REACTION_ROLE: {
emojiName: string; emojiName: string;
emojiId: string; emojiId: string;
roleId: string; roleId: string;
description: string; description: string;
}[] = DEV_MODE }[] = DEV_MODE
? [ ? [
{ {
emojiName: 'sausageroll', emojiName: 'sausageroll',
emojiId: '995712110925451324', emojiId: '995712110925451324',
roleId: process.env.DEV_REACTION_ROLE, roleId: process.env.DEV_REACTION_ROLE,
description: description:
'Join the conversation in the contributors channels (you can still view without this role)', 'Join the conversation in the contributors channels (you can still view without this role)',
}, },
] ]
: [ : [
{ {
emojiName: 'tauri', emojiName: 'tauri',
emojiId: '876938722266972210', emojiId: '876938722266972210',
roleId: '986176820187631616', roleId: '986176820187631616',
description: description:
'Join the conversation in the contributors channels (you can still view without this role)', 'Join the conversation in the contributors channels (you can still view without this role)',
}, },
]; ];
export const REACTION_ROLE_CHANNEL = DEV_MODE export const REACTION_ROLE_CHANNEL = DEV_MODE
? process.env.DEV_REACTION_ROLE_CHANNEL ? process.env.DEV_REACTION_ROLE_CHANNEL
: '616210923354456064'; : '616210923354456064';
export const SUPPORT_FORUM = DEV_MODE export const SUPPORT_FORUM = DEV_MODE
? process.env.DEV_SUPPORT_FORUM_CHANNEL ? process.env.DEV_SUPPORT_FORUM_CHANNEL
: '1047150269156294677'; : '1047150269156294677';
export const SOLVABLE_FORUMS = [SUPPORT_FORUM]; export const SOLVABLE_FORUMS = [SUPPORT_FORUM];
export const UNSOLVED_TAG = 'unsolved'; export const UNSOLVED_TAG = 'unsolved';
export const SOLVED_TAG = 'solved'; export const SOLVED_TAG = 'solved';

View File

@@ -14,7 +14,7 @@ import { add_thread_prefix } from '../utils/threads';
export default event({ export default event({
name: 'messageCreate', name: 'messageCreate',
run: async ({ }, message) => { run: async ({}, message) => {
// Rules for whether or not the message should be dealt with by the bot // Rules for whether or not the message should be dealt with by the bot
const should_ignore = const should_ignore =
message.author.bot || message.author.bot ||

View File

@@ -1,47 +1,76 @@
import { import { ThreadChannel, ChannelType, ForumChannel } from 'discord.js';
ThreadChannel,
ChannelType,
ForumChannel,
} from 'discord.js';
import { event } from 'jellycommands'; import { event } from 'jellycommands';
import { wrap_in_embed } from '../utils/embed_helpers'; 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({ export default event({
name: 'messageCreate', name: 'messageCreate',
run: async ({ }, message) => { run: async ({}, message) => {
// Rules for whether or not the message should be dealt with by the bot // 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 the message should be ignored, return without further processing
if (should_ignore) return; if (should_ignore) return;
// If this is posted in a solvable forum channel // 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 // 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 // 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 // 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 // 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 // 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 // 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 // Add the solved tag
tags.unshift(solveTag) tags.unshift(solveTag);
} }
// If neither tag is going to exist in the channel, add unsolved // 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 // Ensure no duplicates are in the array
tags = [...new Set(tags)].sort() tags = [...new Set(tags)].sort();
// Apply tags // 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 // If this is a new post and not just a regular message
// Disabled for now due to the fact that nobody reads the message // Disabled for now due to the fact that nobody reads the message
if (!message.nonce && message.position === 0 && false) { if (!message.nonce && message.position === 0 && false) {
const msg = await message.channel.send(wrap_in_embed( const msg = await message.channel.send(
`Thank you for your message! wrap_in_embed(
`Thank you for your message!
1. Search the <#${SUPPORT_FORUM}> forum for existing posts 1. Search the <#${SUPPORT_FORUM}> forum for existing posts
2. Search Github issues to see if this is a known issue 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 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) 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` Once you've read this and taken the appropriate steps, react to this message`,
)) ),
await msg.react(MESSAGE_READ) );
await msg.react(MESSAGE_READ);
} }
} }
}, },

View File

@@ -10,11 +10,11 @@ export default event({
// Send the message for role reactions // Send the message for role reactions
sendReactionRoleMessage(client); sendReactionRoleMessage(client);
// Update the cache so that the bot can properly react to messages sent before it went live // 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 // Run a task in the background every 60 minutes
setInterval(async () => { setInterval(async () => {
// Update the cache so that old messages can be reacted to // Update the cache so that old messages can be reacted to
updateCache(client) updateCache(client);
}, 60_000 * 60) // Every 60 minutes }, 60_000 * 60); // Every 60 minutes
}, },
}); });

View File

@@ -1,54 +1,99 @@
import { import { ThreadChannel, ChannelType, ForumChannel } from 'discord.js';
ThreadChannel,
ChannelType,
ForumChannel,
} from 'discord.js';
import { event } from 'jellycommands'; import { event } from 'jellycommands';
import { SOLVABLE_FORUMS, UNSOLVED_TAG, SOLVED_TAG } from '../config'; import { SOLVABLE_FORUMS, UNSOLVED_TAG, SOLVED_TAG } from '../config';
export default event({ export default event({
name: 'threadUpdate', name: 'threadUpdate',
run: async ({ }, oldChannel, newChannel) => { run: async ({}, oldChannel, newChannel) => {
if (newChannel instanceof ThreadChannel) { if (newChannel instanceof ThreadChannel) {
// If newChannel is a solvable channel // If newChannel is a solvable channel
if (SOLVABLE_FORUMS.includes(newChannel.parentId)) { if (SOLVABLE_FORUMS.includes(newChannel.parentId)) {
// Parent forum channel // 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 // 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 // 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 // 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 // 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 // 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 // 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))) { if (
tags.unshift(unsolveTag) 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 // !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))) { } else if (
tags.unshift(solveTag) 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 // 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))) { } else if (
tags.unshift(unsolveTag) 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 // !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))) { } else if (
tags.unshift(solveTag) 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 // > unsolved solved : post was going to be marked as both, assume solved is intended
} else if (newChannel.appliedTags.includes(unsolveTag) && newChannel.appliedTags.includes(solveTag)) { } else if (
tags.unshift(solveTag) 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 // > !unsolved !unsolved : post was going to be marked as neither, assume unsolved is intended
} else if (!newChannel.appliedTags.includes(unsolveTag) && !newChannel.appliedTags.includes(solveTag)) { } else if (
tags.unshift(unsolveTag) !newChannel.appliedTags.includes(unsolveTag) &&
!newChannel.appliedTags.includes(solveTag)
) {
tags.unshift(unsolveTag);
} }
// If neither tag is going to exist for any reason, add unsolved // 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 // 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 // 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);
} }
} }
}, },

View File

@@ -4,24 +4,30 @@ import http from 'http';
const app = express(); const app = express();
const router = express.Router(); const router = express.Router();
router.use((req: express.Request, res: express.Response, next: express.NextFunction) => { router.use(
res.header('Access-Control-Allow-Methods', 'GET'); (
const status = app.locals.getStatus() req: express.Request,
if (status === 200) { res: express.Response,
next(); next: express.NextFunction,
} else { ) => {
res.status(status).send({ error: 'Something failed!' }) 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) => { router.get('/health', (req: express.Request, res: express.Response) => {
res.status(200).send('Ok'); res.status(200).send('Ok');
}); });
app.use('/api/v1', router); app.use('/api/v1', router);
export default function (callback: any) { export default function (callback: any) {
app.locals.getStatus = callback app.locals.getStatus = callback;
const server = http.createServer(app); const server = http.createServer(app);
return server.listen(3000); return server.listen(3000);
} }

View File

@@ -14,7 +14,7 @@ const client = new JellyCommands({
GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.MessageContent, GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMessages GatewayIntentBits.GuildMessages,
], ],
}, },
@@ -33,12 +33,11 @@ const client = new JellyCommands({
}); });
function health() { function health() {
if (!client.isReady()) if (!client.isReady()) return 502;
return 502 return 200;
return 200
} }
healthcheck(health); healthcheck(health);
// Auto reads the DISCORD_TOKEN environment variable // Auto reads the DISCORD_TOKEN environment variable
await client.login() await client.login();

View File

@@ -75,7 +75,7 @@ export async function sendReactionRoleMessage(client: Client) {
); );
messageArray.push('\n**<#879007560429088800>**'); messageArray.push('\n**<#879007560429088800>**');
messageArray.push( 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'); let messageBody = messageArray.join('\n');
@@ -98,7 +98,9 @@ export async function sendReactionRoleMessage(client: Client) {
console.debug('Message edited'); console.debug('Message edited');
} else { } else {
// Delete old messages from the bot // 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...'); console.debug('Attempting to send message...');
// Send the message // Send the message
message = await channel.send(messageBody); message = await channel.send(messageBody);

View File

@@ -1,16 +1,13 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "Node16", "module": "ESNext",
"esModuleInterop": true, "esModuleInterop": true,
"target": "ES2022", "target": "ESNext",
"noImplicitAny": true, "noImplicitAny": true,
"moduleResolution": "node", "moduleResolution": "Node",
"sourceMap": true, "sourceMap": true,
"outDir": "dist", "outDir": "dist",
"skipLibCheck": true, "skipLibCheck": true
"lib": [ },
"ES2021.String" "include": ["src"]
]
},
"include": ["src"]
} }