From 2fbf9574b10595ad158b3701e1d03f42931fabb5 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Mon, 22 May 2023 22:34:48 +1000 Subject: [PATCH 01/33] many changes Added /message Added roleAudits for donor colours in onboarding Added typing status to /say --- .env.example | 19 ---- .gitignore | 3 +- src/discord/commands/guild/d.message.ts | 113 ++++++++++++++++++++++ src/discord/commands/guild/d.say.ts | 12 +++ src/discord/events/roleAudit.ts | 119 ++++++++++++++++++++++++ src/global/utils/env.config.ts | 5 +- 6 files changed, 248 insertions(+), 23 deletions(-) delete mode 100644 .env.example create mode 100644 src/discord/commands/guild/d.message.ts create mode 100644 src/discord/events/roleAudit.ts diff --git a/.env.example b/.env.example deleted file mode 100644 index 2808837ec..000000000 --- a/.env.example +++ /dev/null @@ -1,19 +0,0 @@ -NODE_ENV = development - -DISCORD_CLIENT_ID = In your Discord Developer Portal -DISCORD_CLIENT_TOKEN = In your Discord Developer Portal -DISCORD_GUILD_ID = 960606557622657026 - -MATRIX_ACCESS_TOKEN = - -POSTGRES_DB_URL = postgres://tripsit_api:P@ssw0rd@localhost:5432/tripsit - -DISCORD_CLIENT_SECRET = -DISCORD_CLIENT_REDIRECT_URI = -GITHUB_TOKEN = -RAPID_TOKEN -WOLFRAM_TOKEN = -IMGUR_ID = -IMGUR_SECRET = -YOUTUBE_TOKEN = -IMDB_TOKEN = diff --git a/.gitignore b/.gitignore index 442c6bbff..db3cb45c5 100644 --- a/.gitignore +++ b/.gitignore @@ -366,4 +366,5 @@ node_modules_bak eslint-report.json coverage/ src/discord/assets/img/*/*.png -src/matrix/cache/tripbot.json \ No newline at end of file +src/matrix/cache/tripbot.json +.env.example diff --git a/src/discord/commands/guild/d.message.ts b/src/discord/commands/guild/d.message.ts new file mode 100644 index 000000000..c38d624b7 --- /dev/null +++ b/src/discord/commands/guild/d.message.ts @@ -0,0 +1,113 @@ +import { + GuildMember, + SlashCommandBuilder, + TextChannel, + EmbedBuilder, +} from 'discord.js'; +import { SlashCommand } from '../../@types/commandDef'; +import commandContext from '../../utils/context'; // eslint-disable-line @typescript-eslint/no-unused-vars + +const F = f(__filename); + +export const dSay: SlashCommand = { + data: new SlashCommandBuilder() + .setName('message') + .setDescription('Do stuff with a bot message') + + .addSubcommand(subcommand => subcommand + .setName('edit') + .setDescription('Edit a message') + .addStringOption(option => option.setName('id') + .setDescription('What is the message ID?') + .setRequired(true)) + .addStringOption(option => option.setName('message') + .setDescription('What do you want to say?') + .setRequired(true)), + ) + .addSubcommand(subcommand => subcommand + .setName('grab') + .setDescription('Grab the raw embed code of a message') + .addStringOption(option => option.setName('id') + .setDescription('What is the message ID?') + .setRequired(true)), + ), + async execute(interaction) { + await interaction.deferReply({ ephemeral: true }); + + // if edit command + if (interaction.options.getSubcommand() === 'edit') { + if (!interaction.guild) { + await interaction.editReply({ content: 'This command can only be used in a server!' }); + return false; + } + // check if message id is valid + const id = interaction.options.getString('id', true); + const message = await interaction.channel?.messages.fetch(id); + const say = interaction.options.getString('message', true); + if (!message) { + await interaction.editReply({ content: `Message with ID '${id}' not found!` }); + return false; + } + // check if message is from bot + if (message.author.id !== interaction.client.user?.id) { + await interaction.editReply({ content: `Message with ID '${id}' is not from me!` }); + return false; + } + // check if message is raw embed code + if (say.startsWith('{')) { + try { + const embedData = JSON.parse(say); + const embed = new EmbedBuilder(embedData); + message.edit({ embeds: [embed] }) + .then(() => { + interaction.editReply({ content: `Successfully edited message with new embed!'` }); + return true; + }) + .catch((error) => { + console.error(error); + interaction.editReply({ content: `Failed to edit message with embed.'` }); + return false; + }); + } catch (error) { + console.error(error); + interaction.editReply({ content: `There is an error in your embed code!` }); + return false; + } + return true; + } else { + // edit message + await message.edit(say); + await interaction.editReply({ content: `I edited message with ID '${id}' to say '${say}'` }); + return true; + } + } + // if grab command + if (interaction.options.getSubcommand() === 'grab') { + if (!interaction.guild) { + await interaction.editReply({ content: 'This command can only be used in a server!' }); + return false; + } + // + const id = interaction.options.getString('id', true); + const message = await interaction.channel?.messages.fetch(id); + // check if message id is valid + if (!message) { + await interaction.editReply({ content: `Message with ID '${id}' not found!` }); + return false; + } + // check if message contains embed + if (message.embeds.length > 0) { + const embed = message.embeds[0]; + const embedData = embed.toJSON(); + const embedString = JSON.stringify(embedData, null, 2); + await interaction.editReply({ content: `\`\`\`json\n${embedString}\`\`\`` }); + return true; + } else { + await interaction.editReply({ content: `Message with ID '${id}' does not contain an embed!` }); + return false; + } + } + + return true; + }, +}; \ No newline at end of file diff --git a/src/discord/commands/guild/d.say.ts b/src/discord/commands/guild/d.say.ts index b5be60c0e..579a571e2 100644 --- a/src/discord/commands/guild/d.say.ts +++ b/src/discord/commands/guild/d.say.ts @@ -28,10 +28,22 @@ export const dSay: SlashCommand = { const channel = interaction.options.getChannel('channel') as TextChannel; const say = interaction.options.getString('say', true); + const style = interaction.options.getString('style'); if (channel) { + // display typing status + + await channel.sendTyping(); + // wait 2 seconds + await new Promise(resolve => setTimeout(resolve, 1500)); + // send message await channel.send(say); } else { + // display typing status + await interaction.channel?.sendTyping(); + // wait 2 seconds + await new Promise(resolve => setTimeout(resolve, 1500)); + // send message await interaction.channel?.send(say); } diff --git a/src/discord/events/roleAudit.ts b/src/discord/events/roleAudit.ts new file mode 100644 index 000000000..c0dc45f00 --- /dev/null +++ b/src/discord/events/roleAudit.ts @@ -0,0 +1,119 @@ +import { + // Colors, + Role, + TextChannel, + // Message, +} from 'discord.js'; +import { stripIndents } from 'common-tags'; +import { + GuildMemberUpdateEvent, +} from '../@types/eventDef'; +// import embedTemplate from '../utils/embedTemplate'; +// import { +// ReactionRoleList, +// } from '../../global/@types/database'; + +const mindsetRoles = [ + env.ROLE_DRUNK, + env.ROLE_HIGH, + env.ROLE_ROLLING, + env.ROLE_TRIPPING, + env.ROLE_DISSOCIATING, + env.ROLE_STIMMING, + env.ROLE_SEDATED, + env.ROLE_SOBER, +]; + +const colorRoles = [ + env.ROLE_RED, + env.ROLE_ORANGE, + env.ROLE_YELLOW, + env.ROLE_GREEN, + env.ROLE_BLUE, + env.ROLE_PURPLE, + env.ROLE_PINK, + env.ROLE_WHITE, +]; + +const donorColorRoles = [ + env.ROLE_DONOR_RED, + env.ROLE_DONOR_ORANGE, + env.ROLE_DONOR_YELLOW, + env.ROLE_DONOR_GREEN, + env.ROLE_DONOR_BLUE, + env.ROLE_DONOR_PURPLE, + env.ROLE_DONOR_BLACK, + env.ROLE_DONOR_PINK, +]; + +const donorRoles = [ + env.ROLE_BOOSTER, + env.ROLE_PATRON, +]; + +const F = f(__filename); + +export const guildMemberUpdate: GuildMemberUpdateEvent = { + name: 'guildMemberUpdate', + async execute(oldMember, newMember) { + // log.info(F, `${newMember} was updated`); + const oldRoles = oldMember.roles.cache.map(role => role.id); + const newRoles = newMember.roles.cache.map(role => role.id); + + // If the oldRoles don't match the new roles + if (oldRoles.toString() !== newRoles.toString()) { + // log.debug(F, `roles changed on ${newMember.displayName}!`); + // log.debug(F, `oldRoles: ${oldRoles}`); + // log.debug(F, `newRoles: ${newRoles}`); + + // Find the difference between the two arrays + const rolesAdded = newRoles.filter(x => !oldRoles.includes(x)); + const rolesRemoved = oldRoles.filter(x => !newRoles.includes(x)); + if (rolesAdded.length > 0) { + if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; + // log.debug(F, `roles added: ${rolesAdded}`); + + // Go through each role added + rolesAdded.forEach(async roleId => { + + // Check if the id matches a colorRole + if (donorColorRoles.includes(roleId)) { + // log.debug(F, `donor color role added: ${roleId}`); + // If it does, check if the user also has a donor role + if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON)) { + log.debug(F, `Donor added a color role!`); + } + else { + // If they don't, remove the color role + log.debug(F, `User added a color role without being a donor!`); + const role = newMember.guild.roles.cache.get(roleId); + if (role) { + await newMember.roles.remove(role); + } + } + } + }); + } + if (rolesRemoved.length > 0) { + if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; + // log.debug(F, `roles removed: ${rolesRemoved}`); + // Go through each role removed, and check if the id matches a donorRole + rolesRemoved.forEach(async roleId => { + if (donorRoles.includes(roleId)) { + // log.debug(F, `donor role removed: ${roleId}`); + // If it does, check if the user also has a role id matching a donorColorRole and if so, remove it + const donorColorRole = donorColorRoles.find(role => newRoles.includes(role)); + if (donorColorRole) { + log.debug(F, `Color role removed from ex-donor!`); + const role = newMember.guild.roles.cache.get(donorColorRole); + if (role) { + await newMember.roles.remove(role); + } + } + } + }); + } + + } + }, +}; diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 36fe60543..5dd489461 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -117,6 +117,7 @@ export const env = { CHANNEL_DISSOCIATIVES: isProd ? '978051567989178388' : '1052634188823658496', CHANNEL_PSYCHEDELICS: isProd ? '996096935805063188' : '1052634190203596850', + // CATEGORY_VOICE: isProd ? '848731346959335445' : '1052634085803180062', CHANNEL_CAMPFIRE: isProd ? '1000559873232207902' : '1052634109815562351', CATEGORY_ARCADE: isProd ? '1025976352723185726' : '1052634089238311002', @@ -289,7 +290,6 @@ export const env = { ROLE_PURPLE: isProd ? '957299595644403772' : '1052644683383328798', ROLE_PINK: isProd ? '958073126485368922' : '1052644684473839746', ROLE_WHITE: isProd ? '957298729675784273' : '1052644687065911406', - ROLE_BLACK: isProd ? '957298800236564481' : '1052644685396578345', ROLE_DONOR_RED: isProd ? '1053760004060090389' : '1055267028753186888', ROLE_DONOR_ORANGE: isProd ? '1053760016773042206' : '1055267113998229574', @@ -297,8 +297,7 @@ export const env = { ROLE_DONOR_GREEN: isProd ? '1053760024977088572' : '1055267128988684288', ROLE_DONOR_BLUE: isProd ? '1053760309095059536' : '1055267132591591525', ROLE_DONOR_PURPLE: isProd ? '1053760303332065312' : '1055267157405081711', - // ROLE_DONOR_WHITE: isProd ? '' : '', - // ROLE_DONOR_BLACK: isProd ? '' : '', + ROLE_DONOR_BLACK: isProd ? '957298800236564481' : '1052644685396578345', ROLE_DONOR_PINK: isProd ? '1053759289791086782' : '1055267162551492708', ROLE_TS100: isProd ? '1100937689034924142' : '1100937537096269844', From 04e788880783c1670e546ffac46d211b2c568441 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Tue, 23 May 2023 18:09:24 +1000 Subject: [PATCH 02/33] Team Mindset Roles BETA It works, but is kinda slow sometimes, probably some inefficient looping --- src/discord/events/roleAudit.ts | 69 ++++++++++++++++++++++++++++++++- src/global/utils/env.config.ts | 21 +++++----- 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/discord/events/roleAudit.ts b/src/discord/events/roleAudit.ts index c0dc45f00..c12b2b66b 100644 --- a/src/discord/events/roleAudit.ts +++ b/src/discord/events/roleAudit.ts @@ -24,6 +24,17 @@ const mindsetRoles = [ env.ROLE_SOBER, ]; +const TTSmindsetRoles = [ + env.ROLE_TTS_DRUNK, + env.ROLE_TTS_HIGH, + env.ROLE_TTS_ROLLING, + env.ROLE_TTS_TRIPPING, + env.ROLE_TTS_DISSOCIATING, + env.ROLE_TTS_STIMMING, + env.ROLE_TTS_SEDATED, + env.ROLE_TTS_SOBER, +]; + const colorRoles = [ env.ROLE_RED, env.ROLE_ORANGE, @@ -92,13 +103,69 @@ export const guildMemberUpdate: GuildMemberUpdateEvent = { } } } + // Check if the id matches a mindsetRole + if (mindsetRoles.includes(roleId)) { + // log.debug(F, `mindset role added: ${roleId}`); + // If it does, check if the user also has team tripsit role + if (oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) + // If so, replace the mindset role with the TTS equivalent + log.debug(F, `User added a mindset role while being a TTS!`); + + // Find .env name of role using the mindsetRole table + // Iterate through the mindsetRoles array + for (const mindsetRole of mindsetRoles) { + // Check if the current mindsetRole matches the target ID + const userMindsetEnv = Object.keys(env).find((key) => env[key] === mindsetRole); + if (mindsetRole === roleId) { + // The target ID matches the current mindsetRole object + log.debug(F, `User Mindset role: ${userMindsetEnv}`) + // Change "ROLE_" to "ROLE_TTS" in the .env name + let ttsMindsetEnv = userMindsetEnv!.replace("ROLE_", "ROLE_TTS_"); + log.debug(F, `TTS mindset role: ${ttsMindsetEnv}`) + // Find the role in the guild + const ttsMindsetRole = oldMember.guild.roles.cache.get(env[ttsMindsetEnv]); + log.debug(F, `TTS mindset role load: ${ttsMindsetRole}`) + // If the role exists, add it to the user + if (ttsMindsetRole) { + await newMember.roles.add(ttsMindsetRole); + break; // Exit the loop since we found the desired object + } + } + } + } }); } if (rolesRemoved.length > 0) { if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; // log.debug(F, `roles removed: ${rolesRemoved}`); - // Go through each role removed, and check if the id matches a donorRole + // Go through each role removed rolesRemoved.forEach(async roleId => { + // Check if it's a mindsetRole + if (mindsetRoles.includes(roleId) && newMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { + // Remove all TTS mindsets + // Check if the member has any of the TTSmindsetRoles + for (const mindsetRole of mindsetRoles) { + // Check if the current mindsetRole matches the target ID + const userMindsetEnv = Object.keys(env).find((key) => env[key] === mindsetRole); + if (mindsetRole === roleId) { + // The target ID matches the current mindsetRole object + log.debug(F, `User Mindset role: ${userMindsetEnv}`) + // Change "ROLE_" to "ROLE_TTS" in the .env name + let ttsMindsetEnv = userMindsetEnv!.replace("ROLE_", "ROLE_TTS_"); + log.debug(F, `TTS mindset role: ${ttsMindsetEnv}`) + // Find the role in the guild + const ttsMindsetRole = oldMember.guild.roles.cache.get(env[ttsMindsetEnv]); + log.debug(F, `TTS mindset role load: ${ttsMindsetRole}`) + // If the role exists, add it to the user + if (ttsMindsetRole) { + await newMember.roles.remove(ttsMindsetRole); + break; // Exit the loop since we found the desired object + } + } + } + } + + // Check if it's a donor role if (donorRoles.includes(roleId)) { // log.debug(F, `donor role removed: ${roleId}`); // If it does, check if the user also has a role id matching a donorColorRole and if so, remove it diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 5dd489461..a69d33598 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -268,17 +268,18 @@ export const env = { ROLE_SOBER: isProd ? '955486188268056656' : '960606558071435317', ROLE_TALKATIVE: isProd ? '981437055030677554' : '1052644638487486464', ROLE_WORKING: isProd ? '955486102549049344' : '1052644637380190268', - - ROLE_TTS_DRUNK: isProd ? '955485069294854154' : '1052644628639252500', - ROLE_TTS_HIGH: isProd ? '955482289335320626' : '1052644630912577586', - ROLE_TTS_ROLLING: isProd ? '955485203592261633' : '1052644633492082819', - ROLE_TTS_TRIPPING: isProd ? '955485936915980348' : '1052644632409935872', - ROLE_TTS_DISSOCIATING: isProd ? '955485314305101874' : '1052644634460963038', - ROLE_TTS_STIMMING: isProd ? '955485549035126815' : '1052644635559870525', - ROLE_TTS_SEDATED: isProd ? '955485615879749682' : '1052644636511965184', + ROLE_VOICECHATTY: isProd ? '1094637167202009128' : '1110453458013798420', + + ROLE_TTS_DRUNK: isProd ? '1104648635691577414' : '1110471812053213245', + ROLE_TTS_HIGH: isProd ? '1104648442732613733' : '1052644630912577586', + ROLE_TTS_ROLLING: isProd ? '1104648578242191372' : '1052644633492082819', + ROLE_TTS_TRIPPING: isProd ? '1104648782404128808' : '1110457165258424360', + ROLE_TTS_DISSOCIATING: isProd ? '1104648741245435964' : '1052644634460963038', + ROLE_TTS_STIMMING: isProd ? '1104648557362954291' : '1052644635559870525', + ROLE_TTS_SEDATED: isProd ? '1104648491554308156' : '1052644636511965184', ROLE_TTS_SOBER: isProd ? '955486188268056656' : '960606558071435317', - ROLE_TTS_TALKATIVE: isProd ? '981437055030677554' : '1052644638487486464', - ROLE_TTS_WORKING: isProd ? '955486102549049344' : '1052644637380190268', + ROLE_TTS_TALKATIVE: isProd ? '1079954878606086254' : '1052644638487486464', + ROLE_TTS_VOICECHATTY: isProd ? '1104648238566473769' : '1110453458013798420', ROLE_TRIVIABIGBRAIN: isProd ? '' : '1052644639464767548', From 373913b098b30c74c3c711f8df30c096999c15bd Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Tue, 23 May 2023 18:42:57 +1000 Subject: [PATCH 03/33] Update tents to use new voice category Tents are now in their own category --- src/discord/utils/tents.ts | 4 ++-- src/global/utils/env.config.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index cecea02b4..65cc4063a 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -20,7 +20,7 @@ export async function pitchTent( New.member?.guild.channels.create({ name: `⛺│ ${New.member.displayName}'s tent`, type: ChannelType.GuildVoice, - parent: env.CATEGORY_CAMPGROUND, + parent: env.CATEGORY_VOICE, permissionOverwrites: [ { id: New.member.id, @@ -99,7 +99,7 @@ To undo a command, just type it again.`); export async function teardownTent( Old:VoiceState, ): Promise { - const tempVoiceCategory = await Old.guild.channels.fetch(env.CATEGORY_CAMPGROUND) as CategoryChannel; + const tempVoiceCategory = await Old.guild.channels.fetch(env.CATEGORY_VOICE) as CategoryChannel; tempVoiceCategory.children.cache.forEach(channel => { // Get the number of humans in the channel const humans = channel.members.filter(member => !member.user.bot).size; diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index a69d33598..f40fd57a2 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -117,7 +117,7 @@ export const env = { CHANNEL_DISSOCIATIVES: isProd ? '978051567989178388' : '1052634188823658496', CHANNEL_PSYCHEDELICS: isProd ? '996096935805063188' : '1052634190203596850', - // CATEGORY_VOICE: isProd ? '848731346959335445' : '1052634085803180062', + CATEGORY_VOICE: isProd ? '1108008906095067187' : '1108013999259402271', CHANNEL_CAMPFIRE: isProd ? '1000559873232207902' : '1052634109815562351', CATEGORY_ARCADE: isProd ? '1025976352723185726' : '1052634089238311002', @@ -271,15 +271,15 @@ export const env = { ROLE_VOICECHATTY: isProd ? '1094637167202009128' : '1110453458013798420', ROLE_TTS_DRUNK: isProd ? '1104648635691577414' : '1110471812053213245', - ROLE_TTS_HIGH: isProd ? '1104648442732613733' : '1052644630912577586', - ROLE_TTS_ROLLING: isProd ? '1104648578242191372' : '1052644633492082819', + ROLE_TTS_HIGH: isProd ? '1104648442732613733' : '1110478575695568947', + ROLE_TTS_ROLLING: isProd ? '1104648578242191372' : '1110478674580475994', ROLE_TTS_TRIPPING: isProd ? '1104648782404128808' : '1110457165258424360', - ROLE_TTS_DISSOCIATING: isProd ? '1104648741245435964' : '1052644634460963038', - ROLE_TTS_STIMMING: isProd ? '1104648557362954291' : '1052644635559870525', - ROLE_TTS_SEDATED: isProd ? '1104648491554308156' : '1052644636511965184', + ROLE_TTS_DISSOCIATING: isProd ? '1104648741245435964' : '1110478749469782077', + ROLE_TTS_STIMMING: isProd ? '1104648557362954291' : '1110478814024306740', + ROLE_TTS_SEDATED: isProd ? '1104648491554308156' : '1110478863378698261', ROLE_TTS_SOBER: isProd ? '955486188268056656' : '960606558071435317', - ROLE_TTS_TALKATIVE: isProd ? '1079954878606086254' : '1052644638487486464', - ROLE_TTS_VOICECHATTY: isProd ? '1104648238566473769' : '1110453458013798420', + ROLE_TTS_TALKATIVE: isProd ? '1079954878606086254' : '1110478915388063755', + ROLE_TTS_VOICECHATTY: isProd ? '1104648238566473769' : '1110479003476828280', ROLE_TRIVIABIGBRAIN: isProd ? '' : '1052644639464767548', From 5a316eff6f745a1452885063f548515e7bada19b Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Tue, 23 May 2023 22:27:12 +1000 Subject: [PATCH 04/33] I forgot 2 roles I am silly --- src/discord/events/roleAudit.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/discord/events/roleAudit.ts b/src/discord/events/roleAudit.ts index c12b2b66b..e088e4173 100644 --- a/src/discord/events/roleAudit.ts +++ b/src/discord/events/roleAudit.ts @@ -21,7 +21,8 @@ const mindsetRoles = [ env.ROLE_DISSOCIATING, env.ROLE_STIMMING, env.ROLE_SEDATED, - env.ROLE_SOBER, + env.ROLE_TALKATIVE, + env.ROLE_VOICECHATTY, ]; const TTSmindsetRoles = [ @@ -32,7 +33,8 @@ const TTSmindsetRoles = [ env.ROLE_TTS_DISSOCIATING, env.ROLE_TTS_STIMMING, env.ROLE_TTS_SEDATED, - env.ROLE_TTS_SOBER, + env.ROLE_TTS_TALKATIVE, + env.ROLE_TTS_VOICECHATTY, ]; const colorRoles = [ @@ -107,7 +109,7 @@ export const guildMemberUpdate: GuildMemberUpdateEvent = { if (mindsetRoles.includes(roleId)) { // log.debug(F, `mindset role added: ${roleId}`); // If it does, check if the user also has team tripsit role - if (oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) + if (newMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { // If so, replace the mindset role with the TTS equivalent log.debug(F, `User added a mindset role while being a TTS!`); @@ -133,6 +135,7 @@ export const guildMemberUpdate: GuildMemberUpdateEvent = { } } } + } }); } if (rolesRemoved.length > 0) { From fc96abb150c30f7e957eee0fd16bfdb911554d70 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Wed, 24 May 2023 12:02:53 +1000 Subject: [PATCH 05/33] Important Fixes Make AFK channel immune to deletion Make TTS role count as donor for donor colours --- src/discord/events/roleAudit.ts | 3 ++- src/discord/utils/tents.ts | 2 +- src/global/utils/env.config.ts | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/discord/events/roleAudit.ts b/src/discord/events/roleAudit.ts index e088e4173..62874b53e 100644 --- a/src/discord/events/roleAudit.ts +++ b/src/discord/events/roleAudit.ts @@ -62,6 +62,7 @@ const donorColorRoles = [ const donorRoles = [ env.ROLE_BOOSTER, env.ROLE_PATRON, + env.ROLE_TEAMTRIPSIT, ]; const F = f(__filename); @@ -93,7 +94,7 @@ export const guildMemberUpdate: GuildMemberUpdateEvent = { if (donorColorRoles.includes(roleId)) { // log.debug(F, `donor color role added: ${roleId}`); // If it does, check if the user also has a donor role - if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON)) { + if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON) || oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { log.debug(F, `Donor added a color role!`); } else { diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 65cc4063a..3ee2b79c4 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -106,7 +106,7 @@ export async function teardownTent( // If the channel is a voice channel, and it's not the campfire, and there are no humans in it delete it if (channel.type === ChannelType.GuildVoice - && channel.id !== env.CHANNEL_CAMPFIRE + && (channel.id !== env.CHANNEL_CAMPFIRE || channel.id !== env.CHANNEL_FUTON) && humans < 1) { channel.delete('Removing temporary voice chan!'); // log.debug(F, `deleted an empty temporary voice channel`); diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index f40fd57a2..736c61fb9 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -118,7 +118,7 @@ export const env = { CHANNEL_PSYCHEDELICS: isProd ? '996096935805063188' : '1052634190203596850', CATEGORY_VOICE: isProd ? '1108008906095067187' : '1108013999259402271', - CHANNEL_CAMPFIRE: isProd ? '1000559873232207902' : '1052634109815562351', + CHANNEL_CAMPFIRE: isProd ? '1000559873232207902' : '1110747575495176192', CATEGORY_ARCADE: isProd ? '1025976352723185726' : '1052634089238311002', CHANNEL_TRIPTOWN: isProd ? '1071245245934751764' : '1075858181760233543', @@ -169,7 +169,7 @@ export const env = { CHANNEL_GAMINGRADIO: isProd ? '' : '1052634116975231019', CHANNEL_STUDYRADIO: isProd ? '' : '1052634119458275459', CHANNEL_SLEEPYRADIO: isProd ? '' : '1052634122222309386', - CHANNEL_FUTON: isProd ? '' : '1052634123732271235', + CHANNEL_FUTON: isProd ? '1110746349240074240' : '1110747601713766402', CATEGORY_ARCHIVED: isProd ? '' : '1052634099149443083', CHANNEL_SANDBOX_DEV: isProd ? '' : '960606558373441565', From ee2d78e35f1b1923b52941cc15fb1df96daa8c51 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Thu, 25 May 2023 16:48:38 +1000 Subject: [PATCH 06/33] Add "Busy" role to TTS mindsets --- src/discord/events/guildMemberUpdate.ts | 633 ++++++++++++++++-------- src/global/utils/env.config.ts | 5 +- 2 files changed, 415 insertions(+), 223 deletions(-) diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 4f1571dc2..2f7da60a6 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -1,245 +1,438 @@ -import { - // Colors, - Role, - TextChannel, - // Message, -} from 'discord.js'; +import { GuildMember, Role, TextChannel } from 'discord.js'; import { stripIndents } from 'common-tags'; import { GuildMemberUpdateEvent, } from '../@types/eventDef'; -// import embedTemplate from '../utils/embedTemplate'; import { database } from '../../global/utils/knex'; import { topic } from '../../global/commands/g.topic'; -// import { -// ReactionRoleList, -// } from '../../global/@types/database'; - -// const mindsetRoles = [ -// env.ROLE_DRUNK, -// env.ROLE_HIGH, -// env.ROLE_ROLLING, -// env.ROLE_TRIPPING, -// env.ROLE_DISSOCIATING, -// env.ROLE_STIMMING, -// env.ROLE_SEDATED, -// env.ROLE_SOBER, -// ]; + +type MindsetNames = +| 'ROLE_DRUNK' +| 'ROLE_HIGH' +| 'ROLE_ROLLING' +| 'ROLE_TRIPPING' +| 'ROLE_DISSOCIATING' +| 'ROLE_STIMMING' +| 'ROLE_SEDATED' +| 'ROLE_TALKATIVE' +| 'ROLE_VOICECHATTY' +| 'ROLE_BUSY'; + +const mindsetRoles = { + ROLE_DRUNK: env.ROLE_DRUNK, + ROLE_HIGH: env.ROLE_HIGH, + ROLE_ROLLING: env.ROLE_ROLLING, + ROLE_TRIPPING: env.ROLE_TRIPPING, + ROLE_DISSOCIATING: env.ROLE_DISSOCIATING, + ROLE_STIMMING: env.ROLE_STIMMING, + ROLE_SEDATED: env.ROLE_SEDATED, + ROLE_TALKATIVE: env.ROLE_TALKATIVE, + ROLE_VOICECHATTY: env.ROLE_VOICECHATTY, + ROLE_BUSY: env.ROLE_BUSY, +} as { + [key in MindsetNames]: string; +}; + +type TeamMindsetNames = +| 'ROLE_TTS_DRUNK' +| 'ROLE_TTS_HIGH' +| 'ROLE_TTS_ROLLING' +| 'ROLE_TTS_TRIPPING' +| 'ROLE_TTS_DISSOCIATING' +| 'ROLE_TTS_STIMMING' +| 'ROLE_TTS_SEDATED' +| 'ROLE_TTS_TALKATIVE' +| 'ROLE_TTS_VOICECHATTY' +| 'ROLE_TTS_BUSY'; + +const TTSMindsetRoles = { + ROLE_TTS_DRUNK: env.ROLE_TTS_DRUNK, + ROLE_TTS_HIGH: env.ROLE_TTS_HIGH, + ROLE_TTS_ROLLING: env.ROLE_TTS_ROLLING, + ROLE_TTS_TRIPPING: env.ROLE_TTS_TRIPPING, + ROLE_TTS_DISSOCIATING: env.ROLE_TTS_DISSOCIATING, + ROLE_TTS_STIMMING: env.ROLE_TTS_STIMMING, + ROLE_TTS_SEDATED: env.ROLE_TTS_SEDATED, + ROLE_TTS_TALKATIVE: env.ROLE_TTS_TALKATIVE, + ROLE_TTS_VOICECHATTY: env.ROLE_TTS_VOICECHATTY, + ROLE_TTS_BUSY: env.ROLE_TTS_BUSY, +} as { + [key in TeamMindsetNames]: string; +}; + +// type ColorNames = +// | 'ROLE_RED' +// | 'ROLE_ORANGE' +// | 'ROLE_YELLOW' +// | 'ROLE_GREEN' +// | 'ROLE_BLUE' +// | 'ROLE_PURPLE' +// | 'ROLE_PINK' +// | 'ROLE_WHITE'; + +// const colorRoles = { +// ROLE_RED: env.ROLE_RED, +// ROLE_ORANGE: env.ROLE_ORANGE, +// ROLE_YELLOW: env.ROLE_YELLOW, +// ROLE_GREEN: env.ROLE_GREEN, +// ROLE_BLUE: env.ROLE_BLUE, +// ROLE_PURPLE: env.ROLE_PURPLE, +// ROLE_PINK: env.ROLE_PINK, +// ROLE_WHITE: env.ROLE_WHITE, +// } as { +// [key in ColorNames]: string; +// }; + +type DonorColorNames = +| 'ROLE_DONOR_RED' +| 'ROLE_DONOR_ORANGE' +| 'ROLE_DONOR_YELLOW' +| 'ROLE_DONOR_GREEN' +| 'ROLE_DONOR_BLUE' +| 'ROLE_DONOR_PURPLE' +| 'ROLE_DONOR_BLACK' +| 'ROLE_DONOR_PINK'; + +const donorColorRoles = { + ROLE_DONOR_RED: env.ROLE_DONOR_RED, + ROLE_DONOR_ORANGE: env.ROLE_DONOR_ORANGE, + ROLE_DONOR_YELLOW: env.ROLE_DONOR_YELLOW, + ROLE_DONOR_GREEN: env.ROLE_DONOR_GREEN, + ROLE_DONOR_BLUE: env.ROLE_DONOR_BLUE, + ROLE_DONOR_PURPLE: env.ROLE_DONOR_PURPLE, + ROLE_DONOR_BLACK: env.ROLE_DONOR_BLACK, + ROLE_DONOR_PINK: env.ROLE_DONOR_PINK, +} as { + [key in DonorColorNames]: string; +}; + +type DonorNames = +| 'ROLE_BOOSTER' +| 'ROLE_PATRON'; + +const donorRoles = { + ROLE_BOOSTER: env.ROLE_BOOSTER, + ROLE_PATRON: env.ROLE_PATRON, +} as { + [key in DonorNames]: string; +}; const F = f(__filename); +async function donorColorCheck( + newMember: GuildMember, + oldMember: GuildMember, + roleId: string, +) { + // Check if the id matches a colorRole + if (Object.values(donorColorRoles).includes(roleId)) { + // log.debug(F, `donor color role added: ${roleId}`); + // If it does, check if the user also has a donor role + if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON)) { + log.debug(F, 'Donor added a color role!'); + } else { + // If they don't, remove the color role + log.debug(F, 'User added a color role without being a donor!'); + const role = await newMember.guild.roles.fetch(roleId); + if (role) { + log.debug(F, `Removing ${role.name} from ${newMember.displayName}`); + await newMember.roles.remove(role); + log.debug(F, `Removed ${role.name} from ${newMember.displayName}`); + } + } + } +} + +async function donorColorRemove( + newMember: GuildMember, + roleId: string, +) { + // log.debug(F, `donor color role removed: ${roleId}`); + // log.debug(F, `${Object.keys(donorRoles)}`); + // Check if it's a donor role + if (Object.values(donorRoles).includes(roleId)) { + // log.debug(F, `donor role removed: ${roleId}`); + // If it does, check if the user also has a role id matching a donorColorRole and if so, remove it + const donorColorRole = newMember.roles.cache.find(role => Object.values(donorColorRoles).includes(role.id)); + if (donorColorRole) { + await newMember.roles.remove(donorColorRole); + } + } +} + +async function teamMindsetCheck( + newMember: GuildMember, + roleId: string, +) { + // Check if the id matches a mindsetRole + if (Object.values(mindsetRoles).includes(roleId) + && newMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { + // log.debug(F, `mindset role added: ${roleId}`); + // If it does, check if the user also has team tripsit role + // If so, replace the mindset role with the TTS equivalent + log.debug(F, 'User added a mindset role while being a TTS!'); + + const mindsetData = Object.entries(mindsetRoles).find(([, value]) => value === roleId); + + log.debug(F, `mindsetData: ${mindsetData}`); + + if (mindsetData) { + const [key] = mindsetData; + // The target ID matches the current mindsetRole object + log.debug(F, `User Mindset role: ${key}`); + // Change "ROLE_" to "ROLE_TTS" in the .env name + const ttsMindsetName = key.replace('ROLE_', 'ROLE_TTS_') as TeamMindsetNames; + log.debug(F, `TTS mindset name: ${ttsMindsetName}`); + // Find the role in the TTSMindsetRoles object + const ttsMindsetRoleId = TTSMindsetRoles[ttsMindsetName]; + log.debug(F, `TTS mindset role: ${ttsMindsetRoleId}`); + // Get the role from the guild + const role = await newMember.guild.roles.fetch(ttsMindsetRoleId) as Role; + // Add the role to the user + newMember.roles.add(role); + } + } +} + +async function teamMindsetRemove( + newMember: GuildMember, + roleId: string, +) { + // Check if it's a mindsetRole + if (Object.values(mindsetRoles).includes(roleId) + && newMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { + // Remove all TTS mindsets + // Check if the member has any of the TTSmindsetRoles + + const mindsetData = Object.entries(mindsetRoles).find(([, value]) => value === roleId); + + log.debug(F, `mindsetData: ${mindsetData}`); + + if (mindsetData) { + const [key] = mindsetData; + // The target ID matches the current mindsetRole object + log.debug(F, `User Mindset role: ${key}`); + // Change "ROLE_" to "ROLE_TTS" in the .env name + const ttsMindsetName = key.replace('ROLE_', 'ROLE_TTS_') as TeamMindsetNames; + log.debug(F, `TTS mindset name: ${ttsMindsetName}`); + // Find the role in the TTSMindsetRoles object + const ttsMindsetRoleId = TTSMindsetRoles[ttsMindsetName]; + log.debug(F, `TTS mindset role: ${ttsMindsetRoleId}`); + // Get the role from the guild + const role = await newMember.guild.roles.fetch(ttsMindsetRoleId) as Role; + // Add the role to the user + newMember.roles.remove(role); + } + } +} + +async function removeExTeamFromThreads( + newMember: GuildMember, + roleId: string, +) { + const guildData = await database.guilds.get(newMember.guild.id); + // If the role removed was a helper/tripsitter role, we need to remove them from threads they are in + if (guildData.channel_tripsit + && (roleId === guildData.role_helper + || roleId === guildData.role_tripsitter + ) + ) { + log.debug(F, `${newMember.displayName} was a helper/tripsitter!`); + const channelTripsit = await discordClient.channels.fetch(guildData.channel_tripsit) as TextChannel; + + const fetchedThreads = await channelTripsit.threads.fetch(); + fetchedThreads.threads.forEach(async thread => { + if (thread + && thread.parentId === guildData.channel_tripsit) { + log.debug(F, `Removing ${newMember.displayName} from ${thread.name}`); + await thread.members.remove(newMember.id, 'Helper/Tripsitter role removed'); + } + }); + } +} + +async function addedVerified( + newMember: GuildMember, + roleId: string, +) { + // Check if this was the verified role + if (roleId === env.ROLE_VERIFIED) { + // log.debug(F, `${newMember.displayName} verified!`); + // let colorValue = 1; + + // log.debug(F, `member: ${member.roles.cache}`); + + // log.debug(`Verified button clicked by ${interaction.user.username}#${interaction.user.discriminator}`); + const channelTripbotLogs = await global.discordClient.channels.fetch(env.CHANNEL_BOTLOG) as TextChannel; + await channelTripbotLogs.send({ + content: `Verified button clicked by ${newMember.user.username}#${newMember.user.discriminator}`, + }); + + // NOTE: Can be simplified with luxon + // const diff = Math.abs(Date.now() - Date.parse(newMember.user.createdAt.toString())); + // const years = Math.floor(diff / (1000 * 60 * 60 * 24 * 365)); + // const months = Math.floor(diff / (1000 * 60 * 60 * 24 * 30)); + // const weeks = Math.floor(diff / (1000 * 60 * 60 * 24 * 7)); + // const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + // const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + // const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + // const seconds = Math.floor((diff % (1000 * 60)) / 1000); + + // if (years > 0) { + // colorValue = Colors.White; + // } else if (years === 0 && months > 0) { + // colorValue = Colors.Purple; + // } else if (months === 0 && weeks > 0) { + // colorValue = Colors.Blue; + // } else if (weeks === 0 && days > 0) { + // colorValue = Colors.Green; + // } else if (days === 0 && hours > 0) { + // colorValue = Colors.Yellow; + // } else if (hours === 0 && minutes > 0) { + // colorValue = Colors.Orange; + // } else if (minutes === 0 && seconds > 0) { + // colorValue = Colors.Red; + // } + // log.debug(F, `coloValue: ${colorValue}`); + // const channelStart = await newMember.client.channels.fetch(env.CHANNEL_START); + // const channelTechhelp = await newMember.client.channels.fetch(env.CHANNEL_HELPDESK); + // const channelBotspam = await newMember.client.channels.fetch(env.CHANNEL_BOTSPAM); + // const channelRules = await newMember.client.channels.fetch(env.CHANNEL_RULES); + // const channelTripsit = await member.client.channels.fetch(CHANNEL_TRIPSIT); + // const embed = embedTemplate() + // .setAuthor(null) + // .setColor(colorValue) + // .setThumbnail(newMember.user.displayAvatarURL()) + // .setFooter(null) + // .setDescription(stripIndents` + // **Please welcome ${newMember.toString()} to the guild!** + // Be safe, have fun, /report any issues!`); + + const greetingList = [ + `Welcome to the guild, ${newMember}!`, + `I'm proud to announce that ${newMember} has joined our guild!`, + `Please welcome ${newMember} to our guild!`, + `Hello, ${newMember}! Welcome to our guild!`, + `Welcome to the family, ${newMember}! We're so glad you're here.`, + `Welcome to the guild, ${newMember}!`, + `We're excited to have ${newMember} as part of our guild!`, + `Say hello to our newest member, ${newMember}!`, + `Let's give a warm welcome to ${newMember}!`, + `It's great to see you here, ${newMember}!`, + `Welcome aboard, ${newMember}!`, + `We're happy to have ${newMember} join us!`, + `Say hi to ${newMember}, our newest member!`, + `Join us in welcoming ${newMember} to our guild!`, + `A big welcome to ${newMember}!`, + ]; + + const greeting = greetingList[Math.floor(Math.random() * greetingList.length)]; + + const channelLounge = await newMember.client.channels.fetch(env.CHANNEL_LOUNGE) as TextChannel; + await channelLounge.send({ + content: stripIndents`**${greeting}** + + Be safe, have fun, /report any issues! + + *${await topic()}*`, + }); + } +} + +async function addedBooster( + newMember: GuildMember, + roleId: string, +) { + // Check if the role added was a donator role + if (roleId === env.ROLE_BOOSTER) { + // log.debug(F, `${newMember.displayName} boosted the server!`); + const channelGoldlounge = await discordClient.channels.fetch(env.CHANNEL_GOLDLOUNGE) as TextChannel; + await channelGoldlounge.send(`Hey @here, ${newMember} just boosted the server, give them a big thank you for helping to keep this place awesome!`); // eslint-disable-line max-len + } +} + +async function addedPatreon( + newMember: GuildMember, + roleId: string, +) { + // Check if the role added was a donator role + if (roleId === env.ROLE_PATRON) { + // log.debug(F, `${newMember.displayName} became a patron!`); + const channelGoldlounge = await discordClient.channels.fetch(env.CHANNEL_GOLDLOUNGE) as TextChannel; + const isProd = env.NODE_ENV === 'production'; + await channelGoldlounge.send(`Hey ${isProd ? '@here' : 'here'}, ${newMember} just became a patron, give them a big thank you for helping us keep the lights on and expand!`); // eslint-disable-line max-len + } +} + +async function roleAddProcess( + newMember: GuildMember, + oldMember: GuildMember, + rolesAdded: string[], +) { + // This goes here because we don't really care when other guilds add roles + if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; + // log.debug(F, `roles added: ${rolesAdded}`); + + const auditlog = await discordClient.channels.fetch(env.CHANNEL_AUDITLOG) as TextChannel; + + // Go through each role added + rolesAdded.forEach(async roleId => { + await donorColorCheck(newMember, oldMember, roleId); + await teamMindsetCheck(newMember, roleId); + await addedVerified(newMember, roleId); + await addedBooster(newMember, roleId); + await addedPatreon(newMember, roleId); + + const role = await newMember.guild.roles.fetch(roleId) as Role; + await auditlog.send(`${newMember.displayName} added ${role.name}`); + }); +} + +async function roleRemProcess( + newMember: GuildMember, + rolesRemoved: string[], +) { + // This is commented out because we need to remove people from threads when they remove the tripsitter/helper roles + // if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; + // log.debug(F, `roles removed: ${rolesRemoved}`); + // Go through each role removed + const auditlog = await discordClient.channels.fetch(env.CHANNEL_AUDITLOG) as TextChannel; + rolesRemoved.forEach(async roleId => { + await removeExTeamFromThreads(newMember, roleId); + // We don't want to run the rest of this on any other guild + if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; + await teamMindsetRemove(newMember, roleId); + await donorColorRemove(newMember, roleId); + + const role = await newMember.guild.roles.fetch(roleId) as Role; + await auditlog.send(`${newMember.displayName} removed ${role.name}`); + }); +} + export const guildMemberUpdate: GuildMemberUpdateEvent = { name: 'guildMemberUpdate', async execute(oldMember, newMember) { - // log.info(F, `${newMember} was updated`); + // log.info(F, `${oldMember} was updated`); + // log.info(F, `${newMember} was created`); const oldRoles = oldMember.roles.cache.map(role => role.id); const newRoles = newMember.roles.cache.map(role => role.id); + // log.debug(F, `oldRoles: ${oldRoles}`); + // log.debug(F, `newRoles: ${newRoles}`); // If the oldRoles don't match the new roles if (oldRoles.toString() !== newRoles.toString()) { // log.debug(F, `roles changed on ${newMember.displayName}!`); - // log.debug(F, `oldRoles: ${oldRoles}`); - // log.debug(F, `newRoles: ${newRoles}`); // Find the difference between the two arrays const rolesAdded = newRoles.filter(x => !oldRoles.includes(x)); - const rolesRemoved = oldRoles.filter(x => !newRoles.includes(x)); if (rolesAdded.length > 0) { - if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; - const auditlog = await discordClient.channels.fetch(env.CHANNEL_AUDITLOG) as TextChannel; - // log.debug(F, `roles added: ${rolesAdded}`); - // Go through each role added, and check if it's a mindset role - rolesAdded.forEach(async roleId => { - // If the role added is a mindset role - // if (env.MINDSET_ROLES.includes(roleId)) { - - // const roleDrunk = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Drunk') as ReactionRoles).role_id, - // ) as Role; - // const roleHigh = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'High') as ReactionRoles).role_id, - // ) as Role; - // const roleRolling = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Rolling') as ReactionRoles).role_id, - // ) as Role; - // const roleTripping = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Tripping') as ReactionRoles).role_id, - // ) as Role; - // const roleDissociating = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Dissociated') as ReactionRoles).role_id, - // ) as Role; - // const roleStimming = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Stimming') as ReactionRoles).role_id, - // ) as Role; - // const roleSedated = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Sedated') as ReactionRoles).role_id, - // ) as Role; - // const roleTalkative = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Talkative') as ReactionRoles).role_id, - // ) as Role; - // const roleWorking = await interaction.guild.roles.fetch( - // (reactionroleData.find(roleData => roleData.name === 'Working') as ReactionRoles).role_id, - // ) as Role; - - // const mindsetRoles = [ - // { name: roleDrunk.name, value: roleDrunk.id }, - // { name: roleHigh.name, value: roleHigh.id }, - // { name: roleRolling.name, value: roleRolling.id }, - // { name: roleTripping.name, value: roleTripping.id }, - // { name: roleDissociating.name, value: roleDissociating.id }, - // { name: roleStimming.name, value: roleStimming.id }, - // { name: roleSedated.name, value: roleSedated.id }, - // { name: roleTalkative.name, value: roleTalkative.id }, - // { name: roleWorking.name, value: roleWorking.id }, - // ] as RoleDef[]; - - // // log.debug(F, `${newMember.displayName} ${action} ${roleName}`); - // const mindsetRole = await newMember.guild.roles.fetch(roleId) as Role; - // const channelMindset = await discordClient.channels.fetch(env.CHANNEL_MINDSET) as TextChannel; - // await channelMindset.send(`Hey @here, ${newMember} is ${mindsetRole.name}!`); - - // log.debug(F, `Mindset roles: ${JSON.stringify(mindsetRoles, null, 2)}`); - // // const mindsetNames = mindsetRoles.map(role => role.name); - // const mindsetIds = mindsetRoles.map(roleData => roleData.value); - - // // Remove the other mindset roles if you're adding a mindset role - // if (mindsetIds.includes(role.id)) { - // // log.debug(F, 'Removing other mindset roles'); - // const otherMindsetRoles = mindsetIds.filter(r => r !== role.id); - // await target.roles.remove([...otherMindsetRoles]); - // } - // } - - // Check if the role added was a donator role - if (roleId === env.ROLE_BOOSTER) { - // log.debug(F, `${newMember.displayName} boosted the server!`); - const channelGoldlounge = await discordClient.channels.fetch(env.CHANNEL_GOLDLOUNGE) as TextChannel; - await channelGoldlounge.send(`Hey @here, ${newMember} just boosted the server, give them a big thank you for helping to keep this place awesome!`); // eslint-disable-line max-len - } - - // Check if the role added was a donator role - if (roleId === env.ROLE_PATRON) { - // log.debug(F, `${newMember.displayName} became a patron!`); - const channelGoldlounge = await discordClient.channels.fetch(env.CHANNEL_GOLDLOUNGE) as TextChannel; - await channelGoldlounge.send(`Hey @here, ${newMember} just became a patron, give them a big thank you for helping us keep the lights on and expand!`); // eslint-disable-line max-len - } - - // Check if this was the verified role - if (roleId === env.ROLE_VERIFIED) { - // log.debug(F, `${newMember.displayName} verified!`); - // let colorValue = 1; - - // log.debug(F, `member: ${member.roles.cache}`); - - // log.debug(`Verified button clicked by ${interaction.user.username}#${interaction.user.discriminator}`); - const channelTripbotLogs = await global.discordClient.channels.fetch(env.CHANNEL_BOTLOG) as TextChannel; - await channelTripbotLogs.send({ - content: `Verified button clicked by ${newMember.user.username}#${newMember.user.discriminator}`, - }); - - // NOTE: Can be simplified with luxon - // const diff = Math.abs(Date.now() - Date.parse(newMember.user.createdAt.toString())); - // const years = Math.floor(diff / (1000 * 60 * 60 * 24 * 365)); - // const months = Math.floor(diff / (1000 * 60 * 60 * 24 * 30)); - // const weeks = Math.floor(diff / (1000 * 60 * 60 * 24 * 7)); - // const days = Math.floor(diff / (1000 * 60 * 60 * 24)); - // const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - // const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); - // const seconds = Math.floor((diff % (1000 * 60)) / 1000); - - // if (years > 0) { - // colorValue = Colors.White; - // } else if (years === 0 && months > 0) { - // colorValue = Colors.Purple; - // } else if (months === 0 && weeks > 0) { - // colorValue = Colors.Blue; - // } else if (weeks === 0 && days > 0) { - // colorValue = Colors.Green; - // } else if (days === 0 && hours > 0) { - // colorValue = Colors.Yellow; - // } else if (hours === 0 && minutes > 0) { - // colorValue = Colors.Orange; - // } else if (minutes === 0 && seconds > 0) { - // colorValue = Colors.Red; - // } - // log.debug(F, `coloValue: ${colorValue}`); - // const channelStart = await newMember.client.channels.fetch(env.CHANNEL_START); - // const channelTechhelp = await newMember.client.channels.fetch(env.CHANNEL_HELPDESK); - // const channelBotspam = await newMember.client.channels.fetch(env.CHANNEL_BOTSPAM); - // const channelRules = await newMember.client.channels.fetch(env.CHANNEL_RULES); - // const channelTripsit = await member.client.channels.fetch(CHANNEL_TRIPSIT); - // const embed = embedTemplate() - // .setAuthor(null) - // .setColor(colorValue) - // .setThumbnail(newMember.user.displayAvatarURL()) - // .setFooter(null) - // .setDescription(stripIndents` - // **Please welcome ${newMember.toString()} to the guild!** - // Be safe, have fun, /report any issues!`); - - const greetingList = [ - `Welcome to the guild, ${newMember}!`, - `I'm proud to announce that ${newMember} has joined our guild!`, - `Please welcome ${newMember} to our guild!`, - `Hello, ${newMember}! Welcome to our guild!`, - `Welcome to the family, ${newMember}! We're so glad you're here.`, - `Welcome to the guild, ${newMember}!`, - `We're excited to have ${newMember} as part of our guild!`, - `Say hello to our newest member, ${newMember}!`, - `Let's give a warm welcome to ${newMember}!`, - `It's great to see you here, ${newMember}!`, - `Welcome aboard, ${newMember}!`, - `We're happy to have ${newMember} join us!`, - `Say hi to ${newMember}, our newest member!`, - `Join us in welcoming ${newMember} to our guild!`, - `A big welcome to ${newMember}!`, - ]; - - const greeting = greetingList[Math.floor(Math.random() * greetingList.length)]; - - const channelLounge = await newMember.client.channels.fetch(env.CHANNEL_LOUNGE) as TextChannel; - await channelLounge.send({ - content: stripIndents`**${greeting}** - - Be safe, have fun, /report any issues! - - *${await topic()}*`, - }); - } - - const role = await newMember.guild.roles.fetch(roleId) as Role; - await auditlog.send(`${newMember.displayName} added ${role.name}`); - }); - } else if (rolesRemoved.length > 0) { - // log.debug(F, `roles removed: ${rolesRemoved}`); - const guildData = await database.guilds.get(newMember.guild.id); - - rolesRemoved.forEach(async roleId => { - const role = await newMember.guild.roles.fetch(roleId) as Role; - - // If the role removed was a helper/tripsitter role, we need to remove them from threads they are in - if (guildData.channel_tripsit - && (roleId === guildData.role_helper - || roleId === guildData.role_tripsitter - ) - ) { - log.debug(F, `${newMember.displayName} was a helper/tripsitter!`); - const channelTripsit = await discordClient.channels.fetch(guildData.channel_tripsit) as TextChannel; - - const fetchedThreads = await channelTripsit.threads.fetch(); - fetchedThreads.threads.forEach(async thread => { - if (thread - && thread.parentId === guildData.channel_tripsit) { - log.debug(F, `Removing ${newMember.displayName} from ${thread.name}`); - await thread.members.remove(newMember.id, 'Helper/Tripsitter role removed'); - } - }); - } - - if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; - const auditlog = await discordClient.channels.fetch(env.CHANNEL_AUDITLOG) as TextChannel; - await auditlog.send(`${newMember.displayName} removed ${role.name}`); - }); + log.debug(F, `${rolesAdded.length} roles added`); + await roleAddProcess(newMember, oldMember, rolesAdded); + } + const rolesRemoved = oldRoles.filter(x => !newRoles.includes(x)); + if (rolesRemoved.length > 0) { + log.debug(F, `${rolesRemoved.length} roles removed`); + await roleRemProcess(newMember, rolesRemoved); } } }, diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 736c61fb9..04b38b736 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -265,10 +265,9 @@ export const env = { ROLE_DISSOCIATING: isProd ? '955485314305101874' : '1052644634460963038', ROLE_STIMMING: isProd ? '955485549035126815' : '1052644635559870525', ROLE_SEDATED: isProd ? '955485615879749682' : '1052644636511965184', - ROLE_SOBER: isProd ? '955486188268056656' : '960606558071435317', ROLE_TALKATIVE: isProd ? '981437055030677554' : '1052644638487486464', - ROLE_WORKING: isProd ? '955486102549049344' : '1052644637380190268', ROLE_VOICECHATTY: isProd ? '1094637167202009128' : '1110453458013798420', + ROLE_BUSY: isProd ? '1111179084165304381' : '1111181986036469790', ROLE_TTS_DRUNK: isProd ? '1104648635691577414' : '1110471812053213245', ROLE_TTS_HIGH: isProd ? '1104648442732613733' : '1110478575695568947', @@ -277,9 +276,9 @@ export const env = { ROLE_TTS_DISSOCIATING: isProd ? '1104648741245435964' : '1110478749469782077', ROLE_TTS_STIMMING: isProd ? '1104648557362954291' : '1110478814024306740', ROLE_TTS_SEDATED: isProd ? '1104648491554308156' : '1110478863378698261', - ROLE_TTS_SOBER: isProd ? '955486188268056656' : '960606558071435317', ROLE_TTS_TALKATIVE: isProd ? '1079954878606086254' : '1110478915388063755', ROLE_TTS_VOICECHATTY: isProd ? '1104648238566473769' : '1110479003476828280', + ROLE_TTS_BUSY: isProd ? '1111180620807274506' : '1111181891970805821', ROLE_TRIVIABIGBRAIN: isProd ? '' : '1052644639464767548', From 0afd1362f1630c61746908e7669696e423f29c52 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Thu, 25 May 2023 18:17:56 +1000 Subject: [PATCH 07/33] Update futon ID Silly bot keeps deleting it --- src/global/utils/env.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 04b38b736..92fecf912 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -169,7 +169,7 @@ export const env = { CHANNEL_GAMINGRADIO: isProd ? '' : '1052634116975231019', CHANNEL_STUDYRADIO: isProd ? '' : '1052634119458275459', CHANNEL_SLEEPYRADIO: isProd ? '' : '1052634122222309386', - CHANNEL_FUTON: isProd ? '1110746349240074240' : '1110747601713766402', + CHANNEL_FUTON: isProd ? '1111206330594762803' : '1110747601713766402', CATEGORY_ARCHIVED: isProd ? '' : '1052634099149443083', CHANNEL_SANDBOX_DEV: isProd ? '' : '960606558373441565', From 89ac40939f1a8393b87414c7f1d694cc08fb1e45 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Thu, 25 May 2023 18:27:58 +1000 Subject: [PATCH 08/33] Change how deleting tents works Changed from checking explicit IDs to not delete to simply checking if a voice channel includes a tent emoji or not --- src/discord/utils/tents.ts | 6 +++--- src/global/utils/env.config.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 3ee2b79c4..1b92a32aa 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -104,10 +104,10 @@ export async function teardownTent( // Get the number of humans in the channel const humans = channel.members.filter(member => !member.user.bot).size; - // If the channel is a voice channel, and it's not the campfire, and there are no humans in it delete it + // If the channel is a voice channel, and it's a tent, and there are no humans in it delete it if (channel.type === ChannelType.GuildVoice - && (channel.id !== env.CHANNEL_CAMPFIRE || channel.id !== env.CHANNEL_FUTON) - && humans < 1) { + && (channel.name.includes('⛺')) + && (humans < 1)) { channel.delete('Removing temporary voice chan!'); // log.debug(F, `deleted an empty temporary voice channel`); } diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 92fecf912..d46f991de 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -117,8 +117,8 @@ export const env = { CHANNEL_DISSOCIATIVES: isProd ? '978051567989178388' : '1052634188823658496', CHANNEL_PSYCHEDELICS: isProd ? '996096935805063188' : '1052634190203596850', - CATEGORY_VOICE: isProd ? '1108008906095067187' : '1108013999259402271', - CHANNEL_CAMPFIRE: isProd ? '1000559873232207902' : '1110747575495176192', + CATEGORY_VOICE: isProd ? '1108008906095067187' : '1111208147282055229', + CHANNEL_CAMPFIRE: isProd ? '1000559873232207902' : '1111208546063896676', CATEGORY_ARCADE: isProd ? '1025976352723185726' : '1052634089238311002', CHANNEL_TRIPTOWN: isProd ? '1071245245934751764' : '1075858181760233543', @@ -169,7 +169,7 @@ export const env = { CHANNEL_GAMINGRADIO: isProd ? '' : '1052634116975231019', CHANNEL_STUDYRADIO: isProd ? '' : '1052634119458275459', CHANNEL_SLEEPYRADIO: isProd ? '' : '1052634122222309386', - CHANNEL_FUTON: isProd ? '1111206330594762803' : '1110747601713766402', + CHANNEL_FUTON: isProd ? '1111206330594762803' : '1111208569942061087', CATEGORY_ARCHIVED: isProd ? '' : '1052634099149443083', CHANNEL_SANDBOX_DEV: isProd ? '' : '960606558373441565', From 6d93cd461e31fd3fb8e46fa5c61cf605173ddf0e Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Thu, 25 May 2023 18:50:13 +1000 Subject: [PATCH 09/33] Add bot typing status to announcements --- src/discord/utils/announcements.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/discord/utils/announcements.ts b/src/discord/utils/announcements.ts index 7cb894ce9..1836e78e9 100644 --- a/src/discord/utils/announcements.ts +++ b/src/discord/utils/announcements.ts @@ -325,7 +325,11 @@ export async function announcements(message:Message) { embed.setDescription(randomGenAnnouncement); } - await sleep(3000); + await sleep(1500); + // display typing status + await message.channel.sendTyping(); + // wait 2 seconds + await new Promise(resolve => setTimeout(resolve, 2500)); await message.channel.send({ embeds: [embed] }); } From 1bcac5d0bb8a90d60ae4acf8eb09830f83fc4d88 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Fri, 26 May 2023 16:26:03 +1000 Subject: [PATCH 10/33] Fix TTS access to donor colours --- src/discord/events/guildMemberUpdate.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 2f7da60a6..779b44878 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -108,11 +108,13 @@ const donorColorRoles = { type DonorNames = | 'ROLE_BOOSTER' -| 'ROLE_PATRON'; +| 'ROLE_PATRON' +| 'ROLE_TEAMTRIPSIT'; const donorRoles = { ROLE_BOOSTER: env.ROLE_BOOSTER, ROLE_PATRON: env.ROLE_PATRON, + ROLE_TEAMTRIPSIT: env.ROLE_TEAMTRIPSIT, } as { [key in DonorNames]: string; }; @@ -128,7 +130,7 @@ async function donorColorCheck( if (Object.values(donorColorRoles).includes(roleId)) { // log.debug(F, `donor color role added: ${roleId}`); // If it does, check if the user also has a donor role - if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON)) { + if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON) || oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { log.debug(F, 'Donor added a color role!'); } else { // If they don't, remove the color role From a4615fca18900d953e5ebc39cbc4707da2f04251 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Fri, 26 May 2023 19:34:02 +1000 Subject: [PATCH 11/33] Make typing status 3 seconds --- src/discord/commands/guild/d.say.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/discord/commands/guild/d.say.ts b/src/discord/commands/guild/d.say.ts index 579a571e2..31d400581 100644 --- a/src/discord/commands/guild/d.say.ts +++ b/src/discord/commands/guild/d.say.ts @@ -35,14 +35,14 @@ export const dSay: SlashCommand = { await channel.sendTyping(); // wait 2 seconds - await new Promise(resolve => setTimeout(resolve, 1500)); + await new Promise(resolve => setTimeout(resolve, 3000)); // send message await channel.send(say); } else { // display typing status await interaction.channel?.sendTyping(); // wait 2 seconds - await new Promise(resolve => setTimeout(resolve, 1500)); + await new Promise(resolve => setTimeout(resolve, 3000)); // send message await interaction.channel?.send(say); } From ab193acb81136f0398540718cc7d255fa7447524 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Mon, 29 May 2023 19:38:33 +1000 Subject: [PATCH 12/33] Small fixes / updates Add 'busy' role to TTS mindsets Make tripbot typing 3 seconds instead of 1.5 Add typing to announcements Change how tent deletion works Update IDs in env --- src/discord/commands/guild/d.say.ts | 9 ++++++++- src/discord/events/guildMemberUpdate.ts | 2 +- src/discord/utils/announcements.ts | 12 ++++-------- src/discord/utils/tents.ts | 23 +++++++++++------------ 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/discord/commands/guild/d.say.ts b/src/discord/commands/guild/d.say.ts index 31d400581..0301d8db7 100644 --- a/src/discord/commands/guild/d.say.ts +++ b/src/discord/commands/guild/d.say.ts @@ -47,7 +47,14 @@ export const dSay: SlashCommand = { await interaction.channel?.send(say); } - await interaction.editReply({ content: `I said '${say}' in ${channel ? channel.toString() : interaction.channel?.toString()}` }); // eslint-disable-line max-len + // Set the type so it's not an API channel + + await channel.sendTyping(); // This method automatically stops typing after 10 seconds, or when a message is sent. + setTimeout(async () => { + await (channel as TextChannel).send(say); + }, 3000); + + await interaction.editReply({ content: `I said '${say}' in ${channel.name}` }); // eslint-disable-line max-len const channelBotlog = await interaction.guild.channels.fetch(env.CHANNEL_BOTLOG) as TextChannel; if (channelBotlog) { diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 779b44878..9857d3c04 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -28,7 +28,7 @@ const mindsetRoles = { ROLE_SEDATED: env.ROLE_SEDATED, ROLE_TALKATIVE: env.ROLE_TALKATIVE, ROLE_VOICECHATTY: env.ROLE_VOICECHATTY, - ROLE_BUSY: env.ROLE_BUSY, + ROLE_BUSY: env.ROLE_BUSY } as { [key in MindsetNames]: string; }; diff --git a/src/discord/utils/announcements.ts b/src/discord/utils/announcements.ts index 1836e78e9..d1cb98162 100644 --- a/src/discord/utils/announcements.ts +++ b/src/discord/utils/announcements.ts @@ -324,14 +324,10 @@ export async function announcements(message:Message) { // log.debug(F, `randomGenAnnouncement: ${randomGenAnnouncement}`); embed.setDescription(randomGenAnnouncement); } - - await sleep(1500); - // display typing status - await message.channel.sendTyping(); - // wait 2 seconds - await new Promise(resolve => setTimeout(resolve, 2500)); - - await message.channel.send({ embeds: [embed] }); + await message.channel.sendTyping(); // This method automatically stops typing after 10 seconds, or when a message is sent. + setTimeout(async () => { + await (message.channel.send({ embeds: [embed] })); + }, 3000); } } } diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 1b92a32aa..515c92e23 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -76,16 +76,15 @@ export async function pitchTent( // **/voice cohost @user** - Allows another user to use these commands // `); await newChannel.fetch(); - await newChannel.send(`Welcome to your tent <@${New.member?.id}>! -Manage your tent: - -**/voice lock** - Locks your tent so no one else can join it -**/voice hide** - Hides your tent from the list of voice channels -**/voice rename** - Changes the name of your tent -**/voice mute @user** - Mutes a user for everyone in your tent -**/voice ban @user** - Bans a user from joining and seeing your tent -**/voice cohost @user** - Allows another user to use these commands -To undo a command, just type it again.`); + await newChannel.send(`## Welcome to your tent, <@${New.member?.id}>! +- **Moderate your tent with commands** + - \`/voice lock\`- Locks your tent so no one else can join it + - \`/voice hide\` - Hides your tent from the list of voice channels + - \`/voice rename\` - Choose a new name for your tent + - \`/voice mute\` - Mutes a user for everyone in your tent + - \`/voice ban\` - Bans a user from joining and seeing your tent + - \`/voice cohost\` - Allows another user to use these commands +***To undo a command, just use it again.***`); // await newChannel.send({ embeds: [embed] }); }); } @@ -106,8 +105,8 @@ export async function teardownTent( // If the channel is a voice channel, and it's a tent, and there are no humans in it delete it if (channel.type === ChannelType.GuildVoice - && (channel.name.includes('⛺')) - && (humans < 1)) { + && channel.name.includes('⛺') + && humans < 1) { channel.delete('Removing temporary voice chan!'); // log.debug(F, `deleted an empty temporary voice channel`); } From 626a0a6661cf9116cb88eb024cb3c03cc5c6f60e Mon Sep 17 00:00:00 2001 From: Moonbear <1836049+LunaUrsa@users.noreply.github.com> Date: Mon, 29 May 2023 10:33:37 -0500 Subject: [PATCH 13/33] Merge and lint --- .eslintignore | 5 +- src/discord/commands/global/d.bridge.ts | 7 +- src/discord/commands/guild/d.selftimeout.ts | 8 +- src/discord/events/guildMemberUpdate.ts | 11 +- src/discord/events/legacy/roleUpdate.ts | 12 +- src/discord/events/messageDelete.ts | 27 +- src/discord/events/messageUpdate.ts | 4 +- src/discord/events/roleAudit.ts | 190 ------------- src/discord/utils/announcements.ts | 10 +- src/discord/utils/awayMessage.ts | 10 +- src/discord/utils/messageCommand.ts | 11 +- src/global/@types/global.d.ts | 4 +- src/global/commands/g.learn.ts | 5 +- src/global/commands/g.reagents.ts | 1 + src/global/utils/env.validate.ts | 13 +- src/global/utils/keycloak.ts | 6 +- src/global/utils/knex.ts | 10 +- src/global/utils/timer.ts | 288 ++++++++++---------- 18 files changed, 226 insertions(+), 396 deletions(-) delete mode 100644 src/discord/events/roleAudit.ts diff --git a/.eslintignore b/.eslintignore index a34ce30ba..9e59af033 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,5 @@ **/database.d.ts -**/archive \ No newline at end of file +**/archive +**/src/matrix/** +**/src/telegram/** +**/src/irc/** \ No newline at end of file diff --git a/src/discord/commands/global/d.bridge.ts b/src/discord/commands/global/d.bridge.ts index 93717d4e7..bb4196bd5 100644 --- a/src/discord/commands/global/d.bridge.ts +++ b/src/discord/commands/global/d.bridge.ts @@ -95,7 +95,7 @@ ${externalChannel.guild.name}'s ${externalChannel}! return bridgeInitialized; } - externalChannel.send({ + await externalChannel.send({ embeds: [ embedTemplate() .setTitle('Bridge') @@ -160,11 +160,12 @@ async function confirm( const internalChannel = await interaction.client.channels.fetch(bridgedChannel) as TextChannel; - internalChannel.send({ + await internalChannel.send({ embeds: [ embedTemplate() .setTitle('Bridge') - .setDescription(stripIndents`${(interaction.member as GuildMember).displayName} has confirmed the bridge between \ + .setDescription(stripIndents` + ${(interaction.member as GuildMember).displayName} has confirmed the bridge between \ ${internalChannel.guild.name}'s ${internalChannel} and ${externalChannel.guild.name}'s ${externalChannel}! Either side can */bridge pause* and */bridge resume* to temporarily pause/resume the bridge, \ or */bridge delete* to remove the bridge. diff --git a/src/discord/commands/guild/d.selftimeout.ts b/src/discord/commands/guild/d.selftimeout.ts index 0266d2ced..c00bc316d 100644 --- a/src/discord/commands/guild/d.selftimeout.ts +++ b/src/discord/commands/guild/d.selftimeout.ts @@ -33,7 +33,9 @@ export const selfTimeout: SlashCommand = { const confirmation = interaction.options.getString('confirmation'); if (confirmation === 'no') { - await interaction.editReply({ content: 'This works exactly like you think it does, try again when you\'re sure!' }); + await interaction.editReply({ + content: 'This works exactly like you think it does, try again when you\'re sure!', + }); return false; } @@ -42,13 +44,13 @@ export const selfTimeout: SlashCommand = { const durationValue = await parseDuration(`${duration}`); - target.timeout(durationValue, 'Self timeout'); + await target.timeout(durationValue, 'Self timeout'); await interaction.editReply({ content: `We'll see you in ${duration}!` }); const tripsitGuild = await interaction.client.guilds.fetch(env.DISCORD_GUILD_ID); const modLog = await tripsitGuild.channels.fetch(env.CHANNEL_MODLOG) as TextChannel; - modLog.send(`**${target.user.tag}** self timed out for **${duration}**!`); + await modLog.send(`**${target.user.tag}** self timed out for **${duration}**!`); return true; }, diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 779b44878..d12933f14 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -130,7 +130,9 @@ async function donorColorCheck( if (Object.values(donorColorRoles).includes(roleId)) { // log.debug(F, `donor color role added: ${roleId}`); // If it does, check if the user also has a donor role - if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON) || oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { + if (oldMember.roles.cache.has(env.ROLE_BOOSTER) + || oldMember.roles.cache.has(env.ROLE_PATRON) + || oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { log.debug(F, 'Donor added a color role!'); } else { // If they don't, remove the color role @@ -191,7 +193,7 @@ async function teamMindsetCheck( // Get the role from the guild const role = await newMember.guild.roles.fetch(ttsMindsetRoleId) as Role; // Add the role to the user - newMember.roles.add(role); + await newMember.roles.add(role); } } } @@ -223,7 +225,7 @@ async function teamMindsetRemove( // Get the role from the guild const role = await newMember.guild.roles.fetch(ttsMindsetRoleId) as Role; // Add the role to the user - newMember.roles.remove(role); + await newMember.roles.remove(role); } } } @@ -244,8 +246,7 @@ async function removeExTeamFromThreads( const fetchedThreads = await channelTripsit.threads.fetch(); fetchedThreads.threads.forEach(async thread => { - if (thread - && thread.parentId === guildData.channel_tripsit) { + if (thread && thread.parentId === guildData.channel_tripsit) { log.debug(F, `Removing ${newMember.displayName} from ${thread.name}`); await thread.members.remove(newMember.id, 'Helper/Tripsitter role removed'); } diff --git a/src/discord/events/legacy/roleUpdate.ts b/src/discord/events/legacy/roleUpdate.ts index e3f0f7b15..b5357cdfe 100644 --- a/src/discord/events/legacy/roleUpdate.ts +++ b/src/discord/events/legacy/roleUpdate.ts @@ -12,8 +12,6 @@ import { // https://discordjs.guide/popular-topics/audit-logs.html#who-deleted-a-message -export default roleUpdate; - export const roleUpdate: RoleUpdateEvent = { name: 'roleUpdate', async execute(/** oldRole, newRole* */) { @@ -30,7 +28,9 @@ export const roleUpdate: RoleUpdateEvent = { // if (!perms.hasPermission) { // const guildOwner = await sticker.guild.fetchOwner(); - // await guildOwner.send({ content: `Please make sure I can ${perms.permission} in ${sticker.guild} so I can run ${F}!` }); // eslint-disable-line + // await guildOwner.send({ + // content: `Please make sure I can ${perms.permission} in ${sticker.guild} so I can run ${F}!`, + // }); // log.error(F, `Missing permission ${perms.permission} in ${sticker.guild}!`); // return; // } @@ -50,7 +50,9 @@ export const roleUpdate: RoleUpdateEvent = { // ]); // if (!channelPerms.hasPermission) { // const guildOwner = await channel.guild.fetchOwner(); - // await guildOwner.send({ content: `Please make sure I can ${channelPerms.permission} in ${channel} so I can run ${F}!` }); // eslint-disable-line + // await guildOwner.send({ + // content: `Please make sure I can ${channelPerms.permission} in ${channel} so I can run ${F}!`, + // }); // log.error(F, `Missing permission ${channelPerms.permission} in ${channel}!`); // return; // } @@ -74,3 +76,5 @@ export const roleUpdate: RoleUpdateEvent = { // await channel.send(response); }, }; + +export default roleUpdate; diff --git a/src/discord/events/messageDelete.ts b/src/discord/events/messageDelete.ts index 7ed08a864..3b0ba376f 100644 --- a/src/discord/events/messageDelete.ts +++ b/src/discord/events/messageDelete.ts @@ -7,7 +7,7 @@ import { } from 'discord.js'; import { // ChannelType, - AuditLogEvent, + AuditLogEvent, ChannelType, } from 'discord-api-types/v10'; import { MessageDeleteEvent, @@ -25,8 +25,9 @@ export const messageDelete: MessageDeleteEvent = { // Only run on Tripsit, we don't want to snoop on other guilds ( ͡~ ͜ʖ ͡°) if (!message.guild) return; if (message.guild.id !== env.DISCORD_GUILD_ID) return; + if (message.channel.type !== ChannelType.GuildText) return; const startTime = Date.now(); - log.info(F, `Message in ${message.channel} was deleted.`); + log.info(F, `Message in ${message.channel.name} was deleted.`); // log.debug(F, `message: ${JSON.stringify(message, null, 2)}`); // Get the channel this will be posted in @@ -37,8 +38,8 @@ export const messageDelete: MessageDeleteEvent = { ]); if (!channelPerms.hasPermission) { const guildOwner = await msglogChannel.guild.fetchOwner(); - await guildOwner.send({ content: `Please make sure I can ${channelPerms.permission} in ${msglogChannel} so I can run ${F}!` }); // eslint-disable-line - log.error(F, `Missing permission ${channelPerms.permission} in ${msglogChannel}!`); + await guildOwner.send({ content: `Please make sure I can ${channelPerms.permission} in ${msglogChannel.name} so I can run ${F}!` }); // eslint-disable-line + log.error(F, `Missing permission ${channelPerms.permission} in ${msglogChannel.name}!`); return; } @@ -67,13 +68,15 @@ export const messageDelete: MessageDeleteEvent = { let { author } = message; // log.debug(F, `Author: ${JSON.stringify(author, null, 2)}`); // log.debug(F, `Target: ${JSON.stringify(deletionLog?.target, null, 2)}`); - if (deletionLog && author && deletionLog.target.id === author.id && deletionLog.createdTimestamp > (startTime - 1)) { + if (deletionLog + && author + && deletionLog.target.id === author.id + && deletionLog.createdTimestamp > (startTime - 1)) { // log.debug(F, `Found relevant audit log: ${JSON.stringify(deletionLog, null, 2)}`); if (deletionLog.executor) { executorUser = deletionLog.executor; if (message.content) { content = message.content; - author = message.author; } } } else { @@ -82,7 +85,7 @@ export const messageDelete: MessageDeleteEvent = { executorUser = message.author; content = message.content; } else { - const messageRecord = (message.channel as TextChannel).messages.cache.find(m => m.id === message.id); + const messageRecord = message.channel.messages.cache.find(m => m.id === message.id); if (messageRecord) { executorUser = messageRecord.author; content = messageRecord.content; @@ -91,8 +94,6 @@ export const messageDelete: MessageDeleteEvent = { // log.debug(F, 'Message not found in cache'); } } - // await msglogChannel.send(`A message by ${message.author.tag} was deleted, but no relevant audit logs were found.`); - // return; } // log.debug(F, `Executor: ${JSON.stringify(executorUser, null, 2)}, Content: ${content}`); @@ -104,14 +105,8 @@ export const messageDelete: MessageDeleteEvent = { // log.debug(F, `Author Name: ${authorName}`); // const channelName = message.channel ? (message.channel as TextChannel).name : 'Unknown'; - // // const channel = await discordClient.channels.fetch((deletionLog?.extra as { channel: string, count: number }).channel) as TextChannel; - // const messageRecord = (message.channel as TextChannel).messages.cache.find(m => m.id === message.id); - // if (messageRecord) { - // authorName = message.author.username; - // content = message.content; - // } const embed = embedTemplate() - .setDescription(`**${executorMember ?? 'Someone'} deleted message in ${message.channel}**`) + .setDescription(`**${executorMember ?? 'Someone'} deleted message in ${message.channel.name}**`) .setAuthor(null) .setFooter(null) .setColor(Colors.Red); diff --git a/src/discord/events/messageUpdate.ts b/src/discord/events/messageUpdate.ts index a218592d0..216a42659 100644 --- a/src/discord/events/messageUpdate.ts +++ b/src/discord/events/messageUpdate.ts @@ -2,6 +2,7 @@ import { Colors, TextChannel, } from 'discord.js'; +import { stripIndents } from 'common-tags'; import { MessageUpdateEvent, } from '../@types/eventDef'; @@ -39,7 +40,8 @@ export const messageUpdate: MessageUpdateEvent = { .setAuthor(null) .setFooter(null) .setColor(Colors.Yellow) - .setDescription(`**${newMessage.member} edited [message](${newMessage.url}) in ${(newMessage.channel as TextChannel)}**`); + .setDescription(stripIndents`**${newMessage.member} edited [message](${newMessage.url}) in\ + ${(newMessage.channel as TextChannel)}**`); try { embed.setURL(newMessage.url); embed.addFields([ diff --git a/src/discord/events/roleAudit.ts b/src/discord/events/roleAudit.ts deleted file mode 100644 index 62874b53e..000000000 --- a/src/discord/events/roleAudit.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { - // Colors, - Role, - TextChannel, - // Message, -} from 'discord.js'; -import { stripIndents } from 'common-tags'; -import { - GuildMemberUpdateEvent, -} from '../@types/eventDef'; -// import embedTemplate from '../utils/embedTemplate'; -// import { -// ReactionRoleList, -// } from '../../global/@types/database'; - -const mindsetRoles = [ - env.ROLE_DRUNK, - env.ROLE_HIGH, - env.ROLE_ROLLING, - env.ROLE_TRIPPING, - env.ROLE_DISSOCIATING, - env.ROLE_STIMMING, - env.ROLE_SEDATED, - env.ROLE_TALKATIVE, - env.ROLE_VOICECHATTY, -]; - -const TTSmindsetRoles = [ - env.ROLE_TTS_DRUNK, - env.ROLE_TTS_HIGH, - env.ROLE_TTS_ROLLING, - env.ROLE_TTS_TRIPPING, - env.ROLE_TTS_DISSOCIATING, - env.ROLE_TTS_STIMMING, - env.ROLE_TTS_SEDATED, - env.ROLE_TTS_TALKATIVE, - env.ROLE_TTS_VOICECHATTY, -]; - -const colorRoles = [ - env.ROLE_RED, - env.ROLE_ORANGE, - env.ROLE_YELLOW, - env.ROLE_GREEN, - env.ROLE_BLUE, - env.ROLE_PURPLE, - env.ROLE_PINK, - env.ROLE_WHITE, -]; - -const donorColorRoles = [ - env.ROLE_DONOR_RED, - env.ROLE_DONOR_ORANGE, - env.ROLE_DONOR_YELLOW, - env.ROLE_DONOR_GREEN, - env.ROLE_DONOR_BLUE, - env.ROLE_DONOR_PURPLE, - env.ROLE_DONOR_BLACK, - env.ROLE_DONOR_PINK, -]; - -const donorRoles = [ - env.ROLE_BOOSTER, - env.ROLE_PATRON, - env.ROLE_TEAMTRIPSIT, -]; - -const F = f(__filename); - -export const guildMemberUpdate: GuildMemberUpdateEvent = { - name: 'guildMemberUpdate', - async execute(oldMember, newMember) { - // log.info(F, `${newMember} was updated`); - const oldRoles = oldMember.roles.cache.map(role => role.id); - const newRoles = newMember.roles.cache.map(role => role.id); - - // If the oldRoles don't match the new roles - if (oldRoles.toString() !== newRoles.toString()) { - // log.debug(F, `roles changed on ${newMember.displayName}!`); - // log.debug(F, `oldRoles: ${oldRoles}`); - // log.debug(F, `newRoles: ${newRoles}`); - - // Find the difference between the two arrays - const rolesAdded = newRoles.filter(x => !oldRoles.includes(x)); - const rolesRemoved = oldRoles.filter(x => !newRoles.includes(x)); - if (rolesAdded.length > 0) { - if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; - // log.debug(F, `roles added: ${rolesAdded}`); - - // Go through each role added - rolesAdded.forEach(async roleId => { - - // Check if the id matches a colorRole - if (donorColorRoles.includes(roleId)) { - // log.debug(F, `donor color role added: ${roleId}`); - // If it does, check if the user also has a donor role - if (oldMember.roles.cache.has(env.ROLE_BOOSTER) || oldMember.roles.cache.has(env.ROLE_PATRON) || oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { - log.debug(F, `Donor added a color role!`); - } - else { - // If they don't, remove the color role - log.debug(F, `User added a color role without being a donor!`); - const role = newMember.guild.roles.cache.get(roleId); - if (role) { - await newMember.roles.remove(role); - } - } - } - // Check if the id matches a mindsetRole - if (mindsetRoles.includes(roleId)) { - // log.debug(F, `mindset role added: ${roleId}`); - // If it does, check if the user also has team tripsit role - if (newMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { - // If so, replace the mindset role with the TTS equivalent - log.debug(F, `User added a mindset role while being a TTS!`); - - // Find .env name of role using the mindsetRole table - // Iterate through the mindsetRoles array - for (const mindsetRole of mindsetRoles) { - // Check if the current mindsetRole matches the target ID - const userMindsetEnv = Object.keys(env).find((key) => env[key] === mindsetRole); - if (mindsetRole === roleId) { - // The target ID matches the current mindsetRole object - log.debug(F, `User Mindset role: ${userMindsetEnv}`) - // Change "ROLE_" to "ROLE_TTS" in the .env name - let ttsMindsetEnv = userMindsetEnv!.replace("ROLE_", "ROLE_TTS_"); - log.debug(F, `TTS mindset role: ${ttsMindsetEnv}`) - // Find the role in the guild - const ttsMindsetRole = oldMember.guild.roles.cache.get(env[ttsMindsetEnv]); - log.debug(F, `TTS mindset role load: ${ttsMindsetRole}`) - // If the role exists, add it to the user - if (ttsMindsetRole) { - await newMember.roles.add(ttsMindsetRole); - break; // Exit the loop since we found the desired object - } - } - } - } - } - }); - } - if (rolesRemoved.length > 0) { - if (newMember.guild.id !== env.DISCORD_GUILD_ID) return; - // log.debug(F, `roles removed: ${rolesRemoved}`); - // Go through each role removed - rolesRemoved.forEach(async roleId => { - // Check if it's a mindsetRole - if (mindsetRoles.includes(roleId) && newMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { - // Remove all TTS mindsets - // Check if the member has any of the TTSmindsetRoles - for (const mindsetRole of mindsetRoles) { - // Check if the current mindsetRole matches the target ID - const userMindsetEnv = Object.keys(env).find((key) => env[key] === mindsetRole); - if (mindsetRole === roleId) { - // The target ID matches the current mindsetRole object - log.debug(F, `User Mindset role: ${userMindsetEnv}`) - // Change "ROLE_" to "ROLE_TTS" in the .env name - let ttsMindsetEnv = userMindsetEnv!.replace("ROLE_", "ROLE_TTS_"); - log.debug(F, `TTS mindset role: ${ttsMindsetEnv}`) - // Find the role in the guild - const ttsMindsetRole = oldMember.guild.roles.cache.get(env[ttsMindsetEnv]); - log.debug(F, `TTS mindset role load: ${ttsMindsetRole}`) - // If the role exists, add it to the user - if (ttsMindsetRole) { - await newMember.roles.remove(ttsMindsetRole); - break; // Exit the loop since we found the desired object - } - } - } - } - - // Check if it's a donor role - if (donorRoles.includes(roleId)) { - // log.debug(F, `donor role removed: ${roleId}`); - // If it does, check if the user also has a role id matching a donorColorRole and if so, remove it - const donorColorRole = donorColorRoles.find(role => newRoles.includes(role)); - if (donorColorRole) { - log.debug(F, `Color role removed from ex-donor!`); - const role = newMember.guild.roles.cache.get(donorColorRole); - if (role) { - await newMember.roles.remove(role); - } - } - } - }); - } - - } - }, -}; diff --git a/src/discord/utils/announcements.ts b/src/discord/utils/announcements.ts index d1cb98162..4f54040ca 100644 --- a/src/discord/utils/announcements.ts +++ b/src/discord/utils/announcements.ts @@ -21,11 +21,11 @@ let bigFrequencyCounter = 0; * @param {number} ms * @return {Promise} */ -function sleep(ms:number):Promise { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} +// function sleep(ms:number):Promise { +// return new Promise(resolve => { +// setTimeout(resolve, ms); +// }); +// } const waterAndTeaEmojis = [ // '🏊', '🏊🏻', '🏊🏼', '🏊🏽', '🏊🏾', '🏊🏿', diff --git a/src/discord/utils/awayMessage.ts b/src/discord/utils/awayMessage.ts index b0ce57cd2..d3fafcca2 100644 --- a/src/discord/utils/awayMessage.ts +++ b/src/discord/utils/awayMessage.ts @@ -1,6 +1,7 @@ /* eslint-disable no-unused-vars */ import { Message, TextChannel } from 'discord.js'; +import { stripIndents } from 'common-tags'; import { getUser } from '../../global/utils/knex'; import { sleep } from '../commands/guild/d.bottest'; @@ -26,13 +27,10 @@ export async function awayMessage(message:Message): Promise { await message.channel.sendTyping(); await sleep(1000); - message.channel.send( - `Hey ${message.member?.displayName}, Moonbear is probably sleeping, but they will get back to you when they can!`, + await message.channel.send( + stripIndents`Hey ${message.member?.displayName}, Moonbear is probably sleeping, \ + but they will get back to you when they can!`, ); } } - - // if (chicagoHour >= 16 || chicagoHour <= 20) { - // message.channel.send(`Hey ${message.member?.displayName} Moonbear is probably busy. Maybe send them a DM and they will get back to you when they can!`); - // } } diff --git a/src/discord/utils/messageCommand.ts b/src/discord/utils/messageCommand.ts index 24ab91c4b..acc4fc07e 100644 --- a/src/discord/utils/messageCommand.ts +++ b/src/discord/utils/messageCommand.ts @@ -57,13 +57,6 @@ export async function messageCommand(message: Message): Promise { if (!message.guild) return; // If not in a guild then ignore all messages // if (message.guild.id !== env.DISCORD_GUILD_ID) return; // If not in tripsit ignore all messages const displayName = message.member ? message.member.displayName : message.author.username; - - // log.debug(F, `Message : ${JSON.stringify(message, null, 2)}`); - // log.debug(F, `sadStuff.some(word => (message.cleanContent.includes(word): ${sadStuff.some(word => message.cleanContent.includes(word))}`); // eslint-disable-line - // log.debug(F, `!(message.cleanContent.substring(message.cleanContent.indexOf(':') + 1).includes(':')): ${!(message.cleanContent.substring(message.cleanContent.indexOf(':') + 1).includes(':'))}`); // eslint-disable-line - // log.debug(F, `message.channel.type !== ChannelType.DM: ${message.channel.type !== ChannelType.DM}`); // eslint-disable-line - // log.debug(F, `message.guild.id !== env.DISCORD_GUILD_ID: ${message.guild.id} !== ${env.DISCORD_SERVER_ID}`); // eslint-disable-line - // log.debug(F, `message.reference: ${JSON.stringify(message.content, null, 2)}`); // log.debug(stripIndents`[${PREFIX}] ${displayName} said\ @@ -73,7 +66,7 @@ export async function messageCommand(message: Message): Promise { // If you try to use the old tripbot command prefix while inside of the tripsit guild if (message.guild.id !== env.DISCORD_GUILD_ID) return; - // This doesnt work cuz webchat users are bots + // This doesn't work cuz webchat users are bots // if (message.author.bot) return; // Find the word that appears after ~ @@ -180,7 +173,7 @@ ${roleHelper}. Can you start off by telling us how much you took and the details } await message.channel.send(stripIndents`Hey ${displayName}, uploading emojis...`); // eslint-disable-line - log.debug(F, `message.stickers: ${message.stickers}`); + log.debug(F, `message.stickers: ${JSON.stringify(message.stickers, null, 2)}`); // Upload all the stickers in the message to the guild const stickers = message.content.match(//g); log.debug(F, `stickers: ${stickers}`); diff --git a/src/global/@types/global.d.ts b/src/global/@types/global.d.ts index e0e9c40a5..6bf3a78f7 100644 --- a/src/global/@types/global.d.ts +++ b/src/global/@types/global.d.ts @@ -1,6 +1,6 @@ import { Client as DiscordClient } from 'discord.js'; -import { MatrixClient } from 'matrix-bot-sdk'; -import { Client as IRCClient } from 'matrix-org-irc'; +// import { MatrixClient } from 'matrix-bot-sdk'; +// import { Client as IRCClient } from 'matrix-org-irc'; import { Telegraf as TelegramClient } from 'telegraf'; import Sentry from '@sentry/node'; diff --git a/src/global/commands/g.learn.ts b/src/global/commands/g.learn.ts index 046c86b61..3d2f16600 100644 --- a/src/global/commands/g.learn.ts +++ b/src/global/commands/g.learn.ts @@ -287,7 +287,8 @@ export async function link( discordId?:string, matrixId?:string, ):Promise { - // log.debug(F, `Link started with moodleUsername: ${moodleUsername}, discordId: ${discordId}, matrixId: ${matrixId}`); + // log.debug(F, `Link started with moodleUsername: ${moodleUsername}, \ + // discordId: ${discordId}, matrixId: ${matrixId}`); const userData = discordId ? await database.users.get(discordId, null, null) : await database.users.get(null, matrixId as string, null); @@ -295,7 +296,7 @@ export async function link( const moodleUserData = email ? await getMoodleUser(undefined, email).catch(() => ({} as MoodleUser)) - : await getMoodleUser(moodleUsername, undefined).catch(() => ({} as MoodleUser)); + : await getMoodleUser(moodleUsername).catch(() => ({} as MoodleUser)); // log.debug(F, `moodleUserData: ${JSON.stringify(moodleUserData)}`); diff --git a/src/global/commands/g.reagents.ts b/src/global/commands/g.reagents.ts index 576920d87..2062cf8d1 100644 --- a/src/global/commands/g.reagents.ts +++ b/src/global/commands/g.reagents.ts @@ -8,6 +8,7 @@ export default reagents; */ export async function reagents():Promise { // const response = 'https://i.imgur.com/wETJsZr.png'; + // eslint-disable-next-line max-len const response = 'https://user-images.githubusercontent.com/1836049/222908130-df3a881b-3ced-462f-a0db-6c2a34cd62ec.png'; log.info(F, `response: ${JSON.stringify(response, null, 2)}`); return response; diff --git a/src/global/utils/env.validate.ts b/src/global/utils/env.validate.ts index eec950230..a5c8f0e0c 100644 --- a/src/global/utils/env.validate.ts +++ b/src/global/utils/env.validate.ts @@ -1,3 +1,5 @@ +import { stripIndents } from 'common-tags'; + export default function validateEnv( service: 'DISCORD' | 'MATRIX' | 'IRC' | 'TELEGRAM' | 'SERVICES', ) { @@ -6,7 +8,8 @@ export default function validateEnv( if (service === 'DISCORD') { if (!process.env.DISCORD_CLIENT_ID) { - log.error(F, 'Missing DISCORD_CLIENT_ID: You wont be able to login to discord. You get this from the discord developer portal.'); + log.error(F, stripIndents`Missing DISCORD_CLIENT_ID: You wont be able to login to discord. \ + You get this from the discord developer portal.`); return false; } @@ -16,7 +19,8 @@ export default function validateEnv( } if (!process.env.DISCORD_CLIENT_TOKEN) { - log.error(F, 'Missing DISCORD_CLIENT_TOKEN: You wont be able to login to discord. You get this from the discord developer portal.'); + log.error(F, stripIndents`Missing DISCORD_CLIENT_TOKEN: You wont be able to login to discord.\ + You get this from the discord developer portal.`); return false; } @@ -40,7 +44,10 @@ export default function validateEnv( log.warn(F, 'Missing POSTGRES_DB_URL: You wont be able to use the database!'); } - if (!process.env.KEYCLOAK_BASE_URL || !process.env.KEYCLOAK_REALM_NAME || !process.env.KEYCLOAK_CLIENT_ID || !process.env.KEYCLOAK_CLIENT_SECRET) { + if (!process.env.KEYCLOAK_BASE_URL + || !process.env.KEYCLOAK_REALM_NAME + || !process.env.KEYCLOAK_CLIENT_ID + || !process.env.KEYCLOAK_CLIENT_SECRET) { log.warn(F, 'Missing keycloak credentials: You won\'t be able to interact with KeyCloak.'); } diff --git a/src/global/utils/keycloak.ts b/src/global/utils/keycloak.ts index e3c7c87cf..d70ecb67d 100644 --- a/src/global/utils/keycloak.ts +++ b/src/global/utils/keycloak.ts @@ -117,7 +117,11 @@ export async function getRoleMembers(roleName:string):Promise { * * @returns {Boolean} */ -export async function setUserAttribute(identifier:string, attributeName:string, attributeValue:string):Promise { +export async function setUserAttribute( + identifier:string, + attributeName:string, + attributeValue:string, +):Promise { await ensureAuthentication(); try { await kcAdminClient.users.update( diff --git a/src/global/utils/knex.ts b/src/global/utils/knex.ts index 170b8142f..5c7cbb867 100644 --- a/src/global/utils/knex.ts +++ b/src/global/utils/knex.ts @@ -125,7 +125,11 @@ export async function getMoodleUsers():Promise { return data; } -export async function userExists(discordId:string | null, matrixId:string | null, userId:string | null):Promise { +export async function userExists( + discordId:string | null, + matrixId:string | null, + userId:string | null, +):Promise { return (await getUser(discordId, matrixId, userId) !== undefined); } @@ -529,7 +533,7 @@ export async function experienceGet( // log.debug(F, // `experienceGet started with: limit: ${limit}, category: ${category}, type: ${type}, userId: ${userId}`); - const limit = limitInput || 1000000; + const limit = limitInput ?? 1000000; if (env.POSTGRES_DB_URL === undefined) return []; if (category) { if (type) { @@ -655,7 +659,7 @@ export async function experienceGetTop( ):Promise { // log.debug(F, 'experienceGetTop started'); if (env.POSTGRES_DB_URL === undefined) return [] as LeaderboardList; - const limit = limitInput || 1000000; + const limit = limitInput ?? 1000000; if (category) { if (type) { // NOSONAR try { diff --git a/src/global/utils/timer.ts b/src/global/utils/timer.ts index 70a611aea..fee4e868b 100644 --- a/src/global/utils/timer.ts +++ b/src/global/utils/timer.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-len */ import { ActivityType, CategoryChannel, @@ -82,7 +83,7 @@ async function checkReminders() { // eslint-disable-line @typescript-eslint/no-u const userData = await getUser(null, null, reminder.user_id); // Send the user a message - if (userData && userData.discord_id) { + if (userData?.discord_id) { const user = await global.discordClient.users.fetch(userData.discord_id); if (user) { await user.send(`Hey ${user.username}, you asked me to remind you: ${reminder.reminder_text}`); @@ -175,7 +176,8 @@ async function checkTickets() { // eslint-disable-line @typescript-eslint/no-unu try { await member.roles.add(roleObj); } catch (err) { - log.error(F, `Failed to add ${member.displayName}'s ${roleObj.name} role in ${member.guild.name}: ${err}`); + log.error(F, stripIndents`Failed to add ${member.displayName}'s ${roleObj.name}\ + role in ${member.guild.name}: ${err}`); } } }); @@ -260,7 +262,8 @@ async function checkTickets() { // eslint-disable-line @typescript-eslint/no-unu log.debug(F, `Sending reminder to ${(await guild.fetchOwner()).user.username}...`); // const guildOwner = await channel.guild.fetchOwner(); // await guildOwner.send({ - // content: `I am trying to prune threads in ${channel} but I don't have the ${tripsitPerms.permission} permission.`, // eslint-disable-line max-len + // content: `I am trying to prune threads in ${channel} but + // I don't have the ${tripsitPerms.permission} permission.`, // eslint-disable-line max-len // }); const botOwner = await discordClient.users.fetch(env.DISCORD_OWNER_ID); await botOwner.send({ @@ -747,145 +750,145 @@ async function checkStats() { // } } -async function checkLpm() { // eslint-disable-line - const channels = [ - env.CHANNEL_LOUNGE, - // env.CATEGORY_HARMREDUCTIONCENTRE, - env.CHANNEL_TRIPSITMETA, - env.CHANNEL_TRIPSIT, - env.CHANNEL_OPENTRIPSIT1, - env.CHANNEL_OPENTRIPSIT2, - env.CHANNEL_WEBTRIPSIT1, - env.CHANNEL_WEBTRIPSIT2, - env.CHANNEL_CLOSEDTRIPSIT, - env.CHANNEL_RTRIPSIT, - // env.CATEGORY_BACKSTAGE, - env.CHANNEL_PETS, - env.CHANNEL_FOOD, - env.CHANNEL_OCCULT, - env.CHANNEL_MUSIC, - env.CHANNEL_MEMES, - env.CHANNEL_MOVIES, - env.CHANNEL_GAMING, - env.CHANNEL_SCIENCE, - env.CHANNEL_CREATIVE, - env.CHANNEL_COMPSCI, - env.CHANNEL_REPLICATIONS, - env.CHANNEL_PHOTOGRAPHY, - // env.CHANNEL_RECOVERY, - // env.CATEGORY_CAMPGROUND, - env.CHANNEL_VIPLOUNGE, - env.CHANNEL_GOLDLOUNGE, - env.CHANNEL_SANCTUARY, - env.CHANNEL_TREES, - env.CHANNEL_OPIATES, - env.CHANNEL_STIMULANTS, - env.CHANNEL_DEPRESSANTS, - env.CHANNEL_DISSOCIATIVES, - env.CHANNEL_PSYCHEDELICS, - ]; - - const startTime = Date.now(); - // log.debug(F, 'Checking LPM...'); - - if (!global.lpmDict) { - global.lpmDict = {}; - } - - const guild = await discordClient.guilds.fetch(env.DISCORD_GUILD_ID); - await guild.channels.fetch(); - - async function getLpm(channelId:string, index:number) { - // const channel = await guild.channels.fetch(channelId) as TextChannel; - const channel = guild.channels.cache.get(channelId) as TextChannel; - const messages = await channel.messages.fetch({ limit: 100 }); // eslint-disable-line no-await-in-loop - - // Filter bots out of messages - const filteredMessages = messages.filter(message => !message.author.bot); - - const lines1 = filteredMessages.reduce((acc, cur) => { - if (Date.now() - cur.createdTimestamp > 1000 * 60) return acc; - return acc + cur.content.split('\n').length; - }, 0); - - const lines5 = filteredMessages.reduce((acc, cur) => { - if (Date.now() - cur.createdTimestamp > 1000 * 60 * 5) return acc; - return acc + cur.content.split('\n').length; - }, 0); - - const lines10 = filteredMessages.reduce((acc, cur) => { - if (Date.now() - cur.createdTimestamp > 1000 * 60 * 10) return acc; - return acc + cur.content.split('\n').length; - }, 0); - - const lines30 = filteredMessages.reduce((acc, cur) => { - if (Date.now() - cur.createdTimestamp > 1000 * 60 * 30) return acc; - return acc + cur.content.split('\n').length; - }, 0); - - const lines60 = filteredMessages.reduce((acc, cur) => { - if (Date.now() - cur.createdTimestamp > 1000 * 60 * 60) return acc; - return acc + cur.content.split('\n').length; - }, 0); - - if (lines5) { - if (global.lpmDict[channelId]) { - // log.debug(F, `lpmDict: ${JSON.stringify(global.lpmDict[channelId])}`); - if (global.lpmDict[channelId].lp1 === lines1 && global.lpmDict[channelId].lp60 === lines60) { - return; - } - if (global.lpmDict[channelId].lp1Max < lines1) { - global.lpmDict[channelId].lp1Max = lines1; - } - if (global.lpmDict[channelId].lp5Max < lines5) { - global.lpmDict[channelId].lp5Max = lines5; - } - if (global.lpmDict[channelId].lp10Max < lines10) { - global.lpmDict[channelId].lp10Max = lines10; - } - if (global.lpmDict[channelId].lp30Max < lines30) { - global.lpmDict[channelId].lp30Max = lines30; - } - if (global.lpmDict[channelId].lp60Max < lines60) { - global.lpmDict[channelId].lp60Max = lines60; - } - global.lpmDict[channelId].position = index; - global.lpmDict[channelId].name = channel.name; - global.lpmDict[channelId].lp1 = lines1; - global.lpmDict[channelId].lp5 = lines5; - global.lpmDict[channelId].lp10 = lines10; - global.lpmDict[channelId].lp30 = lines30; - global.lpmDict[channelId].lp60 = lines60; - } else { - global.lpmDict[channelId] = { - position: index, - name: channel.name, - alert: 0, - lp1: lines1, - lp1Max: lines1, - lp5: lines5, - lp5Max: lines5, - lp10: lines10, - lp10Max: lines10, - lp30: lines30, - lp30Max: lines30, - lp60: lines60, - lp60Max: lines60, - }; - } - } - } - - await Promise.all(channels.map(async (channelId, index) => { - await getLpm(channelId, index + 1); - })); - if (global.lpmTime) { - global.lpmTime.push(Date.now() - startTime); - } else { - global.lpmTime = [Date.now() - startTime]; - } - // log.debug(F, `LPM check took ${Date.now() - startTime}ms`); -} +// async function checkLpm() { // eslint-disable-line +// const channels = [ +// env.CHANNEL_LOUNGE, +// // env.CATEGORY_HARMREDUCTIONCENTRE, +// env.CHANNEL_TRIPSITMETA, +// env.CHANNEL_TRIPSIT, +// env.CHANNEL_OPENTRIPSIT1, +// env.CHANNEL_OPENTRIPSIT2, +// env.CHANNEL_WEBTRIPSIT1, +// env.CHANNEL_WEBTRIPSIT2, +// env.CHANNEL_CLOSEDTRIPSIT, +// env.CHANNEL_RTRIPSIT, +// // env.CATEGORY_BACKSTAGE, +// env.CHANNEL_PETS, +// env.CHANNEL_FOOD, +// env.CHANNEL_OCCULT, +// env.CHANNEL_MUSIC, +// env.CHANNEL_MEMES, +// env.CHANNEL_MOVIES, +// env.CHANNEL_GAMING, +// env.CHANNEL_SCIENCE, +// env.CHANNEL_CREATIVE, +// env.CHANNEL_COMPSCI, +// env.CHANNEL_REPLICATIONS, +// env.CHANNEL_PHOTOGRAPHY, +// // env.CHANNEL_RECOVERY, +// // env.CATEGORY_CAMPGROUND, +// env.CHANNEL_VIPLOUNGE, +// env.CHANNEL_GOLDLOUNGE, +// env.CHANNEL_SANCTUARY, +// env.CHANNEL_TREES, +// env.CHANNEL_OPIATES, +// env.CHANNEL_STIMULANTS, +// env.CHANNEL_DEPRESSANTS, +// env.CHANNEL_DISSOCIATIVES, +// env.CHANNEL_PSYCHEDELICS, +// ]; + +// const startTime = Date.now(); +// // log.debug(F, 'Checking LPM...'); + +// if (!global.lpmDict) { +// global.lpmDict = {}; +// } + +// const guild = await discordClient.guilds.fetch(env.DISCORD_GUILD_ID); +// await guild.channels.fetch(); + +// async function getLpm(channelId:string, index:number) { +// // const channel = await guild.channels.fetch(channelId) as TextChannel; +// const channel = guild.channels.cache.get(channelId) as TextChannel; +// const messages = await channel.messages.fetch({ limit: 100 }); // eslint-disable-line no-await-in-loop + +// // Filter bots out of messages +// const filteredMessages = messages.filter(message => !message.author.bot); + +// const lines1 = filteredMessages.reduce((acc, cur) => { +// if (Date.now() - cur.createdTimestamp > 1000 * 60) return acc; +// return acc + cur.content.split('\n').length; +// }, 0); + +// const lines5 = filteredMessages.reduce((acc, cur) => { +// if (Date.now() - cur.createdTimestamp > 1000 * 60 * 5) return acc; +// return acc + cur.content.split('\n').length; +// }, 0); + +// const lines10 = filteredMessages.reduce((acc, cur) => { +// if (Date.now() - cur.createdTimestamp > 1000 * 60 * 10) return acc; +// return acc + cur.content.split('\n').length; +// }, 0); + +// const lines30 = filteredMessages.reduce((acc, cur) => { +// if (Date.now() - cur.createdTimestamp > 1000 * 60 * 30) return acc; +// return acc + cur.content.split('\n').length; +// }, 0); + +// const lines60 = filteredMessages.reduce((acc, cur) => { +// if (Date.now() - cur.createdTimestamp > 1000 * 60 * 60) return acc; +// return acc + cur.content.split('\n').length; +// }, 0); + +// if (lines5) { +// if (global.lpmDict[channelId]) { +// // log.debug(F, `lpmDict: ${JSON.stringify(global.lpmDict[channelId])}`); +// if (global.lpmDict[channelId].lp1 === lines1 && global.lpmDict[channelId].lp60 === lines60) { +// return; +// } +// if (global.lpmDict[channelId].lp1Max < lines1) { +// global.lpmDict[channelId].lp1Max = lines1; +// } +// if (global.lpmDict[channelId].lp5Max < lines5) { +// global.lpmDict[channelId].lp5Max = lines5; +// } +// if (global.lpmDict[channelId].lp10Max < lines10) { +// global.lpmDict[channelId].lp10Max = lines10; +// } +// if (global.lpmDict[channelId].lp30Max < lines30) { +// global.lpmDict[channelId].lp30Max = lines30; +// } +// if (global.lpmDict[channelId].lp60Max < lines60) { +// global.lpmDict[channelId].lp60Max = lines60; +// } +// global.lpmDict[channelId].position = index; +// global.lpmDict[channelId].name = channel.name; +// global.lpmDict[channelId].lp1 = lines1; +// global.lpmDict[channelId].lp5 = lines5; +// global.lpmDict[channelId].lp10 = lines10; +// global.lpmDict[channelId].lp30 = lines30; +// global.lpmDict[channelId].lp60 = lines60; +// } else { +// global.lpmDict[channelId] = { +// position: index, +// name: channel.name, +// alert: 0, +// lp1: lines1, +// lp1Max: lines1, +// lp5: lines5, +// lp5Max: lines5, +// lp10: lines10, +// lp10Max: lines10, +// lp30: lines30, +// lp30Max: lines30, +// lp60: lines60, +// lp60Max: lines60, +// }; +// } +// } +// } + +// await Promise.all(channels.map(async (channelId, index) => { +// await getLpm(channelId, index + 1); +// })); +// if (global.lpmTime) { +// global.lpmTime.push(Date.now() - startTime); +// } else { +// global.lpmTime = [Date.now() - startTime]; +// } +// // log.debug(F, `LPM check took ${Date.now() - startTime}ms`); +// } async function checkMoodle() { // eslint-disable-line // This function will pull all users from postgres that have a moodle_id @@ -940,6 +943,7 @@ async function checkMoodle() { // eslint-disable-line member.roles.add(role); log.info(F, `Gave ${member.user.username} the ${role.name} role`); + // eslint-disable max-len member.user.send({ embeds: [ embedTemplate() From e5ec789de45cfe20276a91ba7dea594a90f9a06b Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Fri, 2 Jun 2023 17:29:01 +1000 Subject: [PATCH 14/33] Update tents permission overwrites --- src/discord/commands/guild/d.voice.ts | 12 ++++----- src/discord/utils/tents.ts | 36 ++++++++++++++++++++++++--- src/global/utils/env.config.ts | 3 ++- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index 8749e2a0a..a09cefcea 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -31,11 +31,11 @@ async function tentLock( ):Promise { let verb = ''; - if (voiceChannel.permissionsFor(env.ROLE_VERIFIED).has(PermissionsBitField.Flags.Connect) === true) { - voiceChannel.permissionOverwrites.edit(env.ROLE_VERIFIED, { Connect: false }); + if (voiceChannel.permissionsFor(voiceChannel.guild.roles.everyone).has(PermissionsBitField.Flags.Connect) === true) { + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { Connect: false }); verb = 'locked'; } else { - voiceChannel.permissionOverwrites.edit(env.ROLE_VERIFIED, { Connect: true }); + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { Connect: true }); verb = 'unlocked'; } @@ -52,11 +52,11 @@ async function tentHide( ):Promise { let verb = ''; - if (voiceChannel.permissionsFor(env.ROLE_VERIFIED).has(PermissionsBitField.Flags.ViewChannel) === true) { - voiceChannel.permissionOverwrites.edit(env.ROLE_VERIFIED, { ViewChannel: false }); + if (voiceChannel.permissionsFor(voiceChannel.guild.roles.everyone).has(PermissionsBitField.Flags.ViewChannel) === true) { + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: false }); verb = 'hidden'; } else { - voiceChannel.permissionOverwrites.edit(env.ROLE_VERIFIED, { ViewChannel: true }); + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: true }); verb = 'unhidden'; } diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 515c92e23..1fdeab0e8 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -18,7 +18,7 @@ export async function pitchTent( New:VoiceState, ): Promise { New.member?.guild.channels.create({ - name: `⛺│ ${New.member.displayName}'s tent`, + name: `⛺│${New.member.displayName}'s tent`, type: ChannelType.GuildVoice, parent: env.CATEGORY_VOICE, permissionOverwrites: [ @@ -43,7 +43,7 @@ export async function pitchTent( ], }, { - id: env.ROLE_VERIFIED, + id: New.member.guild.roles.everyone, allow: [ PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.Connect, @@ -59,6 +59,31 @@ export async function pitchTent( PermissionsBitField.Flags.UseApplicationCommands, ], }, + { + id: env.ROLE_MODERATOR, + allow: [ + PermissionsBitField.Flags.ViewChannel, + ], + }, + { + id: env.ROLE_NEEDSHELP, + deny: [ + PermissionsBitField.Flags.ViewChannel, + ], + }, + { + id: env.ROLE_VERIFYING, + deny: [ + PermissionsBitField.Flags.ViewChannel, + ], + }, + { + id: env.ROLE_UNVERIFIED, + deny: [ + PermissionsBitField.Flags.ViewChannel, + ], + }, + ], }).then(async newChannel => { New.member?.voice.setChannel(newChannel.id); @@ -76,7 +101,12 @@ export async function pitchTent( // **/voice cohost @user** - Allows another user to use these commands // `); await newChannel.fetch(); - await newChannel.send(`## Welcome to your tent, <@${New.member?.id}>! + await newChannel.send(`## Welcome to your tent, <@${New.member?.id}> + +- **Looking for others to join?** + - Pick up the 'Voice Chatty' role in + - This icon indicates you're looking for joiners in chat + - **Moderate your tent with commands** - \`/voice lock\`- Locks your tent so no one else can join it - \`/voice hide\` - Hides your tent from the list of voice channels diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index d46f991de..1893cabbe 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -214,7 +214,8 @@ export const env = { ROLE_RECOVERY: isProd ? '1052629812566573137' : '1052644692711456888', ROLE_DJ: isProd ? '955451412878331974' : '960606558050480157', ROLE_VERIFIED: isProd ? '1009864163478216775' : '1052644673816104990', - ROLE_UNVERIFIED: isProd ? '1009864163478216775' : '1009862883108212766', + ROLE_VERIFYING: isProd ? '1102572404812808296' : '1114087859029278740', + ROLE_UNVERIFIED: isProd ? '1102582379169722458' : '1114087822295568446', ROLE_FRANK: isProd ? '' : '1052644688554905630', ROLE_ALUMNI: isProd ? '' : '1052644662793490532', From 54c6b622620c80d2c9769681e219c9d000bad132 Mon Sep 17 00:00:00 2001 From: Moonbear <1836049+LunaUrsa@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:19:16 -0500 Subject: [PATCH 15/33] belly button linting --- src/discord/events/guildMemberUpdate.ts | 2 -- src/discord/utils/tripsitme.ts | 6 +++--- src/global/utils/timer.ts | 4 ++-- src/start.ts | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 4b68a0b3e..93e331274 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -17,8 +17,6 @@ type MindsetNames = | 'ROLE_TALKATIVE' | 'ROLE_VOICECHATTY' | 'ROLE_BUSY'; -| 'ROLE_VOICECHATTY' -| 'ROLE_BUSY'; const mindsetRoles = { ROLE_DRUNK: env.ROLE_DRUNK, diff --git a/src/discord/utils/tripsitme.ts b/src/discord/utils/tripsitme.ts index f22429c2d..f9adb38cf 100644 --- a/src/discord/utils/tripsitme.ts +++ b/src/discord/utils/tripsitme.ts @@ -212,9 +212,9 @@ export async function needsHelpMode( // Patch for BlueLight: They don't want to remove roles from the target at all if ( - target.guild.id !== env.DISCORD_BL_ID + target.guild.id !== env.DISCORD_BL_ID // && target.guild.id !== env.DISCORD_GUILD_ID // For testing - ) { + ) { // Remove all roles, except team and vanity, from the target target.roles.cache.forEach(async role => { // log.debug(F, `role: ${role.name} - ${role.id}`); @@ -736,7 +736,7 @@ export async function tripsitmeUserClose( // Patch for BlueLight: Since we didn't remove roles, don't re-add them && target.guild.id !== env.DISCORD_BL_ID // && target.guild.id !== env.DISCORD_GUILD_ID // For testing - ) { + ) { const myMember = await interaction.guild.members.fetch(interaction.client.user.id); const myRole = myMember.roles.highest; const targetRoles:string[] = userData.roles.split(',') || []; diff --git a/src/global/utils/timer.ts b/src/global/utils/timer.ts index e450072b1..4e9f393be 100644 --- a/src/global/utils/timer.ts +++ b/src/global/utils/timer.ts @@ -108,8 +108,8 @@ async function checkTickets() { // eslint-disable-line @typescript-eslint/no-unu // Loop through each ticket if (ticketData.length > 0) { ticketData.forEach(async ticket => { - const archiveDate = DateTime.fromJSDate(ticket.archived_at); - const deleteDate = DateTime.fromJSDate(ticket.deleted_at); + // const archiveDate = DateTime.fromJSDate(ticket.archived_at); + // const deleteDate = DateTime.fromJSDate(ticket.deleted_at); // log.debug(F, `Ticket: ${ticket.id} archives on ${archiveDate.toLocaleString(DateTime.DATETIME_FULL)} deletes on ${deleteDate.toLocaleString(DateTime.DATETIME_FULL)}`); // Check if the ticket is ready to be archived if (ticket.archived_at diff --git a/src/start.ts b/src/start.ts index 8cb305d0c..c19039181 100644 --- a/src/start.ts +++ b/src/start.ts @@ -13,7 +13,7 @@ global.bootTime = new Date(); const F = f(__filename); -const net = require("net"); +const net = require('net'); // work around a node v20 bug: https://github.com/nodejs/node/issues/47822#issuecomment-1564708870 if (net.setDefaultAutoSelectFamily) { net.setDefaultAutoSelectFamily(false); From 9d607d8b8121327099c933f96f892e2b7d8788be Mon Sep 17 00:00:00 2001 From: Moonbear <1836049+LunaUrsa@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:41:00 -0500 Subject: [PATCH 16/33] Bug in knex --- src/discord/utils/messageCommand.ts | 35 ++++++++++++++++++++++++----- src/global/utils/knex.ts | 1 + 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/discord/utils/messageCommand.ts b/src/discord/utils/messageCommand.ts index acc4fc07e..bd3dd9aea 100644 --- a/src/discord/utils/messageCommand.ts +++ b/src/discord/utils/messageCommand.ts @@ -4,6 +4,8 @@ import { // GuildTextBasedChannel, Role, PermissionResolvable, + TextChannel, + ThreadChannel, } from 'discord.js'; import { stripIndents } from 'common-tags'; import { sleep } from '../commands/guild/d.bottest'; @@ -220,9 +222,7 @@ ${roleHelper}. Can you start off by telling us how much you took and the details await message.react('💜'); } } - } else if ( - // If 'tripbot' is mentioned in text - message.content.toLowerCase().includes('tripbot') + } else if (message.content.toLowerCase().includes('tripbot') && message.channel.type !== ChannelType.DM) { if (message.author.bot) { // Keep this here because web bots need to be able to use ~tripsit @@ -240,13 +240,38 @@ ${roleHelper}. Can you start off by telling us how much you took and the details // '*beeps quietly*', // ]; // await message.channel.send(responses[Math.floor(Math.random() * responses.length)]); - } else if ( - sadStuff.some(word => (message.cleanContent.includes(word) + } else if (sadStuff.some(word => (message.cleanContent.includes(word) && !(message.cleanContent.substring(message.cleanContent.indexOf(':') + 1).includes(':')))) && message.channel.type !== ChannelType.DM) { if (message.author.bot) return; if (message.guild.id !== env.DISCORD_GUILD_ID) return; // log.debug(F, 'Sad stuff detected'); await message.react(heartEmojis[Math.floor(Math.random() * heartEmojis.length)]); + } else if ( + message.content.match(/(?:anyone|someone+there|here)\b/) + && (message.channel as ThreadChannel).parent?.parentId !== env.CATEGORY_HARMREDUCTIONCENTRE + && (message.channel as TextChannel).parentId !== env.CATEGORY_HARMREDUCTIONCENTRE + ) { + // Find when the last message in that channel was sent + const lastMessage = await message.channel.messages.fetch({ + before: message.id, + limit: 1, + }); + const lastMessageDate = lastMessage.first()?.createdAt; + + // Check if the last message was send in the last 10 minutes + if (lastMessageDate && lastMessageDate.valueOf() > Date.now() - 1000 * 60 * 10) { + // If it was, then don't send the message + return; + } + + await message.channel.sendTyping(); + setTimeout(async () => { + await (message.channel.send({ + content: stripIndents`Hey ${message.member?.displayName}! + Sometimes chat slows down, but go ahead and ask your question: Someone will get back to you when they can! + Who knows, maybe someone is lurking and waiting for the right question... :eyes: `, + })); + }, 2000); } } diff --git a/src/global/utils/knex.ts b/src/global/utils/knex.ts index ff3555e5b..548136a36 100644 --- a/src/global/utils/knex.ts +++ b/src/global/utils/knex.ts @@ -342,6 +342,7 @@ export async function ticketGet( try { tickets = await db('user_tickets') .select('*') + .where('user_id', user_id) .where('type', 'TRIPSIT') .orderBy('thread_id', 'desc'); } catch (err) { From c14975e768238e01a5c24607f249484d69bb1fcc Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Sun, 30 Jul 2023 21:33:28 +1000 Subject: [PATCH 17/33] Add /voice radio First pass, needs work and add function of changing the tent name to signify the bot is being borrowed --- src/discord/commands/guild/d.voice.ts | 187 ++++++++++++++++++++++++-- src/discord/utils/tents.ts | 31 ++++- src/global/utils/env.config.ts | 10 +- 3 files changed, 206 insertions(+), 22 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index a09cefcea..b06e5145f 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -1,4 +1,7 @@ import { + VoiceChannel, + ChannelType, + Guild, Colors, SlashCommandBuilder, GuildMember, @@ -31,12 +34,16 @@ async function tentLock( ):Promise { let verb = ''; - if (voiceChannel.permissionsFor(voiceChannel.guild.roles.everyone).has(PermissionsBitField.Flags.Connect) === true) { - voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { Connect: false }); - verb = 'locked'; + if ( + voiceChannel + .permissionsFor(voiceChannel.guild.roles.everyone) + .has(PermissionsBitField.Flags.ViewChannel) === true + ) { + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: false }); + verb = 'hidden'; } else { - voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { Connect: true }); - verb = 'unlocked'; + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: true }); + verb = 'unhidden'; } // log.debug(F, `Channel is now ${verb}`); @@ -85,6 +92,22 @@ async function tentBan( verb = 'unbanned and unhidden'; } + // Disallow banning bots + if (target.user.bot) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`You cannot ban bots`); + } + + // Disallow banning mods + if (target.roles.cache.has(env.ROLE_MODERATOR) === true) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`You cannot ban mods`); + } + // log.debug(F, `${target.displayName} is now ${verb}`); return embedTemplate() @@ -139,6 +162,124 @@ async function tentCohost( .setDescription(`${target} has been ${verb} in ${voiceChannel}`); } +async function tentRadio( + voiceChannel: VoiceBasedChannel, + stationid: string, + guild: Guild, +):Promise { + let verb = ''; + + const radioChannels: { [key: string]: string } = { + '830530156048285716': env.CHANNEL_LOFIRADIO, + '861363156568113182': env.CHANNEL_JAZZRADIO, + '833406944387268670': env.CHANNEL_SYNTHWAVERADIO, + '831623165632577587': env.CHANNEL_SLEEPYRADIO, + }; + + // If the station choice was "none", send the radio back to the radio room + if (stationid === 'none') { + // Check if any radio bots are in the Tent + const radioBot = voiceChannel.members.find((m) => Object.keys(radioChannels).includes(m.user.id)); + if (!radioBot) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`There is already no radio in this Tent`); + } + // Find what radio bot is in the Tent and use the corresponding radio channel from the radioChannels object + // Check if the current channel has a radio bot in it by checking if any bots in the channel are in the radioChannels object + const botMember = voiceChannel.members.find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); + if (botMember) { + // If it does, find the corresponding radio channel from the bot id and move the bot to it + const radioChannelId = radioChannels[botMember.user.id]; + // Get the radio channel from cache + const radioChannel = guild.channels.cache.get(radioChannelId) as VoiceChannel; + // If the radio channel exists, and is a voice channel, move the bot to it + if (radioChannel && radioChannel.type === ChannelType.GuildVoice) { + voiceChannel.members.forEach(member => { + if (member.user.bot) { + member.voice.setChannel(radioChannel.id); + } + }); + } + } + return embedTemplate() + .setTitle('Success') + .setColor(Colors.Green) + .setDescription(`The radio has been returned to the radio room`); + } + + const station = voiceChannel.guild.members.cache.get(stationid) as GuildMember; + + // If the station returns invalid (not on the server) + if (!station) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`This radio wasn't found! Please report this to the mods`); + } + + // If the radio is offline + if (!station.voice.channel) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`This radio is currently offline, please report this to the mods`); + } + // If the radio is already in another Tent + if (station.voice.channel?.parent?.id === env.CATEGORY_CAMPGROUND && station.voice.channelId !== voiceChannel.id) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`This radio is already being borrowed in another Tent`); + } + // If the radio is already in the Tent + if (station.voice.channelId === voiceChannel.id) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`This radio is already in your Tent`); + } + // If the radio is available, move it to the Tent + if (station.voice.channel?.parent?.id === env.CATEGORY_RADIO) { + await station.voice.setChannel(voiceChannel); + // Edit the corresponding radio channels name to indicate it is in use + const radioChannelId = radioChannels[station.user.id]; + const radioChannel = station.guild.channels.cache.get(radioChannelId) as VoiceChannel; + + return embedTemplate() + .setTitle('Success') + .setColor(Colors.Green) + .setDescription(`${station} has been borrowed to your Tent`); + } + // If the Tent already has a radio, find its corresonding channel in the radioChannels object and move it back before moving the new radio in + const botMember = station.voice.channel.members.find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); + if (botMember) { + // If it does, find the corresponding radio channel from the bot id and move the bot to it + const radioChannelId = radioChannels[botMember.user.id]; + // Get the radio channel from cache + const radioChannel = station.guild.channels.cache.get(radioChannelId) as VoiceChannel; + // If the radio channel exists, and is a voice channel, move the bot to it + if (radioChannel && radioChannel.type === ChannelType.GuildVoice) { + radioChannel.members.forEach((member: GuildMember) => { + if (member.user.bot) { + member.voice.setChannel(radioChannel); + } + }); + } + await station.voice.setChannel(voiceChannel); + } + + + // log.debug(F, `${target.displayName} is now ${verb}`); + + return embedTemplate() + .setTitle('Success') + .setColor(Colors.Green) + .setDescription(`${station} has been borrowed to your Tent`); +} + + export const dVoice: SlashCommand = { data: new SlashCommandBuilder() .setName('voice') @@ -152,20 +293,20 @@ export const dVoice: SlashCommand = { .setRequired(true))) .addSubcommand(subcommand => subcommand .setName('lock') - .setDescription('Lock the Tent from new users')) + .setDescription('Lock/Unlock the Tent from new users')) .addSubcommand(subcommand => subcommand .setName('hide') - .setDescription('Hide the Tent from the channel list')) + .setDescription('Hide/Unhide the Tent from the channel list')) .addSubcommand(subcommand => subcommand .setName('ban') - .setDescription('Ban and hide a user from your Tent') + .setDescription('Ban/Unban and hide a user from your Tent') .addUserOption(option => option .setName('target') - .setDescription('The user to ban') + .setDescription('The user to ban/unban') .setRequired(true))) .addSubcommand(subcommand => subcommand .setName('mute') - .setDescription('Mute a user in your Tent') + .setDescription('Mute/Unmute a user in your Tent') .addUserOption(option => option .setName('target') .setDescription('The user to mute') @@ -176,15 +317,33 @@ export const dVoice: SlashCommand = { .addUserOption(option => option .setName('target') .setDescription('The user to make co-host') - .setRequired(true))), + .setRequired(true))) + .addSubcommand(subcommand => subcommand + .setName('radio') + .setDescription('Borrow a radio bot for your Tent') + .addStringOption(option => option + .setName('station') + .setDescription('The radio station to borrow') + .setRequired(true) + .addChoices( + { name: 'Lofi', value: '830530156048285716' }, + { name: 'Jazz', value: '861363156568113182' }, + { name: 'Synthwave', value: '833406944387268670' }, + { name: 'Sleepy', value: '831623165632577587' }, + { name: 'None', value: 'none'} + ), + ) + ), async execute(interaction) { log.info(F, await commandContext(interaction)); await interaction.deferReply({ ephemeral: true }); - const command = interaction.options.getSubcommand() as 'lock' | 'hide' | 'ban' | 'rename' | 'mute' | 'cohost'; + const command = interaction.options.getSubcommand() as 'lock' | 'hide' | 'ban' | 'rename' | 'mute' | 'cohost' | 'radio'; const member = interaction.member as GuildMember; const target = interaction.options.getMember('target') as GuildMember; const newName = interaction.options.getString('name') as string; + const stationid = interaction.options.getString('station') as string; + const guild = interaction.guild as Guild; const voiceChannel = member.voice.channel; let embed = embedTemplate() .setTitle('Error') @@ -246,6 +405,10 @@ export const dVoice: SlashCommand = { embed = await tentCohost(voiceChannel, target); } + if (command === 'radio') { + embed = await tentRadio(voiceChannel, stationid, guild); + } + await interaction.editReply({ embeds: [embed] }); return true; }, diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index bc31c6110..62c6c61aa 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -1,5 +1,6 @@ import { VoiceState, + VoiceChannel, ChannelType, CategoryChannel, PermissionsBitField, @@ -133,12 +134,32 @@ export async function teardownTent( // Get the number of humans in the channel const humans = channel.members.filter(member => !member.user.bot).size; + const radioChannels: { [key: string]: string } = { + '830530156048285716': env.CHANNEL_LOFIRADIO, + '861363156568113182': env.CHANNEL_JAZZRADIO, + '833406944387268670': env.CHANNEL_SYNTHWAVERADIO, + '831623165632577587': env.CHANNEL_SLEEPYRADIO, + }; + // If the channel is a voice channel, and it's a tent, and there are no humans in it delete it - if (channel.type === ChannelType.GuildVoice - && channel.name.includes('⛺') - && humans < 1) { + if (channel.type === ChannelType.GuildVoice && channel.name.includes('⛺') && humans < 1) { + // Check if the current channel has a radio bot in it by checking if any bots in the channel are in the radioChannels object + const botMember = channel.members.find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); + if (botMember) { + // If it does, find the corresponding radio channel from the bot id and move the bot to it + const radioChannelId = radioChannels[botMember.user.id]; + // Get the radio channel from cache + const radioChannel = Old.guild.channels.cache.get(radioChannelId) as VoiceChannel; + // If the radio channel exists, and is a voice channel, move the bot to it + if (radioChannel && radioChannel.type === ChannelType.GuildVoice) { + channel.members.forEach(member => { + if (member.user.bot) { + member.voice.setChannel(radioChannel.id); + } + }); + } + } channel.delete('Removing temporary voice chan!'); - // log.debug(F, `deleted an empty temporary voice channel`); - } + } }); } diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 543eca516..d51daef8a 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -164,11 +164,11 @@ export const env = { CHANNEL_BOTERRORS: isProd ? '1081018048858824835' : '1081018727992152185', CHANNEL_DEVELOPMENTVOICE: isProd ? '970848692158464021' : '1052634132729036820', - CATEGORY_RADIO: isProd ? '' : '1052634090819551436', - CHANNEL_SYNTHWAVERADIO: isProd ? '' : '1052634114693541898', - CHANNEL_GAMINGRADIO: isProd ? '' : '1052634116975231019', - CHANNEL_STUDYRADIO: isProd ? '' : '1052634119458275459', - CHANNEL_SLEEPYRADIO: isProd ? '' : '1052634122222309386', + CATEGORY_RADIO: isProd ? '981069604665327646' : '1052634090819551436', + CHANNEL_SYNTHWAVERADIO: isProd ? '1050099921811939359' : '1052634114693541898', + CHANNEL_LOFIRADIO: isProd ? '1130662704001065062' : '1052634116975231019', + CHANNEL_JAZZRADIO: isProd ? '1093192174998405181' : '1052634119458275459', + CHANNEL_SLEEPYRADIO: isProd ? '1130662794346373172' : '1052634122222309386', CHANNEL_FUTON: isProd ? '1111206330594762803' : '1111208569942061087', CATEGORY_ARCHIVED: isProd ? '' : '1052634099149443083', From 61a03dbd214c3784ccce21fdcd1831582ed18946 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Sun, 30 Jul 2023 21:50:30 +1000 Subject: [PATCH 18/33] Add /voice bitrate Allows editing of bitrate --- src/discord/commands/guild/d.voice.ts | 48 +++++++++++++++++++++++++-- src/discord/utils/tents.ts | 8 +++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index b06e5145f..54616d943 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -167,7 +167,6 @@ async function tentRadio( stationid: string, guild: Guild, ):Promise { - let verb = ''; const radioChannels: { [key: string]: string } = { '830530156048285716': env.CHANNEL_LOFIRADIO, @@ -268,7 +267,7 @@ async function tentRadio( }); } await station.voice.setChannel(voiceChannel); - } + } // log.debug(F, `${target.displayName} is now ${verb}`); @@ -279,6 +278,27 @@ async function tentRadio( .setDescription(`${station} has been borrowed to your Tent`); } +async function tentBitrate( + voiceChannel: VoiceBasedChannel, + bitrate: string, +):Promise { + + const bitrateNumber = parseInt(bitrate); + // Check if the bitrate is the same as the current bitrate + if (voiceChannel.bitrate === bitrateNumber * 1000) { + return embedTemplate() + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`The bitrate is already set to ${bitrate}kbps`); + } + // Change the bitrate + await voiceChannel.setBitrate(bitrateNumber * 1000); + return embedTemplate() + .setTitle('Success') + .setColor(Colors.Green) + .setDescription(`The bitrate has been set to ${bitrate}kbps`); +} + export const dVoice: SlashCommand = { data: new SlashCommandBuilder() @@ -333,17 +353,35 @@ export const dVoice: SlashCommand = { { name: 'None', value: 'none'} ), ) + ) + .addSubcommand(subcommand => subcommand + .setName('bitrate') + .setDescription('Change the bitrate of your Tent') + .addStringOption(option => option + .setName('bitrate') + .setDescription('The bitrate to set') + .setRequired(true) + .addChoices( + { name: 'Potato (8kbps)', value: '8' }, + { name: 'Low (32kbps)', value: '16' }, + { name: 'Default (64kbps)', value: '64' }, + { name: 'Medium (128kbps)', value: '128' }, + { name: 'High (256kbps)', value: '256' }, + { name: 'Ultra (384kbps)', value: '384' }, + ), + ) ), async execute(interaction) { log.info(F, await commandContext(interaction)); await interaction.deferReply({ ephemeral: true }); - const command = interaction.options.getSubcommand() as 'lock' | 'hide' | 'ban' | 'rename' | 'mute' | 'cohost' | 'radio'; + const command = interaction.options.getSubcommand() as 'lock' | 'hide' | 'ban' | 'rename' | 'mute' | 'cohost' | 'radio' | 'bitrate'; const member = interaction.member as GuildMember; const target = interaction.options.getMember('target') as GuildMember; const newName = interaction.options.getString('name') as string; const stationid = interaction.options.getString('station') as string; const guild = interaction.guild as Guild; + const bitrate = interaction.options.getString('bitrate') as string; const voiceChannel = member.voice.channel; let embed = embedTemplate() .setTitle('Error') @@ -409,6 +447,10 @@ export const dVoice: SlashCommand = { embed = await tentRadio(voiceChannel, stationid, guild); } + if (command === 'bitrate') { + embed = await tentBitrate(voiceChannel, bitrate); + } + await interaction.editReply({ embeds: [embed] }); return true; }, diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 62c6c61aa..fa17e8bd6 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -108,10 +108,14 @@ export async function pitchTent( - Pick up the 'Voice Chatty' role in - This icon indicates you're looking for joiners in chat -- **Moderate your tent with commands** +- **Modify your tent** + - \`/voice radio\` - Borrow a radio bot for your tent + - \`/voice bitrate\` - Change the bitrate of your tent + - \`/voice rename\` - Choose a new name for your tent + +- **Moderate your tent** - \`/voice lock\`- Locks your tent so no one else can join it - \`/voice hide\` - Hides your tent from the list of voice channels - - \`/voice rename\` - Choose a new name for your tent - \`/voice mute\` - Mutes a user for everyone in your tent - \`/voice ban\` - Bans a user from joining and seeing your tent - \`/voice cohost\` - Allows another user to use these commands From 54b7a0e6e1e12227a83f1d78a69f318a83ff9efc Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Sun, 30 Jul 2023 12:56:37 -0500 Subject: [PATCH 19/33] Lint that shit --- src/discord/commands/guild/d.voice.ts | 72 ++++++++++++--------------- src/discord/utils/tents.ts | 2 +- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index 6e7a3cb91..fe5879dae 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -101,7 +101,7 @@ async function tentBan( return embedTemplate() .setTitle('Error') .setColor(Colors.Red) - .setDescription(`You cannot ban bots`); + .setDescription('You cannot ban bots'); } // Disallow banning mods @@ -109,7 +109,7 @@ async function tentBan( return embedTemplate() .setTitle('Error') .setColor(Colors.Red) - .setDescription(`You cannot ban mods`); + .setDescription('You cannot ban mods'); } // log.debug(F, `${target.displayName} is now ${verb}`); @@ -171,7 +171,6 @@ async function tentRadio( stationid: string, guild: Guild, ):Promise { - const radioChannels: { [key: string]: string } = { '830530156048285716': env.CHANNEL_LOFIRADIO, '861363156568113182': env.CHANNEL_JAZZRADIO, @@ -182,12 +181,12 @@ async function tentRadio( // If the station choice was "none", send the radio back to the radio room if (stationid === 'none') { // Check if any radio bots are in the Tent - const radioBot = voiceChannel.members.find((m) => Object.keys(radioChannels).includes(m.user.id)); + const radioBot = voiceChannel.members.find(m => Object.keys(radioChannels).includes(m.user.id)); if (!radioBot) { return embedTemplate() - .setTitle('Error') - .setColor(Colors.Red) - .setDescription(`There is already no radio in this Tent`); + .setTitle('Error') + .setColor(Colors.Red) + .setDescription('There is already no radio in this Tent'); } // Find what radio bot is in the Tent and use the corresponding radio channel from the radioChannels object // Check if the current channel has a radio bot in it by checking if any bots in the channel are in the radioChannels object @@ -207,9 +206,9 @@ async function tentRadio( } } return embedTemplate() - .setTitle('Success') - .setColor(Colors.Green) - .setDescription(`The radio has been returned to the radio room`); + .setTitle('Success') + .setColor(Colors.Green) + .setDescription('The radio has been returned to the radio room'); } const station = voiceChannel.guild.members.cache.get(stationid) as GuildMember; @@ -217,31 +216,31 @@ async function tentRadio( // If the station returns invalid (not on the server) if (!station) { return embedTemplate() - .setTitle('Error') - .setColor(Colors.Red) - .setDescription(`This radio wasn't found! Please report this to the mods`); + .setTitle('Error') + .setColor(Colors.Red) + .setDescription('This radio wasn\'t found! Please report this to the mods'); } // If the radio is offline if (!station.voice.channel) { return embedTemplate() - .setTitle('Error') - .setColor(Colors.Red) - .setDescription(`This radio is currently offline, please report this to the mods`); + .setTitle('Error') + .setColor(Colors.Red) + .setDescription('This radio is currently offline, please report this to the mods'); } // If the radio is already in another Tent if (station.voice.channel?.parent?.id === env.CATEGORY_CAMPGROUND && station.voice.channelId !== voiceChannel.id) { return embedTemplate() - .setTitle('Error') - .setColor(Colors.Red) - .setDescription(`This radio is already being borrowed in another Tent`); + .setTitle('Error') + .setColor(Colors.Red) + .setDescription('This radio is already being borrowed in another Tent'); } // If the radio is already in the Tent if (station.voice.channelId === voiceChannel.id) { return embedTemplate() - .setTitle('Error') - .setColor(Colors.Red) - .setDescription(`This radio is already in your Tent`); + .setTitle('Error') + .setColor(Colors.Red) + .setDescription('This radio is already in your Tent'); } // If the radio is available, move it to the Tent if (station.voice.channel?.parent?.id === env.CATEGORY_RADIO) { @@ -251,9 +250,9 @@ async function tentRadio( const radioChannel = station.guild.channels.cache.get(radioChannelId) as VoiceChannel; return embedTemplate() - .setTitle('Success') - .setColor(Colors.Green) - .setDescription(`${station} has been borrowed to your Tent`); + .setTitle('Success') + .setColor(Colors.Green) + .setDescription(`${station} has been borrowed to your Tent`); } // If the Tent already has a radio, find its corresonding channel in the radioChannels object and move it back before moving the new radio in const botMember = station.voice.channel.members.find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); @@ -268,12 +267,11 @@ async function tentRadio( if (member.user.bot) { member.voice.setChannel(radioChannel); } - }); + }); } await station.voice.setChannel(voiceChannel); } - // log.debug(F, `${target.displayName} is now ${verb}`); return embedTemplate() @@ -286,14 +284,13 @@ async function tentBitrate( voiceChannel: VoiceBasedChannel, bitrate: string, ):Promise { - - const bitrateNumber = parseInt(bitrate); + const bitrateNumber = parseInt(bitrate, 10); // Check if the bitrate is the same as the current bitrate if (voiceChannel.bitrate === bitrateNumber * 1000) { return embedTemplate() - .setTitle('Error') - .setColor(Colors.Red) - .setDescription(`The bitrate is already set to ${bitrate}kbps`); + .setTitle('Error') + .setColor(Colors.Red) + .setDescription(`The bitrate is already set to ${bitrate}kbps`); } // Change the bitrate await voiceChannel.setBitrate(bitrateNumber * 1000); @@ -303,7 +300,6 @@ async function tentBitrate( .setDescription(`The bitrate has been set to ${bitrate}kbps`); } - export const dVoice: SlashCommand = { data: new SlashCommandBuilder() .setName('voice') @@ -354,10 +350,8 @@ export const dVoice: SlashCommand = { { name: 'Jazz', value: '861363156568113182' }, { name: 'Synthwave', value: '833406944387268670' }, { name: 'Sleepy', value: '831623165632577587' }, - { name: 'None', value: 'none'} - ), - ) - ) + { name: 'None', value: 'none' }, + ))) .addSubcommand(subcommand => subcommand .setName('bitrate') .setDescription('Change the bitrate of your Tent') @@ -372,9 +366,7 @@ export const dVoice: SlashCommand = { { name: 'Medium (128kbps)', value: '128' }, { name: 'High (256kbps)', value: '256' }, { name: 'Ultra (384kbps)', value: '384' }, - ), - ) - ), + ))), async execute(interaction) { log.info(F, await commandContext(interaction)); await interaction.deferReply({ ephemeral: true }); diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 10c42c4ce..169e99064 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -162,6 +162,6 @@ export async function teardownTent( } } channel.delete('Removing temporary voice chan!'); - } + } }); } From c6c0c07b23627c80c722149fb716eaf0d4df3816 Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Sun, 30 Jul 2023 12:59:44 -0500 Subject: [PATCH 20/33] One more lint --- src/discord/commands/guild/d.voice.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index fe5879dae..0d7b85817 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -189,8 +189,10 @@ async function tentRadio( .setDescription('There is already no radio in this Tent'); } // Find what radio bot is in the Tent and use the corresponding radio channel from the radioChannels object - // Check if the current channel has a radio bot in it by checking if any bots in the channel are in the radioChannels object - const botMember = voiceChannel.members.find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); + // Check if the current channel has a radio bot in it + // by checking if any bots in the channel are in the radioChannels object + const botMember = voiceChannel.members + .find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); if (botMember) { // If it does, find the corresponding radio channel from the bot id and move the bot to it const radioChannelId = radioChannels[botMember.user.id]; @@ -254,8 +256,10 @@ async function tentRadio( .setColor(Colors.Green) .setDescription(`${station} has been borrowed to your Tent`); } - // If the Tent already has a radio, find its corresonding channel in the radioChannels object and move it back before moving the new radio in - const botMember = station.voice.channel.members.find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); + // If the Tent already has a radio + // find its corresonding channel in the radioChannels object and move it back before moving the new radio in + const botMember = station.voice.channel.members + .find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); if (botMember) { // If it does, find the corresponding radio channel from the bot id and move the bot to it const radioChannelId = radioChannels[botMember.user.id]; From 16cdcfad9d1a63e54fa51e90a8f796d125bddf5e Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:10:16 -0500 Subject: [PATCH 21/33] Finish up --- src/discord/commands/guild/d.voice.ts | 61 +++++++++++++-------------- src/discord/utils/messageCommand.ts | 1 - 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index 0d7b85817..fcb15ad5a 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -29,30 +29,30 @@ async function tentRename( .setDescription(`${voiceChannel} has been renamed to ${newName}`); } -async function tentLock( - voiceChannel: VoiceBasedChannel, -):Promise { - let verb = ''; - - if ( - voiceChannel - .permissionsFor(voiceChannel.guild.roles.everyone) - .has(PermissionsBitField.Flags.ViewChannel) === true - ) { - voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: false }); - verb = 'hidden'; - } else { - voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: true }); - verb = 'unhidden'; - } - - // log.debug(F, `Channel is now ${verb}`); - - return embedTemplate() - .setTitle('Success') - .setColor(Colors.Green) - .setDescription(`${voiceChannel} has been ${verb}`); -} +// async function tentLock( +// voiceChannel: VoiceBasedChannel, +// ):Promise { +// let verb = ''; + +// if ( +// voiceChannel +// .permissionsFor(voiceChannel.guild.roles.everyone) +// .has(PermissionsBitField.Flags.ViewChannel) === true +// ) { +// voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: false }); +// verb = 'hidden'; +// } else { +// voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: true }); +// verb = 'unhidden'; +// } + +// // log.debug(F, `Channel is now ${verb}`); + +// return embedTemplate() +// .setTitle('Success') +// .setColor(Colors.Green) +// .setDescription(`${voiceChannel} has been ${verb}`); +// } async function tentHide( voiceChannel: VoiceBasedChannel, @@ -248,8 +248,8 @@ async function tentRadio( if (station.voice.channel?.parent?.id === env.CATEGORY_RADIO) { await station.voice.setChannel(voiceChannel); // Edit the corresponding radio channels name to indicate it is in use - const radioChannelId = radioChannels[station.user.id]; - const radioChannel = station.guild.channels.cache.get(radioChannelId) as VoiceChannel; + // const radioChannelId = radioChannels[station.user.id]; + // const radioChannel = station.guild.channels.cache.get(radioChannelId) as VoiceChannel; return embedTemplate() .setTitle('Success') @@ -315,9 +315,6 @@ export const dVoice: SlashCommand = { .setName('name') .setDescription('The new name for your Tent') .setRequired(true))) - .addSubcommand(subcommand => subcommand - .setName('lock') - .setDescription('Lock/Unlock the Tent from new users')) .addSubcommand(subcommand => subcommand .setName('hide') .setDescription('Hide/Unhide the Tent from the channel list')) @@ -423,9 +420,9 @@ export const dVoice: SlashCommand = { embed = await tentRename(voiceChannel, newName); } - if (command === 'lock') { - embed = await tentLock(voiceChannel); - } + // if (command === 'lock') { + // embed = await tentLock(voiceChannel); + // } if (command === 'hide') { embed = await tentHide(voiceChannel); diff --git a/src/discord/utils/messageCommand.ts b/src/discord/utils/messageCommand.ts index de2960ba0..c1213703c 100644 --- a/src/discord/utils/messageCommand.ts +++ b/src/discord/utils/messageCommand.ts @@ -6,7 +6,6 @@ import { // GuildTextBasedChannel, Role, PermissionResolvable, - TextChannel, ThreadChannel, EmbedBuilder, TextChannel, From 3db904cdc503036f041f63dfb3c03b0b388a1972 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Fri, 11 Aug 2023 16:38:52 +1000 Subject: [PATCH 22/33] Possible /voice radio fix No way to test in dev. Incorporated what was originally a separate function (checking if there is already a radio bot in the channel before moving a new one in), into the same part of the code that checks if the radio is available and pulls it in --- src/discord/commands/guild/d.voice.ts | 40 ++++++++++----------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index fcb15ad5a..fad66bebd 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -246,6 +246,20 @@ async function tentRadio( } // If the radio is available, move it to the Tent if (station.voice.channel?.parent?.id === env.CATEGORY_RADIO) { + + // Before moving, check if there is already another bot + const botMember = station.voice.channel.members + .find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); + if (botMember) { + // If there is, find the corresponding radio channel from the bot id and move the bot to it + const radioChannelId = radioChannels[botMember.user.id]; + // Get the radio channel from cache + const radioChannel = guild.channels.cache.get(radioChannelId) as VoiceChannel; + // If the radio channel exists, and is a voice channel, move the bot to it + if (radioChannel && radioChannel.type === ChannelType.GuildVoice) { + station.voice.setChannel(radioChannel.id); + } + } await station.voice.setChannel(voiceChannel); // Edit the corresponding radio channels name to indicate it is in use // const radioChannelId = radioChannels[station.user.id]; @@ -256,32 +270,6 @@ async function tentRadio( .setColor(Colors.Green) .setDescription(`${station} has been borrowed to your Tent`); } - // If the Tent already has a radio - // find its corresonding channel in the radioChannels object and move it back before moving the new radio in - const botMember = station.voice.channel.members - .find(member => member.user.bot && Object.keys(radioChannels).includes(member.user.id)); - if (botMember) { - // If it does, find the corresponding radio channel from the bot id and move the bot to it - const radioChannelId = radioChannels[botMember.user.id]; - // Get the radio channel from cache - const radioChannel = station.guild.channels.cache.get(radioChannelId) as VoiceChannel; - // If the radio channel exists, and is a voice channel, move the bot to it - if (radioChannel && radioChannel.type === ChannelType.GuildVoice) { - radioChannel.members.forEach((member: GuildMember) => { - if (member.user.bot) { - member.voice.setChannel(radioChannel); - } - }); - } - await station.voice.setChannel(voiceChannel); - } - - // log.debug(F, `${target.displayName} is now ${verb}`); - - return embedTemplate() - .setTitle('Success') - .setColor(Colors.Green) - .setDescription(`${station} has been borrowed to your Tent`); } async function tentBitrate( From 46de4a2f723468e6ce6fea22eb0f6764e32e4f28 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Fri, 11 Aug 2023 16:53:59 +1000 Subject: [PATCH 23/33] Make "user" entry for /timezone and /birthday required to speed up command entry --- src/discord/commands/guild/d.birthday.ts | 1 + src/discord/commands/guild/d.timezone.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/discord/commands/guild/d.birthday.ts b/src/discord/commands/guild/d.birthday.ts index 47bc6e45f..2583d6157 100644 --- a/src/discord/commands/guild/d.birthday.ts +++ b/src/discord/commands/guild/d.birthday.ts @@ -131,6 +131,7 @@ export const dBirthday: SlashCommand = { .setName('get') .setDescription('Get someone\'s birthday!') .addUserOption(option => option + .setRequired(true) .setName('user') .setDescription('User to lookup')) .addBooleanOption(option => option.setName('ephemeral') diff --git a/src/discord/commands/guild/d.timezone.ts b/src/discord/commands/guild/d.timezone.ts index e1fa2bcc2..c45f69b1b 100644 --- a/src/discord/commands/guild/d.timezone.ts +++ b/src/discord/commands/guild/d.timezone.ts @@ -17,6 +17,7 @@ export const dTimezone: SlashCommand = { .setName('get') .setDescription('Get someone\'s timezone!') .addUserOption(option => option + .setRequired(true) .setName('user') .setDescription('User to lookup')) .addBooleanOption(option => option.setName('ephemeral') From 768f2cf139b6da1b69ad4b6d417a6379eb79ccf9 Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Mon, 2 Oct 2023 18:43:06 +1100 Subject: [PATCH 24/33] Trivia, small fixes Re-enabled Trivia Stopped Verified role from being removed during tripsit session (stops welcome messages) Added code for /voice add (disabled) Removed /voice radio (just way too buggy) Small edit to welcome message --- src/discord/commands/guild/d.rpg.ts | 10 +- src/discord/commands/guild/d.voice.ts | 132 +++++++++++++++--------- src/discord/events/guildMemberUpdate.ts | 2 +- src/discord/utils/tents.ts | 1 - src/discord/utils/tripsitme.ts | 8 +- 5 files changed, 91 insertions(+), 62 deletions(-) diff --git a/src/discord/commands/guild/d.rpg.ts b/src/discord/commands/guild/d.rpg.ts index 689475191..f96263604 100644 --- a/src/discord/commands/guild/d.rpg.ts +++ b/src/discord/commands/guild/d.rpg.ts @@ -1939,7 +1939,7 @@ export async function rpgArcade( .addComponents( customButton(`rpgCoinFlip,user:${interaction.user.id}`, 'CoinFlip', 'buttonCoinflip', ButtonStyle.Secondary), customButton(`rpgRoulette,user:${interaction.user.id}`, 'Roulette', 'buttonRoulette', ButtonStyle.Secondary), - // customButton(`rpgTrivia,user:${interaction.user.id}`, 'Trivia', 'buttonTrivia', ButtonStyle.Secondary), + customButton(`rpgTrivia,user:${interaction.user.id}`, 'Trivia', 'buttonTrivia', ButtonStyle.Secondary), // customButton(`rpgBlackjack,user:${interaction.user.id}`, 'Blackjack', '🃏', ButtonStyle.Primary), // customButton(`rpgSlots,user:${interaction.user.id}`, 'Slots', '🎰', ButtonStyle.Primary), customButton(`rpgTown,user:${interaction.user.id}`, 'Town', 'buttonTown', ButtonStyle.Primary), @@ -3171,10 +3171,10 @@ export const dRpg: SlashCommand = { .setDescription('Go to the coinflip game')) .addSubcommand(subcommand => subcommand .setName('roulette') - .setDescription('Go to the roulette game')), - // .addSubcommand(subcommand => subcommand - // .setName('trivia') - // .setDescription('Go to the trivia parlor')), + .setDescription('Go to the roulette game')) + .addSubcommand(subcommand => subcommand + .setName('trivia') + .setDescription('Go to the trivia parlor')), async execute(interaction) { log.info(F, await commandContext(interaction)); const channelRpg = await interaction.guild?.channels.fetch(env.CHANNEL_TRIPTOWN as string) as TextChannel; diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index b0a2ea7e0..f8cf95a8b 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -1,7 +1,4 @@ import { - VoiceChannel, - ChannelType, - Guild, VoiceChannel, ChannelType, Guild, @@ -18,7 +15,7 @@ import commandContext from '../../utils/context'; const F = f(__filename); -type VoiceActions = 'lock' | 'hide' | 'ban' | 'rename' | 'mute' | 'cohost' | 'radio' | 'bitrate'; +type VoiceActions = 'lock' | 'hide' | 'add' | 'ban' | 'rename' | 'mute' | 'cohost' | 'radio' | 'bitrate'; async function tentRename( voiceChannel: VoiceBasedChannel, @@ -34,30 +31,27 @@ async function tentRename( .setDescription(`${voiceChannel} has been renamed to ${newName}`); } -// async function tentLock( -// voiceChannel: VoiceBasedChannel, -// ):Promise { -// let verb = ''; - -// if ( -// voiceChannel -// .permissionsFor(voiceChannel.guild.roles.everyone) -// .has(PermissionsBitField.Flags.ViewChannel) === true -// ) { -// voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: false }); -// verb = 'hidden'; -// } else { -// voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { ViewChannel: true }); -// verb = 'unhidden'; -// } - -// // log.debug(F, `Channel is now ${verb}`); - -// return embedTemplate() -// .setTitle('Success') -// .setColor(Colors.Green) -// .setDescription(`${voiceChannel} has been ${verb}`); -// } +async function tentLock( + voiceChannel: VoiceBasedChannel, +):Promise { + let verb = ''; + if ( + voiceChannel + .permissionsFor(voiceChannel.guild.roles.everyone) + .has(PermissionsBitField.Flags.Connect) === true + ) { + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { Connect: false }); + verb = 'locked'; + } else { + voiceChannel.permissionOverwrites.edit(voiceChannel.guild.roles.everyone, { Connect: true }); + verb = 'unlocked'; + } + // log.debug(F, `Channel is now ${verb}`); + return embedTemplate() + .setTitle('Success') + .setColor(Colors.Green) + .setDescription(`${voiceChannel} has been ${verb}`); +} async function tentHide( voiceChannel: VoiceBasedChannel, @@ -84,21 +78,49 @@ async function tentHide( .setDescription(`${voiceChannel} has been ${verb}`); } +// async function tentAdd( +// voiceChannel: VoiceBasedChannel, +// target: GuildMember, +// ):Promise { +// let verb = ''; +// +// if (voiceChannel.permissionsFor(target).has(PermissionsBitField.Flags.ViewChannel) === false){ +// return embedTemplate() +// .setTitle('Error') +// .setColor(Colors.Red) +// .setDescription(`${target} is banned from ${voiceChannel}, unban them first!`); +// } +// +// if (!voiceChannel.permissionsFor(target).has(PermissionsBitField.Flags.ViewChannel) === true){ +// voiceChannel.permissionOverwrites.create(target, { ViewChannel: true, Connect: true }); +// verb = 'added'; +// } else { +// voiceChannel.permissionOverwrites.delete(target); +// verb = 'unadded'; +// } +// // log.debug(F, `${target.displayName} is now ${verb}`); +// +// return embedTemplate() +// .setTitle('Success') +// .setColor(Colors.Green) +// .setDescription(`${target} has been ${verb} from ${voiceChannel}`); +// } + async function tentBan( voiceChannel: VoiceBasedChannel, target: GuildMember, ):Promise { let verb = ''; - if (voiceChannel.permissionsFor(target).has(PermissionsBitField.Flags.ViewChannel) === true) { + if (!voiceChannel.permissionsFor(target).has(PermissionsBitField.Flags.ViewChannel) === false) { voiceChannel.permissionOverwrites.edit(target, { ViewChannel: false, Connect: false }); if (target.voice.channel === voiceChannel) { target.voice.setChannel(null); } - verb = 'banned and hidden'; + verb = 'banned and disconnected'; } else { - voiceChannel.permissionOverwrites.edit(target, { ViewChannel: true, Connect: true }); - verb = 'unbanned and unhidden'; + voiceChannel.permissionOverwrites.delete(target);; + verb = 'unbanned'; } // log.debug(F, `${target.displayName} is now ${verb}`); @@ -166,12 +188,22 @@ export const dVoice: SlashCommand = { .setName('name') .setDescription('The new name for your Tent') .setRequired(true))) + .addSubcommand(subcommand => subcommand + .setName('lock') + .setDescription('Lock/Unlock the Tent')) .addSubcommand(subcommand => subcommand .setName('hide') - .setDescription('Hide/Unhide the Tent from the channel list')) + .setDescription('Remove the Tent from the channel list')) + // .addSubcommand(subcommand => subcommand + // .setName('add') + // .setDescription('Allow a user to join your Tent when locked or hidden') + // .addUserOption(option => option + // .setName('target') + // .setDescription('The user to add/unadd') + // .setRequired(true))) .addSubcommand(subcommand => subcommand .setName('ban') - .setDescription('Ban/Unban and hide a user from your Tent') + .setDescription('Ban and disconnect a user from your Tent') .addUserOption(option => option .setName('target') .setDescription('The user to ban/unban') @@ -185,7 +217,7 @@ export const dVoice: SlashCommand = { .setRequired(true))) .addSubcommand(subcommand => subcommand .setName('cohost') - .setDescription('Make another member a co-host in your Tent') + .setDescription('Make another user able to use /voice commands') .addUserOption(option => option .setName('target') .setDescription('The user to make co-host') @@ -260,25 +292,31 @@ export const dVoice: SlashCommand = { return false; } - // // Check if the target user is a moderator - // if (target.roles.cache.has(env.ROLE_MODERATOR)) { - // await interaction.editReply({ embeds: [embed.setDescription('You cannot ban a moderator!')] }); - // return false; - // } + // Check if the target user is a moderator + if (target){ + if (target.roles.cache.has(env.ROLE_MODERATOR)) { + await interaction.editReply({ embeds: [embed.setDescription('You cannot do that to a moderator!')] }); + return false; + } + } // log.debug(F, `Command: ${command}`); if (command === 'rename') { embed = await tentRename(voiceChannel, newName); } - // if (command === 'lock') { - // embed = await tentLock(voiceChannel); - // } + if (command === 'lock') { + embed = await tentLock(voiceChannel); + } if (command === 'hide') { embed = await tentHide(voiceChannel); } + // if (command === 'add') { + // embed = await tentAdd(voiceChannel, target); + // } + if (command === 'ban') { embed = await tentBan(voiceChannel, target); } @@ -291,14 +329,6 @@ export const dVoice: SlashCommand = { embed = await tentCohost(voiceChannel, target); } - if (command === 'radio') { - embed = await tentRadio(voiceChannel, stationid, guild); - } - - if (command === 'bitrate') { - embed = await tentBitrate(voiceChannel, bitrate); - } - await interaction.editReply({ embeds: [embed] }); return true; }, diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 93e331274..5db5488f8 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -340,7 +340,7 @@ async function addedVerified( await channelLounge.send({ content: stripIndents`**${greeting}** - Be safe, have fun, /report any issues! + Be safe, have fun, and don't forget to visit the for more information! *${await topic()}*`, }); diff --git a/src/discord/utils/tents.ts b/src/discord/utils/tents.ts index 81b1413d1..39eadf185 100644 --- a/src/discord/utils/tents.ts +++ b/src/discord/utils/tents.ts @@ -107,7 +107,6 @@ export async function pitchTent( - You can pick up this role in - **Modify your tent** - - \`/voice radio\` - Borrow a radio bot for your tent - \`/voice bitrate\` - Change the bitrate of your tent - \`/voice rename\` - Choose a new name for your tent diff --git a/src/discord/utils/tripsitme.ts b/src/discord/utils/tripsitme.ts index d8ac8915c..cafe624f0 100644 --- a/src/discord/utils/tripsitme.ts +++ b/src/discord/utils/tripsitme.ts @@ -94,11 +94,11 @@ const mindsetRoles = [ env.ROLE_SOBER, ]; -// const otherRoles = [ -// env.ROLE_VERIFIED, -// ]; +const otherRoles = [ + env.ROLE_VERIFIED, +]; -const ignoredRoles = `${teamRoles},${colorRoles},${mindsetRoles}`; +const ignoredRoles = `${teamRoles},${colorRoles},${mindsetRoles},${otherRoles}`; const guildOnly = 'This must be performed in a guild!'; const memberOnly = 'This must be performed by a member of a guild!'; From e2448e1a721748e364708ef11f111836ef58f6c6 Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Thu, 5 Oct 2023 23:27:25 -0500 Subject: [PATCH 25/33] Undo required --- src/discord/commands/guild/d.birthday.ts | 2 +- src/discord/commands/guild/d.timezone.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/discord/commands/guild/d.birthday.ts b/src/discord/commands/guild/d.birthday.ts index 2583d6157..2440727e6 100644 --- a/src/discord/commands/guild/d.birthday.ts +++ b/src/discord/commands/guild/d.birthday.ts @@ -131,7 +131,7 @@ export const dBirthday: SlashCommand = { .setName('get') .setDescription('Get someone\'s birthday!') .addUserOption(option => option - .setRequired(true) + // .setRequired(true) If nothing is provided it defaults to the user who ran the command .setName('user') .setDescription('User to lookup')) .addBooleanOption(option => option.setName('ephemeral') diff --git a/src/discord/commands/guild/d.timezone.ts b/src/discord/commands/guild/d.timezone.ts index c45f69b1b..93e454065 100644 --- a/src/discord/commands/guild/d.timezone.ts +++ b/src/discord/commands/guild/d.timezone.ts @@ -17,7 +17,7 @@ export const dTimezone: SlashCommand = { .setName('get') .setDescription('Get someone\'s timezone!') .addUserOption(option => option - .setRequired(true) + // .setRequired(true) If nothing is provided it defaults to the user who ran the command .setName('user') .setDescription('User to lookup')) .addBooleanOption(option => option.setName('ephemeral') From a78e37602c9aa2511be5c1c2572b92a0e4222293 Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Thu, 5 Oct 2023 23:27:42 -0500 Subject: [PATCH 26/33] Linting --- src/discord/commands/guild/d.rpg.ts | 4 ++-- src/discord/commands/guild/d.voice.ts | 26 ++++++++++------------- src/discord/utils/messageCommand.ts | 30 --------------------------- 3 files changed, 13 insertions(+), 47 deletions(-) diff --git a/src/discord/commands/guild/d.rpg.ts b/src/discord/commands/guild/d.rpg.ts index f96263604..c752c00d3 100644 --- a/src/discord/commands/guild/d.rpg.ts +++ b/src/discord/commands/guild/d.rpg.ts @@ -3173,8 +3173,8 @@ export const dRpg: SlashCommand = { .setName('roulette') .setDescription('Go to the roulette game')) .addSubcommand(subcommand => subcommand - .setName('trivia') - .setDescription('Go to the trivia parlor')), + .setName('trivia') + .setDescription('Go to the trivia parlor')), async execute(interaction) { log.info(F, await commandContext(interaction)); const channelRpg = await interaction.guild?.channels.fetch(env.CHANNEL_TRIPTOWN as string) as TextChannel; diff --git a/src/discord/commands/guild/d.voice.ts b/src/discord/commands/guild/d.voice.ts index f8cf95a8b..15f58f49f 100644 --- a/src/discord/commands/guild/d.voice.ts +++ b/src/discord/commands/guild/d.voice.ts @@ -1,7 +1,5 @@ import { - VoiceChannel, - ChannelType, - Guild, + // Guild, Colors, SlashCommandBuilder, GuildMember, @@ -83,14 +81,14 @@ async function tentHide( // target: GuildMember, // ):Promise { // let verb = ''; -// +// // if (voiceChannel.permissionsFor(target).has(PermissionsBitField.Flags.ViewChannel) === false){ // return embedTemplate() // .setTitle('Error') // .setColor(Colors.Red) // .setDescription(`${target} is banned from ${voiceChannel}, unban them first!`); // } -// +// // if (!voiceChannel.permissionsFor(target).has(PermissionsBitField.Flags.ViewChannel) === true){ // voiceChannel.permissionOverwrites.create(target, { ViewChannel: true, Connect: true }); // verb = 'added'; @@ -99,7 +97,7 @@ async function tentHide( // verb = 'unadded'; // } // // log.debug(F, `${target.displayName} is now ${verb}`); -// +// // return embedTemplate() // .setTitle('Success') // .setColor(Colors.Green) @@ -119,7 +117,7 @@ async function tentBan( } verb = 'banned and disconnected'; } else { - voiceChannel.permissionOverwrites.delete(target);; + voiceChannel.permissionOverwrites.delete(target); verb = 'unbanned'; } @@ -259,9 +257,9 @@ export const dVoice: SlashCommand = { const member = interaction.member as GuildMember; const target = interaction.options.getMember('target') as GuildMember; const newName = interaction.options.getString('name') as string; - const stationid = interaction.options.getString('station') as string; - const guild = interaction.guild as Guild; - const bitrate = interaction.options.getString('bitrate') as string; + // const stationid = interaction.options.getString('station') as string; + // const guild = interaction.guild as Guild; + // const bitrate = interaction.options.getString('bitrate') as string; const voiceChannel = member.voice.channel; let embed = embedTemplate() .setTitle('Error') @@ -293,11 +291,9 @@ export const dVoice: SlashCommand = { } // Check if the target user is a moderator - if (target){ - if (target.roles.cache.has(env.ROLE_MODERATOR)) { - await interaction.editReply({ embeds: [embed.setDescription('You cannot do that to a moderator!')] }); - return false; - } + if (target && target.roles.cache.has(env.ROLE_MODERATOR)) { + await interaction.editReply({ embeds: [embed.setDescription('You cannot do that to a moderator!')] }); + return false; } // log.debug(F, `Command: ${command}`); diff --git a/src/discord/utils/messageCommand.ts b/src/discord/utils/messageCommand.ts index 515d82a83..93844506c 100644 --- a/src/discord/utils/messageCommand.ts +++ b/src/discord/utils/messageCommand.ts @@ -1,14 +1,10 @@ /* eslint-disable max-len */ import { - // ChannelType, Message, - // GuildTextBasedChannel, Role, PermissionResolvable, - ThreadChannel, EmbedBuilder, - TextChannel, } from 'discord.js'; import { stripIndents } from 'common-tags'; import { sleep } from '../commands/guild/d.bottest'; @@ -281,32 +277,6 @@ give people a chance to answer 😄 If no one answers in 5 minutes you can try a if (message.guild.id !== env.DISCORD_GUILD_ID) return; // log.debug(F, 'Sad stuff detected'); await message.react(heartEmojis[Math.floor(Math.random() * heartEmojis.length)]); - } else if ( - message.content.match(/(?:anyone|someone+there|here)\b/) - && (message.channel as ThreadChannel).parent?.parentId !== env.CATEGORY_HARMREDUCTIONCENTRE - && (message.channel as TextChannel).parentId !== env.CATEGORY_HARMREDUCTIONCENTRE - ) { - // Find when the last message in that channel was sent - const lastMessage = await message.channel.messages.fetch({ - before: message.id, - limit: 1, - }); - const lastMessageDate = lastMessage.first()?.createdAt; - - // Check if the last message was send in the last 10 minutes - if (lastMessageDate && lastMessageDate.valueOf() > Date.now() - 1000 * 60 * 10) { - // If it was, then don't send the message - return; - } - - await message.channel.sendTyping(); - setTimeout(async () => { - await (message.channel.send({ - content: stripIndents`Hey ${message.member?.displayName}! - Sometimes chat slows down, but go ahead and ask your question: Someone will get back to you when they can! - Who knows, maybe someone is lurking and waiting for the right question... :eyes: `, - })); - }, 2000); } // else if ( // message.content.match(/(?:anyone|someone+there|here)\b/) From 083e375c45e3d677ddebbf0b7b06a708b0269ede Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Thu, 5 Oct 2023 23:27:54 -0500 Subject: [PATCH 27/33] Fixing actions --- .github/workflows/PullRequestOpenAll.yml | 36 +++++++++---------- .github/workflows/PushToMain.yml | 36 +++++++++---------- .../{ => archive}/EveryFridayScan.yml | 0 3 files changed, 36 insertions(+), 36 deletions(-) rename .github/workflows/{ => archive}/EveryFridayScan.yml (100%) diff --git a/.github/workflows/PullRequestOpenAll.yml b/.github/workflows/PullRequestOpenAll.yml index 21d965c39..82f053a46 100644 --- a/.github/workflows/PullRequestOpenAll.yml +++ b/.github/workflows/PullRequestOpenAll.yml @@ -27,24 +27,24 @@ jobs: run: npm install eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-airbnb-base eslint-config-airbnb-typescript eslint-config-google eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-jest eslint-plugin-sonarjs --save-dev && npx eslint --version - name: Linting run: npx eslint --ext .ts,.js . - test: - name: Test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js '20.5.0' - uses: actions/setup-node@v3 - with: - node-version: '20.5.0' - cache: 'npm' - - name: Update npm - run: npm install -g npm && npm --version - - name: Install dependencies - run: npm ci - - name: Copy env - run: cp .env.example .env - - name: Test - run: npx jest --silent -c ./src/jest/jest.unit.config.ts + # test: + # name: Test + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - name: Use Node.js '20.5.0' + # uses: actions/setup-node@v3 + # with: + # node-version: '20.5.0' + # cache: 'npm' + # - name: Update npm + # run: npm install -g npm && npm --version + # - name: Install dependencies + # run: npm ci + # - name: Copy env + # run: cp .env.example .env + # - name: Test + # run: npx jest --silent -c ./src/jest/jest.unit.config.ts codeql: name: CodeQL runs-on: ubuntu-latest diff --git a/.github/workflows/PushToMain.yml b/.github/workflows/PushToMain.yml index c843ab1fa..d5c5b6707 100644 --- a/.github/workflows/PushToMain.yml +++ b/.github/workflows/PushToMain.yml @@ -22,24 +22,24 @@ jobs: run: npm install eslint eslint-config-airbnb-base eslint-config-airbnb-typescript eslint-config-google eslint-import-resolver-typescript eslint-plugin-import --save-dev && npx eslint --version - name: Linting run: npx eslint --ext .ts,.js . - test: - name: Test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js '20.5.0' - uses: actions/setup-node@v3 - with: - node-version: '20.5.0' - cache: 'npm' - - name: Update npm - run: npm install -g npm && npm --version - - name: Install dependencies - run: npm ci - - name: Copy env - run: cp .env.example .env - - name: Test - run: npx jest --silent -c ./src/jest/jest.unit.config.ts + # test: + # name: Test + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - name: Use Node.js '20.5.0' + # uses: actions/setup-node@v3 + # with: + # node-version: '20.5.0' + # cache: 'npm' + # - name: Update npm + # run: npm install -g npm && npm --version + # - name: Install dependencies + # run: npm ci + # - name: Copy env + # run: cp .env.example .env + # - name: Test + # run: npx jest --silent -c ./src/jest/jest.unit.config.ts codeql: name: CodeQL runs-on: ubuntu-latest diff --git a/.github/workflows/EveryFridayScan.yml b/.github/workflows/archive/EveryFridayScan.yml similarity index 100% rename from .github/workflows/EveryFridayScan.yml rename to .github/workflows/archive/EveryFridayScan.yml From 3c5615e371958cc59f3093a6fa0038b4442c446c Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Sat, 28 Oct 2023 19:42:41 +1100 Subject: [PATCH 28/33] New donator system Becoming a patron sub now also gives the "Premium Member" role. This new role is what activates all the donator benefits. Supporter role now only acts as a cosmetic with as a hoisted role with gem icon. Premium Member is permanent for Patreon or Kofi donations. Booster is unchanged and all donator perks for boosters is removed once they stop boosting. --- src/discord/events/guildMemberUpdate.ts | 18 ++++++++++-------- src/global/utils/env.config.ts | 6 ++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 5db5488f8..03157ba1e 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -131,7 +131,7 @@ async function donorColorCheck( // log.debug(F, `donor color role added: ${roleId}`); // If it does, check if the user also has a donor role if (oldMember.roles.cache.has(env.ROLE_BOOSTER) - || oldMember.roles.cache.has(env.ROLE_PATRON) + || oldMember.roles.cache.has(env.ROLE_PREMIUM) || oldMember.roles.cache.has(env.ROLE_TEAMTRIPSIT)) { log.debug(F, 'Donor added a color role!'); } else { @@ -153,8 +153,8 @@ async function donorColorRemove( ) { // log.debug(F, `donor color role removed: ${roleId}`); // log.debug(F, `${Object.keys(donorRoles)}`); - // Check if it's a donor role - if (Object.values(donorRoles).includes(roleId)) { + // Check if it's the booster role, if it is, remove colour role if they don't also have the premium role + if (roleId === env.ROLE_BOOSTER && !newMember.roles.cache.has(env.ROLE_PREMIUM) || (roleId === env.ROLE_PREMIUM)){ // log.debug(F, `donor role removed: ${roleId}`); // If it does, check if the user also has a role id matching a donorColorRole and if so, remove it const donorColorRole = newMember.roles.cache.find(role => Object.values(donorColorRoles).includes(role.id)); @@ -354,8 +354,8 @@ async function addedBooster( // Check if the role added was a donator role if (roleId === env.ROLE_BOOSTER) { // log.debug(F, `${newMember.displayName} boosted the server!`); - const channelGoldlounge = await discordClient.channels.fetch(env.CHANNEL_GOLDLOUNGE) as TextChannel; - await channelGoldlounge.send(`Hey @here, ${newMember} just boosted the server, give them a big thank you for helping to keep this place awesome!`); // eslint-disable-line max-len + const channelviplounge = await discordClient.channels.fetch(env.CHANNEL_VIPLOUNGE) as TextChannel; + await channelviplounge.send(`${newMember} just boosted the server, give them a big thank you for helping to keep this place awesome!`); // eslint-disable-line max-len } } @@ -364,11 +364,13 @@ async function addedPatreon( roleId: string, ) { // Check if the role added was a donator role - if (roleId === env.ROLE_PATRON) { + if (roleId === env.ROLE_PREMIUM) { // log.debug(F, `${newMember.displayName} became a patron!`); - const channelGoldlounge = await discordClient.channels.fetch(env.CHANNEL_GOLDLOUNGE) as TextChannel; + const channelviplounge = await discordClient.channels.fetch(env.CHANNEL_VIPLOUNGE) as TextChannel; const isProd = env.NODE_ENV === 'production'; - await channelGoldlounge.send(`Hey ${isProd ? '@here' : 'here'}, ${newMember} just became a patron, give them a big thank you for helping us keep the lights on and expand!`); // eslint-disable-line max-len + // Give them the "Premium Member role" + await newMember.roles.add(env.ROLE_PREMIUM); + await channelviplounge.send(`${newMember} just became a Premium Member by donating via [Patreon](https://www.patreon.com/TripSit) or [KoFi](KOFI URL HERE!), give them a big **thank you** for helping us keep the lights on and expand!`); // eslint-disable-line max-len } } diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index b755bbde7..ad308b9d5 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -266,10 +266,8 @@ export const env = { ROLE_VUTEUNDERBAN: isProd ? '991811318464139416' : '989287082222579792', ROLE_PATRON: isProd ? '954133862601089095' : '1052644652349665310', - ROLE_TREE: isProd ? '954133862601089095' : '960606558050480148', - ROLE_SPROUT: isProd ? '955618510631993414' : '960606557622657033', - ROLE_SEEDLING: isProd ? '955618661274644491' : '960606557622657032', - ROLE_BOOSTER: isProd ? '853082033224024135' : '980116577846431774', + ROLE_PREMIUM: isProd ? '1139454371613122640' : '1167714206418735144', + ROLE_BOOSTER: isProd ? '853082033224024135' : '1167725202302574642', ROLE_DRUNK: isProd ? '955485069294854154' : '1052644628639252500', ROLE_HIGH: isProd ? '955482289335320626' : '1052644630912577586', From 555d500396ee770747c11ebe3aad74920d24192f Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Sat, 28 Oct 2023 19:44:16 +1100 Subject: [PATCH 29/33] Update env.config.ts --- src/global/utils/env.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index ad308b9d5..2a6332dce 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -267,7 +267,7 @@ export const env = { ROLE_PATRON: isProd ? '954133862601089095' : '1052644652349665310', ROLE_PREMIUM: isProd ? '1139454371613122640' : '1167714206418735144', - ROLE_BOOSTER: isProd ? '853082033224024135' : '1167725202302574642', + ROLE_BOOSTER: isProd ? '853082033224024135' : '980116577846431774', ROLE_DRUNK: isProd ? '955485069294854154' : '1052644628639252500', ROLE_HIGH: isProd ? '955482289335320626' : '1052644630912577586', From 47e9236b3a7b2c71934391b6051e14bf86587c6d Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Sat, 28 Oct 2023 23:28:38 +1100 Subject: [PATCH 30/33] Add kofi link --- src/discord/events/guildMemberUpdate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 03157ba1e..18f746663 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -370,7 +370,7 @@ async function addedPatreon( const isProd = env.NODE_ENV === 'production'; // Give them the "Premium Member role" await newMember.roles.add(env.ROLE_PREMIUM); - await channelviplounge.send(`${newMember} just became a Premium Member by donating via [Patreon](https://www.patreon.com/TripSit) or [KoFi](KOFI URL HERE!), give them a big **thank you** for helping us keep the lights on and expand!`); // eslint-disable-line max-len + await channelviplounge.send(`${newMember} just became a Premium Member by donating via [Patreon](https://www.patreon.com/TripSit) or [KoFi](https://ko-fi.com/tripsit), give them a big **thank you** for helping us keep the lights on and expand!`); // eslint-disable-line max-len } } From c78877210cd9a8222a0857bc53c50960a9c01bdf Mon Sep 17 00:00:00 2001 From: Hipperooni Date: Mon, 30 Oct 2023 21:16:32 +1100 Subject: [PATCH 31/33] Ignore donor roles in tripsit mode To prevent duplicate donation announcement messages --- src/discord/utils/tripsitme.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/discord/utils/tripsitme.ts b/src/discord/utils/tripsitme.ts index cafe624f0..8fb5fde5c 100644 --- a/src/discord/utils/tripsitme.ts +++ b/src/discord/utils/tripsitme.ts @@ -96,6 +96,9 @@ const mindsetRoles = [ const otherRoles = [ env.ROLE_VERIFIED, + env.ROLE_PREMIUM, + env.ROLE_BOOSTER, + env.ROLE_PATRON, ]; const ignoredRoles = `${teamRoles},${colorRoles},${mindsetRoles},${otherRoles}`; From 09e1c0806376286752e6ef28f45a2b1dde3219be Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:33:27 -0500 Subject: [PATCH 32/33] Update d.donate and a few minor things --- src/discord/commands/global/d.donate.ts | 37 +++++++++++--- src/discord/events/guildMemberUpdate.ts | 64 +++++++++++++++++-------- src/global/commands/g.donate.ts | 10 ++-- src/global/utils/env.config.ts | 2 +- 4 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/discord/commands/global/d.donate.ts b/src/discord/commands/global/d.donate.ts index 5fad2b502..892ca3e01 100644 --- a/src/discord/commands/global/d.donate.ts +++ b/src/discord/commands/global/d.donate.ts @@ -25,14 +25,37 @@ export const dDonate: SlashCommand = { const donateInfo = await donate(); const embed = embedTemplate() .setColor(Colors.Purple) - .setTitle('Donate to keep TripSit running and fund our future projects!') + .setTitle('🚀 **TripSit\'s Donation Info!** 🚀') .setURL('https://tripsit.me/donate/') - .setDescription( - stripIndents`The best way to support us is to join the discord and help out people! - We run on volunteers and need your help to keep the org going - If you can donate, our preferred method is Patreon, and we're happy for all donation sizes! - You can get supporter benefits for as little as $1 a month!`, - ); + .setDescription(stripIndents` + At TripSit, we're all about harm reduction, and we'll never charge for our services or hide information behind paywalls or annoying ads. Our mission is to help anyone who needs it, no strings attached. 🌟 + + But we can't pay for servers with good intentions alone, so your support means the world to us. + + There are two awesome ways to contribute: + + 1️⃣ **Patreon Subscription** + For as little as $1 a month, you can become a patron and keep supporting the good cause. 🌈 + + 2️⃣ **Ko-Fi Donation** + If that isn't your style, you can give a one-time boost to our cause through Ko-Fi. ☕ + + 🎁 What's in it for you? Well, we've got some fantastic benefits for our supporters: + + - 📣 **Announcement**: We'll tell the guild you've made a difference in #vip-lounge. + - 🪙 **Gold Lounge Access**: Gain entry to our exclusive donor space, #gold-lounge. + - 🌈 **Special Donor Colors**: Deck out your Discord persona with unique colors. + - 💎 **Supporter Role (Patreon)**: Be shown at the top of the member list with a unique icon. + - 🎉 More surprises are in the works! Your suggestions are welcome. + + These are **permanent** benefits, excluding the Supporter role, which is only for active Patreons. + + No spare change? Boosting our server will also give you donor perks while your boost is active! + + Your donations directly fuel our server costs, ensuring TripSit keeps doing what we do best. 🌐 With enough support, we can even expand and provide new services – who's up for a Minecraft server? 😎 + + Thank you for being a part of our journey, and for helping make the world a safer place! 💕 + `); // for (const entry of donateInfo) { donateInfo.forEach(entry => { if (entry.value.length > 0) { diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 18f746663..1eb79ec29 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -106,18 +106,36 @@ const donorColorRoles = { [key in DonorColorNames]: string; }; -type DonorNames = -| 'ROLE_BOOSTER' -| 'ROLE_PATRON' -| 'ROLE_TEAMTRIPSIT'; - -const donorRoles = { - ROLE_BOOSTER: env.ROLE_BOOSTER, - ROLE_PATRON: env.ROLE_PATRON, - ROLE_TEAMTRIPSIT: env.ROLE_TEAMTRIPSIT, -} as { - [key in DonorNames]: string; -}; +// type DonorNames = +// | 'ROLE_BOOSTER' +// | 'ROLE_PATRON' +// | 'ROLE_TEAMTRIPSIT'; + +// const donorRoles = { +// ROLE_BOOSTER: env.ROLE_BOOSTER, +// ROLE_PATRON: env.ROLE_PATRON, +// ROLE_TEAMTRIPSIT: env.ROLE_TEAMTRIPSIT, +// } as { +// [key in DonorNames]: string; +// }; + +const thankYouPhrases = [ + 'A heartfelt thanks for their generous contribution. Your support is invaluable!', + "Big shout out for their donation. We couldn't do it without you!", + 'Thank you for your incredible support. Your contribution makes a world of difference.', + 'Our gratitude knows no bounds. Thank you for helping us grow and thrive.', + "We're over the moon with your donation. Your generosity warms our hearts.", + 'A round of applause! Your donation keeps our mission alive and thriving.', + 'A standing ovation! Your support illuminates our path forward.', + "With your donation, you've become a crucial part of our journey. Thank you!", + 'Thank you for being a beacon of support. You light up our endeavors.', + "Our deepest gratitude for their contribution. Together, we'll reach new heights.", +]; + +const donationTagline = '*`/donate` to TripSit to access special username colors and the snazzy Gold Lounge!*'; + +const boostEmoji = env.NODE_ENV === 'production' ? '<:ts_boost:981799280396353596>' : '<:ts_boost:1168968973082185800>'; +const donorEmoji = env.NODE_ENV === 'production' ? '<:ts_donor:1121625178774966272>' : '<:ts_donor:1168969578836144233>'; const F = f(__filename); @@ -154,7 +172,8 @@ async function donorColorRemove( // log.debug(F, `donor color role removed: ${roleId}`); // log.debug(F, `${Object.keys(donorRoles)}`); // Check if it's the booster role, if it is, remove colour role if they don't also have the premium role - if (roleId === env.ROLE_BOOSTER && !newMember.roles.cache.has(env.ROLE_PREMIUM) || (roleId === env.ROLE_PREMIUM)){ + if ((roleId === env.ROLE_BOOSTER && !newMember.roles.cache.has(env.ROLE_PREMIUM)) + || (roleId === env.ROLE_PREMIUM && !newMember.roles.cache.has(env.ROLE_BOOSTER))) { // log.debug(F, `donor role removed: ${roleId}`); // If it does, check if the user also has a role id matching a donorColorRole and if so, remove it const donorColorRole = newMember.roles.cache.find(role => Object.values(donorColorRoles).includes(role.id)); @@ -355,7 +374,12 @@ async function addedBooster( if (roleId === env.ROLE_BOOSTER) { // log.debug(F, `${newMember.displayName} boosted the server!`); const channelviplounge = await discordClient.channels.fetch(env.CHANNEL_VIPLOUNGE) as TextChannel; - await channelviplounge.send(`${newMember} just boosted the server, give them a big thank you for helping to keep this place awesome!`); // eslint-disable-line max-len + await channelviplounge.send(stripIndents` + ** ${boostEmoji} ${newMember.toString()} just boosted the server! ${boostEmoji} ** + + ${thankYouPhrases[Math.floor(Math.random() * thankYouPhrases.length)]} + + ${donationTagline}`); } } @@ -363,14 +387,14 @@ async function addedPatreon( newMember: GuildMember, roleId: string, ) { - // Check if the role added was a donator role if (roleId === env.ROLE_PREMIUM) { - // log.debug(F, `${newMember.displayName} became a patron!`); const channelviplounge = await discordClient.channels.fetch(env.CHANNEL_VIPLOUNGE) as TextChannel; - const isProd = env.NODE_ENV === 'production'; - // Give them the "Premium Member role" - await newMember.roles.add(env.ROLE_PREMIUM); - await channelviplounge.send(`${newMember} just became a Premium Member by donating via [Patreon](https://www.patreon.com/TripSit) or [KoFi](https://ko-fi.com/tripsit), give them a big **thank you** for helping us keep the lights on and expand!`); // eslint-disable-line max-len + await channelviplounge.send(stripIndents` + ** ${donorEmoji} ${newMember} just became a Premium Member by donating via [Patreon]() or [KoFi]()! ${donorEmoji} ** + + ${thankYouPhrases[Math.floor(Math.random() * thankYouPhrases.length)]} + + ${donationTagline}`); } } diff --git a/src/global/commands/g.donate.ts b/src/global/commands/g.donate.ts index 9ea91ad25..ab18b92ce 100644 --- a/src/global/commands/g.donate.ts +++ b/src/global/commands/g.donate.ts @@ -9,16 +9,16 @@ export default donate; export async function donate():Promise { const response = [ { - name: 'Patreon (Preferred)', + name: 'Patreon Subscription', value: 'https://patreon.com/tripsit', }, { - name: 'Discord Boosts', - value: 'http://discord.gg/TripSit', + name: 'KoFi Tips', + value: 'https://ko-fi.com/tripsit', }, { - name: '\u200B', - value: '\u200B', + name: 'Discord Boosts', + value: 'http://discord.gg/TripSit', }, { name: 'Spreadshop', diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index 2a6332dce..ad308b9d5 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -267,7 +267,7 @@ export const env = { ROLE_PATRON: isProd ? '954133862601089095' : '1052644652349665310', ROLE_PREMIUM: isProd ? '1139454371613122640' : '1167714206418735144', - ROLE_BOOSTER: isProd ? '853082033224024135' : '980116577846431774', + ROLE_BOOSTER: isProd ? '853082033224024135' : '1167725202302574642', ROLE_DRUNK: isProd ? '955485069294854154' : '1052644628639252500', ROLE_HIGH: isProd ? '955482289335320626' : '1052644630912577586', From ab424ba207437717af8811cd1e481972f3d60b0a Mon Sep 17 00:00:00 2001 From: LunaUrsa <1836049+LunaUrsa@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:54:22 -0500 Subject: [PATCH 33/33] Add premium role add --- src/discord/events/guildMemberUpdate.ts | 19 +++++++++++++------ src/global/utils/env.config.ts | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/discord/events/guildMemberUpdate.ts b/src/discord/events/guildMemberUpdate.ts index 1eb79ec29..7dc0bac30 100644 --- a/src/discord/events/guildMemberUpdate.ts +++ b/src/discord/events/guildMemberUpdate.ts @@ -387,14 +387,21 @@ async function addedPatreon( newMember: GuildMember, roleId: string, ) { - if (roleId === env.ROLE_PREMIUM) { + if (roleId === env.ROLE_PATRON && !newMember.roles.cache.has(env.ROLE_PREMIUM)) { + // Check if the user already has the premium role + // If they don't add it, and send the message, remove the patreon role + const role = await newMember.guild.roles.fetch(env.ROLE_PREMIUM) as Role; + // log.debug(F, `Adding ${role.name} from ${newMember.displayName}`); + await newMember.roles.add(role); + // log.debug(F, `Added ${role.name} from ${newMember.displayName}`); + const channelviplounge = await discordClient.channels.fetch(env.CHANNEL_VIPLOUNGE) as TextChannel; await channelviplounge.send(stripIndents` - ** ${donorEmoji} ${newMember} just became a Premium Member by donating via [Patreon]() or [KoFi]()! ${donorEmoji} ** - - ${thankYouPhrases[Math.floor(Math.random() * thankYouPhrases.length)]} - - ${donationTagline}`); + ** ${donorEmoji} ${newMember} just became a Premium Member by donating via [Patreon]() or [KoFi]()! ${donorEmoji} ** + + ${thankYouPhrases[Math.floor(Math.random() * thankYouPhrases.length)]} + + ${donationTagline}`); } } diff --git a/src/global/utils/env.config.ts b/src/global/utils/env.config.ts index ad308b9d5..d4cb3c4cd 100644 --- a/src/global/utils/env.config.ts +++ b/src/global/utils/env.config.ts @@ -266,8 +266,8 @@ export const env = { ROLE_VUTEUNDERBAN: isProd ? '991811318464139416' : '989287082222579792', ROLE_PATRON: isProd ? '954133862601089095' : '1052644652349665310', - ROLE_PREMIUM: isProd ? '1139454371613122640' : '1167714206418735144', ROLE_BOOSTER: isProd ? '853082033224024135' : '1167725202302574642', + ROLE_PREMIUM: isProd ? '1139454371613122640' : '1167714206418735144', ROLE_DRUNK: isProd ? '955485069294854154' : '1052644628639252500', ROLE_HIGH: isProd ? '955482289335320626' : '1052644630912577586',