mirror of
https://github.com/tauri-apps/tauri-discord-bot.git
synced 2026-01-31 00:35:21 +01:00
Update ping command and some config and formatting cleanup (#147)
This commit is contained in:
18
.prettierrc
18
.prettierrc
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"semi": true,
|
||||
"useTabs": false,
|
||||
"tabWidth": 4
|
||||
}
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"semi": true,
|
||||
"useTabs": false,
|
||||
"tabWidth": 4
|
||||
}
|
||||
|
||||
62
package.json
62
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
"extends": ["config:base"]
|
||||
}
|
||||
|
||||
60
src/commands/ping.ts
Normal file
60
src/commands/ping.ts
Normal 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';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
},
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
114
src/config.ts
114
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';
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user