diff --git a/db/initialize.ts b/db/initialize.ts index b4a0e57..1b59f5d 100644 --- a/db/initialize.ts +++ b/db/initialize.ts @@ -21,8 +21,20 @@ await dbClient.execute(`DROP TABLE IF EXISTS roll_time_heatmap;`); await dbClient.execute(`DROP PROCEDURE IF EXISTS INC_CNT;`); await dbClient.execute(`DROP TABLE IF EXISTS command_cnt;`); await dbClient.execute(`DROP TABLE IF EXISTS ignore_list;`); +await dbClient.execute(`DROP TABLE IF EXISTS allow_inline;`); console.log('Tables dropped'); +// Holds guilds that have explicitly allowed inline rolls +console.log('Attempting to create table allow_inline'); +await dbClient.execute(` + CREATE TABLE allow_inline ( + guildid bigint unsigned NOT NULL, + PRIMARY KEY (guildid), + UNIQUE KEY allow_inline_guildid_UNIQUE (guildid) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +`); +console.log('Table created'); + // Table to hold list of users who want to be ignored by the bot console.log('Attempting to create table ignore_list'); await dbClient.execute(` diff --git a/db/populateDefaults.ts b/db/populateDefaults.ts index 9265a7f..2d9807e 100644 --- a/db/populateDefaults.ts +++ b/db/populateDefaults.ts @@ -17,6 +17,7 @@ const commands = [ 'heatmap', 'help', 'info', + 'inline', 'mention', 'opt-in', 'opt-out', diff --git a/src/commands/_index.ts b/src/commands/_index.ts index 3b1678a..8952c51 100644 --- a/src/commands/_index.ts +++ b/src/commands/_index.ts @@ -14,6 +14,7 @@ import { report } from 'commands/report.ts'; import { roll } from 'commands/roll.ts'; import { rollHelp } from 'commands/rollHelp.ts'; import { stats } from 'commands/stats.ts'; +import { toggleInline } from 'commands/toggleInline.ts'; import { version } from 'commands/version.ts'; export default { @@ -33,5 +34,6 @@ export default { roll, rollHelp, stats, + toggleInline, version, }; diff --git a/src/commands/roll.ts b/src/commands/roll.ts index ef69d3c..0127345 100644 --- a/src/commands/roll.ts +++ b/src/commands/roll.ts @@ -60,7 +60,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command: return; } - let rollCmd = message.content.startsWith(`${config.prefix}r`) ? remainingArgs.join('') : `${config.prefix}${command}${remainingArgs.join('')}`; + let rollCmd = message.content.startsWith(`${config.prefix}r`) ? remainingArgs.join('') : `${command}${remainingArgs.join('')}`; // Try to ensure the roll is wrapped if (!rollCmd.includes(config.postfix)) { diff --git a/src/commands/toggleInline.ts b/src/commands/toggleInline.ts new file mode 100644 index 0000000..e618a4b --- /dev/null +++ b/src/commands/toggleInline.ts @@ -0,0 +1,122 @@ +import { DiscordenoMessage, hasGuildPermissions } from '@discordeno'; + +import config from '~config'; + +import dbClient from 'db/client.ts'; +import { inlineList, queries } from 'db/common.ts'; + +import { failColor, infoColor1, successColor } from 'embeds/colors.ts'; + +import utils from 'utils/utils.ts'; + +export const toggleInline = async (message: DiscordenoMessage, args: string[]) => { + // Light telemetry to see how many times a command is being run + dbClient.execute(queries.callIncCnt('inline')).catch((e) => utils.commonLoggers.dbError('toggleInline.ts:16', 'call sproc INC_CNT on', e)); + + // Local apiArg in lowercase + const apiArg = (args[0] || '').toLowerCase(); + + // Alert users who DM the bot that this command is for guilds only + if (message.guildId === 0n) { + message + .send({ + embeds: [ + { + color: failColor, + title: 'Toggle Inline commands are only available in guilds.', + }, + ], + }) + .catch((e: Error) => utils.commonLoggers.messageSendError('toggleInline.ts:30', message, e)); + return; + } + + let errorOut = false; + const guildQuery = await dbClient.query(`SELECT guildid FROM allow_inline WHERE guildid = ?`, [message.guildId]).catch((e0) => { + utils.commonLoggers.dbError('toggleInline.ts:36', 'query', e0); + message + .send({ + embeds: [ + { + color: failColor, + title: 'Failed to check Inline roll status for this guild.', + description: 'If this issue persists, please report this to the developers.', + }, + ], + }) + .catch((e: Error) => utils.commonLoggers.messageSendError('toggleInline.ts:47', message, e)); + errorOut = true; + }); + if (errorOut) return; + + // Makes sure the user is authenticated to run the API command + if (await hasGuildPermissions(message.authorId, message.guildId, ['ADMINISTRATOR'])) { + let enable = false; + switch (apiArg) { + case 'allow': + case 'enable': + enable = true; + await dbClient.execute('INSERT INTO allow_inline(guildid) values(?)', [message.guildId]).catch((e) => { + utils.commonLoggers.dbError('toggleInline.ts:58', 'insert into allow_inline', e); + errorOut = true; + }); + if (!errorOut) { + inlineList.push(message.guildId); + } + break; + case 'block': + case 'disable': + await dbClient.execute('DELETE FROM allow_inline WHERE guildid = ?', [message.guildId]).catch((e) => { + utils.commonLoggers.dbError('toggleInline.ts:65', 'delete from allow_inline', e); + errorOut = true; + }); + if (!errorOut && inlineList.indexOf(message.guildId) !== -1) { + inlineList.splice(inlineList.indexOf(message.guildId), 1); + } + break; + case 'status': + default: + message.send({ + embeds: [ + { + color: infoColor1, + title: `Inline Rolls are ${guildQuery.length ? 'Enabled' : 'Disabled'} for this guild`, + description: `To ${guildQuery.length ? 'disable' : 'enable'} them, run the following command:\n\`${config.prefix}inline ${guildQuery.length ? 'disable' : 'enable'}\``, + }, + ], + }); + return; + } + if (errorOut) { + message.send({ + embeds: [ + { + color: failColor, + title: `Failed to ${enable ? 'Enable' : 'Disable'} Inline Rolls for this guild`, + description: 'Please try the command again. If this issue persists, please report this to the developers.', + }, + ], + }); + return; + } + message.send({ + embeds: [ + { + color: successColor, + title: `Successfully ${enable ? 'Enabled' : 'Disabled'} Inline Rolls for this guild`, + }, + ], + }); + } else { + message + .send({ + embeds: [ + { + color: failColor, + title: 'Toggle Inline commands are powerful and can only be used by guild Owners and Admins.', + }, + ], + }) + .catch((e: Error) => utils.commonLoggers.messageSendError('toggleInline.ts:77', message, e)); + } +}; diff --git a/src/db/common.ts b/src/db/common.ts index 4367bac..b65a929 100644 --- a/src/db/common.ts +++ b/src/db/common.ts @@ -3,6 +3,9 @@ import dbClient from 'db/client.ts'; interface UserIdObj { userid: bigint; } +interface GuildIdObj { + guildid: bigint; +} // List of userIds who have requested that the bot ignore them export const ignoreList: Array = []; @@ -11,6 +14,13 @@ dbIgnoreList.forEach((userIdObj: UserIdObj) => { ignoreList.push(userIdObj.userid); }); +// List of guilds who have allowed inline rolls +export const inlineList: Array = []; +const dbInlineList = await dbClient.query('SELECT * FROM allow_inline'); +dbInlineList.forEach((guildIdObj: GuildIdObj) => { + inlineList.push(guildIdObj.guildid); +}); + export const weekDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; export const queries = { diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index f7e6b8b..97785ff 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -5,7 +5,7 @@ import config from '~config'; import commands from 'commands/_index.ts'; -import { ignoreList } from 'db/common.ts'; +import { ignoreList, inlineList } from 'db/common.ts'; export const messageCreateHandler = (message: DiscordenoMessage) => { // Ignore all other bots @@ -21,21 +21,22 @@ export const messageCreateHandler = (message: DiscordenoMessage) => { commands.handleMentions(message); } - // return as we are done handling this command - return; + // return as we are done handling this command, unless the guild allows inline rolls + if (!inlineList.includes(message.guildId)) return; } log(LT.LOG, `Handling ${config.prefix}command message: ${JSON.stringify(message)}`); + const sliceLength = message.content.startsWith(config.prefix) ? config.prefix.length : 0; // Split into standard command + args format const args = message.content - .slice(config.prefix.length) + .slice(sliceLength) .trim() .split(/[ \n]+/g); const argSpaces = message.content - .slice(config.prefix.length) + .slice(sliceLength) .trim() - .split(new RegExp(/([ \n]+)/, 'g')); + .split(/([ \n]+)/g); const command = args.shift()?.toLowerCase(); argSpaces.shift(); @@ -129,6 +130,11 @@ export const messageCreateHandler = (message: DiscordenoMessage) => { // Audit sub commands commands.heatmap(message); break; + case 'inline': + // [[inline arg + // Enable or Disable inline rolling + commands.toggleInline(message, args); + break; case 'roll': case 'r': // [[roll or [[r