Initial work on V2.0.0

Updated dependencies and corrected syntax errors caused by the newer deps.
This commit is contained in:
Ean Milligan (Bastion) 2021-11-21 22:14:57 -05:00
parent 73288073b1
commit 60188ca5d8
9 changed files with 827 additions and 809 deletions

View File

@ -1,6 +1,6 @@
export const config = { export const config = {
"name": "The Artificer", // Name of the bot "name": "The Artificer", // Name of the bot
"version": "1.4.3", // Version of the bot "version": "2.0.0", // Version of the bot
"token": "the_bot_token", // Discord API Token for this bot "token": "the_bot_token", // Discord API Token for this bot
"localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token" "localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token"
"prefix": "[[", // Prefix for all commands "prefix": "[[", // Prefix for all commands
@ -13,7 +13,7 @@ export const config = {
"rateLimitCnt": 10, // Amount of requests that can be made (successful or not) during above time range before getting rate limited "rateLimitCnt": 10, // Amount of requests that can be made (successful or not) during above time range before getting rate limited
"admin": 0n, // Discord user ID of the bot admin, this user will be the user that can ban/unban user/channel combos and API keys "admin": 0n, // Discord user ID of the bot admin, this user will be the user that can ban/unban user/channel combos and API keys
"adminKey": "your_25char_api_token", // API Key generated by nanoid that is 25 char long, this gets pre-populated into all_keys "adminKey": "your_25char_api_token", // API Key generated by nanoid that is 25 char long, this gets pre-populated into all_keys
"email": "" // Temporary set up for email, this will be adjusted to an actual email using deno-smtp in the future. "email": 0n // Temporary set up for email, this will be adjusted to an actual email using deno-smtp in the future.
}, },
"db": { // Settings for the MySQL database, this is required for use with the API, if you do not want to set this up, you will need to rip all code relating to the DB out of the bot "db": { // Settings for the MySQL database, this is required for use with the API, if you do not want to set this up, you will need to rip all code relating to the DB out of the bot
"host": "", // IP address for the db, usually localhost "host": "", // IP address for the db, usually localhost
@ -24,9 +24,9 @@ export const config = {
"name": "" // Name of the database Schema to use for the bot "name": "" // Name of the database Schema to use for the bot
}, },
"logRolls": false, // Enables logging of roll commands, this should be left disabled for privacy, but exists to allow verification of rolls before deployment, all API rolls will always be logged no matter what this is set to "logRolls": false, // Enables logging of roll commands, this should be left disabled for privacy, but exists to allow verification of rolls before deployment, all API rolls will always be logged no matter what this is set to
"logChannel": "the_log_channel", // Discord channel ID where the bot should put startup messages and other error messages needed "logChannel": 0n, // Discord channel ID where the bot should put startup messages and other error messages needed
"reportChannel": "the_report_channel", // Discord channel ID where reports will be sent when using the built-in report command "reportChannel": 0n, // Discord channel ID where reports will be sent when using the built-in report command
"devServer": "the_dev_server", // Discord guild ID where testing of indev features/commands will be handled, used in conjuction with the DEVMODE bool in mod.ts "devServer": 0n, // Discord guild ID where testing of indev features/commands will be handled, used in conjuction with the DEVMODE bool in mod.ts
"emojis": [ // Array of objects containing all emojis that the bot can send on your behalf, empty this array if you don't want any of them "emojis": [ // Array of objects containing all emojis that the bot can send on your behalf, empty this array if you don't want any of them
{ // Emoji object, duplicate for each emoji { // Emoji object, duplicate for each emoji
"name": "emoji_name", // Name of emoji in discord "name": "emoji_name", // Name of emoji in discord

19
deps.ts
View File

@ -1,19 +1,18 @@
// All external dependancies are to be loaded here to make updating dependancy versions much easier // All external dependancies are to be loaded here to make updating dependancy versions much easier
export { export {
startBot, editBotsStatus, startBot, editBotStatus, editBotNickname,
Intents, StatusTypes, ActivityType, Intents, DiscordActivityTypes,
sendMessage, sendDirectMessage, sendMessage, sendDirectMessage,
cache, botID, cache, cacheHandlers, botId,
memberIDHasPermission hasGuildPermissions
} from "https://deno.land/x/discordeno@10.3.0/mod.ts"; } from "https://deno.land/x/discordeno@12.0.1/mod.ts";
export type { export type {
CacheData, Message, Guild, MessageContent DiscordenoMessage, DiscordenoGuild, CreateMessage
} from "https://deno.land/x/discordeno@10.3.0/mod.ts"; } from "https://deno.land/x/discordeno@12.0.1/mod.ts";
export { Client } from "https://deno.land/x/mysql@v2.7.0/mod.ts"; export { Client } from "https://deno.land/x/mysql@v2.10.1/mod.ts";
export { serve } from "https://deno.land/std@0.83.0/http/server.ts"; export { Status, STATUS_TEXT } from "https://deno.land/std@0.115.1/http/http_status.ts";
export { Status, STATUS_TEXT } from "https://deno.land/std@0.83.0/http/http_status.ts";
export { nanoid } from "https://deno.land/x/nanoid@v3.0.0/mod.ts"; export { nanoid } from "https://deno.land/x/nanoid@v3.0.0/mod.ts";

View File

@ -3,4 +3,4 @@ export const DEVMODE = false;
// DEBUG is used to toggle the cmdPrompt // DEBUG is used to toggle the cmdPrompt
export const DEBUG = false; export const DEBUG = false;
// LOCALMODE is used to run a differnt bot token for local testing // LOCALMODE is used to run a differnt bot token for local testing
export const LOCALMODE = false; export const LOCALMODE = true;

164
mod.ts
View File

@ -6,12 +6,12 @@
import { import {
// Discordeno deps // Discordeno deps
startBot, editBotsStatus, startBot, editBotStatus, editBotNickname,
Intents, StatusTypes, ActivityType, Intents,
sendMessage, sendDirectMessage, sendMessage, sendDirectMessage,
cache, botID, cache, botId,
memberIDHasPermission, hasGuildPermissions,
Message, Guild, DiscordActivityTypes, DiscordenoGuild, DiscordenoMessage,
// MySQL Driver deps // MySQL Driver deps
Client Client
@ -44,18 +44,32 @@ utils.initLog("logs");
// Start up the Discord Bot // Start up the Discord Bot
startBot({ startBot({
token: LOCALMODE ? config.localtoken : config.token, token: LOCALMODE ? config.localtoken : config.token,
intents: [Intents.GUILD_MESSAGES, Intents.DIRECT_MESSAGES, Intents.GUILDS], intents: [Intents.GuildMessages, Intents.DirectMessages, Intents.Guilds],
eventHandlers: { eventHandlers: {
ready: () => { ready: () => {
utils.log(LT.INFO, `${config.name} Logged in!`); utils.log(LT.INFO, `${config.name} Logged in!`);
editBotsStatus(StatusTypes.Online, "Booting up . . .", ActivityType.Game); editBotStatus({
activities: [{
name: "Booting up . . .",
type: DiscordActivityTypes.Game,
createdAt: new Date().getTime()
}],
status: "online"
});
// Interval to rotate the status text every 30 seconds to show off more commands // Interval to rotate the status text every 30 seconds to show off more commands
setInterval(() => { setInterval(async () => {
utils.log(LT.LOG, "Changing bot status"); utils.log(LT.LOG, "Changing bot status");
try { try {
// Wrapped in try-catch due to hard crash possible // Wrapped in try-catch due to hard crash possible
editBotsStatus(StatusTypes.Online, intervals.getRandomStatus(cache), ActivityType.Game); editBotStatus({
activities: [{
name: await intervals.getRandomStatus(),
type: DiscordActivityTypes.Game,
createdAt: new Date().getTime()
}],
status: "online"
});
} catch (e) { } catch (e) {
utils.log(LT.ERROR, `Failed to update status: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to update status: ${JSON.stringify(e)}`);
} }
@ -64,34 +78,42 @@ startBot({
// Interval to update bot list stats every 24 hours // Interval to update bot list stats every 24 hours
LOCALMODE ? utils.log(LT.INFO, "updateListStatistics not running") : setInterval(() => { LOCALMODE ? utils.log(LT.INFO, "updateListStatistics not running") : setInterval(() => {
utils.log(LT.LOG, "Updating all bot lists statistics"); utils.log(LT.LOG, "Updating all bot lists statistics");
intervals.updateListStatistics(botID, cache.guilds.size); intervals.updateListStatistics(botId, cache.guilds.size);
}, 86400000); }, 86400000);
// setTimeout added to make sure the startup message does not error out // setTimeout added to make sure the startup message does not error out
setTimeout(() => { setTimeout(() => {
LOCALMODE ? utils.log(LT.INFO, "updateListStatistics not running") : intervals.updateListStatistics(botID, cache.guilds.size); LOCALMODE && editBotNickname(config.devServer, `LOCAL - ${config.name}`);
editBotsStatus(StatusTypes.Online, `Boot Complete`, ActivityType.Game); LOCALMODE ? utils.log(LT.INFO, "updateListStatistics not running") : intervals.updateListStatistics(botId, cache.guilds.size);
editBotStatus({
activities: [{
name: "Booting Complete",
type: DiscordActivityTypes.Game,
createdAt: new Date().getTime()
}],
status: "online"
});
sendMessage(config.logChannel, `${config.name} has started, running version ${config.version}.`).catch(e => { sendMessage(config.logChannel, `${config.name} has started, running version ${config.version}.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
}); });
}, 1000); }, 1000);
}, },
guildCreate: (guild: Guild) => { guildCreate: (guild: DiscordenoGuild) => {
utils.log(LT.LOG, `Handling joining guild ${JSON.stringify(guild)}`); utils.log(LT.LOG, `Handling joining guild ${JSON.stringify(guild)}`);
sendMessage(config.logChannel, `New guild joined: ${guild.name} (id: ${guild.id}). This guild has ${guild.memberCount} members!`).catch(e => { sendMessage(config.logChannel, `New guild joined: ${guild.name} (id: ${guild.id}). This guild has ${guild.memberCount} members!`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
}); });
}, },
guildDelete: (guild: Guild) => { guildDelete: (guild: DiscordenoGuild) => {
utils.log(LT.LOG, `Handling leaving guild ${JSON.stringify(guild)}`); utils.log(LT.LOG, `Handling leaving guild ${JSON.stringify(guild)}`);
sendMessage(config.logChannel, `I have been removed from: ${guild.name} (id: ${guild.id}).`).catch(e => { sendMessage(config.logChannel, `I have been removed from: ${guild.name} (id: ${guild.id}).`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
}); });
}, },
debug: dmsg => utils.log(LT.LOG, `${JSON.stringify(dmsg)}`), debug: dmsg => utils.log(LT.LOG, `Debug Message | ${JSON.stringify(dmsg)}`),
messageCreate: async (message: Message) => { messageCreate: async (message: DiscordenoMessage) => {
// Ignore all other bots // Ignore all other bots
if (message.author.bot) return; if (message.isBot) return;
// Ignore all messages that are not commands // Ignore all messages that are not commands
if (message.content.indexOf(config.prefix) !== 0) return; if (message.content.indexOf(config.prefix) !== 0) return;
@ -114,7 +136,7 @@ startBot({
// Calculates ping between sending a message and editing it, giving a nice round-trip latency. // Calculates ping between sending a message and editing it, giving a nice round-trip latency.
try { try {
const m = await utils.sendIndirectMessage(message, "Ping?", sendMessage, sendDirectMessage); const m = await message.send("Ping?");
m.edit(`Pong! Latency is ${m.timestamp - message.timestamp}ms.`); m.edit(`Pong! Latency is ${m.timestamp - message.timestamp}ms.`);
} catch (e) { } catch (e) {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
@ -129,7 +151,7 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, "The Artificer was built in memory of my Grandmother, Babka\nWith much love, Ean\n\nDecember 21, 2020", sendMessage, sendDirectMessage).catch(e => { message.send("The Artificer was built in memory of my Grandmother, Babka\nWith much love, Ean\n\nDecember 21, 2020").catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -142,7 +164,7 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, longStrs.rollhelp.join("\n"), sendMessage, sendDirectMessage).catch(e => { message.send(longStrs.rollhelp.join("\n")).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -155,7 +177,7 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, longStrs.help.join("\n"), sendMessage, sendDirectMessage).catch(e => { message.send(longStrs.help.join("\n")).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -168,7 +190,7 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, longStrs.info.join("\n"), sendMessage, sendDirectMessage).catch(e => { message.send(longStrs.info.join("\n")).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -181,7 +203,7 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, longStrs.privacy.join("\n"), sendMessage, sendDirectMessage).catch(e => { message.send(longStrs.privacy.join("\n")).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -194,7 +216,7 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, `My current version is ${config.version}.`, sendMessage, sendDirectMessage).catch(e => { message.send(`My current version is ${config.version}.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -207,10 +229,10 @@ startBot({
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
sendMessage(config.reportChannel, ("USER REPORT:\n" + args.join(" "))).catch(e => { sendMessage(config.reportChannel, (`USER REPORT:\n${args.join(" ")}`)).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
utils.sendIndirectMessage(message, "Failed command has been reported to my developer.\n\nFor more in depth support, and information about planned maintenance, please join the support server here: https://discord.gg/peHASXMZYv", sendMessage, sendDirectMessage).catch(e => { message.send("Failed command has been reported to my developer.\n\nFor more in depth support, and information about planned maintenance, please join the support server here: https://discord.gg/peHASXMZYv").catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -233,7 +255,7 @@ startBot({
const rolls = BigInt(rollQuery[0].count); const rolls = BigInt(rollQuery[0].count);
const total = BigInt(totalQuery[0].count); const total = BigInt(totalQuery[0].count);
utils.sendIndirectMessage(message, `${config.name} is rolling dice for ${cache.members.size} active users, in ${cache.channels.size} channels of ${cache.guilds.size} servers.\n\nSo far, ${rolls} dice have been rolled and ${total - rolls} utility commands have been run.`, sendMessage, sendDirectMessage).catch(e => { message.send(`${config.name} is rolling dice for ${cache.members.size} active users, in ${cache.channels.size} channels of ${cache.guilds.size} servers.\n\nSo far, ${rolls} dice have been rolled and ${total - rolls} utility commands have been run.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -250,19 +272,19 @@ startBot({
const apiArg = args[0].toLowerCase(); const apiArg = args[0].toLowerCase();
// Alert users who DM the bot that this command is for guilds only // Alert users who DM the bot that this command is for guilds only
if (message.guildID === "") { if (message.guildId === 0n) {
utils.sendIndirectMessage(message, `API commands are only available in guilds.`, sendMessage, sendDirectMessage).catch(e => { message.send(`API commands are only available in guilds.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
return; return;
} }
// Makes sure the user is authenticated to run the API command // Makes sure the user is authenticated to run the API command
if (await memberIDHasPermission(message.author.id, message.guildID, ["ADMINISTRATOR"])) { if (await hasGuildPermissions(message.authorId, message.guildId, ["ADMINISTRATOR"])) {
// [[api help // [[api help
// Shows API help details // Shows API help details
if (apiArg === "help") { if (apiArg === "help") {
utils.sendIndirectMessage(message, longStrs.apihelp.join("\n"), sendMessage, sendDirectMessage).catch(e => { message.send(longStrs.apihelp.join("\n")).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -270,9 +292,9 @@ startBot({
// [[api allow/block // [[api allow/block
// Lets a guild admin allow or ban API rolls from happening in said guild // Lets a guild admin allow or ban API rolls from happening in said guild
else if (apiArg === "allow" || apiArg === "block" || apiArg === "enable" || apiArg === "disable") { else if (apiArg === "allow" || apiArg === "block" || apiArg === "enable" || apiArg === "disable") {
const guildQuery = await dbClient.query(`SELECT guildid FROM allowed_guilds WHERE guildid = ?`, [message.guildID]).catch(e0 => { const guildQuery = await dbClient.query(`SELECT guildid FROM allowed_guilds WHERE guildid = ?`, [message.guildId]).catch(e0 => {
utils.log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`); utils.log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
utils.sendIndirectMessage(message, `Failed to ${apiArg} API rolls for this guild. If this issue persists, please report this to the developers.`, sendMessage, sendDirectMessage).catch(e1 => { message.send(`Failed to ${apiArg} API rolls for this guild. If this issue persists, please report this to the developers.`).catch(e1 => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
}); });
return; return;
@ -280,25 +302,25 @@ startBot({
if (guildQuery.length === 0) { if (guildQuery.length === 0) {
// Since guild is not in our DB, add it in // Since guild is not in our DB, add it in
await dbClient.execute(`INSERT INTO allowed_guilds(guildid,active) values(?,?)`, [BigInt(message.guildID), ((apiArg === "allow" || apiArg === "enable") ? 1 : 0)]).catch(e0 => { await dbClient.execute(`INSERT INTO allowed_guilds(guildid,active) values(?,?)`, [BigInt(message.guildId), ((apiArg === "allow" || apiArg === "enable") ? 1 : 0)]).catch(e0 => {
utils.log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e0)}`); utils.log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e0)}`);
utils.sendIndirectMessage(message, `Failed to ${apiArg} API rolls for this guild. If this issue persists, please report this to the developers.`, sendMessage, sendDirectMessage).catch(e1 => { message.send(`Failed to ${apiArg} API rolls for this guild. If this issue persists, please report this to the developers.`).catch(e1 => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
}); });
return; return;
}); });
} else { } else {
// Since guild is in our DB, update it // Since guild is in our DB, update it
await dbClient.execute(`UPDATE allowed_guilds SET active = ? WHERE guildid = ?`, [((apiArg === "allow" || apiArg === "enable") ? 1 : 0), BigInt(message.guildID)]).catch(e0 => { await dbClient.execute(`UPDATE allowed_guilds SET active = ? WHERE guildid = ?`, [((apiArg === "allow" || apiArg === "enable") ? 1 : 0), BigInt(message.guildId)]).catch(e0 => {
utils.log(LT.ERROR, `Failed to update DB: ${JSON.stringify(e0)}`); utils.log(LT.ERROR, `Failed to update DB: ${JSON.stringify(e0)}`);
utils.sendIndirectMessage(message, `Failed to ${apiArg} API rolls for this guild. If this issue persists, please report this to the developers.`, sendMessage, sendDirectMessage).catch(e1 => { message.send(`Failed to ${apiArg} API rolls for this guild. If this issue persists, please report this to the developers.`).catch(e1 => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
}); });
return; return;
}); });
} }
// We won't get here if there's any errors, so we know it has bee successful, so report as such // We won't get here if there's any errors, so we know it has bee successful, so report as such
utils.sendIndirectMessage(message, `API rolls have successfully been ${apiArg}ed for this guild.`, sendMessage, sendDirectMessage).catch(e => { message.send(`API rolls have successfully been ${apiArg}ed for this guild.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -306,16 +328,16 @@ startBot({
// [[api delete // [[api delete
// Lets a guild admin delete their server from the database // Lets a guild admin delete their server from the database
else if (apiArg === "delete") { else if (apiArg === "delete") {
await dbClient.execute(`DELETE FROM allowed_guilds WHERE guildid = ?`, [message.guildID]).catch(e0 => { await dbClient.execute(`DELETE FROM allowed_guilds WHERE guildid = ?`, [message.guildId]).catch(e0 => {
utils.log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`); utils.log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
utils.sendIndirectMessage(message, `Failed to delete this guild from the database. If this issue persists, please report this to the developers.`, sendMessage, sendDirectMessage).catch(e1 => { message.send(`Failed to delete this guild from the database. If this issue persists, please report this to the developers.`).catch(e1 => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
}); });
return; return;
}); });
// We won't get here if there's any errors, so we know it has bee successful, so report as such // We won't get here if there's any errors, so we know it has bee successful, so report as such
utils.sendIndirectMessage(message, `This guild's API setting has been removed from The Artifier's Database.`, sendMessage, sendDirectMessage).catch(e => { message.send(`This guild's API setting has been removed from The Artifier's Database.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -324,9 +346,9 @@ startBot({
// Lets a guild admin check the status of API rolling in said guild // Lets a guild admin check the status of API rolling in said guild
else if (apiArg === "status") { else if (apiArg === "status") {
// Get status of guild from the db // Get status of guild from the db
const guildQuery = await dbClient.query(`SELECT active, banned FROM allowed_guilds WHERE guildid = ?`, [message.guildID]).catch(e0 => { const guildQuery = await dbClient.query(`SELECT active, banned FROM allowed_guilds WHERE guildid = ?`, [message.guildId]).catch(e0 => {
utils.log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`); utils.log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
utils.sendIndirectMessage(message, `Failed to check API rolls status for this guild. If this issue persists, please report this to the developers.`, sendMessage, sendDirectMessage).catch(e1 => { message.send(`Failed to check API rolls status for this guild. If this issue persists, please report this to the developers.`).catch(e1 => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
}); });
return; return;
@ -336,23 +358,23 @@ startBot({
if (guildQuery.length > 0) { if (guildQuery.length > 0) {
// Check if guild is banned from using API and return appropriate message // Check if guild is banned from using API and return appropriate message
if (guildQuery[0].banned) { if (guildQuery[0].banned) {
utils.sendIndirectMessage(message, `The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.\n\nAPI rolls are banned from being used in this guild. This will not be reversed.`, sendMessage, sendDirectMessage).catch(e => { message.send(`The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.\n\nAPI rolls are banned from being used in this guild. This will not be reversed.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} else { } else {
utils.sendIndirectMessage(message, `The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.\n\nAPI rolls are ${guildQuery[0].active ? "allowed" : "blocked from being used"} in this guild.`, sendMessage, sendDirectMessage).catch(e => { message.send(`The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.\n\nAPI rolls are ${guildQuery[0].active ? "allowed" : "blocked from being used"} in this guild.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
} else { } else {
// Guild is not in DB, therefore they are blocked // Guild is not in DB, therefore they are blocked
utils.sendIndirectMessage(message, `The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.\n\nAPI rolls are blocked from being used in this guild.`, sendMessage, sendDirectMessage).catch(e => { message.send(`The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.\n\nAPI rolls are blocked from being used in this guild.`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
} }
} else { } else {
utils.sendIndirectMessage(message, `API commands are powerful and can only be used by guild Owners and Admins.\n\nFor information on how to use the API, please check the GitHub README for more information: <https://github.com/Burn-E99/TheArtificer>`, sendMessage, sendDirectMessage).catch(e => { message.send(`API commands are powerful and can only be used by guild Owners and Admins.\n\nFor information on how to use the API, please check the GitHub README for more information: <https://github.com/Burn-E99/TheArtificer>`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
} }
@ -360,15 +382,15 @@ startBot({
// [[roll]] // [[roll]]
// Dice rolling commence! // Dice rolling commence!
else if ((command + args.join("")).indexOf(config.postfix) > -1) { else if ((`${command}${args.join("")}`).indexOf(config.postfix) > -1) {
// Light telemetry to see how many times a command is being run // Light telemetry to see how many times a command is being run
dbClient.execute(`CALL INC_CNT("roll");`).catch(e => { dbClient.execute(`CALL INC_CNT("roll");`).catch(e => {
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
// If DEVMODE is on, only allow this command to be used in the devServer // If DEVMODE is on, only allow this command to be used in the devServer
if (DEVMODE && message.guildID !== config.devServer) { if (DEVMODE && message.guildId !== config.devServer) {
utils.sendIndirectMessage(message, "Command is in development, please try again later.", sendMessage, sendDirectMessage).catch(e => { message.send("Command is in development, please try again later.").catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
return; return;
@ -376,9 +398,9 @@ startBot({
// Rest of this command is in a try-catch to protect all sends/edits from erroring out // Rest of this command is in a try-catch to protect all sends/edits from erroring out
try { try {
const originalCommand = config.prefix + command + " " + args.join(" "); const originalCommand = `${config.prefix}${command} ${args.join(" ")}`;
const m = await utils.sendIndirectMessage(message, "Rolling...", sendMessage, sendDirectMessage); const m = await message.send("Rolling...");
const modifiers = { const modifiers = {
noDetails: false, noDetails: false,
@ -392,7 +414,7 @@ startBot({
// Check if any of the args are command flags and pull those out into the modifiers object // Check if any of the args are command flags and pull those out into the modifiers object
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
utils.log(LT.LOG, `Checking ${command + args.join(" ")} for command modifiers ${i}`); utils.log(LT.LOG, `Checking ${command}${args.join(" ")} for command modifiers ${i}`);
switch (args[i].toLowerCase()) { switch (args[i].toLowerCase()) {
case "-nd": case "-nd":
modifiers.noDetails = true; modifiers.noDetails = true;
@ -484,7 +506,7 @@ startBot({
} }
// Rejoin all of the args and send it into the solver, if solver returns a falsy item, an error object will be substituded in // Rejoin all of the args and send it into the solver, if solver returns a falsy item, an error object will be substituded in
const rollCmd = command + " " + args.join(" "); const rollCmd = `${command} ${args.join(" ")}`;
const returnmsg = solver.parseRoll(rollCmd, config.prefix, config.postfix, modifiers.maxRoll, modifiers.nominalRoll, modifiers.order) || { error: true, errorCode: "EmptyMessage", errorMsg: "Error: Empty message", line1: "", line2: "", line3: "" }; const returnmsg = solver.parseRoll(rollCmd, config.prefix, config.postfix, modifiers.maxRoll, modifiers.nominalRoll, modifiers.order) || { error: true, errorCode: "EmptyMessage", errorMsg: "Error: Empty message", line1: "", line2: "", line3: "" };
let returnText = ""; let returnText = "";
@ -503,19 +525,19 @@ startBot({
return; return;
} else { } else {
// Else format the output using details from the solver // Else format the output using details from the solver
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2; returnText = `<@${message.authorId}>${returnmsg.line1}\n${returnmsg.line2}`;
if (modifiers.noDetails) { if (modifiers.noDetails) {
returnText += "\nDetails suppressed by -nd flag."; returnText += "\nDetails suppressed by -nd flag.";
} else { } else {
returnText += "\nDetails:\n" + modifiers.spoiler + returnmsg.line3 + modifiers.spoiler; returnText += `\nDetails:\n${modifiers.spoiler}${returnmsg.line3}${modifiers.spoiler}`;
} }
} }
// If the roll was a GM roll, send DMs to all the GMs // If the roll was a GM roll, send DMs to all the GMs
if (modifiers.gmRoll) { if (modifiers.gmRoll) {
// Make a new return line to be sent to the roller // Make a new return line to be sent to the roller
const normalText = "<@" + message.author.id + ">" + returnmsg.line1 + "\nResults have been messaged to the following GMs: " + modifiers.gms.join(" "); const normalText = `<@${message.authorId}>${returnmsg.line1}\nResults have been messaged to the following GMs: ${modifiers.gms.join(" ")}`;
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged // And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
modifiers.gms.forEach(async e => { modifiers.gms.forEach(async e => {
@ -525,19 +547,19 @@ startBot({
if (b.size > 8388290) { if (b.size > 8388290) {
// Update return text // Update return text
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one."; returnText = `<@${message.authorId}>${returnmsg.line1}\n${returnmsg.line2}\nFull details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.`;
// Attempt to DM the GMs and send a warning if it could not DM a GM // Attempt to DM the GMs and send a warning if it could not DM a GM
await sendDirectMessage(e.substr(2, (e.length - 3)), returnText).catch(() => { await sendDirectMessage(BigInt(e.substr(2, (e.length - 3))), returnText).catch(() => {
utils.sendIndirectMessage(message, "WARNING: " + e + " could not be messaged. If this issue persists, make sure direct messages are allowed from this server.", sendMessage, sendDirectMessage); message.send(`WARNING: ${e} could not be messaged. If this issue persists, make sure direct messages are allowed from this server.`);
}); });
} else { } else {
// Update return text // Update return text
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details have been attached to this messaged as a `.txt` file for verification purposes."; returnText = `<@${message.authorId}>${returnmsg.line1}\n${returnmsg.line2}\nFull details have been attached to this messaged as a \`.txt\` file for verification purposes.`;
// Attempt to DM the GMs and send a warning if it could not DM a GM // Attempt to DM the GMs and send a warning if it could not DM a GM
await sendDirectMessage(e.substr(2, (e.length - 3)), { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }).catch(() => { await sendDirectMessage(BigInt(e.substr(2, (e.length - 3))), { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }).catch(() => {
utils.sendIndirectMessage(message, "WARNING: " + e + " could not be messaged. If this issue persists, make sure direct messages are allowed from this server.", sendMessage, sendDirectMessage); message.send(`WARNING: ${e} could not be messaged. If this issue persists, make sure direct messages are allowed from this server.`);
}); });
} }
}); });
@ -559,18 +581,18 @@ startBot({
if (b.size > 8388290) { if (b.size > 8388290) {
// Update return text // Update return text
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one."; returnText = `<@${message.authorId}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.`;
// Send the results // Send the results
m.edit(returnText); m.edit(returnText);
} else { } else {
// Update return text // Update return text
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a `.txt` file for verification purposes."; returnText = `<@${message.authorId}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a \`.txt\` file for verification purposes.`;
// Remove the original message to send new one with attachment // Remove the original message to send new one with attachment
m.delete(); m.delete();
await utils.sendIndirectMessage(message, { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }, sendMessage, sendDirectMessage); await message.send({ "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } });
} }
} else { } else {
// Finally send the text // Finally send the text
@ -594,16 +616,16 @@ startBot({
else { else {
// Start looping thru the possible emojis // Start looping thru the possible emojis
config.emojis.some((emoji: EmojiConf) => { config.emojis.some((emoji: EmojiConf) => {
utils.log(LT.LOG, `Checking if command was emoji ${emoji}`); utils.log(LT.LOG, `Checking if command was emoji ${JSON.stringify(emoji)}`);
// If a match gets found // If a match gets found
if (emoji.aliases.indexOf(command || "") > -1) { if (emoji.aliases.indexOf(command || "") > -1) {
// Light telemetry to see how many times a command is being run // Light telemetry to see how many times a command is being run
dbClient.execute(`CALL INC_CNT("emoji");`).catch(e => { dbClient.execute(`CALL INC_CNT("emojis");`).catch(e => {
utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
}); });
// Send the needed emoji1 // Send the needed emoji1
utils.sendIndirectMessage(message, `<${emoji.animated ? "a" : ""}:${emoji.name}:${emoji.id}>`, sendMessage, sendDirectMessage).catch(e => { message.send(`<${emoji.animated ? "a" : ""}:${emoji.name}:${emoji.id}>`).catch(e => {
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
}); });
// And attempt to delete if needed // And attempt to delete if needed
@ -622,10 +644,10 @@ startBot({
// Start up the command prompt for debug usage // Start up the command prompt for debug usage
if (DEBUG) { if (DEBUG) {
utils.cmdPrompt(config.logChannel, config.name, sendMessage); utils.cmdPrompt(config.logChannel, config.name);
} }
// Start up the API for rolling from third party apps (like excel macros) // Start up the API for rolling from third party apps (like excel macros)
if (config.api.enable) { if (config.api.enable) {
api.start(dbClient, cache, sendMessage, sendDirectMessage); api.start(dbClient);
} }

View File

@ -6,13 +6,13 @@
import { import {
// Discordeno deps // Discordeno deps
CacheData, Message, MessageContent, cache, CreateMessage,
sendMessage, sendDirectMessage,
// MySQL Driver deps // MySQL Driver deps
Client, Client,
// httpd deps // httpd deps
serve,
Status, STATUS_TEXT, Status, STATUS_TEXT,
// nanoid deps // nanoid deps
@ -27,8 +27,8 @@ import config from "../config.ts";
// start(databaseClient, botCache, sendMessage, sendDirectMessage) returns nothing // start(databaseClient, botCache, sendMessage, sendDirectMessage) returns nothing
// start initializes and runs the entire API for the bot // start initializes and runs the entire API for the bot
const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string, m: (string | MessageContent)) => Promise<Message>, sendDirectMessage: (c: string, m: (string | MessageContent)) => Promise<Message>): Promise<void> => { const start = async (dbClient: Client): Promise<void> => {
const server = serve({ hostname: "0.0.0.0", port: config.api.port }); const server = Deno.listen({ port: config.api.port });
utils.log(LT.INFO, `HTTP api running at: http://localhost:${config.api.port}/`); utils.log(LT.INFO, `HTTP api running at: http://localhost:${config.api.port}/`);
// rateLimitTime holds all users with the last time they started a rate limit timer // rateLimitTime holds all users with the last time they started a rate limit timer
@ -37,7 +37,11 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
const rateLimitCnt = new Map<string, number>(); const rateLimitCnt = new Map<string, number>();
// Catching every request made to the server // Catching every request made to the server
for await (const request of server) { for await (const conn of server) {
(async () => {
const httpConn = Deno.serveHttp(conn);
for await (const requestEvent of httpConn) {
const request = requestEvent.request;
utils.log(LT.LOG, `Handling request: ${JSON.stringify(request)}`); utils.log(LT.LOG, `Handling request: ${JSON.stringify(request)}`);
// Check if user is authenticated to be using this API // Check if user is authenticated to be using this API
let authenticated = false; let authenticated = false;
@ -90,7 +94,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// Turn the query into a map (if it exists) // Turn the query into a map (if it exists)
const query = new Map<string, string>(); const query = new Map<string, string>();
if (tempQ !== undefined) { if (tempQ !== undefined) {
tempQ.split("&").forEach(e => { tempQ.split("&").forEach((e: string) => {
utils.log(LT.LOG, `Breaking down request query: ${request} ${e}`); utils.log(LT.LOG, `Breaking down request query: ${request} ${e}`);
const [option, params] = e.split("="); const [option, params] = e.split("=");
query.set(option.toLowerCase(), params); query.set(option.toLowerCase(), params);
@ -104,7 +108,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
case "/api/key": case "/api/key":
case "/api/key/": case "/api/key/":
if ((query.has("user") && ((query.get("user") || "").length > 0)) && (query.has("a") && ((query.get("a") || "").length > 0))) { if ((query.has("user") && ((query.get("user") || "").length > 0)) && (query.has("a") && ((query.get("a") || "").length > 0))) {
if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a"))) { if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a") || "0")) {
// Generate new secure key // Generate new secure key
const newKey = await nanoid(25); const newKey = await nanoid(25);
@ -114,7 +118,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// Insert new key/user pair into the db // Insert new key/user pair into the db
await dbClient.execute("INSERT INTO all_keys(userid,apiKey) values(?,?)", [apiUserid, newKey]).catch(e => { await dbClient.execute("INSERT INTO all_keys(userid,apiKey) values(?,?)", [apiUserid, newKey]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -123,29 +127,29 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: JSON.stringify({ "key": newKey, "userid": query.get("user") }) }); requestEvent.respondWith(new Response(JSON.stringify({ "key": newKey, "userid": query.get("user") }), { status: Status.OK }));
break; break;
} }
} else { } else {
// Only allow the db admin to use this API // Only allow the db admin to use this API
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
case "/api/channel": case "/api/channel":
case "/api/channel/": case "/api/channel/":
if (query.has("user") && ((query.get("user") || "").length > 0)) { if (query.has("user") && ((query.get("user") || "").length > 0)) {
if (apiUserid === BigInt(query.get("user"))) { if (apiUserid === BigInt(query.get("user") || "0")) {
// Flag to see if there is an error inside the catch // Flag to see if there is an error inside the catch
let erroredOut = false; let erroredOut = false;
// Get all channels userid has authorized // Get all channels userid has authorized
const dbAllowedChannelQuery = await dbClient.query("SELECT * FROM allowed_channels WHERE userid = ?", [apiUserid]).catch(e => { const dbAllowedChannelQuery = await dbClient.query("SELECT * FROM allowed_channels WHERE userid = ?", [apiUserid]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -155,16 +159,16 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// Customized strinification to handle BigInts correctly // Customized strinification to handle BigInts correctly
const returnChannels = JSON.stringify(dbAllowedChannelQuery, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)); const returnChannels = JSON.stringify(dbAllowedChannelQuery, (_key, value) => (typeof value === 'bigint' ? value.toString() : value));
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: returnChannels }); requestEvent.respondWith(new Response(returnChannels, { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
case "/api/roll": case "/api/roll":
@ -173,7 +177,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if ((query.has("rollstr") && ((query.get("rollstr") || "").length > 0)) && (query.has("channel") && ((query.get("channel") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) { if ((query.has("rollstr") && ((query.get("rollstr") || "").length > 0)) && (query.has("channel") && ((query.get("channel") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) {
if (query.has("n") && query.has("m")) { if (query.has("n") && query.has("m")) {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
break; break;
} }
@ -181,12 +185,12 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
let authorized = false; let authorized = false;
// Check if the db has the requested userid/channelid combo, and that the requested userid matches the userid linked with the api key // Check if the db has the requested userid/channelid combo, and that the requested userid matches the userid linked with the api key
const dbChannelQuery = await dbClient.query("SELECT active, banned FROM allowed_channels WHERE userid = ? AND channelid = ?", [apiUserid, BigInt(query.get("channel"))]); const dbChannelQuery = await dbClient.query("SELECT active, banned FROM allowed_channels WHERE userid = ? AND channelid = ?", [apiUserid, BigInt(query.get("channel") || "0")]);
if (dbChannelQuery.length === 1 && (apiUserid === BigInt(query.get("user"))) && dbChannelQuery[0].active && !dbChannelQuery[0].banned) { if (dbChannelQuery.length === 1 && (apiUserid === BigInt(query.get("user") || "0")) && dbChannelQuery[0].active && !dbChannelQuery[0].banned) {
// Get the guild from the channel and make sure user is in said guild // Get the guild from the channel and make sure user is in said guild
const guild = cache.channels.get(query.get("channel") || "")?.guild; const guild = cache.channels.get(BigInt(query.get("channel") || ""))?.guild;
if (guild && guild.members.get(query.get("user") || "")?.id) { if (guild && guild.members.get(BigInt(query.get("user") || ""))?.id) {
const dbGuildQuery = await dbClient.query("SELECT active, banned FROM allowed_guilds WHERE guildid = ?", [BigInt(guild.id)]); const dbGuildQuery = await dbClient.query("SELECT active, banned FROM allowed_guilds WHERE guildid = ?", [BigInt(guild.id)]);
// Make sure guild allows API rolls // Make sure guild allows API rolls
@ -207,7 +211,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if (rollCmd.length === 0) { if (rollCmd.length === 0) {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
// Always log API rolls for abuse detection // Always log API rolls for abuse detection
dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, "EmptyInput", null]).catch(e => { dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, "EmptyInput", null]).catch(e => {
@ -218,7 +222,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if (query.has("o") && (query.get("o")?.toLowerCase() !== "d" && query.get("o")?.toLowerCase() !== "a")) { if (query.has("o") && (query.get("o")?.toLowerCase() !== "d" && query.get("o")?.toLowerCase() !== "a")) {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
// Always log API rolls for abuse detection // Always log API rolls for abuse detection
dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, "BadOrder", null]).catch(e => { dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, "BadOrder", null]).catch(e => {
@ -234,12 +238,12 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
const returnmsg = solver.parseRoll(rollCmd, config.prefix, config.postfix, query.has("m"), query.has("n"), query.has("o") ? (query.get("o")?.toLowerCase() || "") : ""); const returnmsg = solver.parseRoll(rollCmd, config.prefix, config.postfix, query.has("m"), query.has("n"), query.has("o") ? (query.get("o")?.toLowerCase() || "") : "");
// Alert users why this message just appeared and how they can report abues pf this feature // Alert users why this message just appeared and how they can report abues pf this feature
const apiPrefix = "The following roll was conducted using my built in API. If someone in this channel did not request this roll, please report API abuse here: <" + config.api.supportURL + ">\n\n"; const apiPrefix = `The following roll was conducted using my built in API. If someone in this channel did not request this roll, please report API abuse here: <${config.api.supportURL}>\n\n`;
let m, returnText = ""; let m, returnText = "";
// Handle sending the error message to whoever called the api // Handle sending the error message to whoever called the api
if (returnmsg.error) { if (returnmsg.error) {
request.respond({ status: Status.InternalServerError, body: returnmsg.errorMsg }); requestEvent.respondWith(new Response(returnmsg.errorMsg, { status: Status.InternalServerError }));
// Always log API rolls for abuse detection // Always log API rolls for abuse detection
dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, returnmsg.errorCode, null]).catch(e => { dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, returnmsg.errorCode, null]).catch(e => {
@ -247,7 +251,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
}); });
break; break;
} else { } else {
returnText = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2; returnText = `${apiPrefix}<@${query.get("user")}>${returnmsg.line1}\n${returnmsg.line2}`;
let spoilerTxt = ""; let spoilerTxt = "";
// Determine if spoiler flag was on // Determine if spoiler flag was on
@ -259,7 +263,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if (query.has("nd")) { if (query.has("nd")) {
returnText += "\nDetails suppressed by nd query."; returnText += "\nDetails suppressed by nd query.";
} else { } else {
returnText += "\nDetails:\n" + spoilerTxt + returnmsg.line3 + spoilerTxt; returnText += `\nDetails:\n${spoilerTxt}${returnmsg.line3}${spoilerTxt}`;
} }
} }
@ -269,7 +273,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
const gms = (query.get("gms") || "").split(","); const gms = (query.get("gms") || "").split(",");
if (gms.length === 0) { if (gms.length === 0) {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
// Always log API rolls for abuse detection // Always log API rolls for abuse detection
dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, "NoGMsSent", null]).catch(e => { dbClient.execute("INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,1,1)", [originalCommand, "NoGMsSent", null]).catch(e => {
@ -279,35 +283,35 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
} }
// Make a new return line to be sent to the roller // Make a new return line to be sent to the roller
let normalText = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\nResults have been messaged to the following GMs: "; let normalText = `${apiPrefix}<@${query.get("user")}>${returnmsg.line1}\nResults have been messaged to the following GMs: `;
gms.forEach(e => { gms.forEach(e => {
utils.log(LT.LOG, `Appending GM ${e} to roll text`); utils.log(LT.LOG, `Appending GM ${e} to roll text`);
normalText += "<@" + e + "> "; normalText += `<@${e}> `;
}); });
// Send the return message as a DM or normal message depening on if the channel is set // Send the return message as a DM or normal message depening on if the channel is set
if ((query.get("channel") || "").length > 0) { if ((query.get("channel") || "").length > 0) {
m = await sendMessage(query.get("channel") || "", normalText).catch(() => { m = await sendMessage(BigInt(query.get("channel") || ""), normalText).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message 00 failed to send." }); requestEvent.respondWith(new Response("Message 00 failed to send.", { status: Status.InternalServerError }));
errorOut = true; errorOut = true;
}); });
} else { } else {
m = await sendDirectMessage(query.get("user") || "", normalText).catch(() => { m = await sendDirectMessage(BigInt(query.get("user") || ""), normalText).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message 01 failed to send." }); requestEvent.respondWith(new Response("Message 01 failed to send.", { status: Status.InternalServerError }));
errorOut = true; errorOut = true;
}); });
} }
const newMessage: MessageContent = {}; const newMessage: CreateMessage = {};
// If its too big, collapse it into a .txt file and send that instead. // If its too big, collapse it into a .txt file and send that instead.
const b = await new Blob([returnText as BlobPart], { "type": "text" }); const b = await new Blob([returnText as BlobPart], { "type": "text" });
if (b.size > 8388290) { if (b.size > 8388290) {
// Update return text // Update return text
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one."; newMessage.content = `${apiPrefix}<@${query.get("user")}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.`;
} else { } else {
// Update return text // Update return text
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details have been attached to this messaged as a `.txt` file for verification purposes."; newMessage.content = `${apiPrefix}<@${query.get("user")}>${returnmsg.line1}\n${returnmsg.line2}\nFull details have been attached to this messaged as a \`.txt\` file for verification purposes.`;
newMessage.file = { "blob": b, "name": "rollDetails.txt" }; newMessage.file = { "blob": b, "name": "rollDetails.txt" };
} }
@ -315,17 +319,17 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
gms.forEach(async e => { gms.forEach(async e => {
utils.log(LT.LOG, `Messaging GM ${e} roll results`); utils.log(LT.LOG, `Messaging GM ${e} roll results`);
// Attempt to DM the GMs and send a warning if it could not DM a GM // Attempt to DM the GMs and send a warning if it could not DM a GM
await sendDirectMessage(e, newMessage).catch(async () => { await sendDirectMessage(BigInt(e), newMessage).catch(async () => {
const failedSend = "WARNING: <@" + e + "> could not be messaged. If this issue persists, make sure direct messages are allowed from this server." const failedSend = `WARNING: <@${e}> could not be messaged. If this issue persists, make sure direct messages are allowed from this server.`
// Send the return message as a DM or normal message depening on if the channel is set // Send the return message as a DM or normal message depening on if the channel is set
if ((query.get("channel") || "").length > 0) { if ((query.get("channel") || "").length > 0) {
m = await sendMessage(query.get("channel") || "", failedSend).catch(() => { m = await sendMessage(BigInt(query.get("channel") || ""), failedSend).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message failed to send." }); requestEvent.respondWith(new Response("Message failed to send.", { status: Status.InternalServerError }));
errorOut = true; errorOut = true;
}); });
} else { } else {
m = await sendDirectMessage(query.get("user") || "", failedSend).catch(() => { m = await sendDirectMessage(BigInt(query.get("user") || ""), failedSend).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message failed to send." }); requestEvent.respondWith(new Response("Message failed to send.", { status: Status.InternalServerError }));
errorOut = true; errorOut = true;
}); });
} }
@ -341,11 +345,11 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if (errorOut) { if (errorOut) {
break; break;
} else { } else {
request.respond({ status: Status.OK, body: normalText }); requestEvent.respondWith(new Response(normalText, { status: Status.OK }));
break; break;
} }
} else { } else {
const newMessage: MessageContent = {}; const newMessage: CreateMessage = {};
newMessage.content = returnText; newMessage.content = returnText;
// When not a GM roll, make sure the message is not too big // When not a GM roll, make sure the message is not too big
@ -355,23 +359,23 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if (b.size > 8388290) { if (b.size > 8388290) {
// Update return text // Update return text
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one."; newMessage.content = `${apiPrefix}<@${query.get("user")}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.`;
} else { } else {
// Update return text // Update return text
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a `.txt` file for verification purposes."; newMessage.content = `${apiPrefix}<@${query.get("user")}>${returnmsg.line1}\n${returnmsg.line2}\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a \`.txt\` file for verification purposes.`;
newMessage.file = { "blob": b, "name": "rollDetails.txt" }; newMessage.file = { "blob": b, "name": "rollDetails.txt" };
} }
} }
// Send the return message as a DM or normal message depening on if the channel is set // Send the return message as a DM or normal message depening on if the channel is set
if ((query.get("channel") || "").length > 0) { if ((query.get("channel") || "").length > 0) {
m = await sendMessage(query.get("channel") || "", newMessage).catch(() => { m = await sendMessage(BigInt(query.get("channel") || ""), newMessage).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message 20 failed to send." }); requestEvent.respondWith(new Response("Message 20 failed to send.", { status: Status.InternalServerError }));
errorOut = true; errorOut = true;
}); });
} else { } else {
m = await sendDirectMessage(query.get("user") || "", newMessage).catch(() => { m = await sendDirectMessage(BigInt(query.get("user") || ""), newMessage).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message 21 failed to send." }); requestEvent.respondWith(new Response("Message 21 failed to send.", { status: Status.InternalServerError }));
errorOut = true; errorOut = true;
}); });
} }
@ -385,27 +389,27 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
if (errorOut) { if (errorOut) {
break; break;
} else { } else {
request.respond({ status: Status.OK, body: returnText }); requestEvent.respondWith(new Response(returnText, { status: Status.OK }));
break; break;
} }
} }
} catch (err) { } catch (err) {
// Handle any errors we missed // Handle any errors we missed
utils.log(LT.ERROR, `Unhandled Error: ${JSON.stringify(err)}`); utils.log(LT.ERROR, `Unhandled Error: ${JSON.stringify(err)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.NotFound, body: STATUS_TEXT.get(Status.NotFound) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.NotFound), { status: Status.NotFound }));
break; break;
} }
break; break;
@ -414,14 +418,14 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
case "/api/channel/add": case "/api/channel/add":
case "/api/channel/add/": case "/api/channel/add/":
if ((query.has("user") && ((query.get("user") || "").length > 0)) && (query.has("channel") && ((query.get("channel") || "").length > 0))) { if ((query.has("user") && ((query.get("user") || "").length > 0)) && (query.has("channel") && ((query.get("channel") || "").length > 0))) {
if (apiUserid === BigInt(query.get("user"))) { if (apiUserid === BigInt(query.get("user") || "0")) {
// Flag to see if there is an error inside the catch // Flag to see if there is an error inside the catch
let erroredOut = false; let erroredOut = false;
// Insert new user/channel pair into the db // Insert new user/channel pair into the db
await dbClient.execute("INSERT INTO allowed_channels(userid,channelid) values(?,?)", [apiUserid, BigInt(query.get("channel"))]).catch(e => { await dbClient.execute("INSERT INTO allowed_channels(userid,channelid) values(?,?)", [apiUserid, BigInt(query.get("channel") || "0")]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -430,21 +434,21 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: STATUS_TEXT.get(Status.OK) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.OK), { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.NotFound, body: STATUS_TEXT.get(Status.NotFound) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.NotFound), { status: Status.NotFound }));
break; break;
} }
break; break;
@ -459,7 +463,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
case "/api/key/deactivate": case "/api/key/deactivate":
case "/api/key/deactivate/": case "/api/key/deactivate/":
if ((query.has("a") && ((query.get("a") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) { if ((query.has("a") && ((query.get("a") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) {
if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a"))) { if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a") || "0")) {
// Flag to see if there is an error inside the catch // Flag to see if there is an error inside the catch
let key, value, erroredOut = false; let key, value, erroredOut = false;
@ -480,7 +484,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// Execute the DB modification // Execute the DB modification
await dbClient.execute("UPDATE all_keys SET ?? = ? WHERE userid = ?", [key, value, apiUserid]).catch(e => { await dbClient.execute("UPDATE all_keys SET ?? = ? WHERE userid = ?", [key, value, apiUserid]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -489,16 +493,16 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: STATUS_TEXT.get(Status.OK) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.OK), { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
case "/api/channel/ban": case "/api/channel/ban":
@ -506,7 +510,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
case "/api/channel/unban": case "/api/channel/unban":
case "/api/channel/unban/": case "/api/channel/unban/":
if ((query.has("a") && ((query.get("a") || "").length > 0)) && (query.has("channel") && ((query.get("channel") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) { if ((query.has("a") && ((query.get("a") || "").length > 0)) && (query.has("channel") && ((query.get("channel") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) {
if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a"))) { if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a") || "0")) {
// Flag to see if there is an error inside the catch // Flag to see if there is an error inside the catch
let value, erroredOut = false; let value, erroredOut = false;
@ -518,9 +522,9 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
} }
// Execute the DB modification // Execute the DB modification
await dbClient.execute("UPDATE allowed_channels SET banned = ? WHERE userid = ? AND channelid = ?", [value, apiUserid, BigInt(query.get("channel"))]).catch(e => { await dbClient.execute("UPDATE allowed_channels SET banned = ? WHERE userid = ? AND channelid = ?", [value, apiUserid, BigInt(query.get("channel") || "0")]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -529,16 +533,16 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: STATUS_TEXT.get(Status.OK) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.OK), { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
case "/api/channel/activate": case "/api/channel/activate":
@ -546,7 +550,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
case "/api/channel/deactivate": case "/api/channel/deactivate":
case "/api/channel/deactivate/": case "/api/channel/deactivate/":
if ((query.has("channel") && ((query.get("channel") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) { if ((query.has("channel") && ((query.get("channel") || "").length > 0)) && (query.has("user") && ((query.get("user") || "").length > 0))) {
if (apiUserid === BigInt(query.get("user"))) { if (apiUserid === BigInt(query.get("user") || "0")) {
// Flag to see if there is an error inside the catch // Flag to see if there is an error inside the catch
let value, erroredOut = false; let value, erroredOut = false;
@ -558,9 +562,9 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
} }
// Update the requested entry // Update the requested entry
await dbClient.execute("UPDATE allowed_channels SET active = ? WHERE userid = ? AND channelid = ?", [value, apiUserid, BigInt(query.get("channel"))]).catch(e => { await dbClient.execute("UPDATE allowed_channels SET active = ? WHERE userid = ? AND channelid = ?", [value, apiUserid, BigInt(query.get("channel") || "0")]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -569,21 +573,21 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: STATUS_TEXT.get(Status.OK) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.OK), { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.NotFound, body: STATUS_TEXT.get(Status.NotFound) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.NotFound), { status: Status.NotFound }));
break; break;
} }
break; break;
@ -592,7 +596,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
case "/api/key/delete": case "/api/key/delete":
case "/api/key/delete/": case "/api/key/delete/":
if (query.has("user") && ((query.get("user") || "").length > 0) && query.has("email") && ((query.get("email") || "").length > 0)) { if (query.has("user") && ((query.get("user") || "").length > 0) && query.has("email") && ((query.get("email") || "").length > 0)) {
if (apiUserid === BigInt(query.get("user")) && apiUserEmail === query.get("email")) { if (apiUserid === BigInt(query.get("user") || "0") && apiUserEmail === query.get("email")) {
if (query.has("code") && ((query.get("code") || "").length > 0)) { if (query.has("code") && ((query.get("code") || "").length > 0)) {
if ((query.get("code") || "") === apiUserDelCode) { if ((query.get("code") || "") === apiUserDelCode) {
// User has recieved their delete code and we need to delete the account now // User has recieved their delete code and we need to delete the account now
@ -600,7 +604,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
await dbClient.execute("DELETE FROM allowed_channels WHERE userid = ?", [apiUserid]).catch(e => { await dbClient.execute("DELETE FROM allowed_channels WHERE userid = ?", [apiUserid]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
if (erroredOut) { if (erroredOut) {
@ -609,19 +613,19 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
await dbClient.execute("DELETE FROM all_keys WHERE userid = ?", [apiUserid]).catch(e => { await dbClient.execute("DELETE FROM all_keys WHERE userid = ?", [apiUserid]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
if (erroredOut) { if (erroredOut) {
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: STATUS_TEXT.get(Status.OK) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.OK), { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// User does not have their delete code yet, so we need to generate one and email it to them // User does not have their delete code yet, so we need to generate one and email it to them
@ -632,7 +636,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// Execute the DB modification // Execute the DB modification
await dbClient.execute("UPDATE all_keys SET deleteCode = ? WHERE userid = ?", [deleteCode, apiUserid]).catch(e => { await dbClient.execute("UPDATE all_keys SET deleteCode = ? WHERE userid = ?", [deleteCode, apiUserid]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
if (erroredOut) { if (erroredOut) {
@ -641,35 +645,35 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// "Send" the email // "Send" the email
await sendMessage(config.api.email, `<@${config.api.admin}> A USER HAS REQUESTED A DELETE CODE\n\nEmail Address: ${apiUserEmail}\n\nSubject: \`Artificer API Delete Code\`\n\n\`\`\`Hello Artificer API User,\n\nI am sorry to see you go. If you would like, please respond to this email detailing what I could have done better.\n\nAs requested, here is your delete code: ${deleteCode}\n\nSorry to see you go,\nThe Artificer Developer - Ean Milligan\`\`\``).catch(() => { await sendMessage(config.api.email, `<@${config.api.admin}> A USER HAS REQUESTED A DELETE CODE\n\nEmail Address: ${apiUserEmail}\n\nSubject: \`Artificer API Delete Code\`\n\n\`\`\`Hello Artificer API User,\n\nI am sorry to see you go. If you would like, please respond to this email detailing what I could have done better.\n\nAs requested, here is your delete code: ${deleteCode}\n\nSorry to see you go,\nThe Artificer Developer - Ean Milligan\`\`\``).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message 30 failed to send." }); requestEvent.respondWith(new Response("Message 30 failed to send.", { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
if (erroredOut) { if (erroredOut) {
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.FailedDependency, body: STATUS_TEXT.get(Status.FailedDependency) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.FailedDependency), { status: Status.FailedDependency }));
break; break;
} }
} }
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.NotFound, body: STATUS_TEXT.get(Status.NotFound) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.NotFound), { status: Status.NotFound }));
break; break;
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.MethodNotAllowed, body: STATUS_TEXT.get(Status.MethodNotAllowed) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.MethodNotAllowed), { status: Status.MethodNotAllowed }));
break; break;
} }
@ -684,7 +688,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// Turn the query into a map (if it exists) // Turn the query into a map (if it exists)
const query = new Map<string, string>(); const query = new Map<string, string>();
if (tempQ !== undefined) { if (tempQ !== undefined) {
tempQ.split("&").forEach(e => { tempQ.split("&").forEach((e: string) => {
utils.log(LT.LOG, `Parsing request query #2 ${request} ${e}`); utils.log(LT.LOG, `Parsing request query #2 ${request} ${e}`);
const [option, params] = e.split("="); const [option, params] = e.split("=");
query.set(option.toLowerCase(), params); query.set(option.toLowerCase(), params);
@ -705,9 +709,9 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
let erroredOut = false; let erroredOut = false;
// Insert new key/user pair into the db // Insert new key/user pair into the db
await dbClient.execute("INSERT INTO all_keys(userid,apiKey,email) values(?,?,?)", [BigInt(query.get("user")), newKey, (query.get("email") || "").toLowerCase()]).catch(e => { await dbClient.execute("INSERT INTO all_keys(userid,apiKey,email) values(?,?,?)", [BigInt(query.get("user") || "0"), newKey, (query.get("email") || "").toLowerCase()]).catch(e => {
utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`); utils.log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
request.respond({ status: Status.InternalServerError, body: STATUS_TEXT.get(Status.InternalServerError) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -718,7 +722,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
// "Send" the email // "Send" the email
await sendMessage(config.api.email, `<@${config.api.admin}> A USER HAS REQUESTED AN API KEY\n\nEmail Address: ${query.get("email")}\n\nSubject: \`Artificer API Key\`\n\n\`\`\`Hello Artificer API User,\n\nWelcome aboard The Artificer's API. You can find full details about the API on the GitHub: https://github.com/Burn-E99/TheArtificer\n\nYour API Key is: ${newKey}\n\nGuard this well, as there is zero tolerance for API abuse.\n\nWelcome aboard,\nThe Artificer Developer - Ean Milligan\`\`\``).catch(() => { await sendMessage(config.api.email, `<@${config.api.admin}> A USER HAS REQUESTED AN API KEY\n\nEmail Address: ${query.get("email")}\n\nSubject: \`Artificer API Key\`\n\n\`\`\`Hello Artificer API User,\n\nWelcome aboard The Artificer's API. You can find full details about the API on the GitHub: https://github.com/Burn-E99/TheArtificer\n\nYour API Key is: ${newKey}\n\nGuard this well, as there is zero tolerance for API abuse.\n\nWelcome aboard,\nThe Artificer Developer - Ean Milligan\`\`\``).catch(() => {
request.respond({ status: Status.InternalServerError, body: "Message 31 failed to send." }); requestEvent.respondWith(new Response("Message 31 failed to send.", { status: Status.InternalServerError }));
erroredOut = true; erroredOut = true;
}); });
@ -726,33 +730,35 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
break; break;
} else { } else {
// Send API key as response // Send API key as response
request.respond({ status: Status.OK, body: STATUS_TEXT.get(Status.OK) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.OK), { status: Status.OK }));
break; break;
} }
} else { } else {
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.BadRequest, body: STATUS_TEXT.get(Status.BadRequest) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.NotFound, body: STATUS_TEXT.get(Status.NotFound) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.NotFound), { status: Status.NotFound }));
break; break;
} }
break; break;
default: default:
// Alert API user that they messed up // Alert API user that they messed up
request.respond({ status: Status.MethodNotAllowed, body: STATUS_TEXT.get(Status.MethodNotAllowed) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.MethodNotAllowed), { status: Status.MethodNotAllowed }));
break; break;
} }
} else if (authenticated && rateLimited) { } else if (authenticated && rateLimited) {
// Alert API user that they are doing this too often // Alert API user that they are doing this too often
request.respond({ status: Status.TooManyRequests, body: STATUS_TEXT.get(Status.TooManyRequests) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.TooManyRequests), { status: Status.TooManyRequests }));
} else { } else {
// Alert API user that they shouldn't be doing this // Alert API user that they shouldn't be doing this
request.respond({ status: Status.Forbidden, body: STATUS_TEXT.get(Status.Forbidden) }); requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: Status.Forbidden }));
} }
} }
})();
}
}; };
export default { start }; export default { start };

View File

@ -6,16 +6,16 @@
import { import {
// Discordeno deps // Discordeno deps
CacheData cache, cacheHandlers
} from "../deps.ts"; } from "../deps.ts";
import { LogTypes as LT } from "./utils.enums.ts"; import { LogTypes as LT } from "./utils.enums.ts";
import utils from "./utils.ts"; import utils from "./utils.ts";
import config from "../config.ts"; import config from "../config.ts";
// getRandomStatus(bot cache) returns status as string // getRandomStatus() returns status as string
// Gets a new random status for the bot // Gets a new random status for the bot
const getRandomStatus = (cache: CacheData): string => { const getRandomStatus = async (): Promise<string> => {
let status = ""; let status = "";
switch (Math.floor((Math.random() * 4) + 1)) { switch (Math.floor((Math.random() * 4) + 1)) {
case 1: case 1:
@ -27,17 +27,19 @@ const getRandomStatus = (cache: CacheData): string => {
case 3: case 3:
status = `${config.prefix}info to learn more`; status = `${config.prefix}info to learn more`;
break; break;
default: default: {
status = `Rolling dice for ${cache.guilds.size} servers`; const cachedCount = await cacheHandlers.size("guilds")
status = `Rolling dice for ${cachedCount + cache.dispatchedGuildIds.size} servers`;
break; break;
} }
}
return status; return status;
}; };
// updateListStatistics(bot ID, current guild count) returns nothing // updateListStatistics(bot ID, current guild count) returns nothing
// Sends the current server count to all bot list sites we are listed on // Sends the current server count to all bot list sites we are listed on
const updateListStatistics = (botID: string, serverCount: number): void => { const updateListStatistics = (botID: bigint, serverCount: number): void => {
config.botLists.forEach(async e => { config.botLists.forEach(async e => {
utils.log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`) utils.log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`)
if (e.enabled) { if (e.enabled) {
@ -45,7 +47,7 @@ const updateListStatistics = (botID: string, serverCount: number): void => {
tempHeaders.append(e.headers[0].header, e.headers[0].value); tempHeaders.append(e.headers[0].header, e.headers[0].value);
tempHeaders.append("Content-Type", "application/json"); tempHeaders.append("Content-Type", "application/json");
// ?{} is a template used in config, just need to replace it with the real value // ?{} is a template used in config, just need to replace it with the real value
const response = await fetch(e.apiUrl.replace("?{bot_id}", botID), { const response = await fetch(e.apiUrl.replace("?{bot_id}", botID.toString()), {
"method": 'POST', "method": 'POST',
"headers": tempHeaders, "headers": tempHeaders,
"body": JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()) // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number "body": JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()) // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number

View File

@ -64,7 +64,7 @@ const escapeCharacters = (str: string, esc: string): string => {
utils.log(LT.LOG, `Escaping character ${esc[i]} | ${str}, ${esc}`); utils.log(LT.LOG, `Escaping character ${esc[i]} | ${str}, ${esc}`);
// Create a new regex to look for that char that needs replaced and escape it // Create a new regex to look for that char that needs replaced and escape it
const temprgx = new RegExp(`[${esc[i]}]`, "g"); const temprgx = new RegExp(`[${esc[i]}]`, "g");
str = str.replace(temprgx, ("\\" + esc[i])); str = str.replace(temprgx, `\\${esc[i]}`);
} }
return str; return str;
}; };
@ -158,7 +158,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
if (remains.length > 0) { if (remains.length > 0) {
// Determine if the first item is a drop, and if it is, add the d back in // Determine if the first item is a drop, and if it is, add the d back in
if (remains.search(/\D/) !== 0 || remains.indexOf("l") === 0 || remains.indexOf("h") === 0) { if (remains.search(/\D/) !== 0 || remains.indexOf("l") === 0 || remains.indexOf("h") === 0) {
remains = "d" + remains; remains = `d${remains}`;
} }
// Loop until all remaining args are parsed // Loop until all remaining args are parsed
@ -260,7 +260,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
break; break;
default: default:
// Throw error immediately if unknown op is encountered // Throw error immediately if unknown op is encountered
throw new Error("UnknownOperation_" + tSep); throw new Error(`UnknownOperation_${tSep}`);
} }
// Finally slice off everything else parsed this loop // Finally slice off everything else parsed this loop
remains = remains.slice(afterNumIdx); remains = remains.slice(afterNumIdx);
@ -538,22 +538,22 @@ const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll: boolea
// If the roll was a crit hit or fail, or dropped/rerolled, add the formatting needed // If the roll was a crit hit or fail, or dropped/rerolled, add the formatting needed
if (e.critHit) { if (e.critHit) {
// Bold for crit success // Bold for crit success
preFormat = "**" + preFormat; preFormat = `**${preFormat}`;
postFormat = postFormat + "**"; postFormat = `${postFormat}**`;
} }
if (e.critFail) { if (e.critFail) {
// Underline for crit fail // Underline for crit fail
preFormat = "__" + preFormat; preFormat = `__${preFormat}`;
postFormat = postFormat + "__"; postFormat = `${postFormat}__`;
} }
if (e.dropped || e.rerolled) { if (e.dropped || e.rerolled) {
// Strikethrough for dropped/rerolled rolls // Strikethrough for dropped/rerolled rolls
preFormat = "~~" + preFormat; preFormat = `~~${preFormat}`;
postFormat = postFormat + "~~"; postFormat = `${postFormat}~~`;
} }
// Finally add this to the roll's details // Finally add this to the roll's details
tempDetails += preFormat + e.roll + postFormat + " + "; tempDetails += `${preFormat}${e.roll}${postFormat} + `;
}); });
// After the looping is done, remove the extra " + " from the details and cap it with the closing ] // After the looping is done, remove the extra " + " from the details and cap it with the closing ]
tempDetails = tempDetails.substr(0, (tempDetails.length - 3)); tempDetails = tempDetails.substr(0, (tempDetails.length - 3));
@ -660,13 +660,13 @@ const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean
// If operand1 is a SolvedStep, populate our subStepSolve with its details and crit/fail flags // If operand1 is a SolvedStep, populate our subStepSolve with its details and crit/fail flags
if (typeof operand1 === "object") { if (typeof operand1 === "object") {
oper1 = operand1.total; oper1 = operand1.total;
subStepSolve.details = operand1.details + "\\" + conf[i]; subStepSolve.details = `${operand1.details}\\${conf[i]}`;
subStepSolve.containsCrit = operand1.containsCrit; subStepSolve.containsCrit = operand1.containsCrit;
subStepSolve.containsFail = operand1.containsFail; subStepSolve.containsFail = operand1.containsFail;
} else { } else {
// else parse it as a number and add it to the subStep details // else parse it as a number and add it to the subStep details
oper1 = parseFloat(operand1.toString()); oper1 = parseFloat(operand1.toString());
subStepSolve.details = oper1.toString() + "\\" + conf[i]; subStepSolve.details = `${oper1.toString()}\\${conf[i]}`;
} }
// If operand2 is a SolvedStep, populate our subStepSolve with its details without overriding what operand1 filled in // If operand2 is a SolvedStep, populate our subStepSolve with its details without overriding what operand1 filled in
@ -740,7 +740,7 @@ const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean
// If this was a nested call, add on parens around the details to show what math we've done // If this was a nested call, add on parens around the details to show what math we've done
if (wrapDetails) { if (wrapDetails) {
stepSolve.details = "(" + stepSolve.details + ")"; stepSolve.details = `(${stepSolve.details})`;
} }
// If our total has reached undefined for some reason, error out now // If our total has reached undefined for some reason, error out now
@ -899,25 +899,25 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
// If the roll containted a crit success or fail, set the formatting around it // If the roll containted a crit success or fail, set the formatting around it
if (e.containsCrit) { if (e.containsCrit) {
preFormat = "**" + preFormat; preFormat = `**${preFormat}`;
postFormat = postFormat + "**"; postFormat = `${postFormat}**`;
} }
if (e.containsFail) { if (e.containsFail) {
preFormat = "__" + preFormat; preFormat = `__${preFormat}`;
postFormat = postFormat + "__"; postFormat = `${postFormat}__`;
} }
// Populate line2 (the results) and line3 (the details) with their data // Populate line2 (the results) and line3 (the details) with their data
if (order === "") { if (order === "") {
line2 += preFormat + e.rollTotal + postFormat + escapeCharacters(e.rollPostFormat, "|*_~`"); line2 += `${preFormat}${e.rollTotal}${postFormat}${escapeCharacters(e.rollPostFormat, "|*_~`")}`;
} else { } else {
// If order is on, turn rolls into csv without formatting // If order is on, turn rolls into csv without formatting
line2 += preFormat + e.rollTotal + postFormat + ", "; line2 += `${preFormat}${e.rollTotal}${postFormat}, `;
} }
line2 = line2.replace(/\*\*\*\*/g, "** **").replace(/____/g, "__ __").replace(/~~~~/g, "~~ ~~"); line2 = line2.replace(/\*\*\*\*/g, "** **").replace(/____/g, "__ __").replace(/~~~~/g, "~~ ~~");
line3 += "`" + e.initConfig + "` = " + e.rollDetails + " = " + preFormat + e.rollTotal + postFormat + "\n"; line3 += `\`${e.initConfig}\` = ${e.rollDetails} = ${preFormat}${e.rollTotal}${postFormat}\n`;
}); });
// If order is on, remove trailing ", " // If order is on, remove trailing ", "
@ -950,11 +950,11 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
errorMsg = "Formatting Error: CritScore range specified without a maximum, remove - or add maximum to correct"; errorMsg = "Formatting Error: CritScore range specified without a maximum, remove - or add maximum to correct";
break; break;
case "UnknownOperation": case "UnknownOperation":
errorMsg = "Error: Unknown Operation " + errorDetails; errorMsg = `Error: Unknown Operation ${errorDetails}`;
if (errorDetails === "-") { if (errorDetails === "-") {
errorMsg += "\nNote: Negative numbers are not supported"; errorMsg += "\nNote: Negative numbers are not supported";
} else if (errorDetails === " ") { } else if (errorDetails === " ") {
errorMsg += "\nNote: Every roll must be closed by " + localPostfix; errorMsg += `\nNote: Every roll must be closed by ${localPostfix}`;
} }
break; break;
case "NoZerosAllowed": case "NoZerosAllowed":
@ -982,7 +982,7 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
errorMsg += "Crit Score (cs)"; errorMsg += "Crit Score (cs)";
break; break;
default: default:
errorMsg += "Unhandled - " + errorDetails; errorMsg += `Unhandled - ${errorDetails}`;
break; break;
} }
errorMsg += " cannot be zero"; errorMsg += " cannot be zero";
@ -1013,7 +1013,7 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
break; break;
default: default:
utils.log(LT.ERROR, `Undangled Error: ${errorName}, ${errorDetails}`); utils.log(LT.ERROR, `Undangled Error: ${errorName}, ${errorDetails}`);
errorMsg = "Unhandled Error: " + solverError.message + "\nCheck input and try again, if issue persists, please use `[[report` to alert the devs of the issue"; errorMsg = `Unhandled Error: ${solverError.message}\nCheck input and try again, if issue persists, please use \`[[report\` to alert the devs of the issue`;
break; break;
} }

View File

@ -6,7 +6,7 @@
import { import {
// Discordeno deps // Discordeno deps
Message, MessageContent, sendMessage,
// nanoid deps // nanoid deps
nanoid nanoid
@ -35,9 +35,9 @@ const ask = async (question: string, stdin = Deno.stdin, stdout = Deno.stdout):
return answer.trim(); return answer.trim();
}; };
// cmdPrompt(logChannel, botName, sendMessage) returns nothing // cmdPrompt(logChannel, botName) returns nothing
// cmdPrompt creates an interactive CLI for the bot, commands can vary // cmdPrompt creates an interactive CLI for the bot, commands can vary
const cmdPrompt = async (logChannel: string, botName: string, sendMessage: (c: string, m: string) => Promise<Message>): Promise<void> => { const cmdPrompt = async (logChannel: bigint, botName: string): Promise<void> => {
let done = false; let done = false;
while (!done) { while (!done) {
@ -69,10 +69,10 @@ const cmdPrompt = async (logChannel: string, botName: string, sendMessage: (c: s
// Sends [message] to specified [channel] // Sends [message] to specified [channel]
else if (command === "m") { else if (command === "m") {
try { try {
const channelID = args.shift() || ""; const channelId = args.shift() || "";
const message = args.join(" "); const message = args.join(" ");
sendMessage(channelID, message).catch(reason => { sendMessage(BigInt(channelId), message).catch(reason => {
console.error(reason); console.error(reason);
}); });
} }
@ -104,18 +104,6 @@ const cmdPrompt = async (logChannel: string, botName: string, sendMessage: (c: s
} }
}; };
// sendIndirectMessage(originalMessage, messageContent, sendMessage, sendDirectMessage) returns Message
// sendIndirectMessage determines if the message needs to be sent as a direct message or as a normal message
const sendIndirectMessage = async (originalMessage: Message, messageContent: (string | MessageContent), sendMessage: (c: string, m: (string | MessageContent)) => Promise<Message>, sendDirectMessage: (c: string, m: (string | MessageContent)) => Promise<Message>): Promise<Message> => {
if (originalMessage.guildID === "") {
// guildID was empty, meaning the original message was sent as a DM
return await sendDirectMessage(originalMessage.author.id, messageContent);
} else {
// guildID was not empty, meaning the original message was sent in a server
return await sendMessage(originalMessage.channelID, messageContent);
}
};
// initLog() returns nothing // initLog() returns nothing
// Handles ensuring the required directory structure is created // Handles ensuring the required directory structure is created
const initLog = (name: string): void => { const initLog = (name: string): void => {
@ -161,4 +149,4 @@ const log = async (level: LogTypes, message: string, error = new Error()): Promi
} }
}; };
export default { cmdPrompt, sendIndirectMessage, initLog, log }; export default { cmdPrompt, initLog, log };

1
start.command Normal file
View File

@ -0,0 +1 @@
deno run --allow-write=./logs --allow-net .\mod.ts