diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fa91f6f..3435181 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -11,7 +11,7 @@ A big welcome and thank you for considering contributing to this project. We wan * [References](#references) ## Code of Conduct -We take our open source community seriously and hold ourselves and other contributors to high standards of communication. By participating and contributing to this project, you agree to uphold yo our [Code Of Conduct](https://github.com/IESN-IG/DataDrop/blob/master/.github/CODE_OF_CONDUCT.md). +We take our open source community seriously and hold ourselves and other contributors to high standards of communication. By participating and contributing to this project, you agree to uphold yo our [Code Of Conduct](https://github.com/section-IG/DataDrop/blob/master/.github/CODE_OF_CONDUCT.md). ## Getting started We use [GitHub](https://github.com) to host code, to track Issues and feature requests, as well as accept Pull Requests (PRs). A few guidelines that cover all these topics: @@ -19,7 +19,7 @@ We use [GitHub](https://github.com) to host code, to track Issues and feature re - We work hard to makes sure issues are handled in a timely manner but, depending on the impact, it could take a while to investigate the root cause. A friendly ping in the comment thread to the submitter or a contributor can help draw attention if your issue is blocking. ### Issues -We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/IESN-IG/DataDrop/issues/new/choose); it's that easy! +We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/section-IG/DataDrop/issues/new/choose); it's that easy! **Great Bug Reports** tend to have: - A quick summary and/or background diff --git a/LICENSE b/LICENSE index 215826c..9a84975 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 IESN - IG +Copyright (c) 2019 Section - IODA Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6047f1b..d38005f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # DataDrop [![Continuous Delivery](https://github.com/Section-IG/DataDrop/actions/workflows/deployment.yml/badge.svg)](https://github.com/Section-IG/DataDrop/actions/workflows/deployment.yml) -Discord bot built with Discord.JS for Section IG guild. +Discord bot built with Discord.JS for Section IODA guild. The following environment variables must be filled in a `.env` file. This file is used when building the container to generate a production-ready .env file. diff --git a/config.development.json b/config.development.json index 13e3d2f..e4200d1 100644 --- a/config.development.json +++ b/config.development.json @@ -5,8 +5,8 @@ ], "minLevel": "debug", "includeTimestamp": true, - "prefix": "igb!", - "botName": "IG Bot Beta", + "prefix": "dab!", + "botName": "Yoda Beta", "communitymanagerRoleid": "1028257512383848478", "adminRoleid": "1028257512358674472", "delegatesRoleid": "1028257512358674468", @@ -14,7 +14,7 @@ "verifiedRoleId": "1048774508007407726", "informationsChannelid": "1028257513109454855", "faqChannelid": "1028257513109454856", - "igcomiteeChannelid": "1028257513109454857", + "comiteeChannelid": "1028257513109454857", "dynamicChannelPrefix": "[DRoom]", "dynamicChannelPrefixRegex": "^\\[DRoom\\]", "staticTriggerChannelids": [ @@ -25,7 +25,7 @@ "1028257515680583727" ], "rolesChannelid": "1028257513319170089", - "ig1": { + "first": { "channelid": "1028257513604390939", "roleid": "1028257512337711148", "emote": "1⃣", @@ -56,7 +56,7 @@ } ] }, - "ig2": { + "second": { "channelid": "1028257514296463431", "roleid": "1028257512337711152", "emote": "2⃣", @@ -75,7 +75,7 @@ } ] }, - "ig3": { + "third": { "channelid": "1028257514799779857", "roleid": "1028257512358674464", "emote": "3⃣", @@ -109,7 +109,6 @@ }, "ok_hand": "👌", "warning": "⚠️", - "zeroWidthSpace": "​", "communicationServiceOptions": { "mailData": { "from": "mdpdevti@henallux.be", diff --git a/config.production.json b/config.production.json index be2fafd..55edf5d 100644 --- a/config.production.json +++ b/config.production.json @@ -5,8 +5,8 @@ ], "minLevel": "info", "includeTimestamp": true, - "prefix": "ig!", - "botName": "IG Bot", + "prefix": "da!", + "botName": "Yoda", "communitymanagerRoleid": "288659580064366592", "adminRoleid": "360850813914185738", "delegatesRoleid": "288659613732306944", @@ -14,7 +14,7 @@ "verifiedRoleId": "1048774703206109264", "informationsChannelid": "288666915314991107", "faqChannelid": "360126831376203778", - "igcomiteeChannelid": "506564987914027008", + "comiteeChannelid": "506564987914027008", "dynamicChannelPrefix": "[DRoom]", "dynamicChannelPrefixRegex": "^\\[DRoom\\]", "staticTriggerChannelids": [ @@ -25,7 +25,7 @@ "762382057157558352" ], "rolesChannelid": "522843160594874368", - "ig1": { + "first": { "channelid": "764241363452690472", "roleid": "353210852700061696", "emote": "1⃣", @@ -56,7 +56,7 @@ } ] }, - "ig2": { + "second": { "channelid": "764241472534085662", "roleid": "353210788271357954", "emote": "2⃣", @@ -75,7 +75,7 @@ } ] }, - "ig3": { + "third": { "channelid": "628864027321303049", "roleid": "353210727978237952", "emote": "3⃣", @@ -109,7 +109,6 @@ }, "ok_hand": "👌", "warning": "⚠️", - "zeroWidthSpace": "​", "communicationServiceOptions": { "mailData": { "from": "mdpdevti@henallux.be", diff --git a/docker-compose.yaml b/docker-compose.yaml index 8fced0f..78b6e6f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -12,9 +12,7 @@ x-restart-policy: version: '3.8' services: database: - <<: *env-file - <<: *network - <<: *restart-policy + <<: [*env-file, *network, *restart-policy] build: context: . dockerfile: ./Database.Dockerfile @@ -30,9 +28,7 @@ services: timeout: 1s retries: 60 bot: - <<: *env-file - <<: *network - <<: *restart-policy + <<: [*env-file, *network, *restart-policy] build: context: . dockerfile: ./Dockerfile diff --git a/package.json b/package.json index 5138782..e3fd263 100644 --- a/package.json +++ b/package.json @@ -11,17 +11,17 @@ }, "repository": { "type": "git", - "url": "git+ssh://git@github.com:IESN-IG/DataDrop.git" + "url": "git+ssh://git@github.com:section-IG/DataDrop.git" }, "author": "HunteRoi ", "license": "MIT", "bugs": { - "url": "https://github.com/IESN-IG/DataDrop/issues" + "url": "https://github.com/section-IG/DataDrop/issues" }, - "homepage": "https://github.com/IESN-IG/DataDrop#readme", + "homepage": "https://github.com/section-IG/DataDrop#readme", "dependencies": { "@hunteroi/advanced-logger": "^0.0.3", - "@hunteroi/discord-selfrole": "^3.1.0", + "@hunteroi/discord-selfrole": "^3.2.0", "@hunteroi/discord-temp-channels": "^3.1.0", "@hunteroi/discord-verification": "^1.4.0", "discord.js": "^14.8.0", diff --git a/src/commands/email.ts b/src/commands/email.ts index fb2e285..b909a77 100644 --- a/src/commands/email.ts +++ b/src/commands/email.ts @@ -8,7 +8,7 @@ const people = [ emails: ['cehenallux@gmail.com'], }, { - name: 'Comité IG', + name: 'Comité IODA', emails: ['ighenallux@gmail.com'], }, ]; diff --git a/src/commands/eval.ts b/src/commands/eval.ts index e6e17cf..699d124 100644 --- a/src/commands/eval.ts +++ b/src/commands/eval.ts @@ -1,7 +1,7 @@ import { Message, codeBlock } from 'discord.js'; import { DatadropClient } from '../datadrop'; -import { Configuration } from '../models/Configuration'; +import { clean } from '../helpers'; module.exports = { name: 'eval', @@ -25,18 +25,11 @@ module.exports = { evaled = util.inspect(evaled); } - content = clean(evaled, config); + content = clean(evaled); } catch (err) { - content = `// An error occured\n\n${clean(err, config)}`; + content = `// An error occured\n\n${clean(err)}`; } finally { message.channel.send(codeBlock('xl', content)); } } }; - -function clean(text: any, config: Configuration): string { - if (typeof (text) === 'string') { - return text.replace(/@/g, `@${config.zeroWidthSpace}`); - } - return text; -} diff --git a/src/config.ts b/src/config.ts index 5111ae1..e31d2cf 100644 --- a/src/config.ts +++ b/src/config.ts @@ -17,20 +17,19 @@ const defaultConfig: Configuration = { verifiedRoleId: '', informationsChannelid: '', faqChannelid: '', - igcomiteeChannelid: '', + comiteeChannelid: '', dynamicChannelPrefix: '', dynamicChannelPrefixRegex: /.*/, staticTriggerChannelids: [], rolesChannelid: '', - ig1: { channelid: '', roleid: '', emote: '', groups: [] }, - ig2: { channelid: '', roleid: '', emote: '', groups: [] }, - ig3: { channelid: '', roleid: '', emote: '', groups: [] }, + first: { channelid: '', roleid: '', emote: '', groups: [] }, + second: { channelid: '', roleid: '', emote: '', groups: [] }, + third: { channelid: '', roleid: '', emote: '', groups: [] }, alumni: { roleid: '', emote: '' }, tutor: { roleid: '', emote: '' }, announce: { roleid: '', emote: '', channelid: '' }, ok_hand: '', warning: '', - zeroWidthSpace: '', communicationServiceOptions: { apiKey: '', mailData: { from: '', templateId: '' } diff --git a/src/datadrop.ts b/src/datadrop.ts index f326a5a..5238f5d 100644 --- a/src/datadrop.ts +++ b/src/datadrop.ts @@ -35,15 +35,12 @@ export class DatadropClient extends Client { includeTimestamp: config.includeTimestamp, }); this.commands = new Collection(); + this.selfRoleManager = new SelfRoleManager(this, { channelsMessagesFetchLimit: 10, - deleteAfterUnregistration: false, - useReactions: true, + deleteAfterUnregistration: false }); - this.#listenToSelfRoleEvents(); - this.tempChannelsManager = new TempChannelsManager(this); - this.#listenToTempChannelsEvents(); this.database = new PostgresDatabaseService(this.logger); const communicationService = new SendGridService(config.communicationServiceOptions); @@ -57,7 +54,6 @@ export class DatadropClient extends Client { validCodeMessage: (user: User, code: string) => `Le code ${code} est valide. Bienvenue ${user.username}!`, invalidCodeMessage: (_, code: string) => `Le code ${code} est invalide!` }); - this.#listenToVerificationEvents(); } get config(): Configuration { @@ -116,24 +112,33 @@ export class DatadropClient extends Client { const channel = msg.channel as GuildTextBasedChannel; this.logger.info(`Message récupéré dans ${channel.parent!.name}-${channel.name} (${msg.channelId})`); }); - this.selfRoleManager.on(SelfRoleManagerEvents.roleAdd, (role, member) => this.logger.info(`Le rôle ${role.name} (<${role.id}>) a été ajouté à <${member.user.tag}>`)); - this.selfRoleManager.on(SelfRoleManagerEvents.roleRemove, (role, member) => this.logger.info(`Le rôle ${role.name} (<${role.id}>) a été retiré de <${member.user.tag}>`)); - this.selfRoleManager.on(SelfRoleManagerEvents.requiredRolesMissing, async (member: GuildMember, reaction: ButtonInteraction | MessageReaction | PartialMessageReaction, role: Role, requiredRoles: string[]) => { + this.selfRoleManager.on(SelfRoleManagerEvents.roleAdd, async (role: Role, member: GuildMember, interaction: ButtonInteraction) => { + this.logger.info(`Le rôle ${role.name} (<${role.id}>) a été ajouté à <${member.user.tag}>`); + + await interaction.editReply(`Le rôle ${role} t'a été ajouté.`); + }); + this.selfRoleManager.on(SelfRoleManagerEvents.roleRemove, async (role: Role, member: GuildMember, interaction: ButtonInteraction) => { + this.logger.info(`Le rôle ${role.name} (<${role.id}>) a été retiré de <${member.user.tag}>`); + + await interaction.editReply(`Le rôle ${role} t'a été retiré.`); + }); + this.selfRoleManager.on(SelfRoleManagerEvents.requiredRolesMissing, async (member: GuildMember, interaction: ButtonInteraction, role: Role, requiredRoles: string[]) => { const requiredRolesMissing = (await Promise.all(requiredRoles.map(requiredRole => member.guild.roles.fetch(requiredRole)))) .map((requiredRole: Role | null) => requiredRole?.name) .filter(requiredRoles => !!requiredRoles); - this.logger.info(`Le rôle ${role.name} (<${role.id}>) n'a pas pu être donné à <${member.user.tag}> parce que tous les rôles requis ne sont pas assignés à ce membre: ${requiredRolesMissing.join(', ')}`); - if (!(reaction instanceof ButtonInteraction)) { - try { - await member.send({ content: `Tu ne peux pas t'assigner le rôle ${role.name}! Tu dois d'abord avoir les rôles suivants: ${requiredRolesMissing.join(', ')}` }); - } catch { /** ignore */ } - finally { - await reaction.users.remove(member); - } - } + this.logger.info(`Le rôle ${role.name} (<${role.id}>) n'a pas pu être donné à <${member.user.tag}> parce que tous les rôles requis ne sont pas assignés à ce membre: ${requiredRolesMissing.join(', ')}.`); + + await interaction.editReply(`Tu ne peux pas t'assigner le rôle ${role}! Tu dois d'abord avoir les rôles suivants: ${requiredRolesMissing.join(', ')}.`); + }); + this.selfRoleManager.on(SelfRoleManagerEvents.maxRolesReach, async (member: GuildMember, interaction: ButtonInteraction, currentRolesNumber: number, maxRolesNumber: number, role: Role) => { + this.logger.info(`Le rôle ${role.name} (<${role.id}>) n'a pas pu être donné à <${member.user.tag}> parce que ce membre a été la limite de rôles: ${currentRolesNumber}/${maxRolesNumber}.`); + + await interaction.editReply(`Tu ne peux pas t'assigner le rôle ${role}! Tu as atteint la limite: ${currentRolesNumber}/${maxRolesNumber}.`); + }); + this.selfRoleManager.on(SelfRoleManagerEvents.error, (error: unknown, message: string) => { + this.logger.error(`Une erreur est survenue lors de la gestion des rôles automatiques.\nErreur: ${message}\n${getErrorMessage(error)}`); }); - this.selfRoleManager.on(SelfRoleManagerEvents.error, (error: unknown, message: string) => this.logger.error(`Une erreur est survenue lors de la gestion des rôles automatiques.\nErreur: ${message}\n${getErrorMessage(error)}`)); } #bindEvents(): void { @@ -155,7 +160,13 @@ export class DatadropClient extends Client { } async start(): Promise { + + this.#listenToSelfRoleEvents(); + this.#listenToTempChannelsEvents(); + this.#listenToVerificationEvents(); + this.#bindEvents(); + this.#bindCommands(); await this.database?.start(); this.login(); diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index df9814d..824ddba 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -6,9 +6,9 @@ import { DatadropClient } from '../datadrop'; module.exports = async (client: DatadropClient, member: GuildMember) => { if (member.user.bot) return; - client.logger.info(`L'utilisateur <${member.nickname} a rejoint le serveur.`); + client.logger.info(`L'utilisateur <${member.displayName} a rejoint le serveur.`); - const { zeroWidthSpace, announce, informationsChannelid, faqChannelid, rolesChannelid, igcomiteeChannelid } = client.config; + const { announce, informationsChannelid, faqChannelid, rolesChannelid, comiteeChannelid } = client.config; const annoncesRole = await member.guild.roles.fetch(announce.roleid); const userFromDatabase = await client.database.read(member.id); @@ -16,7 +16,7 @@ module.exports = async (client: DatadropClient, member: GuildMember) => { await client.database.undoDelete(member.id); } - const embed = generateEmbed(zeroWidthSpace, informationsChannelid, faqChannelid, igcomiteeChannelid, rolesChannelid, announce); + const embed = generateEmbed(informationsChannelid, faqChannelid, comiteeChannelid, rolesChannelid, announce); const linkAccountButton = new ButtonBuilder() .setLabel('Lier son compte') .setEmoji('🔗') @@ -37,31 +37,19 @@ module.exports = async (client: DatadropClient, member: GuildMember) => { } }; -function generateEmbed(zeroWidthSpace: string, informationsChannelid: string, faqChannelid: string, igcomiteeChannelid: string, rolesChannelid: string, announce: AnnounceConfiguration) { +function generateEmbed(informationsChannelid: string, faqChannelid: string, comiteeChannelid: string, rolesChannelid: string, announce: AnnounceConfiguration) { const fields = [ - { - name: zeroWidthSpace, - value: zeroWidthSpace, - }, { name: '1. Lie ton compte', value: `Pour accéder au serveur, tu dois lier ton compte Discord avec ton adresse Hénallux. Pour se faire, rien de plus simple que de cliquer sur le bouton ci-dessous et remplir le formulaire! Tu recevras un code par email qu'il faudra envoyer ici!`, }, - { - name: zeroWidthSpace, - value: zeroWidthSpace, - }, { name: '2. Change ton pseudo', value: `Sur Discord, tu peux changer ton pseudo sur chaque serveur (tu as donc un pseudo différent par serveur!). Pour cela, fais un clic-droit sur l'icône du serveur en question et sélectionne **Changer le pseudo**.`, }, - { - name: zeroWidthSpace, - value: zeroWidthSpace, - }, { name: '3. Lis les canaux importants', - value: `En arrivant, tu vas être un peu perdu. C'est normal, il y a beaucoup de choses et c'est pas forcément simple à suivre.\nOn te conseille d'abord de jeter un oeil aux différents canaux listés ci-dessous :\n - <#${informationsChannelid}>\n - <#${faqChannelid}>\n - <#${igcomiteeChannelid}>\n - <#${rolesChannelid}>\n - <#${announce.channelid}>`, + value: `En arrivant, tu vas être un peu perdu. C'est normal, il y a beaucoup de choses et c'est pas forcément simple à suivre.\nOn te conseille d'abord de jeter un oeil aux différents canaux listés ci-dessous :\n- <#${informationsChannelid}>\n- <#${faqChannelid}>\n- <#${comiteeChannelid}>\n- <#${rolesChannelid}>\n- <#${announce.channelid}>`, }, ]; @@ -72,11 +60,11 @@ function generateEmbed(zeroWidthSpace: string, informationsChannelid: string, fa ) .setTitle('Salut toi!') .setDescription( - `Bienvenue sur le serveur Discord non-officiel de la section **Informatique de Gestion** de l'IESN. Ce serveur est une initiative étudiante et n'est donc pas une plateforme de communication officielle de la Haute-École Namur-Liège-Luxembourg.\n\nPour bien commencer l'année, on te recommande de suivre les quelques étapes suivantes :` + `Bienvenue sur le serveur Discord non-officiel de la section **Informatique Orientation _Développement d'Application_** de l'IESN. Ce serveur est une initiative étudiante et n'est donc pas une plateforme de communication officielle de la Haute-École Namur-Liège-Luxembourg.\n\nPour bien commencer l'année, on te recommande de suivre les quelques étapes suivantes :` ) .addFields(fields) .setFooter({ - text: `Le Comité IG`, + text: `Le Comité IODA`, iconURL: 'https://cdn.discordapp.com/icons/491312065785364482/c9d724c34519c57d3cc1c28f79813f73.png' }) .setTimestamp(); diff --git a/src/events/guildMemberRemove.ts b/src/events/guildMemberRemove.ts index 10d7193..0a07b89 100644 --- a/src/events/guildMemberRemove.ts +++ b/src/events/guildMemberRemove.ts @@ -5,7 +5,7 @@ import { DatadropClient } from '../datadrop'; module.exports = async (client: DatadropClient, member: GuildMember) => { if (member.user.bot) return; if (member.guild.id !== client.config.guildId) return; - client.logger.info(`L'utilisateur <${member.nickname} a quitté le serveur.`); + client.logger.info(`L'utilisateur <${member.displayName} a quitté le serveur.`); try { await client.database.delete(member.id); diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index a3b5894..a5fcb24 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -78,7 +78,7 @@ module.exports = async (client: DatadropClient, interaction: Interaction) => { } } } - else if (interaction.isRepliable()) { - interaction.reply({ ephemeral: true, content: "Ce message ne t'était assurément pas destiné!" }); + else if ((interaction.isButton() || interaction.isModalSubmit()) && !interaction.customId.startsWith('sr-') && !interaction.customId.includes(user.id)) { + await interaction.reply({ ephemeral: true, content: "Ce message ne t'était assurément pas destiné!" }); } }; diff --git a/src/events/ready.ts b/src/events/ready.ts index c8cebb9..68c6814 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -16,7 +16,7 @@ module.exports = async (client: DatadropClient) => { }; async function registerRolesChannels(client: DatadropClient, config: Configuration): Promise { - const { rolesChannelid, ig1, ig2, ig3, alumni, tutor, announce } = config; + const { rolesChannelid, first, second, third, alumni, tutor, announce } = config; const format = (rte: RoleToEmojiData) => `${rte.emoji} - ${rte.role instanceof Role ? rte.role : roleMention(rte.role)}${rte.smallNote ? ` (${rte.smallNote})` : ''}`; const message = { @@ -32,7 +32,7 @@ async function registerRolesChannels(client: DatadropClient, config: Configurati await Promise.all([ client.selfRoleManager.registerChannel(rolesChannelid, { rolesToEmojis: [ - ...([ig1, ig2, ig3, alumni, tutor].map(cfg => ({ role: cfg.roleid, emoji: cfg.emote }))), + ...([first, second, third, alumni, tutor].map(cfg => ({ role: cfg.roleid, emoji: cfg.emote }))), { role: announce.roleid, emoji: announce.emote, @@ -45,11 +45,11 @@ async function registerRolesChannels(client: DatadropClient, config: Configurati options: { ...message.options, descriptionSuffix: - '\nLes Professeurs, les Délégués et les membres du Comité IG doivent notifier un Admin/Community Manager pour avoir leur rôle.' + '\nLes Professeurs, les Délégués et les membres du Comité IODA doivent notifier un Admin/Community Manager pour avoir leur rôle.' } }, }), - ...([ig1, ig2, ig3].map(({ roleid, channelid, groups }) => + ...([first, second, third].map(({ roleid, channelid, groups }) => client.selfRoleManager.registerChannel(channelid, { rolesToEmojis: groups.map((group) => ({ role: group.roleid, diff --git a/src/helpers.ts b/src/helpers.ts index 27f1c5f..b48999a 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -12,6 +12,13 @@ export function readFilesFrom(path: string, callback: (name: string, props: any) }); } +export function clean(text: any): string { + if (typeof (text) === 'string') { + return text.replace(/@/g, '@​'); + } + return text; +} + // #region Error handling helper // source: https://kentcdodds.com/blog/get-a-catch-block-error-message-with-typescript diff --git a/src/models/Configuration.ts b/src/models/Configuration.ts index b911915..047b3a4 100644 --- a/src/models/Configuration.ts +++ b/src/models/Configuration.ts @@ -42,16 +42,16 @@ export interface Configuration { informationsChannelid: Snowflake; faqChannelid: Snowflake; - igcomiteeChannelid: Snowflake; + comiteeChannelid: Snowflake; dynamicChannelPrefix: string; dynamicChannelPrefixRegex: RegExp; staticTriggerChannelids: Snowflake[]; rolesChannelid: Snowflake; - ig1: YearConfiguration; - ig2: YearConfiguration; - ig3: YearConfiguration; + first: YearConfiguration; + second: YearConfiguration; + third: YearConfiguration; alumni: SpecialRoleConfiguration; tutor: SpecialRoleConfiguration; @@ -60,7 +60,6 @@ export interface Configuration { ok_hand: string; warning: string; - zeroWidthSpace: string; communicationServiceOptions: SendGridOptions; } diff --git a/yarn.lock b/yarn.lock index 7f3e9bc..3784ab3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,10 +93,10 @@ chalk "^3.0.0" moment "^2.24.0" -"@hunteroi/discord-selfrole@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@hunteroi/discord-selfrole/-/discord-selfrole-3.1.0.tgz#9ee5f13f4f0d93ba10124f3497843f71ef11a338" - integrity sha512-4/PUvNpGgs3Ijcil0hZ0hqH41iBIjPHod9Se8xiCuC45htBlS3pbTD4LUGEy2ijvwpIOrL8cQCPxmr/bkG9Lqg== +"@hunteroi/discord-selfrole@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@hunteroi/discord-selfrole/-/discord-selfrole-3.2.0.tgz#7c515d6e8fb553b39d31d9e0afe43b1932b3d712" + integrity sha512-2hi26NOI2kNGjTFJUhEXwP16uf+GfnTyi9hpNQ4isP1xyjPlMItNMz0EDXZVf/6WOtH8lpGq/HVfK0N4+kmn7Q== dependencies: discord.js "14.x"