added deno.json, ran deno fmt to standardize formatting
This commit is contained in:
parent
925eb08205
commit
5e84b1c0b4
|
@ -1,25 +1,25 @@
|
||||||
// This file will create all tables for the artificer schema
|
// This file will create all tables for the artificer schema
|
||||||
// DATA WILL BE LOST IF DB ALREADY EXISTS, RUN AT OWN RISK
|
// DATA WILL BE LOST IF DB ALREADY EXISTS, RUN AT OWN RISK
|
||||||
|
|
||||||
import config from "../config.ts";
|
import config from '../config.ts';
|
||||||
import { dbClient } from "../src/db.ts";
|
import { dbClient } from '../src/db.ts';
|
||||||
|
|
||||||
console.log("Attempting to create DB");
|
console.log('Attempting to create DB');
|
||||||
await dbClient.execute(`CREATE SCHEMA IF NOT EXISTS ${config.db.name};`);
|
await dbClient.execute(`CREATE SCHEMA IF NOT EXISTS ${config.db.name};`);
|
||||||
await dbClient.execute(`USE ${config.db.name}`);
|
await dbClient.execute(`USE ${config.db.name}`);
|
||||||
console.log("DB created");
|
console.log('DB created');
|
||||||
|
|
||||||
console.log("Attempt to drop all tables");
|
console.log('Attempt to drop all tables');
|
||||||
await dbClient.execute(`DROP TABLE IF EXISTS allowed_channels;`);
|
await dbClient.execute(`DROP TABLE IF EXISTS allowed_channels;`);
|
||||||
await dbClient.execute(`DROP TABLE IF EXISTS all_keys;`);
|
await dbClient.execute(`DROP TABLE IF EXISTS all_keys;`);
|
||||||
await dbClient.execute(`DROP TABLE IF EXISTS allowed_guilds;`);
|
await dbClient.execute(`DROP TABLE IF EXISTS allowed_guilds;`);
|
||||||
await dbClient.execute(`DROP TABLE IF EXISTS roll_log;`);
|
await dbClient.execute(`DROP TABLE IF EXISTS roll_log;`);
|
||||||
await dbClient.execute(`DROP PROCEDURE IF EXISTS INC_CNT;`);
|
await dbClient.execute(`DROP PROCEDURE IF EXISTS INC_CNT;`);
|
||||||
await dbClient.execute(`DROP TABLE IF EXISTS command_cnt;`);
|
await dbClient.execute(`DROP TABLE IF EXISTS command_cnt;`);
|
||||||
console.log("Tables dropped");
|
console.log('Tables dropped');
|
||||||
|
|
||||||
// Light telemetry on how many commands have been run
|
// Light telemetry on how many commands have been run
|
||||||
console.log("Attempting to create table command_cnt");
|
console.log('Attempting to create table command_cnt');
|
||||||
await dbClient.execute(`
|
await dbClient.execute(`
|
||||||
CREATE TABLE command_cnt (
|
CREATE TABLE command_cnt (
|
||||||
command char(20) NOT NULL,
|
command char(20) NOT NULL,
|
||||||
|
@ -28,9 +28,9 @@ await dbClient.execute(`
|
||||||
UNIQUE KEY command_cnt_command_UNIQUE (command)
|
UNIQUE KEY command_cnt_command_UNIQUE (command)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
`);
|
`);
|
||||||
console.log("Table created");
|
console.log('Table created');
|
||||||
|
|
||||||
console.log("Attempt creating increment Stored Procedure");
|
console.log('Attempt creating increment Stored Procedure');
|
||||||
await dbClient.execute(`
|
await dbClient.execute(`
|
||||||
CREATE PROCEDURE INC_CNT(
|
CREATE PROCEDURE INC_CNT(
|
||||||
IN cmd CHAR(20)
|
IN cmd CHAR(20)
|
||||||
|
@ -41,10 +41,10 @@ await dbClient.execute(`
|
||||||
UPDATE command_cnt SET count = oldcnt + 1 WHERE command = cmd;
|
UPDATE command_cnt SET count = oldcnt + 1 WHERE command = cmd;
|
||||||
END
|
END
|
||||||
`);
|
`);
|
||||||
console.log("Stored Procedure created");
|
console.log('Stored Procedure created');
|
||||||
|
|
||||||
// Roll log, holds rolls when requests
|
// Roll log, holds rolls when requests
|
||||||
console.log("Attempting to create table roll_log");
|
console.log('Attempting to create table roll_log');
|
||||||
await dbClient.execute(`
|
await dbClient.execute(`
|
||||||
CREATE TABLE roll_log (
|
CREATE TABLE roll_log (
|
||||||
id int unsigned NOT NULL AUTO_INCREMENT,
|
id int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
@ -59,10 +59,10 @@ await dbClient.execute(`
|
||||||
UNIQUE KEY roll_log_resultid_UNIQUE (resultid)
|
UNIQUE KEY roll_log_resultid_UNIQUE (resultid)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
`);
|
`);
|
||||||
console.log("Table created");
|
console.log('Table created');
|
||||||
|
|
||||||
// Api guild settings
|
// Api guild settings
|
||||||
console.log("Attempting to create table allowed_guilds");
|
console.log('Attempting to create table allowed_guilds');
|
||||||
await dbClient.execute(`
|
await dbClient.execute(`
|
||||||
CREATE TABLE allowed_guilds (
|
CREATE TABLE allowed_guilds (
|
||||||
guildid bigint unsigned NOT NULL,
|
guildid bigint unsigned NOT NULL,
|
||||||
|
@ -74,10 +74,10 @@ await dbClient.execute(`
|
||||||
PRIMARY KEY (guildid, channelid)
|
PRIMARY KEY (guildid, channelid)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
`);
|
`);
|
||||||
console.log("Table created");
|
console.log('Table created');
|
||||||
|
|
||||||
// Api keys
|
// Api keys
|
||||||
console.log("Attempting to create table all_keys");
|
console.log('Attempting to create table all_keys');
|
||||||
await dbClient.execute(`
|
await dbClient.execute(`
|
||||||
CREATE TABLE all_keys (
|
CREATE TABLE all_keys (
|
||||||
userid bigint unsigned NOT NULL,
|
userid bigint unsigned NOT NULL,
|
||||||
|
@ -93,10 +93,10 @@ await dbClient.execute(`
|
||||||
UNIQUE KEY all_keys_email_UNIQUE (email)
|
UNIQUE KEY all_keys_email_UNIQUE (email)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
`);
|
`);
|
||||||
console.log("Table created");
|
console.log('Table created');
|
||||||
|
|
||||||
// Api user settings
|
// Api user settings
|
||||||
console.log("Attempting to create table allowed_channels");
|
console.log('Attempting to create table allowed_channels');
|
||||||
await dbClient.execute(`
|
await dbClient.execute(`
|
||||||
CREATE TABLE allowed_channels (
|
CREATE TABLE allowed_channels (
|
||||||
userid bigint unsigned NOT NULL,
|
userid bigint unsigned NOT NULL,
|
||||||
|
@ -108,7 +108,7 @@ await dbClient.execute(`
|
||||||
CONSTRAINT allowed_channels_userid_FK FOREIGN KEY (userid) REFERENCES all_keys (userid) ON DELETE RESTRICT ON UPDATE RESTRICT
|
CONSTRAINT allowed_channels_userid_FK FOREIGN KEY (userid) REFERENCES all_keys (userid) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
`);
|
`);
|
||||||
console.log("Table created");
|
console.log('Table created');
|
||||||
|
|
||||||
await dbClient.close();
|
await dbClient.close();
|
||||||
console.log("Done!");
|
console.log('Done!');
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
// This file will populate the tables with default values
|
// This file will populate the tables with default values
|
||||||
|
|
||||||
import config from "../config.ts";
|
import config from '../config.ts';
|
||||||
import { dbClient } from "../src/db.ts";
|
import { dbClient } from '../src/db.ts';
|
||||||
|
|
||||||
console.log("Attempting to populate DB Admin API key");
|
console.log('Attempting to populate DB Admin API key');
|
||||||
await dbClient.execute("INSERT INTO all_keys(userid,apiKey) values(?,?)", [config.api.admin, config.api.adminKey]).catch(e => {
|
await dbClient.execute('INSERT INTO all_keys(userid,apiKey) values(?,?)', [config.api.admin, config.api.adminKey]).catch((e) => {
|
||||||
console.log("Failed to insert into database", e);
|
console.log('Failed to insert into database', e);
|
||||||
});
|
});
|
||||||
console.log("Inesrtion done");
|
console.log('Inesrtion done');
|
||||||
|
|
||||||
console.log("Attempting to insert default commands into command_cnt");
|
console.log('Attempting to insert default commands into command_cnt');
|
||||||
const commands = ["ping", "rip", "rollhelp", "help", "info", "version", "report", "stats", "roll", "emojis", "api", "privacy", "mention"];
|
const commands = ['ping', 'rip', 'rollhelp', 'help', 'info', 'version', 'report', 'stats', 'roll', 'emojis', 'api', 'privacy', 'mention'];
|
||||||
for (let i = 0; i < commands.length; i++) {
|
for (let i = 0; i < commands.length; i++) {
|
||||||
await dbClient.execute("INSERT INTO command_cnt(command) values(?)", [commands[i]]).catch(e => {
|
await dbClient.execute('INSERT INTO command_cnt(command) values(?)', [commands[i]]).catch((e) => {
|
||||||
console.log(`Failed to insert into database`, e);
|
console.log(`Failed to insert into database`, e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("Insertion done");
|
console.log('Insertion done');
|
||||||
|
|
||||||
await dbClient.close();
|
await dbClient.close();
|
||||||
console.log("Done!");
|
console.log('Done!');
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"lib": ["deno.window"],
|
||||||
|
"strict": true
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"files": {
|
||||||
|
"include": ["src/", "db/", "mod.ts"],
|
||||||
|
"exclude": []
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"tags": ["recommended"],
|
||||||
|
"include": ["ban-untagged-todo"],
|
||||||
|
"exclude": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fmt": {
|
||||||
|
"files": {
|
||||||
|
"include": ["src/", "db/", "mod.ts"],
|
||||||
|
"exclude": []
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"useTabs": true,
|
||||||
|
"lineWidth": 200,
|
||||||
|
"indentWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"proseWrap": "preserve"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
mod.ts
142
mod.ts
|
@ -4,26 +4,32 @@
|
||||||
* December 21, 2020
|
* December 21, 2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import config from "./config.ts";
|
import config from './config.ts';
|
||||||
import { DEBUG, DEVMODE, LOCALMODE } from "./flags.ts";
|
import { DEBUG, DEVMODE, LOCALMODE } from './flags.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
botId,
|
||||||
startBot, editBotStatus, editBotNickname,
|
cache,
|
||||||
|
DiscordActivityTypes,
|
||||||
|
DiscordenoGuild,
|
||||||
|
DiscordenoMessage,
|
||||||
|
editBotNickname,
|
||||||
|
editBotStatus,
|
||||||
|
initLog,
|
||||||
Intents,
|
Intents,
|
||||||
sendMessage,
|
log,
|
||||||
cache, botId,
|
|
||||||
DiscordActivityTypes, DiscordenoGuild, DiscordenoMessage,
|
|
||||||
|
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, initLog, log
|
LT,
|
||||||
} from "./deps.ts";
|
sendMessage,
|
||||||
import api from "./src/api.ts";
|
// Discordeno deps
|
||||||
import commands from "./src/commands/_index.ts";
|
startBot,
|
||||||
import intervals from "./src/intervals.ts";
|
} from './deps.ts';
|
||||||
import utils from "./src/utils.ts";
|
import api from './src/api.ts';
|
||||||
|
import commands from './src/commands/_index.ts';
|
||||||
|
import intervals from './src/intervals.ts';
|
||||||
|
import utils from './src/utils.ts';
|
||||||
|
|
||||||
// Initialize logging client with folder to use for logs, needs --allow-write set on Deno startup
|
// Initialize logging client with folder to use for logs, needs --allow-write set on Deno startup
|
||||||
initLog("logs", DEBUG);
|
initLog('logs', DEBUG);
|
||||||
|
|
||||||
// Start up the Discord Bot
|
// Start up the Discord Bot
|
||||||
startBot({
|
startBot({
|
||||||
|
@ -34,25 +40,25 @@ startBot({
|
||||||
log(LT.INFO, `${config.name} Logged in!`);
|
log(LT.INFO, `${config.name} Logged in!`);
|
||||||
editBotStatus({
|
editBotStatus({
|
||||||
activities: [{
|
activities: [{
|
||||||
name: "Booting up . . .",
|
name: 'Booting up . . .',
|
||||||
type: DiscordActivityTypes.Game,
|
type: DiscordActivityTypes.Game,
|
||||||
createdAt: new Date().getTime()
|
createdAt: new Date().getTime(),
|
||||||
}],
|
}],
|
||||||
status: "online"
|
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(async () => {
|
setInterval(async () => {
|
||||||
log(LT.LOG, "Changing bot status");
|
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
|
||||||
editBotStatus({
|
editBotStatus({
|
||||||
activities: [{
|
activities: [{
|
||||||
name: await intervals.getRandomStatus(),
|
name: await intervals.getRandomStatus(),
|
||||||
type: DiscordActivityTypes.Game,
|
type: DiscordActivityTypes.Game,
|
||||||
createdAt: new Date().getTime()
|
createdAt: new Date().getTime(),
|
||||||
}],
|
}],
|
||||||
status: "online"
|
status: 'online',
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(LT.ERROR, `Failed to update status: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to update status: ${JSON.stringify(e)}`);
|
||||||
|
@ -60,45 +66,45 @@ startBot({
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
// Interval to update bot list stats every 24 hours
|
// Interval to update bot list stats every 24 hours
|
||||||
LOCALMODE ? log(LT.INFO, "updateListStatistics not running") : setInterval(() => {
|
LOCALMODE ? log(LT.INFO, 'updateListStatistics not running') : setInterval(() => {
|
||||||
log(LT.LOG, "Updating all bot lists statistics");
|
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 && editBotNickname(config.devServer, `LOCAL - ${config.name}`);
|
LOCALMODE && editBotNickname(config.devServer, `LOCAL - ${config.name}`);
|
||||||
LOCALMODE ? log(LT.INFO, "updateListStatistics not running") : intervals.updateListStatistics(botId, cache.guilds.size);
|
LOCALMODE ? log(LT.INFO, 'updateListStatistics not running') : intervals.updateListStatistics(botId, cache.guilds.size);
|
||||||
editBotStatus({
|
editBotStatus({
|
||||||
activities: [{
|
activities: [{
|
||||||
name: "Booting Complete",
|
name: 'Booting Complete',
|
||||||
type: DiscordActivityTypes.Game,
|
type: DiscordActivityTypes.Game,
|
||||||
createdAt: new Date().getTime()
|
createdAt: new Date().getTime(),
|
||||||
}],
|
}],
|
||||||
status: "online"
|
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) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
guildCreate: (guild: DiscordenoGuild) => {
|
guildCreate: (guild: DiscordenoGuild) => {
|
||||||
log(LT.LOG, `Handling joining guild ${JSON.stringify(guild)}`);
|
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) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
guildDelete: (guild: DiscordenoGuild) => {
|
guildDelete: (guild: DiscordenoGuild) => {
|
||||||
log(LT.LOG, `Handling leaving guild ${JSON.stringify(guild)}`);
|
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) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
debug: DEVMODE ? dmsg => log(LT.LOG, `Debug Message | ${JSON.stringify(dmsg)}`) : () => {},
|
debug: DEVMODE ? (dmsg) => log(LT.LOG, `Debug Message | ${JSON.stringify(dmsg)}`) : () => {},
|
||||||
messageCreate: (message: DiscordenoMessage) => {
|
messageCreate: (message: DiscordenoMessage) => {
|
||||||
// Ignore all other bots
|
// Ignore all other bots
|
||||||
if (message.isBot) 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) {
|
if (message.content.indexOf(config.prefix) !== 0) {
|
||||||
// Handle @bot messages
|
// Handle @bot messages
|
||||||
|
@ -109,7 +115,7 @@ startBot({
|
||||||
// return as we are done handling this command
|
// return as we are done handling this command
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(LT.LOG, `Handling ${config.prefix}command message: ${JSON.stringify(message)}`);
|
log(LT.LOG, `Handling ${config.prefix}command message: ${JSON.stringify(message)}`);
|
||||||
|
|
||||||
// Split into standard command + args format
|
// Split into standard command + args format
|
||||||
|
@ -120,77 +126,55 @@ startBot({
|
||||||
|
|
||||||
// [[ping
|
// [[ping
|
||||||
// Its a ping test, what else do you want.
|
// Its a ping test, what else do you want.
|
||||||
if (command === "ping") {
|
if (command === 'ping') {
|
||||||
commands.ping(message);
|
commands.ping(message);
|
||||||
}
|
} // [[rip [[memory
|
||||||
|
|
||||||
// [[rip [[memory
|
|
||||||
// Displays a short message I wanted to include
|
// Displays a short message I wanted to include
|
||||||
else if (command === "rip" || command === "memory") {
|
else if (command === 'rip' || command === 'memory') {
|
||||||
commands.rip(message);
|
commands.rip(message);
|
||||||
}
|
} // [[rollhelp or [[rh or [[hr or [[??
|
||||||
|
|
||||||
// [[rollhelp or [[rh or [[hr or [[??
|
|
||||||
// Help command specifically for the roll command
|
// Help command specifically for the roll command
|
||||||
else if (command === "rollhelp" || command === "rh" || command === "hr" || command === "??" || command?.startsWith("xdy")) {
|
else if (command === 'rollhelp' || command === 'rh' || command === 'hr' || command === '??' || command?.startsWith('xdy')) {
|
||||||
commands.rollHelp(message);
|
commands.rollHelp(message);
|
||||||
}
|
} // [[help or [[h or [[?
|
||||||
|
|
||||||
// [[help or [[h or [[?
|
|
||||||
// Help command, prints from help file
|
// Help command, prints from help file
|
||||||
else if (command === "help" || command === "h" || command === "?") {
|
else if (command === 'help' || command === 'h' || command === '?') {
|
||||||
commands.help(message);
|
commands.help(message);
|
||||||
}
|
} // [[info or [[i
|
||||||
|
|
||||||
// [[info or [[i
|
|
||||||
// Info command, prints short desc on bot and some links
|
// Info command, prints short desc on bot and some links
|
||||||
else if (command === "info" || command === "i") {
|
else if (command === 'info' || command === 'i') {
|
||||||
commands.info(message);
|
commands.info(message);
|
||||||
}
|
} // [[privacy
|
||||||
|
|
||||||
// [[privacy
|
|
||||||
// Privacy command, prints short desc on bot's privacy policy
|
// Privacy command, prints short desc on bot's privacy policy
|
||||||
else if (command === "privacy") {
|
else if (command === 'privacy') {
|
||||||
commands.privacy(message);
|
commands.privacy(message);
|
||||||
}
|
} // [[version or [[v
|
||||||
|
|
||||||
// [[version or [[v
|
|
||||||
// Returns version of the bot
|
// Returns version of the bot
|
||||||
else if (command === "version" || command === "v") {
|
else if (command === 'version' || command === 'v') {
|
||||||
commands.version(message);
|
commands.version(message);
|
||||||
}
|
} // [[report or [[r (command that failed)
|
||||||
|
|
||||||
// [[report or [[r (command that failed)
|
|
||||||
// Manually report a failed roll
|
// Manually report a failed roll
|
||||||
else if (command === "report" || command === "r") {
|
else if (command === 'report' || command === 'r') {
|
||||||
commands.report(message, args);
|
commands.report(message, args);
|
||||||
}
|
} // [[stats or [[s
|
||||||
|
|
||||||
// [[stats or [[s
|
|
||||||
// Displays stats on the bot
|
// Displays stats on the bot
|
||||||
else if (command === "stats" || command === "s") {
|
else if (command === 'stats' || command === 's') {
|
||||||
commands.stats(message);
|
commands.stats(message);
|
||||||
}
|
} // [[api arg
|
||||||
|
|
||||||
// [[api arg
|
|
||||||
// API sub commands
|
// API sub commands
|
||||||
else if (command === "api") {
|
else if (command === 'api') {
|
||||||
commands.api(message, args);
|
commands.api(message, args);
|
||||||
}
|
} // [[roll]]
|
||||||
|
|
||||||
// [[roll]]
|
|
||||||
// Dice rolling commence!
|
// Dice rolling commence!
|
||||||
else if (command && (`${command}${args.join("")}`).indexOf(config.postfix) > -1) {
|
else if (command && (`${command}${args.join('')}`).indexOf(config.postfix) > -1) {
|
||||||
commands.roll(message, args, command);
|
commands.roll(message, args, command);
|
||||||
}
|
} // [[emoji or [[emojialias
|
||||||
|
|
||||||
// [[emoji or [[emojialias
|
|
||||||
// Check if the unhandled command is an emoji request
|
// Check if the unhandled command is an emoji request
|
||||||
else if (command) {
|
else if (command) {
|
||||||
commands.emoji(message, command);
|
commands.emoji(message, command);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start up the command prompt for debug usage
|
// Start up the command prompt for debug usage
|
||||||
|
|
351
src/api.ts
351
src/api.ts
|
@ -6,27 +6,26 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
cache, CreateMessage,
|
cache,
|
||||||
sendMessage, sendDirectMessage,
|
CreateMessage,
|
||||||
|
log,
|
||||||
// httpd deps
|
// Log4Deno deps
|
||||||
Status, STATUS_TEXT,
|
LT,
|
||||||
|
|
||||||
// nanoid deps
|
// nanoid deps
|
||||||
nanoid,
|
nanoid,
|
||||||
|
sendDirectMessage,
|
||||||
|
sendMessage,
|
||||||
|
// httpd deps
|
||||||
|
Status,
|
||||||
|
STATUS_TEXT,
|
||||||
|
} from '../deps.ts';
|
||||||
|
|
||||||
// Log4Deno deps
|
import { RollModifiers } from './mod.d.ts';
|
||||||
LT, log
|
import { dbClient, queries } from './db.ts';
|
||||||
} from "../deps.ts";
|
import solver from './solver/_index.ts';
|
||||||
|
import { generateApiDeleteEmail, generateApiKeyEmail, generateDMFailed } from './constantCmds.ts';
|
||||||
|
|
||||||
import { RollModifiers } from "./mod.d.ts";
|
import config from '../config.ts';
|
||||||
import { dbClient, queries } from "./db.ts";
|
|
||||||
import solver from "./solver/_index.ts";
|
|
||||||
import {
|
|
||||||
generateApiKeyEmail, generateApiDeleteEmail, generateDMFailed
|
|
||||||
} from "./constantCmds.ts";
|
|
||||||
|
|
||||||
import config from "../config.ts";
|
|
||||||
|
|
||||||
// start(databaseClient) returns nothing
|
// start(databaseClient) returns nothing
|
||||||
// start initializes and runs the entire API for the bot
|
// start initializes and runs the entire API for the bot
|
||||||
|
@ -51,14 +50,14 @@ const start = async (): Promise<void> => {
|
||||||
let rateLimited = false;
|
let rateLimited = false;
|
||||||
let updateRateLimitTime = false;
|
let updateRateLimitTime = false;
|
||||||
let apiUserid = 0n;
|
let apiUserid = 0n;
|
||||||
let apiUseridStr = "";
|
let apiUseridStr = '';
|
||||||
let apiUserEmail = "";
|
let apiUserEmail = '';
|
||||||
let apiUserDelCode = "";
|
let apiUserDelCode = '';
|
||||||
|
|
||||||
// Check the requests API key
|
// Check the requests API key
|
||||||
if (request.headers.has("X-Api-Key")) {
|
if (request.headers.has('X-Api-Key')) {
|
||||||
// Get the userid and flags for the specific key
|
// Get the userid and flags for the specific key
|
||||||
const dbApiQuery = await dbClient.query("SELECT userid, email, deleteCode FROM all_keys WHERE apiKey = ? AND active = 1 AND banned = 0", [request.headers.get("X-Api-Key")]);
|
const dbApiQuery = await dbClient.query('SELECT userid, email, deleteCode FROM all_keys WHERE apiKey = ? AND active = 1 AND banned = 0', [request.headers.get('X-Api-Key')]);
|
||||||
|
|
||||||
// If only one user returned, is not banned, and is currently active, mark as authenticated
|
// If only one user returned, is not banned, and is currently active, mark as authenticated
|
||||||
if (dbApiQuery.length === 1) {
|
if (dbApiQuery.length === 1) {
|
||||||
|
@ -77,7 +76,7 @@ const start = async (): Promise<void> => {
|
||||||
const currentCnt = rateLimitCnt.get(apiUseridStr) || 0;
|
const currentCnt = rateLimitCnt.get(apiUseridStr) || 0;
|
||||||
if (currentCnt < config.api.rateLimitCnt) {
|
if (currentCnt < config.api.rateLimitCnt) {
|
||||||
// Limit not yet exceeded, update count
|
// Limit not yet exceeded, update count
|
||||||
rateLimitCnt.set(apiUseridStr, (currentCnt + 1));
|
rateLimitCnt.set(apiUseridStr, currentCnt + 1);
|
||||||
} else {
|
} else {
|
||||||
// Limit exceeded, prevent API use
|
// Limit exceeded, prevent API use
|
||||||
rateLimited = true;
|
rateLimited = true;
|
||||||
|
@ -92,26 +91,26 @@ const start = async (): Promise<void> => {
|
||||||
|
|
||||||
if (authenticated && !rateLimited) {
|
if (authenticated && !rateLimited) {
|
||||||
// Get path and query as a string
|
// Get path and query as a string
|
||||||
const [path, tempQ] = request.url.split("?");
|
const [path, tempQ] = request.url.split('?');
|
||||||
|
|
||||||
// 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: string) => {
|
tempQ.split('&').forEach((e: string) => {
|
||||||
log(LT.LOG, `Breaking down request query: ${request} ${e}`);
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the request
|
// Handle the request
|
||||||
switch (request.method) {
|
switch (request.method) {
|
||||||
case "GET":
|
case 'GET':
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
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") || "0")) {
|
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);
|
||||||
|
|
||||||
|
@ -119,7 +118,7 @@ const start = async (): Promise<void> => {
|
||||||
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) values(?,?)", [apiUserid, newKey]).catch(e => {
|
await dbClient.execute('INSERT INTO all_keys(userid,apiKey) values(?,?)', [apiUserid, newKey]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -130,7 +129,7 @@ const start = async (): Promise<void> => {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Send API key as response
|
// Send API key as response
|
||||||
requestEvent.respondWith(new Response(JSON.stringify({ "key": newKey, "userid": query.get("user") }), { status: Status.OK }));
|
requestEvent.respondWith(new Response(JSON.stringify({ 'key': newKey, 'userid': query.get('user') }), { status: Status.OK }));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,15 +141,15 @@ const start = async (): Promise<void> => {
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: 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") || "0")) {
|
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) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -174,11 +173,14 @@ const start = async (): Promise<void> => {
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "/api/roll":
|
case '/api/roll':
|
||||||
case "/api/roll/":
|
case '/api/roll/':
|
||||||
// Make sure query contains all the needed parts
|
// Make sure query contains all the needed parts
|
||||||
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 (
|
||||||
if (query.has("n") && query.has("m")) {
|
(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')) {
|
||||||
// Alert API user that they shouldn't be doing this
|
// Alert API user that they shouldn't be doing this
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
||||||
break;
|
break;
|
||||||
|
@ -189,13 +191,15 @@ const start = async (): Promise<void> => {
|
||||||
let hideWarn = false;
|
let hideWarn = 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") || "0")]);
|
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") || "0")) && 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(BigInt(query.get("channel") || ""))?.guild;
|
const guild = cache.channels.get(BigInt(query.get('channel') || ''))?.guild;
|
||||||
if (guild && guild.members.get(BigInt(query.get("user") || ""))?.id) {
|
if (guild && guild.members.get(BigInt(query.get('user') || ''))?.id) {
|
||||||
const dbGuildQuery = await dbClient.query("SELECT active, banned, hidewarn FROM allowed_guilds WHERE guildid = ? AND channelid = ?", [guild.id, BigInt(query.get("channel") || "0")]);
|
const dbGuildQuery = await dbClient.query('SELECT active, banned, hidewarn FROM allowed_guilds WHERE guildid = ? AND channelid = ?', [
|
||||||
|
guild.id,
|
||||||
|
BigInt(query.get('channel') || '0'),
|
||||||
|
]);
|
||||||
|
|
||||||
// Make sure guild allows API rolls
|
// Make sure guild allows API rolls
|
||||||
if (dbGuildQuery.length === 1 && dbGuildQuery[0].active && !dbGuildQuery[0].banned) {
|
if (dbGuildQuery.length === 1 && dbGuildQuery[0].active && !dbGuildQuery[0].banned) {
|
||||||
|
@ -211,76 +215,78 @@ const start = async (): Promise<void> => {
|
||||||
// Flag to tell if roll was completely successful
|
// Flag to tell if roll was completely successful
|
||||||
let errorOut = false;
|
let errorOut = false;
|
||||||
// Make sure rollCmd is not undefined
|
// Make sure rollCmd is not undefined
|
||||||
let rollCmd = query.get("rollstr") || "";
|
let rollCmd = query.get('rollstr') || '';
|
||||||
const originalCommand = query.get("rollstr");
|
const originalCommand = query.get('rollstr');
|
||||||
|
|
||||||
if (rollCmd.length === 0) {
|
if (rollCmd.length === 0) {
|
||||||
// Alert API user that they messed up
|
// Alert API user that they messed up
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: 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(queries.insertRollLogCmd(1, 1), [originalCommand, "EmptyInput", null]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(1, 1), [originalCommand, 'EmptyInput', null]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: 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(queries.insertRollLogCmd(1, 1), [originalCommand, "BadOrder", null]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(1, 1), [originalCommand, 'BadOrder', null]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clip off the leading prefix. API calls must be formatted with a prefix at the start to match how commands are sent in Discord
|
// Clip off the leading prefix. API calls must be formatted with a prefix at the start to match how commands are sent in Discord
|
||||||
rollCmd = rollCmd.substring(rollCmd.indexOf(config.prefix) + 2).replace(/%20/g, " ");
|
rollCmd = rollCmd.substring(rollCmd.indexOf(config.prefix) + 2).replace(/%20/g, ' ');
|
||||||
|
|
||||||
const modifiers: RollModifiers = {
|
const modifiers: RollModifiers = {
|
||||||
noDetails: false,
|
noDetails: false,
|
||||||
superNoDetails: false,
|
superNoDetails: false,
|
||||||
spoiler: "",
|
spoiler: '',
|
||||||
maxRoll: query.has("m"),
|
maxRoll: query.has('m'),
|
||||||
nominalRoll: query.has("n"),
|
nominalRoll: query.has('n'),
|
||||||
gmRoll: false,
|
gmRoll: false,
|
||||||
gms: [],
|
gms: [],
|
||||||
order: query.has("o") ? (query.get("o")?.toLowerCase() || "") : "",
|
order: query.has('o') ? (query.get('o')?.toLowerCase() || '') : '',
|
||||||
valid: true,
|
valid: true,
|
||||||
count: query.has("c")
|
count: query.has('c'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse the roll and get the return text
|
// Parse the roll and get the return text
|
||||||
const returnmsg = solver.parseRoll(rollCmd, modifiers);
|
const returnmsg = solver.parseRoll(rollCmd, modifiers);
|
||||||
|
|
||||||
// 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 = hideWarn ? '' : `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 = hideWarn
|
||||||
let m, returnText = "";
|
? ''
|
||||||
|
: `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 = '';
|
||||||
|
|
||||||
// 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) {
|
||||||
requestEvent.respondWith(new Response(returnmsg.errorMsg, { status: Status.InternalServerError }));
|
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(queries.insertRollLogCmd(1, 1), [originalCommand, returnmsg.errorCode, null]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(1, 1), [originalCommand, returnmsg.errorCode, null]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
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
|
||||||
if (query.has("s")) {
|
if (query.has('s')) {
|
||||||
spoilerTxt = "||";
|
spoilerTxt = '||';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if no details flag was on
|
// Determine if no details flag was on
|
||||||
if (!query.has("snd")) {
|
if (!query.has('snd')) {
|
||||||
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}`;
|
||||||
}
|
}
|
||||||
|
@ -288,70 +294,74 @@ const start = async (): Promise<void> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (query.has("gms")) {
|
if (query.has('gms')) {
|
||||||
// Get all the GM user IDs from the query
|
// Get all the GM user IDs from the query
|
||||||
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
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: 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(queries.insertRollLogCmd(1, 1), [originalCommand, "NoGMsSent", null]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(1, 1), [originalCommand, 'NoGMsSent', null]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) => {
|
||||||
log(LT.LOG, `Appending GM ${e} to roll text`);
|
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) {
|
||||||
// todo: embedify
|
// todo: embedify
|
||||||
m = await sendMessage(BigInt(query.get("channel") || ""), normalText).catch(() => {
|
m = await sendMessage(BigInt(query.get('channel') || ''), normalText).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message 00 failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message 00 failed to send.', { status: Status.InternalServerError }));
|
||||||
errorOut = true;
|
errorOut = true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// todo: embedify
|
// todo: embedify
|
||||||
m = await sendDirectMessage(BigInt(query.get("user") || ""), normalText).catch(() => {
|
m = await sendDirectMessage(BigInt(query.get('user') || ''), normalText).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message 01 failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message 01 failed to send.', { status: Status.InternalServerError }));
|
||||||
errorOut = true;
|
errorOut = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newMessage: CreateMessage = {};
|
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}<@${
|
||||||
newMessage.file = { "blob": b, "name": "rollDetails.txt" };
|
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' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
gms.forEach(async e => {
|
gms.forEach(async (e) => {
|
||||||
log(LT.LOG, `Messaging GM ${e} roll results`);
|
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(BigInt(e), newMessage).catch(async () => {
|
await sendDirectMessage(BigInt(e), newMessage).catch(async () => {
|
||||||
const failedSend = generateDMFailed(e);
|
const failedSend = generateDMFailed(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(BigInt(query.get("channel") || ""), failedSend).catch(() => {
|
m = await sendMessage(BigInt(query.get('channel') || ''), failedSend).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message failed to send.', { status: Status.InternalServerError }));
|
||||||
errorOut = true;
|
errorOut = true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
m = await sendDirectMessage(BigInt(query.get("user") || ""), failedSend).catch(() => {
|
m = await sendDirectMessage(BigInt(query.get('user') || ''), failedSend).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message failed to send.', { status: Status.InternalServerError }));
|
||||||
errorOut = true;
|
errorOut = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -359,7 +369,7 @@ const start = async (): Promise<void> => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Always log API rolls for abuse detection
|
// Always log API rolls for abuse detection
|
||||||
dbClient.execute(queries.insertRollLogCmd(1, 0), [originalCommand, returnText, ((typeof m === "object") ? m.id : null)]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(1, 0), [originalCommand, returnText, (typeof m === 'object') ? m.id : null]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -378,33 +388,37 @@ const start = async (): Promise<void> => {
|
||||||
// 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
|
||||||
if (returnText.length > 2000) {
|
if (returnText.length > 2000) {
|
||||||
// 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}\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}<@${
|
||||||
newMessage.file = { "blob": b, "name": "rollDetails.txt" };
|
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' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(BigInt(query.get("channel") || ""), newMessage).catch(() => {
|
m = await sendMessage(BigInt(query.get('channel') || ''), newMessage).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message 20 failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message 20 failed to send.', { status: Status.InternalServerError }));
|
||||||
errorOut = true;
|
errorOut = true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
m = await sendDirectMessage(BigInt(query.get("user") || ""), newMessage).catch(() => {
|
m = await sendDirectMessage(BigInt(query.get('user') || ''), newMessage).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message 21 failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message 21 failed to send.', { status: Status.InternalServerError }));
|
||||||
errorOut = true;
|
errorOut = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(1, 0), [originalCommand, returnText, ((typeof m === "object") ? m.id : null)]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(1, 0), [originalCommand, returnText, (typeof m === 'object') ? m.id : null]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -436,17 +450,17 @@ const start = async (): Promise<void> => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "POST":
|
case 'POST':
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
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") || "0")) {
|
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") || "0")]).catch(e => {
|
await dbClient.execute('INSERT INTO allowed_channels(userid,channelid) values(?,?)', [apiUserid, BigInt(query.get('channel') || '0')]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -475,37 +489,37 @@ const start = async (): Promise<void> => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "PUT":
|
case 'PUT':
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
case "/api/key/ban":
|
case '/api/key/ban':
|
||||||
case "/api/key/ban/":
|
case '/api/key/ban/':
|
||||||
case "/api/key/unban":
|
case '/api/key/unban':
|
||||||
case "/api/key/unban/":
|
case '/api/key/unban/':
|
||||||
case "/api/key/activate":
|
case '/api/key/activate':
|
||||||
case "/api/key/activate/":
|
case '/api/key/activate/':
|
||||||
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") || "0")) {
|
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;
|
||||||
|
|
||||||
// Determine key to edit
|
// Determine key to edit
|
||||||
if (path.toLowerCase().indexOf("ban") > 0) {
|
if (path.toLowerCase().indexOf('ban') > 0) {
|
||||||
key = "banned";
|
key = 'banned';
|
||||||
} else {
|
} else {
|
||||||
key = "active";
|
key = 'active';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine value to set
|
// Determine value to set
|
||||||
if (path.toLowerCase().indexOf("de") > 0 || path.toLowerCase().indexOf("un") > 0) {
|
if (path.toLowerCase().indexOf('de') > 0 || path.toLowerCase().indexOf('un') > 0) {
|
||||||
value = 0;
|
value = 0;
|
||||||
} else {
|
} else {
|
||||||
value = 1;
|
value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -528,24 +542,27 @@ const start = async (): Promise<void> => {
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "/api/channel/ban":
|
case '/api/channel/ban':
|
||||||
case "/api/channel/ban/":
|
case '/api/channel/ban/':
|
||||||
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 (
|
||||||
if (apiUserid === config.api.admin && apiUserid === BigInt(query.get("a") || "0")) {
|
(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') || '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;
|
||||||
|
|
||||||
// Determine value to set
|
// Determine value to set
|
||||||
if (path.toLowerCase().indexOf("un") > 0) {
|
if (path.toLowerCase().indexOf('un') > 0) {
|
||||||
value = 0;
|
value = 0;
|
||||||
} else {
|
} else {
|
||||||
value = 1;
|
value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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") || "0")]).catch(e => {
|
await dbClient.execute('UPDATE allowed_channels SET banned = ? WHERE userid = ? AND channelid = ?', [value, apiUserid, BigInt(query.get('channel') || '0')]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -568,24 +585,24 @@ const start = async (): Promise<void> => {
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "/api/channel/activate":
|
case '/api/channel/activate':
|
||||||
case "/api/channel/activate/":
|
case '/api/channel/activate/':
|
||||||
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") || "0")) {
|
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;
|
||||||
|
|
||||||
// Determine value to set
|
// Determine value to set
|
||||||
if (path.toLowerCase().indexOf("de") > 0) {
|
if (path.toLowerCase().indexOf('de') > 0) {
|
||||||
value = 0;
|
value = 0;
|
||||||
} else {
|
} else {
|
||||||
value = 1;
|
value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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") || "0")]).catch(e => {
|
await dbClient.execute('UPDATE allowed_channels SET active = ? WHERE userid = ? AND channelid = ?', [value, apiUserid, BigInt(query.get('channel') || '0')]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -601,7 +618,7 @@ const start = async (): Promise<void> => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Alert API user that they shouldn't be doing this
|
// Alert API user that they shouldn't be doing this
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.Forbidden), { status: 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
|
||||||
|
@ -614,18 +631,18 @@ const start = async (): Promise<void> => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "DELETE":
|
case 'DELETE':
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
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") || "0") && 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
|
||||||
let erroredOut = false;
|
let erroredOut = false;
|
||||||
|
|
||||||
await dbClient.execute("DELETE FROM allowed_channels WHERE userid = ?", [apiUserid]).catch(e => {
|
await dbClient.execute('DELETE FROM allowed_channels WHERE userid = ?', [apiUserid]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -634,7 +651,7 @@ const start = async (): Promise<void> => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await dbClient.execute("DELETE FROM all_keys WHERE userid = ?", [apiUserid]).catch(e => {
|
await dbClient.execute('DELETE FROM all_keys WHERE userid = ?', [apiUserid]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -657,7 +674,7 @@ const start = async (): Promise<void> => {
|
||||||
let erroredOut = false;
|
let erroredOut = false;
|
||||||
|
|
||||||
// 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) => {
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
|
@ -668,7 +685,7 @@ const start = async (): Promise<void> => {
|
||||||
|
|
||||||
// "Send" the email
|
// "Send" the email
|
||||||
await sendMessage(config.api.email, generateApiDeleteEmail(apiUserEmail, deleteCode)).catch(() => {
|
await sendMessage(config.api.email, generateApiDeleteEmail(apiUserEmail, deleteCode)).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message 30 failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message 30 failed to send.', { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
});
|
});
|
||||||
if (erroredOut) {
|
if (erroredOut) {
|
||||||
|
@ -685,7 +702,7 @@ const start = async (): Promise<void> => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Alert API user that they messed up
|
// Alert API user that they messed up
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.BadRequest), { status: Status.BadRequest }));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -706,25 +723,25 @@ const start = async (): Promise<void> => {
|
||||||
}
|
}
|
||||||
} else if (!authenticated && !rateLimited) {
|
} else if (!authenticated && !rateLimited) {
|
||||||
// Get path and query as a string
|
// Get path and query as a string
|
||||||
const [path, tempQ] = request.url.split("?");
|
const [path, tempQ] = request.url.split('?');
|
||||||
|
|
||||||
// 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: string) => {
|
tempQ.split('&').forEach((e: string) => {
|
||||||
log(LT.LOG, `Parsing request query #2 ${request} ${e}`);
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the request
|
// Handle the request
|
||||||
switch (request.method) {
|
switch (request.method) {
|
||||||
case "GET":
|
case 'GET':
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
case "/api/key":
|
case '/api/key':
|
||||||
case "/api/key/":
|
case '/api/key/':
|
||||||
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))) {
|
||||||
// Generate new secure key
|
// Generate new secure key
|
||||||
const newKey = await nanoid(25);
|
const newKey = await nanoid(25);
|
||||||
|
|
||||||
|
@ -732,20 +749,22 @@ const start = async (): Promise<void> => {
|
||||||
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") || "0"), 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(
|
||||||
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
(e) => {
|
||||||
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
log(LT.ERROR, `Failed to insert into database: ${JSON.stringify(e)}`);
|
||||||
erroredOut = true;
|
requestEvent.respondWith(new Response(STATUS_TEXT.get(Status.InternalServerError), { status: Status.InternalServerError }));
|
||||||
});
|
erroredOut = true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Exit this case now if catch errored
|
// Exit this case now if catch errored
|
||||||
if (erroredOut) {
|
if (erroredOut) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Send" the email
|
// "Send" the email
|
||||||
await sendMessage(config.api.email, generateApiKeyEmail(query.get("email") || "no email", newKey)).catch(() => {
|
await sendMessage(config.api.email, generateApiKeyEmail(query.get('email') || 'no email', newKey)).catch(() => {
|
||||||
requestEvent.respondWith(new Response("Message 31 failed to send.", { status: Status.InternalServerError }));
|
requestEvent.respondWith(new Response('Message 31 failed to send.', { status: Status.InternalServerError }));
|
||||||
erroredOut = true;
|
erroredOut = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { ping } from "./ping.ts";
|
import { ping } from './ping.ts';
|
||||||
import { rip } from "./rip.ts";
|
import { rip } from './rip.ts';
|
||||||
import { rollHelp } from "./rollHelp.ts";
|
import { rollHelp } from './rollHelp.ts';
|
||||||
import { help } from "./help.ts";
|
import { help } from './help.ts';
|
||||||
import { info } from "./info.ts";
|
import { info } from './info.ts';
|
||||||
import { privacy } from "./privacy.ts";
|
import { privacy } from './privacy.ts';
|
||||||
import { version } from "./version.ts";
|
import { version } from './version.ts';
|
||||||
import { report } from "./report.ts";
|
import { report } from './report.ts';
|
||||||
import { stats } from "./stats.ts";
|
import { stats } from './stats.ts';
|
||||||
import { api } from "./apiCmd.ts";
|
import { api } from './apiCmd.ts';
|
||||||
import { emoji } from "./emoji.ts";
|
import { emoji } from './emoji.ts';
|
||||||
import { roll } from "./roll.ts";
|
import { roll } from './roll.ts';
|
||||||
import { handleMentions } from "./handleMentions.ts";
|
import { handleMentions } from './handleMentions.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
ping,
|
ping,
|
||||||
|
@ -25,5 +25,5 @@ export default {
|
||||||
api,
|
api,
|
||||||
emoji,
|
emoji,
|
||||||
roll,
|
roll,
|
||||||
handleMentions
|
handleMentions,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,65 +1,57 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage, hasGuildPermissions,
|
DiscordenoMessage,
|
||||||
|
hasGuildPermissions,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import apiCommands from "./apiCmd/_index.ts";
|
import apiCommands from './apiCmd/_index.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const api = async (message: DiscordenoMessage, args: string[]) => {
|
export const api = async (message: DiscordenoMessage, args: string[]) => {
|
||||||
// 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("api");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("api");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Local apiArg in lowercase
|
// Local apiArg in lowercase
|
||||||
const apiArg = (args[0] || "help").toLowerCase();
|
const apiArg = (args[0] || 'help').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 === 0n) {
|
if (message.guildId === 0n) {
|
||||||
message.send(constantCmds.apiGuildOnly).catch(e => {
|
message.send(constantCmds.apiGuildOnly).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
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 hasGuildPermissions(message.authorId, 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') {
|
||||||
apiCommands.help(message);
|
apiCommands.help(message);
|
||||||
}
|
} // [[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') {
|
||||||
apiCommands.allowBlock(message, apiArg);
|
apiCommands.allowBlock(message, apiArg);
|
||||||
}
|
} // [[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') {
|
||||||
apiCommands.deleteGuild(message);
|
apiCommands.deleteGuild(message);
|
||||||
}
|
} // [[api status
|
||||||
|
|
||||||
// [[api status
|
|
||||||
// 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') {
|
||||||
apiCommands.status(message);
|
apiCommands.status(message);
|
||||||
}
|
} // [[api show-warn/hide-warn
|
||||||
|
|
||||||
// [[api show-warn/hide-warn
|
|
||||||
// Lets a guild admin decide if the API warning should be shown on messages from the API
|
// Lets a guild admin decide if the API warning should be shown on messages from the API
|
||||||
else if (apiArg === "show-warn" || apiArg === "hide-warn") {
|
else if (apiArg === 'show-warn' || apiArg === 'hide-warn') {
|
||||||
apiCommands.showHideWarn(message, apiArg);
|
apiCommands.showHideWarn(message, apiArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
message.send(constantCmds.apiPermError).catch(e => {
|
message.send(constantCmds.apiPermError).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { help } from "./apiHelp.ts";
|
import { help } from './apiHelp.ts';
|
||||||
import { allowBlock } from "./allowBlock.ts";
|
import { allowBlock } from './allowBlock.ts';
|
||||||
import { deleteGuild } from "./deleteGuild.ts";
|
import { deleteGuild } from './deleteGuild.ts';
|
||||||
import { status } from "./status.ts";
|
import { status } from './status.ts';
|
||||||
import { showHideWarn } from "./showHideWarn.ts";
|
import { showHideWarn } from './showHideWarn.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
help,
|
help,
|
||||||
allowBlock,
|
allowBlock,
|
||||||
deleteGuild,
|
deleteGuild,
|
||||||
status,
|
status,
|
||||||
showHideWarn
|
showHideWarn,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { dbClient } from "../../db.ts";
|
import { dbClient } from '../../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../../deps.ts";
|
} from '../../../deps.ts';
|
||||||
import { generateApiFailed, generateApiSuccess } from "../../constantCmds.ts";
|
import { generateApiFailed, generateApiSuccess } from '../../constantCmds.ts';
|
||||||
|
|
||||||
export const allowBlock = async (message: DiscordenoMessage, apiArg: string) => {
|
export const allowBlock = async (message: DiscordenoMessage, apiArg: string) => {
|
||||||
const guildQuery = await dbClient.query(`SELECT guildid, channelid FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch(e0 => {
|
const guildQuery = await dbClient.query(`SELECT guildid, channelid FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch((e0) => {
|
||||||
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
||||||
message.send(generateApiFailed(apiArg)).catch(e1 => {
|
message.send(generateApiFailed(apiArg)).catch((e1) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -19,26 +19,30 @@ export const allowBlock = async (message: DiscordenoMessage, apiArg: string) =>
|
||||||
|
|
||||||
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,channelid,active) values(?,?,?)`, [message.guildId, message.channelId, ((apiArg === "allow" || apiArg === "enable") ? 1 : 0)]).catch(e0 => {
|
await dbClient.execute(`INSERT INTO allowed_guilds(guildid,channelid,active) values(?,?,?)`, [message.guildId, message.channelId, (apiArg === 'allow' || apiArg === 'enable') ? 1 : 0]).catch(
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e0)}`);
|
(e0) => {
|
||||||
message.send(generateApiFailed(apiArg)).catch(e1 => {
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e0)}`);
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
message.send(generateApiFailed(apiArg)).catch((e1) => {
|
||||||
});
|
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 = ? AND channelid = ?`, [((apiArg === "allow" || apiArg === "enable") ? 1 : 0), message.guildId, message.channelId]).catch(e0 => {
|
await dbClient.execute(`UPDATE allowed_guilds SET active = ? WHERE guildid = ? AND channelid = ?`, [(apiArg === 'allow' || apiArg === 'enable') ? 1 : 0, message.guildId, message.channelId]).catch(
|
||||||
log(LT.ERROR, `Failed to update DB: ${JSON.stringify(e0)}`);
|
(e0) => {
|
||||||
message.send(generateApiFailed(apiArg)).catch(e1 => {
|
log(LT.ERROR, `Failed to update DB: ${JSON.stringify(e0)}`);
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
message.send(generateApiFailed(apiArg)).catch((e1) => {
|
||||||
});
|
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
|
||||||
message.send(generateApiSuccess(`${apiArg}ed`)).catch(e => {
|
message.send(generateApiSuccess(`${apiArg}ed`)).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../../deps.ts";
|
} from '../../../deps.ts';
|
||||||
import { constantCmds } from "../../constantCmds.ts";
|
import { constantCmds } from '../../constantCmds.ts';
|
||||||
|
|
||||||
export const help = (message: DiscordenoMessage) => {
|
export const help = (message: DiscordenoMessage) => {
|
||||||
message.send(constantCmds.apiHelp).catch(e => {
|
message.send(constantCmds.apiHelp).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { dbClient } from "../../db.ts";
|
import { dbClient } from '../../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../../deps.ts";
|
} from '../../../deps.ts';
|
||||||
import { constantCmds } from "../../constantCmds.ts";
|
import { constantCmds } from '../../constantCmds.ts';
|
||||||
|
|
||||||
export const deleteGuild = async (message: DiscordenoMessage) => {
|
export const deleteGuild = async (message: DiscordenoMessage) => {
|
||||||
await dbClient.execute(`DELETE FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch(e0 => {
|
await dbClient.execute(`DELETE FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch((e0) => {
|
||||||
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
||||||
message.send(constantCmds.apiDeleteFail).catch(e1 => {
|
message.send(constantCmds.apiDeleteFail).catch((e1) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
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
|
||||||
message.send(constantCmds.apiRemoveGuild).catch(e => {
|
message.send(constantCmds.apiRemoveGuild).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { dbClient } from "../../db.ts";
|
import { dbClient } from '../../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../../deps.ts";
|
} from '../../../deps.ts';
|
||||||
import { generateApiFailed, generateApiSuccess } from "../../constantCmds.ts";
|
import { generateApiFailed, generateApiSuccess } from '../../constantCmds.ts';
|
||||||
|
|
||||||
export const showHideWarn = async (message: DiscordenoMessage, apiArg: string) => {
|
export const showHideWarn = async (message: DiscordenoMessage, apiArg: string) => {
|
||||||
const guildQuery = await dbClient.query(`SELECT guildid, channelid FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch(e0 => {
|
const guildQuery = await dbClient.query(`SELECT guildid, channelid FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch((e0) => {
|
||||||
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
||||||
message.send(generateApiFailed(`${apiArg} on`)).catch(e1 => {
|
message.send(generateApiFailed(`${apiArg} on`)).catch((e1) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -19,18 +19,18 @@ export const showHideWarn = async (message: DiscordenoMessage, apiArg: string) =
|
||||||
|
|
||||||
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,channelid,hidewarn) values(?,?,?)`, [message.guildId, message.channelId, ((apiArg === "hide-warn") ? 1 : 0)]).catch(e0 => {
|
await dbClient.execute(`INSERT INTO allowed_guilds(guildid,channelid,hidewarn) values(?,?,?)`, [message.guildId, message.channelId, (apiArg === 'hide-warn') ? 1 : 0]).catch((e0) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e0)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e0)}`);
|
||||||
message.send(generateApiFailed(`${apiArg} on`)).catch(e1 => {
|
message.send(generateApiFailed(`${apiArg} on`)).catch((e1) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
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 hidewarn = ? WHERE guildid = ? AND channelid = ?`, [((apiArg === "hide-warn") ? 1 : 0), message.guildId, message.channelId]).catch(e0 => {
|
await dbClient.execute(`UPDATE allowed_guilds SET hidewarn = ? WHERE guildid = ? AND channelid = ?`, [(apiArg === 'hide-warn') ? 1 : 0, message.guildId, message.channelId]).catch((e0) => {
|
||||||
log(LT.ERROR, `Failed to update DB: ${JSON.stringify(e0)}`);
|
log(LT.ERROR, `Failed to update DB: ${JSON.stringify(e0)}`);
|
||||||
message.send(generateApiFailed(`${apiArg} on`)).catch(e1 => {
|
message.send(generateApiFailed(`${apiArg} on`)).catch((e1) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -38,7 +38,7 @@ export const showHideWarn = async (message: DiscordenoMessage, apiArg: string) =
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
message.send(generateApiSuccess(apiArg)).catch(e => {
|
message.send(generateApiSuccess(apiArg)).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { dbClient } from "../../db.ts";
|
import { dbClient } from '../../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../../deps.ts";
|
} from '../../../deps.ts';
|
||||||
import { constantCmds, generateApiStatus } from "../../constantCmds.ts";
|
import { constantCmds, generateApiStatus } from '../../constantCmds.ts';
|
||||||
|
|
||||||
export const status = async (message: DiscordenoMessage) => {
|
export const status = async (message: DiscordenoMessage) => {
|
||||||
// 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 = ? AND channelid = ?`, [message.guildId, message.channelId]).catch(e0 => {
|
const guildQuery = await dbClient.query(`SELECT active, banned FROM allowed_guilds WHERE guildid = ? AND channelid = ?`, [message.guildId, message.channelId]).catch((e0) => {
|
||||||
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e0)}`);
|
||||||
message.send(constantCmds.apiStatusFail).catch(e1 => {
|
message.send(constantCmds.apiStatusFail).catch((e1) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e1)}`);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -22,17 +22,17 @@ export const status = async (message: DiscordenoMessage) => {
|
||||||
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) {
|
||||||
message.send(generateApiStatus(true, false)).catch(e => {
|
message.send(generateApiStatus(true, false)).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
message.send(generateApiStatus(false, guildQuery[0].active)).catch(e => {
|
message.send(generateApiStatus(false, guildQuery[0].active)).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
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
|
||||||
message.send(generateApiStatus(false, false)).catch(e => {
|
message.send(generateApiStatus(false, false)).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
import config from "../../config.ts";
|
import config from '../../config.ts';
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { EmojiConf } from "../mod.d.ts";
|
import { EmojiConf } from '../mod.d.ts';
|
||||||
|
|
||||||
const allEmojiAliases: string[] = [];
|
const allEmojiAliases: string[] = [];
|
||||||
|
|
||||||
config.emojis.forEach((emoji: EmojiConf) => {
|
config.emojis.forEach((emoji: EmojiConf) => {
|
||||||
allEmojiAliases.push(...emoji.aliases)
|
allEmojiAliases.push(...emoji.aliases);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const emoji = (message: DiscordenoMessage, command: string) => {
|
export const emoji = (message: DiscordenoMessage, command: string) => {
|
||||||
// shortcut
|
// shortcut
|
||||||
if (allEmojiAliases.indexOf(command)) {
|
if (allEmojiAliases.indexOf(command)) {
|
||||||
// Start looping thru the possible emojis
|
// Start looping thru the possible emojis
|
||||||
config.emojis.some((emoji: EmojiConf) => {
|
config.emojis.some((emoji: EmojiConf) => {
|
||||||
log(LT.LOG, `Checking if command was emoji ${JSON.stringify(emoji)}`);
|
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("emojis");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("emojis");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send the needed emoji1
|
// Send the needed emoji1
|
||||||
message.send(`<${emoji.animated ? "a" : ""}:${emoji.name}:${emoji.id}>`).catch(e => {
|
message.send(`<${emoji.animated ? 'a' : ''}:${emoji.name}:${emoji.id}>`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
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
|
||||||
if (emoji.deleteSender) {
|
if (emoji.deleteSender) {
|
||||||
message.delete().catch(e => {
|
message.delete().catch((e) => {
|
||||||
log(LT.WARN, `Failed to delete message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.WARN, `Failed to delete message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const handleMentions = (message: DiscordenoMessage) => {
|
export const handleMentions = (message: DiscordenoMessage) => {
|
||||||
log(LT.LOG, `Handling @mention message: ${JSON.stringify(message)}`);
|
log(LT.LOG, `Handling @mention message: ${JSON.stringify(message)}`);
|
||||||
|
|
||||||
// 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("mention");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("mention");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.mention).catch(e => {
|
message.send(constantCmds.mention).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const help = (message: DiscordenoMessage) => {
|
export const help = (message: DiscordenoMessage) => {
|
||||||
// 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("help");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("help");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.help).catch(e => {
|
message.send(constantCmds.help).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const info = (message: DiscordenoMessage) => {
|
export const info = (message: DiscordenoMessage) => {
|
||||||
// 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("info");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("info");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.info).catch(e => {
|
message.send(constantCmds.info).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { generatePing } from "../constantCmds.ts";
|
import { generatePing } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const ping = async (message: DiscordenoMessage) => {
|
export const ping = async (message: DiscordenoMessage) => {
|
||||||
// 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("ping");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("ping");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const privacy = (message: DiscordenoMessage) => {
|
export const privacy = (message: DiscordenoMessage) => {
|
||||||
// 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("privacy");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("privacy");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.privacy).catch(e => {
|
message.send(constantCmds.privacy).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
import config from "../../config.ts";
|
import config from '../../config.ts';
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage, sendMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
sendMessage,
|
||||||
import { constantCmds, generateReport } from "../constantCmds.ts";
|
} from '../../deps.ts';
|
||||||
|
import { constantCmds, generateReport } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const report = (message: DiscordenoMessage, args: string[]) => {
|
export const report = (message: DiscordenoMessage, args: string[]) => {
|
||||||
// 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("report");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("report");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (args.join(" ")) {
|
if (args.join(' ')) {
|
||||||
sendMessage(config.reportChannel, generateReport(args.join(" "))).catch(e => {
|
sendMessage(config.reportChannel, generateReport(args.join(' '))).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
message.send(constantCmds.report).catch(e => {
|
message.send(constantCmds.report).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
message.send(constantCmds.reportFail).catch(e => {
|
message.send(constantCmds.reportFail).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const rip = (message: DiscordenoMessage) => {
|
export const rip = (message: DiscordenoMessage) => {
|
||||||
// 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("rip");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("rip");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.rip).catch(e => {
|
message.send(constantCmds.rip).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
import config from "../../config.ts";
|
import config from '../../config.ts';
|
||||||
import { DEVMODE } from "../../flags.ts";
|
import { DEVMODE } from '../../flags.ts';
|
||||||
import { dbClient, queries } from "../db.ts";
|
import { dbClient, queries } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage, sendDirectMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
sendDirectMessage,
|
||||||
import solver from "../solver/_index.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds, generateDMFailed } from "../constantCmds.ts";
|
import solver from '../solver/_index.ts';
|
||||||
import rollFuncs from "./roll/_index.ts";
|
import { constantCmds, generateDMFailed } from '../constantCmds.ts';
|
||||||
|
import rollFuncs from './roll/_index.ts';
|
||||||
|
|
||||||
export const roll = async (message: DiscordenoMessage, args: string[], command: string) => {
|
export const roll = async (message: DiscordenoMessage, args: string[], command: string) => {
|
||||||
// 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) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
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) {
|
||||||
message.send(constantCmds.indev).catch(e => {
|
message.send(constantCmds.indev).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -28,7 +29,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
|
|
||||||
// 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 message.send(constantCmds.rolling);
|
const m = await message.send(constantCmds.rolling);
|
||||||
|
|
||||||
|
@ -41,10 +42,10 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, modifiers) || { error: true, errorCode: "EmptyMessage", errorMsg: "Error: Empty message", line1: "", line2: "", line3: "" };
|
const returnmsg = solver.parseRoll(rollCmd, modifiers) || { error: true, errorCode: 'EmptyMessage', errorMsg: 'Error: Empty message', line1: '', line2: '', line3: '' };
|
||||||
|
|
||||||
let returnText = "";
|
let returnText = '';
|
||||||
|
|
||||||
// If there was an error, report it to the user in hopes that they can determine what they did wrong
|
// If there was an error, report it to the user in hopes that they can determine what they did wrong
|
||||||
if (returnmsg.error) {
|
if (returnmsg.error) {
|
||||||
|
@ -53,7 +54,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
if (DEVMODE && config.logRolls) {
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, returnmsg.errorCode, m.id]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, returnmsg.errorCode, m.id]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -64,7 +65,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
|
|
||||||
if (!modifiers.superNoDetails) {
|
if (!modifiers.superNoDetails) {
|
||||||
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}`;
|
||||||
}
|
}
|
||||||
|
@ -74,30 +75,31 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
// 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.authorId}>${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) => {
|
||||||
log(LT.LOG, `Messaging GM ${e}`);
|
log(LT.LOG, `Messaging GM ${e}`);
|
||||||
// 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
|
||||||
// todo: embedify
|
// todo: embedify
|
||||||
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.`;
|
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(BigInt(e.substring(2, (e.length - 1))), returnText).catch(() => {
|
await sendDirectMessage(BigInt(e.substring(2, e.length - 1)), returnText).catch(() => {
|
||||||
message.send(generateDMFailed(e));
|
message.send(generateDMFailed(e));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Update return
|
// Update return
|
||||||
// todo: embedify
|
// todo: embedify
|
||||||
returnText = `<@${message.authorId}>${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(BigInt(e.substring(2, (e.length - 1))), { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }).catch(() => {
|
await sendDirectMessage(BigInt(e.substring(2, e.length - 1)), { 'content': returnText, 'file': { 'blob': b, 'name': 'rollDetails.txt' } }).catch(() => {
|
||||||
message.send(generateDMFailed(e));
|
message.send(generateDMFailed(e));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -108,7 +110,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
if (DEVMODE && config.logRolls) {
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 0), [originalCommand, returnText, m.id]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(0, 0), [originalCommand, returnText, m.id]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -116,23 +118,25 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
// 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
|
||||||
if (returnText.length > 2000) {
|
if (returnText.length > 2000) {
|
||||||
// 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
|
||||||
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.`;
|
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.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.`;
|
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();
|
||||||
|
|
||||||
// todo: embedify
|
// todo: embedify
|
||||||
await message.send({ "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } });
|
await message.send({ 'content': returnText, 'file': { 'blob': b, 'name': 'rollDetails.txt' } });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Finally send the text
|
// Finally send the text
|
||||||
|
@ -141,7 +145,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
if (DEVMODE && config.logRolls) {
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 0), [originalCommand, returnText, m.id]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(0, 0), [originalCommand, returnText, m.id]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { getModifiers } from "./getModifiers.ts";
|
import { getModifiers } from './getModifiers.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getModifiers
|
getModifiers,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,88 +1,88 @@
|
||||||
import config from "../../../config.ts";
|
import config from '../../../config.ts';
|
||||||
import { DEVMODE } from "../../../flags.ts";
|
import { DEVMODE } from '../../../flags.ts';
|
||||||
import { dbClient, queries } from "../../db.ts";
|
import { dbClient, queries } from '../../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../../deps.ts";
|
} from '../../../deps.ts';
|
||||||
import { generateRollError } from "../../constantCmds.ts";
|
import { generateRollError } from '../../constantCmds.ts';
|
||||||
import { RollModifiers } from "../../mod.d.ts";
|
import { RollModifiers } from '../../mod.d.ts';
|
||||||
|
|
||||||
export const getModifiers = (m: DiscordenoMessage, args: string[], command: string, originalCommand: string): RollModifiers => {
|
export const getModifiers = (m: DiscordenoMessage, args: string[], command: string, originalCommand: string): RollModifiers => {
|
||||||
const errorType = "Modifiers invalid:";
|
const errorType = 'Modifiers invalid:';
|
||||||
const modifiers: RollModifiers = {
|
const modifiers: RollModifiers = {
|
||||||
noDetails: false,
|
noDetails: false,
|
||||||
superNoDetails: false,
|
superNoDetails: false,
|
||||||
spoiler: "",
|
spoiler: '',
|
||||||
maxRoll: false,
|
maxRoll: false,
|
||||||
nominalRoll: false,
|
nominalRoll: false,
|
||||||
gmRoll: false,
|
gmRoll: false,
|
||||||
gms: [],
|
gms: [],
|
||||||
order: "",
|
order: '',
|
||||||
valid: false,
|
valid: false,
|
||||||
count: false
|
count: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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++) {
|
||||||
log(LT.LOG, `Checking ${command}${args.join(" ")} for command modifiers ${i}`);
|
log(LT.LOG, `Checking ${command}${args.join(' ')} for command modifiers ${i}`);
|
||||||
let defaultCase = false;
|
let defaultCase = false;
|
||||||
switch (args[i].toLowerCase()) {
|
switch (args[i].toLowerCase()) {
|
||||||
case "-c":
|
case '-c':
|
||||||
modifiers.count = true;
|
modifiers.count = true;
|
||||||
break;
|
break;
|
||||||
case "-nd":
|
case '-nd':
|
||||||
modifiers.noDetails = true;
|
modifiers.noDetails = true;
|
||||||
break;
|
break;
|
||||||
case "-snd":
|
case '-snd':
|
||||||
modifiers.superNoDetails = true;
|
modifiers.superNoDetails = true;
|
||||||
break;
|
break;
|
||||||
case "-s":
|
case '-s':
|
||||||
modifiers.spoiler = "||";
|
modifiers.spoiler = '||';
|
||||||
break;
|
break;
|
||||||
case "-m":
|
case '-m':
|
||||||
modifiers.maxRoll = true;
|
modifiers.maxRoll = true;
|
||||||
break;
|
break;
|
||||||
case "-n":
|
case '-n':
|
||||||
modifiers.nominalRoll = true;
|
modifiers.nominalRoll = true;
|
||||||
break;
|
break;
|
||||||
case "-gm":
|
case '-gm':
|
||||||
modifiers.gmRoll = true;
|
modifiers.gmRoll = true;
|
||||||
|
|
||||||
// -gm is a little more complex, as we must get all of the GMs that need to be DMd
|
// -gm is a little more complex, as we must get all of the GMs that need to be DMd
|
||||||
while (((i + 1) < args.length) && args[i + 1].startsWith("<@")) {
|
while (((i + 1) < args.length) && args[i + 1].startsWith('<@')) {
|
||||||
log(LT.LOG, `Finding all GMs, checking args ${JSON.stringify(args)}`);
|
log(LT.LOG, `Finding all GMs, checking args ${JSON.stringify(args)}`);
|
||||||
// Keep looping thru the rest of the args until one does not start with the discord mention code
|
// Keep looping thru the rest of the args until one does not start with the discord mention code
|
||||||
modifiers.gms.push(args[i + 1].replace(/[!]/g, ""));
|
modifiers.gms.push(args[i + 1].replace(/[!]/g, ''));
|
||||||
args.splice((i + 1), 1);
|
args.splice(i + 1, 1);
|
||||||
}
|
}
|
||||||
if (modifiers.gms.length < 1) {
|
if (modifiers.gms.length < 1) {
|
||||||
// If -gm is on and none were found, throw an error
|
// If -gm is on and none were found, throw an error
|
||||||
m.edit(generateRollError(errorType, "Must specifiy at least one GM by @mentioning them"));
|
m.edit(generateRollError(errorType, 'Must specifiy at least one GM by @mentioning them'));
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
if (DEVMODE && config.logRolls) {
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, "NoGMsFound", m.id]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, 'NoGMsFound', m.id]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return modifiers;
|
return modifiers;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "-o":
|
case '-o':
|
||||||
// Shift the -o out of the array so the next item is the direction
|
// Shift the -o out of the array so the next item is the direction
|
||||||
args.splice(i, 1);
|
args.splice(i, 1);
|
||||||
|
|
||||||
if (!args[i] || args[i].toLowerCase()[0] !== "d" && args[i].toLowerCase()[0] !== "a") {
|
if (!args[i] || args[i].toLowerCase()[0] !== 'd' && args[i].toLowerCase()[0] !== 'a') {
|
||||||
// If -o is on and asc or desc was not specified, error out
|
// If -o is on and asc or desc was not specified, error out
|
||||||
m.edit(generateRollError(errorType, "Must specifiy `a` or `d` to order the rolls ascending or descending"));
|
m.edit(generateRollError(errorType, 'Must specifiy `a` or `d` to order the rolls ascending or descending'));
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
if (DEVMODE && config.logRolls) {
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, "NoOrderFound", m.id]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, 'NoOrderFound', m.id]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -105,11 +105,11 @@ export const getModifiers = (m: DiscordenoMessage, args: string[], command: stri
|
||||||
|
|
||||||
// maxRoll and nominalRoll cannot both be on, throw an error
|
// maxRoll and nominalRoll cannot both be on, throw an error
|
||||||
if (modifiers.maxRoll && modifiers.nominalRoll) {
|
if (modifiers.maxRoll && modifiers.nominalRoll) {
|
||||||
m.edit(generateRollError(errorType, "Cannot maximise and nominise the roll at the same time"));
|
m.edit(generateRollError(errorType, 'Cannot maximise and nominise the roll at the same time'));
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
if (DEVMODE && config.logRolls) {
|
||||||
// If enabled, log rolls so we can verify the bots math
|
// If enabled, log rolls so we can verify the bots math
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, "MaxAndNominal", m.id]).catch(e => {
|
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, 'MaxAndNominal', m.id]).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const rollHelp = (message: DiscordenoMessage) => {
|
export const rollHelp = (message: DiscordenoMessage) => {
|
||||||
// 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("rollhelp");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("rollhelp");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.rollHelp).catch(e => {
|
message.send(constantCmds.rollHelp).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
cache, cacheHandlers, DiscordenoMessage,
|
cache,
|
||||||
|
cacheHandlers,
|
||||||
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds, generateStats } from "../constantCmds.ts";
|
import { constantCmds, generateStats } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const stats = async (message: DiscordenoMessage) => {
|
export const stats = async (message: DiscordenoMessage) => {
|
||||||
// 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("stats");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("stats");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -18,19 +20,19 @@ export const stats = async (message: DiscordenoMessage) => {
|
||||||
const m = await message.send(constantCmds.loadingStats);
|
const m = await message.send(constantCmds.loadingStats);
|
||||||
|
|
||||||
// Calculate how many times commands have been run
|
// Calculate how many times commands have been run
|
||||||
const rollQuery = await dbClient.query(`SELECT count FROM command_cnt WHERE command = "roll";`).catch(e => {
|
const rollQuery = await dbClient.query(`SELECT count FROM command_cnt WHERE command = "roll";`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
const totalQuery = await dbClient.query(`SELECT SUM(count) as count FROM command_cnt;`).catch(e => {
|
const totalQuery = await dbClient.query(`SELECT SUM(count) as count FROM command_cnt;`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
const rolls = BigInt(rollQuery[0].count);
|
const rolls = BigInt(rollQuery[0].count);
|
||||||
const total = BigInt(totalQuery[0].count);
|
const total = BigInt(totalQuery[0].count);
|
||||||
|
|
||||||
const cachedGuilds = await cacheHandlers.size("guilds");
|
const cachedGuilds = await cacheHandlers.size('guilds');
|
||||||
const cachedChannels = await cacheHandlers.size("channels");
|
const cachedChannels = await cacheHandlers.size('channels');
|
||||||
const cachedMembers = await cacheHandlers.size("members");
|
const cachedMembers = await cacheHandlers.size('members');
|
||||||
m.edit(generateStats(cachedGuilds + cache.dispatchedGuildIds.size, cachedChannels + cache.dispatchedChannelIds.size, cachedMembers, rolls, total - rolls)).catch(e => {
|
m.edit(generateStats(cachedGuilds + cache.dispatchedGuildIds.size, cachedChannels + cache.dispatchedChannelIds.size, cachedMembers, rolls, total - rolls)).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { dbClient } from "../db.ts";
|
import { dbClient } from '../db.ts';
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
import { constantCmds } from "../constantCmds.ts";
|
import { constantCmds } from '../constantCmds.ts';
|
||||||
|
|
||||||
export const version = (message: DiscordenoMessage) => {
|
export const version = (message: DiscordenoMessage) => {
|
||||||
// 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("version");`).catch(e => {
|
dbClient.execute(`CALL INC_CNT("version");`).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
message.send(constantCmds.version).catch(e => {
|
message.send(constantCmds.version).catch((e) => {
|
||||||
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import config from "../config.ts";
|
import config from '../config.ts';
|
||||||
import { CountDetails } from "./solver/solver.d.ts";
|
import { CountDetails } from './solver/solver.d.ts';
|
||||||
|
|
||||||
const failColor = 0xe71212;
|
const failColor = 0xe71212;
|
||||||
const warnColor = 0xe38f28;
|
const warnColor = 0xe38f28;
|
||||||
|
@ -11,211 +11,231 @@ export const constantCmds = {
|
||||||
apiDeleteFail: {
|
apiDeleteFail: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: "Failed to delete this guild from the database.",
|
title: 'Failed to delete this guild from the database.',
|
||||||
description: "If this issue persists, please report this to the developers."
|
description: 'If this issue persists, please report this to the developers.',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
apiGuildOnly: {
|
apiGuildOnly: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: "API commands are only available in guilds."
|
title: 'API commands are only available in guilds.',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
apiHelp: {
|
apiHelp: {
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "The Artificer's API Details:",
|
title: 'The Artificer\'s API Details:',
|
||||||
description: `The Artificer has a built in API that allows user to roll dice into Discord using third party programs. By default, API rolls are blocked from being sent in your guild. The API warning is also enabled by default. These commands may only be used by the Owner or Admins of your guild.
|
description:
|
||||||
|
`The Artificer has a built in API that allows user to roll dice into Discord using third party programs. By default, API rolls are blocked from being sent in your guild. The API warning is also enabled by default. These commands may only be used by the Owner or Admins of your guild.
|
||||||
|
|
||||||
For information on how to use the API, please check the GitHub README for more information [here](https://github.com/Burn-E99/TheArtificer).
|
For information on how to use the API, please check the GitHub README for more information [here](https://github.com/Burn-E99/TheArtificer).
|
||||||
|
|
||||||
You may enable and disable the API rolls for your guild as needed.`
|
You may enable and disable the API rolls for your guild as needed.`,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: "Available API Commands:",
|
title: 'Available API Commands:',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: `\`${config.prefix}api help\``,
|
name: `\`${config.prefix}api help\``,
|
||||||
value: "This command",
|
value: 'This command',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api status\``,
|
name: `\`${config.prefix}api status\``,
|
||||||
value: "Shows the current status of the API for the channel this was run in",
|
value: 'Shows the current status of the API for the channel this was run in',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api allow/enable\``,
|
name: `\`${config.prefix}api allow/enable\``,
|
||||||
value: "Allows API Rolls to be sent to the channel this was run in",
|
value: 'Allows API Rolls to be sent to the channel this was run in',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api block/disable\``,
|
name: `\`${config.prefix}api block/disable\``,
|
||||||
value: "Blocks API Rolls from being sent to the channel this was run in",
|
value: 'Blocks API Rolls from being sent to the channel this was run in',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api delete\``,
|
name: `\`${config.prefix}api delete\``,
|
||||||
value: "Deletes this channel's settings from The Artificer's database",
|
value: 'Deletes this channel\'s settings from The Artificer\'s database',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api show-warn\``,
|
name: `\`${config.prefix}api show-warn\``,
|
||||||
value: "Shows the API warning on all rolls sent to the channel this was run in",
|
value: 'Shows the API warning on all rolls sent to the channel this was run in',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api hide-warn\``,
|
name: `\`${config.prefix}api hide-warn\``,
|
||||||
value: "Hides the API warning on all rolls sent to the channel this was run in",
|
value: 'Hides the API warning on all rolls sent to the channel this was run in',
|
||||||
inline: true
|
inline: true,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
apiPermError: {
|
apiPermError: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: "API commands are powerful and can only be used by guild Owners and Admins.",
|
title: 'API commands are powerful and can only be used by guild Owners and Admins.',
|
||||||
description: "For information on how to use the API, please check the GitHub README for more information [here](https://github.com/Burn-E99/TheArtificer)."
|
description: 'For information on how to use the API, please check the GitHub README for more information [here](https://github.com/Burn-E99/TheArtificer).',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
apiRemoveGuild: {
|
apiRemoveGuild: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: successColor,
|
color: successColor,
|
||||||
title: "This guild's API setting has been removed from The Artifier's Database."
|
title: 'This guild\'s API setting has been removed from The Artifier\'s Database.',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
apiStatusFail: {
|
apiStatusFail: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: "Failed to check API rolls status for this guild.",
|
title: 'Failed to check API rolls status for this guild.',
|
||||||
description: "If this issue persists, please report this to the developers."
|
description: 'If this issue persists, please report this to the developers.',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
help: {
|
help: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "The Artificer's Available Commands:",
|
title: 'The Artificer\'s Available Commands:',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: `\`${config.prefix}?\``,
|
name: `\`${config.prefix}?\``,
|
||||||
value: "This command",
|
value: 'This command',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}rollhelp\` or \`${config.prefix}??\``,
|
name: `\`${config.prefix}rollhelp\` or \`${config.prefix}??\``,
|
||||||
value: `Details on how to use the roll command, listed as \`${config.prefix}xdy...${config.postfix}\` below`,
|
value: `Details on how to use the roll command, listed as \`${config.prefix}xdy...${config.postfix}\` below`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}api [subcommand]\``,
|
name: `\`${config.prefix}api [subcommand]\``,
|
||||||
value: `Administrative tools for the bots's API, run \`${config.prefix}api help\` for more details`,
|
value: `Administrative tools for the bots's API, run \`${config.prefix}api help\` for more details`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}ping\``,
|
name: `\`${config.prefix}ping\``,
|
||||||
value: "Pings the bot to check connectivity",
|
value: 'Pings the bot to check connectivity',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}info\``,
|
name: `\`${config.prefix}info\``,
|
||||||
value: "Prints some information and links relating to the bot",
|
value: 'Prints some information and links relating to the bot',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}privacy\``,
|
name: `\`${config.prefix}privacy\``,
|
||||||
value: "Prints some information about the Privacy Policy",
|
value: 'Prints some information about the Privacy Policy',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}version\``,
|
name: `\`${config.prefix}version\``,
|
||||||
value: "Prints the bots version",
|
value: 'Prints the bots version',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}popcat\``,
|
name: `\`${config.prefix}popcat\``,
|
||||||
value: "Popcat",
|
value: 'Popcat',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}report [text]\``,
|
name: `\`${config.prefix}report [text]\``,
|
||||||
value: "Report a command that failed to run",
|
value: 'Report a command that failed to run',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}stats\``,
|
name: `\`${config.prefix}stats\``,
|
||||||
value: "Statistics on the bot",
|
value: 'Statistics on the bot',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
|
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
|
||||||
value: `Rolls all configs requested, you may repeat the command multiple times in the same message (just ensure you close each roll with \`${config.postfix}\`), run \`${config.prefix}??\` for more details`,
|
value:
|
||||||
inline: true
|
`Rolls all configs requested, you may repeat the command multiple times in the same message (just ensure you close each roll with \`${config.postfix}\`), run \`${config.prefix}??\` for more details`,
|
||||||
}
|
inline: true,
|
||||||
]
|
},
|
||||||
}]
|
],
|
||||||
|
}],
|
||||||
},
|
},
|
||||||
indev: {
|
indev: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: warnColor,
|
color: warnColor,
|
||||||
title: "Command is in development, please try again later."
|
title: 'Command is in development, please try again later.',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
info: {
|
info: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "The Artificer, a Discord bot that specializing in rolling dice and calculating math",
|
title: 'The Artificer, a Discord bot that specializing in rolling dice and calculating math',
|
||||||
description: `The Artificer is developed by Ean AKA Burn_E99.
|
description: `The Artificer is developed by Ean AKA Burn_E99.
|
||||||
Additional information can be found on my website [here](https://discord.burne99.com/TheArtificer/).
|
Additional information can be found on my website [here](https://discord.burne99.com/TheArtificer/).
|
||||||
Want to check out my source code? Check it out [here](https://github.com/Burn-E99/TheArtificer).
|
Want to check out my source code? Check it out [here](https://github.com/Burn-E99/TheArtificer).
|
||||||
Need help with this bot? Join my support server [here](https://discord.gg/peHASXMZYv).`
|
Need help with this bot? Join my support server [here](https://discord.gg/peHASXMZYv).`,
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
loadingStats: {
|
loadingStats: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: warnColor,
|
color: warnColor,
|
||||||
title: "Compiling latest statistics . . ."
|
title: 'Compiling latest statistics . . .',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
mention: {
|
mention: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: `Hello! I am ${config.name}!`,
|
title: `Hello! I am ${config.name}!`,
|
||||||
fields: [{
|
fields: [{
|
||||||
name: "I am a bot that specializes in rolling dice and doing basic algebra",
|
name: 'I am a bot that specializes in rolling dice and doing basic algebra',
|
||||||
value: `To learn about my available commands, please run \`${config.prefix}help\``
|
value: `To learn about my available commands, please run \`${config.prefix}help\``,
|
||||||
}]
|
}],
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
privacy: {
|
privacy: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: "Privacy Policy",
|
title: 'Privacy Policy',
|
||||||
fields: [{
|
fields: [{
|
||||||
name: "The Artificer does not track or collect user information via Discord.",
|
name: 'The Artificer does not track or collect user information via Discord.',
|
||||||
value: `The only user submitted information that is stored is submitted via the \`${config.prefix}report\` command. This information is only stored for a short period of time in a location that only the Developer of The Artificer can see.
|
value:
|
||||||
|
`The only user submitted information that is stored is submitted via the \`${config.prefix}report\` command. This information is only stored for a short period of time in a location that only the Developer of The Artificer can see.
|
||||||
|
|
||||||
For more details, please check out the Privacy Policy on the GitHub [here](https://github.com/Burn-E99/TheArtificer/blob/master/PRIVACY.md).
|
For more details, please check out the Privacy Policy on the GitHub [here](https://github.com/Burn-E99/TheArtificer/blob/master/PRIVACY.md).
|
||||||
|
|
||||||
Terms of Service can also be found on GitHub [here](https://github.com/Burn-E99/TheArtificer/blob/master/TERMS.md).`
|
Terms of Service can also be found on GitHub [here](https://github.com/Burn-E99/TheArtificer/blob/master/TERMS.md).`,
|
||||||
}]
|
}],
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
report: {
|
report: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: successColor,
|
color: successColor,
|
||||||
title: "Failed command has been reported to my developer.",
|
title: 'Failed command has been reported to my developer.',
|
||||||
description: `For more in depth support, and information about planned maintenance, please join the support server [here](https://discord.gg/peHASXMZYv).`
|
description: `For more in depth support, and information about planned maintenance, please join the support server [here](https://discord.gg/peHASXMZYv).`,
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
reportFail: {
|
reportFail: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: "Please provide a short description of what failed",
|
title: 'Please provide a short description of what failed',
|
||||||
description: "Providing a short description helps my developer quickly diagnose what went wrong."
|
description: 'Providing a short description helps my developer quickly diagnose what went wrong.',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
rip: {
|
rip: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "The Artificer was built in memory of my Grandmother, Babka",
|
title: 'The Artificer was built in memory of my Grandmother, Babka',
|
||||||
description: `With much love, Ean
|
description: `With much love, Ean
|
||||||
|
|
||||||
December 21, 2020`
|
December 21, 2020`,
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
rollHelp: {
|
rollHelp: {
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "The Artificer's Roll Command Details:",
|
title: 'The Artificer\'s Roll Command Details:',
|
||||||
description: `You can chain as many of these options as you want, as long as the option does not disallow it.
|
description: `You can chain as many of these options as you want, as long as the option does not disallow it.
|
||||||
|
|
||||||
This command also can fully solve math equations with parenthesis.
|
This command also can fully solve math equations with parenthesis.
|
||||||
|
|
||||||
|
@ -223,273 +243,314 @@ Terms of Service can also be found on GitHub [here](https://github.com/Burn-E99/
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
|
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
|
||||||
value: `Rolls all configs requested, you may repeat the command multiple times in the same message (just ensure you close each roll with \`${config.postfix}\`)`
|
value: `Rolls all configs requested, you may repeat the command multiple times in the same message (just ensure you close each roll with \`${config.postfix}\`)`,
|
||||||
}, {
|
},
|
||||||
name: "`x` [Optional]",
|
{
|
||||||
value: "Number of dice to roll, if omitted, 1 is used",
|
name: '`x` [Optional]',
|
||||||
inline: true
|
value: 'Number of dice to roll, if omitted, 1 is used',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`dy` [Required]",
|
},
|
||||||
value: "Size of dice to roll, `d20` = 20 sided die",
|
{
|
||||||
inline: true
|
name: '`dy` [Required]',
|
||||||
}, {
|
value: 'Size of dice to roll, `d20` = 20 sided die',
|
||||||
name: "`dz` or `dlz` [Optional]",
|
inline: true,
|
||||||
value: "Drops the lowest `z` dice, cannot be used with `kz`",
|
},
|
||||||
inline: true
|
{
|
||||||
}, {
|
name: '`dz` or `dlz` [Optional]',
|
||||||
name: "`kz` or `khz` [Optional]",
|
value: 'Drops the lowest `z` dice, cannot be used with `kz`',
|
||||||
value: "Keeps the highest `z` dice, cannot be used with `dz`",
|
inline: true,
|
||||||
inline: true
|
},
|
||||||
}, {
|
{
|
||||||
name: "`dhz` [Optional]",
|
name: '`kz` or `khz` [Optional]',
|
||||||
value: "Drops the highest `z` dice, cannot be used with `kz`",
|
value: 'Keeps the highest `z` dice, cannot be used with `dz`',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`klz` [Optional]",
|
{
|
||||||
value: "Keeps the lowest `z` dice, cannot be used with `dz`",
|
name: '`dhz` [Optional]',
|
||||||
inline: true
|
value: 'Drops the highest `z` dice, cannot be used with `kz`',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`ra` or `r=q` [Optional]",
|
},
|
||||||
value: "Rerolls any rolls that match `a`, `r3` will reroll every die that land on 3, throwing out old rolls, cannot be used with `ro`",
|
{
|
||||||
inline: true
|
name: '`klz` [Optional]',
|
||||||
}, {
|
value: 'Keeps the lowest `z` dice, cannot be used with `dz`',
|
||||||
name: "`r<q` [Optional]",
|
inline: true,
|
||||||
value: "Rerolls any rolls that are less than or equal to `a`, `r3` will reroll every die that land on 3, 2, or 1, throwing out old rolls, cannot be used with `ro`",
|
},
|
||||||
inline: true
|
{
|
||||||
}, {
|
name: '`ra` or `r=q` [Optional]',
|
||||||
name: "`r>q` [Optional]",
|
value: 'Rerolls any rolls that match `a`, `r3` will reroll every die that land on 3, throwing out old rolls, cannot be used with `ro`',
|
||||||
value: "Rerolls any rolls that are greater than or equal to `a`, `r3` will reroll every die that land on 3 or greater, throwing out old rolls, cannot be used with `ro`",
|
inline: true,
|
||||||
inline: true
|
},
|
||||||
}, {
|
{
|
||||||
name: "`roa` or `ro=q` [Optional]",
|
name: '`r<q` [Optional]',
|
||||||
value: "Rerolls any rolls that match `a`, `ro3` will reroll each die that lands on 3 ONLY ONE TIME, throwing out old rolls, cannot be used with `r`",
|
value: 'Rerolls any rolls that are less than or equal to `a`, `r3` will reroll every die that land on 3, 2, or 1, throwing out old rolls, cannot be used with `ro`',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`ro<q` [Optional]",
|
{
|
||||||
value: "Rerolls any rolls that are less than or equal to `a`, `ro3` will reroll each die that lands on 3, 2, or 1 ONLY ONE TIME, throwing out old rolls, cannot be used with `r`",
|
name: '`r>q` [Optional]',
|
||||||
inline: true
|
value: 'Rerolls any rolls that are greater than or equal to `a`, `r3` will reroll every die that land on 3 or greater, throwing out old rolls, cannot be used with `ro`',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`ro>q` [Optional]",
|
},
|
||||||
value: "Rerolls any rolls that are greater than or equal to `a`, `ro3` will reroll each die that lands on 3 or greater ONLY ONE TIME, throwing out old rolls, cannot be used with `r`",
|
{
|
||||||
inline: true
|
name: '`roa` or `ro=q` [Optional]',
|
||||||
}, {
|
value: 'Rerolls any rolls that match `a`, `ro3` will reroll each die that lands on 3 ONLY ONE TIME, throwing out old rolls, cannot be used with `r`',
|
||||||
name: "`csq` or `cs=q` [Optional]",
|
inline: true,
|
||||||
value: "Changes crit score to `q`",
|
},
|
||||||
inline: true
|
{
|
||||||
}, {
|
name: '`ro<q` [Optional]',
|
||||||
name: "`cs<q` [Optional]",
|
value: 'Rerolls any rolls that are less than or equal to `a`, `ro3` will reroll each die that lands on 3, 2, or 1 ONLY ONE TIME, throwing out old rolls, cannot be used with `r`',
|
||||||
value: "Changes crit score to be less than or equal to `q`",
|
inline: true,
|
||||||
inline: true
|
},
|
||||||
}, {
|
{
|
||||||
name: "`cs>q` [Optional]",
|
name: '`ro>q` [Optional]',
|
||||||
value: "Changes crit score to be greater than or equal to `q`",
|
value: 'Rerolls any rolls that are greater than or equal to `a`, `ro3` will reroll each die that lands on 3 or greater ONLY ONE TIME, throwing out old rolls, cannot be used with `r`',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`cfq` or `cf=q` [Optional]",
|
{
|
||||||
value: "Changes crit fail to `q`",
|
name: '`csq` or `cs=q` [Optional]',
|
||||||
inline: true
|
value: 'Changes crit score to `q`',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`cf<q` [Optional]",
|
},
|
||||||
value: "Changes crit fail to be less than or equal to `q`",
|
{
|
||||||
inline: true
|
name: '`cs<q` [Optional]',
|
||||||
}, {
|
value: 'Changes crit score to be less than or equal to `q`',
|
||||||
name: "`cf>q` [Optional]",
|
inline: true,
|
||||||
value: "Changes crit fail to be greater than or equal to `q`",
|
},
|
||||||
inline: true
|
{
|
||||||
}, {
|
name: '`cs>q` [Optional]',
|
||||||
name: "`!` [Optional]",
|
value: 'Changes crit score to be greater than or equal to `q`',
|
||||||
value: "Exploding, rolls another `dy` for every crit success",
|
inline: true,
|
||||||
inline: true
|
},
|
||||||
}, {
|
{
|
||||||
name: "`!o` [Optional]",
|
name: '`cfq` or `cf=q` [Optional]',
|
||||||
value: "Exploding Once, rolls one `dy` for each original crit success",
|
value: 'Changes crit fail to `q`',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`!=u` [Optional]",
|
{
|
||||||
value: "Explode on `u`, rolls another `dy` for every die that lands on `u`",
|
name: '`cf<q` [Optional]',
|
||||||
inline: true
|
value: 'Changes crit fail to be less than or equal to `q`',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`!>u` [Optional]",
|
},
|
||||||
value: "Explode on `u` and greater, rolls another `dy` for every die that lands on `u` or greater",
|
{
|
||||||
inline: true
|
name: '`cf>q` [Optional]',
|
||||||
}, {
|
value: 'Changes crit fail to be greater than or equal to `q`',
|
||||||
name: "`!<u` [Optional]",
|
inline: true,
|
||||||
value: "Explode on `u` and under, rolls another `dy` for every die that lands on `u` or less",
|
},
|
||||||
inline: true
|
{
|
||||||
}, {
|
name: '`!` [Optional]',
|
||||||
name: "`!o=u` [Optional]",
|
value: 'Exploding, rolls another `dy` for every crit success',
|
||||||
value: "Explodes Once on `u`, rolls another `dy` for each original die that landed on `u`",
|
inline: true,
|
||||||
inline: true
|
},
|
||||||
}
|
{
|
||||||
]
|
name: '`!o` [Optional]',
|
||||||
}, {
|
value: 'Exploding Once, rolls one `dy` for each original crit success',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '`!=u` [Optional]',
|
||||||
|
value: 'Explode on `u`, rolls another `dy` for every die that lands on `u`',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '`!>u` [Optional]',
|
||||||
|
value: 'Explode on `u` and greater, rolls another `dy` for every die that lands on `u` or greater',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '`!<u` [Optional]',
|
||||||
|
value: 'Explode on `u` and under, rolls another `dy` for every die that lands on `u` or less',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '`!o=u` [Optional]',
|
||||||
|
value: 'Explodes Once on `u`, rolls another `dy` for each original die that landed on `u`',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "`!o>u` [Optional]",
|
name: '`!o>u` [Optional]',
|
||||||
value: "Explode Once on `u` and greater, rolls another `dy` for each original die that landed on `u` or greater",
|
value: 'Explode Once on `u` and greater, rolls another `dy` for each original die that landed on `u` or greater',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`!o<u` [Optional]",
|
{
|
||||||
value: "Explode Once on `u` and under, rolls another `dy` for each original die that landed on `u` or less",
|
name: '`!o<u` [Optional]',
|
||||||
inline: true
|
value: 'Explode Once on `u` and under, rolls another `dy` for each original die that landed on `u` or less',
|
||||||
}
|
inline: true,
|
||||||
]
|
},
|
||||||
}, {
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: "Roll Command Decorators:",
|
title: 'Roll Command Decorators:',
|
||||||
description: `This command also has some useful decorators that can used. These decorators simply need to be placed after all rolls in the message.
|
description: `This command also has some useful decorators that can used. These decorators simply need to be placed after all rolls in the message.
|
||||||
|
|
||||||
Examples: \`${config.prefix}d20${config.postfix} -nd\`, \`${config.prefix}d20${config.postfix} -nd -s\`, \`${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} -o a\``,
|
Examples: \`${config.prefix}d20${config.postfix} -nd\`, \`${config.prefix}d20${config.postfix} -nd -s\`, \`${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} -o a\``,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "`-nd` - No Details",
|
name: '`-nd` - No Details',
|
||||||
value: "Suppresses all details of the requested roll",
|
value: 'Suppresses all details of the requested roll',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`-snd` - Super No Details",
|
{
|
||||||
value: "Suppresses all details of the requested roll and hides no details message",
|
name: '`-snd` - Super No Details',
|
||||||
inline: true
|
value: 'Suppresses all details of the requested roll and hides no details message',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`-s` - Spoiler",
|
},
|
||||||
value: "Spoilers all details of the requested roll",
|
{
|
||||||
inline: true
|
name: '`-s` - Spoiler',
|
||||||
}, {
|
value: 'Spoilers all details of the requested roll',
|
||||||
name: "`-m` - Maximize Roll",
|
inline: true,
|
||||||
value: "Rolls the theoretical maximum roll, cannot be used with -n",
|
},
|
||||||
inline: true
|
{
|
||||||
}, {
|
name: '`-m` - Maximize Roll',
|
||||||
name: "`-n` - Nominal Roll",
|
value: 'Rolls the theoretical maximum roll, cannot be used with -n',
|
||||||
value: "Rolls the theoretical nominal roll, cannot be used with -m",
|
inline: true,
|
||||||
inline: true
|
},
|
||||||
}, {
|
{
|
||||||
name: "`-gm @user1 @user2 @usern` - GM Roll",
|
name: '`-n` - Nominal Roll',
|
||||||
value: "Rolls the requested roll in GM mode, suppressing all publicly shown results and details and sending the results directly to the specified GMs",
|
value: 'Rolls the theoretical nominal roll, cannot be used with -m',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "`-c` - Count Rolls",
|
{
|
||||||
value: "Shows the Count Embed, containing the count of successful rolls, failed rolls, rerolls, drops, and explosions",
|
name: '`-gm @user1 @user2 @usern` - GM Roll',
|
||||||
inline: true
|
value: 'Rolls the requested roll in GM mode, suppressing all publicly shown results and details and sending the results directly to the specified GMs',
|
||||||
}, {
|
inline: true,
|
||||||
name: "`-o [direction]` - Order Roll",
|
},
|
||||||
|
{
|
||||||
|
name: '`-c` - Count Rolls',
|
||||||
|
value: 'Shows the Count Embed, containing the count of successful rolls, failed rolls, rerolls, drops, and explosions',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '`-o [direction]` - Order Roll',
|
||||||
value: `Rolls the requested roll and orders the results in the requested direction
|
value: `Rolls the requested roll and orders the results in the requested direction
|
||||||
|
|
||||||
Available directions:
|
Available directions:
|
||||||
\`a\` - Ascending (least to greatest)
|
\`a\` - Ascending (least to greatest)
|
||||||
\`d\` - Descending (greatest to least)`,
|
\`d\` - Descending (greatest to least)`,
|
||||||
inline: true
|
inline: true,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
color: successColor,
|
color: successColor,
|
||||||
title: "Results Formatting:",
|
title: 'Results Formatting:',
|
||||||
description: "The results have some formatting applied on them to provide details on what happened during this roll.",
|
description: 'The results have some formatting applied on them to provide details on what happened during this roll.',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "Bold",
|
name: 'Bold',
|
||||||
value: "Critical successes will be **bolded**.",
|
value: 'Critical successes will be **bolded**.',
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Underline",
|
{
|
||||||
value: "Critical fails will be __underlined__.",
|
name: 'Underline',
|
||||||
inline: true
|
value: 'Critical fails will be __underlined__.',
|
||||||
}, {
|
inline: true,
|
||||||
name: "Strikethrough",
|
},
|
||||||
value: "Rolls that were dropped or rerolled ~~crossed out~~.",
|
{
|
||||||
inline: true
|
name: 'Strikethrough',
|
||||||
}
|
value: 'Rolls that were dropped or rerolled ~~crossed out~~.',
|
||||||
]
|
inline: true,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
rolling: {
|
rolling: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: "Rolling . . ."
|
title: 'Rolling . . .',
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
version: {
|
version: {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: `My current version is ${config.version}`
|
title: `My current version is ${config.version}`,
|
||||||
}]
|
}],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generatePing = (time: number) => ({
|
export const generatePing = (time: number) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: time === -1 ? "Ping?" : `Pong! Latency is ${time}ms.`
|
title: time === -1 ? 'Ping?' : `Pong! Latency is ${time}ms.`,
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateReport = (msg: string) => ({
|
export const generateReport = (msg: string) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "USER REPORT:",
|
title: 'USER REPORT:',
|
||||||
description: msg || "No message"
|
description: msg || 'No message',
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateStats = (guildCount: number, channelCount: number, memberCount: number, rollCount: bigint, utilityCount: bigint) => ({
|
export const generateStats = (guildCount: number, channelCount: number, memberCount: number, rollCount: bigint, utilityCount: bigint) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
title: "The Artificer's Statistics:",
|
title: 'The Artificer\'s Statistics:',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "Guilds:",
|
name: 'Guilds:',
|
||||||
value: `${guildCount}`,
|
value: `${guildCount}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Channels:",
|
{
|
||||||
|
name: 'Channels:',
|
||||||
value: `${channelCount}`,
|
value: `${channelCount}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Active Members:",
|
{
|
||||||
|
name: 'Active Members:',
|
||||||
value: `${memberCount}`,
|
value: `${memberCount}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Roll Commands:",
|
{
|
||||||
|
name: 'Roll Commands:',
|
||||||
value: `${rollCount}`,
|
value: `${rollCount}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Utility Commands:",
|
{
|
||||||
|
name: 'Utility Commands:',
|
||||||
value: `${utilityCount}`,
|
value: `${utilityCount}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateApiFailed = (args: string) => ({
|
export const generateApiFailed = (args: string) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: `Failed to ${args} API rolls for this guild.`,
|
title: `Failed to ${args} API rolls for this guild.`,
|
||||||
description: "If this issue persists, please report this to the developers."
|
description: 'If this issue persists, please report this to the developers.',
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateApiStatus = (banned: boolean, active: boolean) => ({
|
export const generateApiStatus = (banned: boolean, active: boolean) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: `The Artificer's API is ${config.api.enable ? "currently enabled" : "currently disabled"}.`,
|
title: `The Artificer's API is ${config.api.enable ? 'currently enabled' : 'currently disabled'}.`,
|
||||||
description: banned ? "API rolls are banned from being used in this guild.\n\nThis will not be reversed." : `API rolls are ${active ? "allowed" : "blocked from being used"} in this guild.`
|
description: banned ? 'API rolls are banned from being used in this guild.\n\nThis will not be reversed.' : `API rolls are ${active ? 'allowed' : 'blocked from being used'} in this guild.`,
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateApiSuccess = (args: string) => ({
|
export const generateApiSuccess = (args: string) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: successColor,
|
color: successColor,
|
||||||
title: `API rolls have successfully been ${args} for this guild.`
|
title: `API rolls have successfully been ${args} for this guild.`,
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateDMFailed = (user: string) => ({
|
export const generateDMFailed = (user: string) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: `WARNING: ${user} could not be messaged.`,
|
title: `WARNING: ${user} could not be messaged.`,
|
||||||
description: "If this issue persists, make sure direct messages are allowed from this server."
|
description: 'If this issue persists, make sure direct messages are allowed from this server.',
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateApiKeyEmail = (email: string, key: string) => ({
|
export const generateApiKeyEmail = (email: string, key: string) => ({
|
||||||
|
@ -498,13 +559,15 @@ export const generateApiKeyEmail = (email: string, key: string) => ({
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "Send to:",
|
name: 'Send to:',
|
||||||
value: email
|
value: email,
|
||||||
}, {
|
},
|
||||||
name: "Subject:",
|
{
|
||||||
value: "Artificer API Key"
|
name: 'Subject:',
|
||||||
}, {
|
value: 'Artificer API Key',
|
||||||
name: "Body:",
|
},
|
||||||
|
{
|
||||||
|
name: 'Body:',
|
||||||
value: `Hello Artificer API User,
|
value: `Hello Artificer API User,
|
||||||
|
|
||||||
Welcome aboard The Artificer's API. You can find full details about the API on the GitHub: https://github.com/Burn-E99/TheArtificer
|
Welcome aboard The Artificer's API. You can find full details about the API on the GitHub: https://github.com/Burn-E99/TheArtificer
|
||||||
|
@ -514,10 +577,10 @@ Your API Key is: ${key}
|
||||||
Guard this well, as there is zero tolerance for API abuse.
|
Guard this well, as there is zero tolerance for API abuse.
|
||||||
|
|
||||||
Welcome aboard,
|
Welcome aboard,
|
||||||
The Artificer Developer - Ean Milligan`
|
The Artificer Developer - Ean Milligan`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateApiDeleteEmail = (email: string, deleteCode: string) => ({
|
export const generateApiDeleteEmail = (email: string, deleteCode: string) => ({
|
||||||
|
@ -526,13 +589,15 @@ export const generateApiDeleteEmail = (email: string, deleteCode: string) => ({
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "Send to:",
|
name: 'Send to:',
|
||||||
value: email
|
value: email,
|
||||||
}, {
|
},
|
||||||
name: "Subject:",
|
{
|
||||||
value: "Artificer API Delete Code"
|
name: 'Subject:',
|
||||||
}, {
|
value: 'Artificer API Delete Code',
|
||||||
name: "Body:",
|
},
|
||||||
|
{
|
||||||
|
name: 'Body:',
|
||||||
value: `Hello Artificer API User,
|
value: `Hello Artificer API User,
|
||||||
|
|
||||||
I am sorry to see you go. If you would like, please respond to this email detailing what I could have done better.
|
I am sorry to see you go. If you would like, please respond to this email detailing what I could have done better.
|
||||||
|
@ -540,53 +605,58 @@ I am sorry to see you go. If you would like, please respond to this email detai
|
||||||
As requested, here is your delete code: ${deleteCode}
|
As requested, here is your delete code: ${deleteCode}
|
||||||
|
|
||||||
Sorry to see you go,
|
Sorry to see you go,
|
||||||
The Artificer Developer - Ean Milligan`
|
The Artificer Developer - Ean Milligan`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateRollError = (errorType: string, errorMsg: string) => ({
|
export const generateRollError = (errorType: string, errorMsg: string) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: failColor,
|
color: failColor,
|
||||||
title: "Roll command encountered the following error:",
|
title: 'Roll command encountered the following error:',
|
||||||
fields: [{
|
fields: [{
|
||||||
name: errorType,
|
name: errorType,
|
||||||
value: `${errorMsg}\n\nPlease try again. If the error is repeated, please report the issue using the \`${config.prefix}report\` command.`
|
value: `${errorMsg}\n\nPlease try again. If the error is repeated, please report the issue using the \`${config.prefix}report\` command.`,
|
||||||
}]
|
}],
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const generateCountDetails = (counts: CountDetails) => ({
|
export const generateCountDetails = (counts: CountDetails) => ({
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
title: "Roll Count Details:",
|
title: 'Roll Count Details:',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "Total Rolls:",
|
name: 'Total Rolls:',
|
||||||
details: `${counts.total}`,
|
details: `${counts.total}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Successful Rolls:",
|
{
|
||||||
|
name: 'Successful Rolls:',
|
||||||
details: `${counts.successful}`,
|
details: `${counts.successful}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Failed Rolls:",
|
{
|
||||||
|
name: 'Failed Rolls:',
|
||||||
details: `${counts.failed}`,
|
details: `${counts.failed}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Rerolled Dice:",
|
{
|
||||||
|
name: 'Rerolled Dice:',
|
||||||
details: `${counts.rerolled}`,
|
details: `${counts.rerolled}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Dropped Dice:",
|
{
|
||||||
|
name: 'Dropped Dice:',
|
||||||
details: `${counts.dropped}`,
|
details: `${counts.dropped}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}, {
|
},
|
||||||
name: "Exploded Dice:",
|
{
|
||||||
|
name: 'Exploded Dice:',
|
||||||
details: `${counts.exploded}`,
|
details: `${counts.exploded}`,
|
||||||
inline: true
|
inline: true,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}]
|
}],
|
||||||
});
|
});
|
||||||
|
|
10
src/db.ts
10
src/db.ts
|
@ -1,15 +1,15 @@
|
||||||
import config from "../config.ts";
|
import config from '../config.ts';
|
||||||
import { Client } from "../deps.ts";
|
import { Client } from '../deps.ts';
|
||||||
import { LOCALMODE } from "../flags.ts";
|
import { LOCALMODE } from '../flags.ts';
|
||||||
|
|
||||||
export const dbClient = await new Client().connect({
|
export const dbClient = await new Client().connect({
|
||||||
hostname: LOCALMODE ? config.db.localhost : config.db.host,
|
hostname: LOCALMODE ? config.db.localhost : config.db.host,
|
||||||
port: config.db.port,
|
port: config.db.port,
|
||||||
db: config.db.name,
|
db: config.db.name,
|
||||||
username: config.db.username,
|
username: config.db.username,
|
||||||
password: config.db.password
|
password: config.db.password,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const queries = {
|
export const queries = {
|
||||||
insertRollLogCmd: (api: number, error: number) => `INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,${api},${error})`
|
insertRollLogCmd: (api: number, error: number) => `INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,${api},${error})`,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,18 +6,19 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
cache, cacheHandlers,
|
cache,
|
||||||
|
cacheHandlers,
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../deps.ts";
|
} from '../deps.ts';
|
||||||
|
|
||||||
import config from "../config.ts";
|
import config from '../config.ts';
|
||||||
|
|
||||||
// getRandomStatus() 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 = async (): Promise<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:
|
||||||
status = `${config.prefix}help for commands`;
|
status = `${config.prefix}help for commands`;
|
||||||
|
@ -29,29 +30,29 @@ const getRandomStatus = async (): Promise<string> => {
|
||||||
status = `${config.prefix}info to learn more`;
|
status = `${config.prefix}info to learn more`;
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
const cachedCount = await cacheHandlers.size("guilds")
|
const cachedCount = await cacheHandlers.size('guilds');
|
||||||
status = `Rolling dice for ${cachedCount + cache.dispatchedGuildIds.size} servers`;
|
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: bigint, serverCount: number): void => {
|
const updateListStatistics = (botID: bigint, serverCount: number): void => {
|
||||||
config.botLists.forEach(async e => {
|
config.botLists.forEach(async (e) => {
|
||||||
log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`)
|
log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`);
|
||||||
if (e.enabled) {
|
if (e.enabled) {
|
||||||
const tempHeaders = new Headers();
|
const tempHeaders = new Headers();
|
||||||
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.toString()), {
|
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
|
||||||
});
|
});
|
||||||
log(LT.INFO, `Posted server count to ${e.name}. Results: ${JSON.stringify(response)}`);
|
log(LT.INFO, `Posted server count to ${e.name}. Results: ${JSON.stringify(response)}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,23 @@
|
||||||
|
|
||||||
// EmojiConf is used as a structure for the emojis stored in config.ts
|
// EmojiConf is used as a structure for the emojis stored in config.ts
|
||||||
export type EmojiConf = {
|
export type EmojiConf = {
|
||||||
name: string,
|
name: string;
|
||||||
aliases: Array<string>,
|
aliases: Array<string>;
|
||||||
id: string,
|
id: string;
|
||||||
animated: boolean,
|
animated: boolean;
|
||||||
deleteSender: boolean
|
deleteSender: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RollModifiers is the structure to keep track of the decorators applied to a roll command
|
// RollModifiers is the structure to keep track of the decorators applied to a roll command
|
||||||
export type RollModifiers = {
|
export type RollModifiers = {
|
||||||
noDetails: boolean,
|
noDetails: boolean;
|
||||||
superNoDetails: boolean,
|
superNoDetails: boolean;
|
||||||
spoiler: string,
|
spoiler: string;
|
||||||
maxRoll: boolean,
|
maxRoll: boolean;
|
||||||
nominalRoll: boolean,
|
nominalRoll: boolean;
|
||||||
gmRoll: boolean,
|
gmRoll: boolean;
|
||||||
gms: string[],
|
gms: string[];
|
||||||
order: string,
|
order: string;
|
||||||
valid: boolean,
|
valid: boolean;
|
||||||
count: boolean
|
count: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { parseRoll } from "./parser.ts";
|
import { parseRoll } from './parser.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
parseRoll
|
parseRoll,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
import {
|
import {
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import config from "../../config.ts";
|
import config from '../../config.ts';
|
||||||
|
|
||||||
import { RollModifiers } from "../mod.d.ts";
|
import { RollModifiers } from '../mod.d.ts';
|
||||||
import { SolvedStep, SolvedRoll, ReturnData } from "./solver.d.ts";
|
import { ReturnData, SolvedRoll, SolvedStep } from './solver.d.ts';
|
||||||
import { compareTotalRolls, escapeCharacters } from "./rollUtils.ts";
|
import { compareTotalRolls, escapeCharacters } from './rollUtils.ts';
|
||||||
import { formatRoll } from "./rollFormatter.ts";
|
import { formatRoll } from './rollFormatter.ts';
|
||||||
import { fullSolver } from "./solver.ts";
|
import { fullSolver } from './solver.ts';
|
||||||
|
|
||||||
// parseRoll(fullCmd, modifiers)
|
// parseRoll(fullCmd, modifiers)
|
||||||
// parseRoll handles converting fullCmd into a computer readable format for processing, and finally executes the solving
|
// parseRoll handles converting fullCmd into a computer readable format for processing, and finally executes the solving
|
||||||
export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll => {
|
export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll => {
|
||||||
const returnmsg = {
|
const returnmsg = {
|
||||||
error: false,
|
error: false,
|
||||||
errorMsg: "",
|
errorMsg: '',
|
||||||
errorCode: "",
|
errorCode: '',
|
||||||
line1: "",
|
line1: '',
|
||||||
line2: "",
|
line2: '',
|
||||||
line3: ""
|
line3: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Whole function lives in a try-catch to allow safe throwing of errors on purpose
|
// Whole function lives in a try-catch to allow safe throwing of errors on purpose
|
||||||
|
@ -37,22 +38,22 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
const [tempConf, tempFormat] = sepRolls[i].split(config.postfix);
|
const [tempConf, tempFormat] = sepRolls[i].split(config.postfix);
|
||||||
|
|
||||||
// Remove all spaces from the operation config and split it by any operator (keeping the operator in mathConf for fullSolver to do math on)
|
// Remove all spaces from the operation config and split it by any operator (keeping the operator in mathConf for fullSolver to do math on)
|
||||||
const mathConf: (string | number | SolvedStep)[] = <(string | number | SolvedStep)[]>tempConf.replace(/ /g, "").split(/([-+()*/%^])/g);
|
const mathConf: (string | number | SolvedStep)[] = <(string | number | SolvedStep)[]> tempConf.replace(/ /g, '').split(/([-+()*/%^])/g);
|
||||||
|
|
||||||
// Verify there are equal numbers of opening and closing parenthesis by adding 1 for opening parens and subtracting 1 for closing parens
|
// Verify there are equal numbers of opening and closing parenthesis by adding 1 for opening parens and subtracting 1 for closing parens
|
||||||
let parenCnt = 0;
|
let parenCnt = 0;
|
||||||
mathConf.forEach(e => {
|
mathConf.forEach((e) => {
|
||||||
log(LT.LOG, `Parsing roll ${fullCmd} | Checking parenthesis balance ${e}`);
|
log(LT.LOG, `Parsing roll ${fullCmd} | Checking parenthesis balance ${e}`);
|
||||||
if (e === "(") {
|
if (e === '(') {
|
||||||
parenCnt++;
|
parenCnt++;
|
||||||
} else if (e === ")") {
|
} else if (e === ')') {
|
||||||
parenCnt--;
|
parenCnt--;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the parenCnt is not 0, then we do not have balanced parens and need to error out now
|
// If the parenCnt is not 0, then we do not have balanced parens and need to error out now
|
||||||
if (parenCnt !== 0) {
|
if (parenCnt !== 0) {
|
||||||
throw new Error("UnbalancedParens");
|
throw new Error('UnbalancedParens');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate all rolls into stepSolve format and all numbers into floats
|
// Evaluate all rolls into stepSolve format and all numbers into floats
|
||||||
|
@ -68,35 +69,35 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
} else if (/([0123456789])/g.test(mathConf[i].toString())) {
|
} else if (/([0123456789])/g.test(mathConf[i].toString())) {
|
||||||
// If there is a number somewhere in mathconf[i] but there are also other characters preventing it from parsing correctly as a number, it should be a dice roll, parse it as such (if it for some reason is not a dice roll, formatRoll/roll will handle it)
|
// If there is a number somewhere in mathconf[i] but there are also other characters preventing it from parsing correctly as a number, it should be a dice roll, parse it as such (if it for some reason is not a dice roll, formatRoll/roll will handle it)
|
||||||
mathConf[i] = formatRoll(mathConf[i].toString(), modifiers.maxRoll, modifiers.nominalRoll);
|
mathConf[i] = formatRoll(mathConf[i].toString(), modifiers.maxRoll, modifiers.nominalRoll);
|
||||||
} else if (mathConf[i].toString().toLowerCase() === "e") {
|
} else if (mathConf[i].toString().toLowerCase() === 'e') {
|
||||||
// If the operand is the constant e, create a SolvedStep for it
|
// If the operand is the constant e, create a SolvedStep for it
|
||||||
mathConf[i] = {
|
mathConf[i] = {
|
||||||
total: Math.E,
|
total: Math.E,
|
||||||
details: "*e*",
|
details: '*e*',
|
||||||
containsCrit: false,
|
containsCrit: false,
|
||||||
containsFail: false
|
containsFail: false,
|
||||||
};
|
};
|
||||||
} else if (mathConf[i].toString().toLowerCase() === "pi" || mathConf[i].toString().toLowerCase() == "𝜋") {
|
} else if (mathConf[i].toString().toLowerCase() === 'pi' || mathConf[i].toString().toLowerCase() == '𝜋') {
|
||||||
// If the operand is the constant pi, create a SolvedStep for it
|
// If the operand is the constant pi, create a SolvedStep for it
|
||||||
mathConf[i] = {
|
mathConf[i] = {
|
||||||
total: Math.PI,
|
total: Math.PI,
|
||||||
details: "𝜋",
|
details: '𝜋',
|
||||||
containsCrit: false,
|
containsCrit: false,
|
||||||
containsFail: false
|
containsFail: false,
|
||||||
};
|
};
|
||||||
} else if (mathConf[i].toString().toLowerCase() === "pie") {
|
} else if (mathConf[i].toString().toLowerCase() === 'pie') {
|
||||||
// If the operand is pie, pi*e, create a SolvedStep for e and pi (and the multiplication symbol between them)
|
// If the operand is pie, pi*e, create a SolvedStep for e and pi (and the multiplication symbol between them)
|
||||||
mathConf[i] = {
|
mathConf[i] = {
|
||||||
total: Math.PI,
|
total: Math.PI,
|
||||||
details: "𝜋",
|
details: '𝜋',
|
||||||
containsCrit: false,
|
containsCrit: false,
|
||||||
containsFail: false
|
containsFail: false,
|
||||||
};
|
};
|
||||||
mathConf.splice((i + 1), 0, ...["*", {
|
mathConf.splice(i + 1, 0, ...['*', {
|
||||||
total: Math.E,
|
total: Math.E,
|
||||||
details: "*e*",
|
details: '*e*',
|
||||||
containsCrit: false,
|
containsCrit: false,
|
||||||
containsFail: false
|
containsFail: false,
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,51 +112,51 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
rollDetails: tempSolved.details,
|
rollDetails: tempSolved.details,
|
||||||
containsCrit: tempSolved.containsCrit,
|
containsCrit: tempSolved.containsCrit,
|
||||||
containsFail: tempSolved.containsFail,
|
containsFail: tempSolved.containsFail,
|
||||||
initConfig: tempConf
|
initConfig: tempConf,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsing/Solving done, time to format the output for Discord
|
// Parsing/Solving done, time to format the output for Discord
|
||||||
|
|
||||||
// Remove any floating spaces from fullCmd
|
// Remove any floating spaces from fullCmd
|
||||||
if (fullCmd[fullCmd.length - 1] === " ") {
|
if (fullCmd[fullCmd.length - 1] === ' ') {
|
||||||
fullCmd = fullCmd.substring(0, (fullCmd.length - 1));
|
fullCmd = fullCmd.substring(0, fullCmd.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape any | and ` chars in fullCmd to prevent spoilers and code blocks from acting up
|
// Escape any | and ` chars in fullCmd to prevent spoilers and code blocks from acting up
|
||||||
fullCmd = escapeCharacters(fullCmd, "|");
|
fullCmd = escapeCharacters(fullCmd, '|');
|
||||||
fullCmd = fullCmd.replace(/`/g, "");
|
fullCmd = fullCmd.replace(/`/g, '');
|
||||||
|
|
||||||
let line1 = "";
|
let line1 = '';
|
||||||
let line2 = "";
|
let line2 = '';
|
||||||
let line3 = "";
|
let line3 = '';
|
||||||
|
|
||||||
// If maximiseRoll or nominalRoll are on, mark the output as such, else use default formatting
|
// If maximiseRoll or nominalRoll are on, mark the output as such, else use default formatting
|
||||||
if (modifiers.maxRoll) {
|
if (modifiers.maxRoll) {
|
||||||
line1 = ` requested the theoretical maximum of: \`${config.prefix}${fullCmd}\``;
|
line1 = ` requested the theoretical maximum of: \`${config.prefix}${fullCmd}\``;
|
||||||
line2 = "Theoretical Maximum Results: ";
|
line2 = 'Theoretical Maximum Results: ';
|
||||||
} else if (modifiers.nominalRoll) {
|
} else if (modifiers.nominalRoll) {
|
||||||
line1 = ` requested the theoretical nominal of: \`${config.prefix}${fullCmd}\``;
|
line1 = ` requested the theoretical nominal of: \`${config.prefix}${fullCmd}\``;
|
||||||
line2 = "Theoretical Nominal Results: ";
|
line2 = 'Theoretical Nominal Results: ';
|
||||||
} else if (modifiers.order === "a") {
|
} else if (modifiers.order === 'a') {
|
||||||
line1 = ` requested the following rolls to be ordered from least to greatest: \`${config.prefix}${fullCmd}\``;
|
line1 = ` requested the following rolls to be ordered from least to greatest: \`${config.prefix}${fullCmd}\``;
|
||||||
line2 = "Results: ";
|
line2 = 'Results: ';
|
||||||
tempReturnData.sort(compareTotalRolls);
|
tempReturnData.sort(compareTotalRolls);
|
||||||
} else if (modifiers.order === "d") {
|
} else if (modifiers.order === 'd') {
|
||||||
line1 = ` requested the following rolls to be ordered from greatest to least: \`${config.prefix}${fullCmd}\``;
|
line1 = ` requested the following rolls to be ordered from greatest to least: \`${config.prefix}${fullCmd}\``;
|
||||||
line2 = "Results: ";
|
line2 = 'Results: ';
|
||||||
tempReturnData.sort(compareTotalRolls);
|
tempReturnData.sort(compareTotalRolls);
|
||||||
tempReturnData.reverse();
|
tempReturnData.reverse();
|
||||||
} else {
|
} else {
|
||||||
line1 = ` rolled: \`${config.prefix}${fullCmd}\``;
|
line1 = ` rolled: \`${config.prefix}${fullCmd}\``;
|
||||||
line2 = "Results: ";
|
line2 = 'Results: ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out all of the details and results now
|
// Fill out all of the details and results now
|
||||||
tempReturnData.forEach(e => {
|
tempReturnData.forEach((e) => {
|
||||||
log(LT.LOG, `Parsing roll ${fullCmd} | Making return text ${JSON.stringify(e)}`);
|
log(LT.LOG, `Parsing roll ${fullCmd} | Making return text ${JSON.stringify(e)}`);
|
||||||
let preFormat = "";
|
let preFormat = '';
|
||||||
let postFormat = "";
|
let postFormat = '';
|
||||||
|
|
||||||
// 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) {
|
||||||
|
@ -168,108 +169,107 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate line2 (the results) and line3 (the details) with their data
|
// Populate line2 (the results) and line3 (the details) with their data
|
||||||
if (modifiers.order === "") {
|
if (modifiers.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 ", "
|
||||||
if (modifiers.order !== "") {
|
if (modifiers.order !== '') {
|
||||||
line2 = line2.substring(0, (line2.length - 2));
|
line2 = line2.substring(0, line2.length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the return block
|
// Fill in the return block
|
||||||
returnmsg.line1 = line1;
|
returnmsg.line1 = line1;
|
||||||
returnmsg.line2 = line2;
|
returnmsg.line2 = line2;
|
||||||
returnmsg.line3 = line3;
|
returnmsg.line3 = line3;
|
||||||
|
|
||||||
} catch (solverError) {
|
} catch (solverError) {
|
||||||
// Welp, the unthinkable happened, we hit an error
|
// Welp, the unthinkable happened, we hit an error
|
||||||
|
|
||||||
// Split on _ for the error messages that have more info than just their name
|
// Split on _ for the error messages that have more info than just their name
|
||||||
const [errorName, errorDetails] = solverError.message.split("_");
|
const [errorName, errorDetails] = solverError.message.split('_');
|
||||||
|
|
||||||
let errorMsg = "";
|
let errorMsg = '';
|
||||||
|
|
||||||
// Translate the errorName to a specific errorMsg
|
// Translate the errorName to a specific errorMsg
|
||||||
switch (errorName) {
|
switch (errorName) {
|
||||||
case "YouNeedAD":
|
case 'YouNeedAD':
|
||||||
errorMsg = "Formatting Error: Missing die size and count config";
|
errorMsg = 'Formatting Error: Missing die size and count config';
|
||||||
break;
|
break;
|
||||||
case "FormattingError":
|
case 'FormattingError':
|
||||||
errorMsg = "Formatting Error: Cannot use Keep and Drop at the same time, remove all but one and repeat roll";
|
errorMsg = 'Formatting Error: Cannot use Keep and Drop at the same time, remove all but one and repeat roll';
|
||||||
break;
|
break;
|
||||||
case "NoMaxWithDash":
|
case 'NoMaxWithDash':
|
||||||
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 ${config.postfix}`;
|
errorMsg += `\nNote: Every roll must be closed by ${config.postfix}`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "NoZerosAllowed":
|
case 'NoZerosAllowed':
|
||||||
errorMsg = "Formatting Error: ";
|
errorMsg = 'Formatting Error: ';
|
||||||
switch (errorDetails) {
|
switch (errorDetails) {
|
||||||
case "base":
|
case 'base':
|
||||||
errorMsg += "Die Size and Die Count";
|
errorMsg += 'Die Size and Die Count';
|
||||||
break;
|
break;
|
||||||
case "drop":
|
case 'drop':
|
||||||
errorMsg += "Drop (d or dl)";
|
errorMsg += 'Drop (d or dl)';
|
||||||
break;
|
break;
|
||||||
case "keep":
|
case 'keep':
|
||||||
errorMsg += "Keep (k or kh)";
|
errorMsg += 'Keep (k or kh)';
|
||||||
break;
|
break;
|
||||||
case "dropHigh":
|
case 'dropHigh':
|
||||||
errorMsg += "Drop Highest (dh)";
|
errorMsg += 'Drop Highest (dh)';
|
||||||
break;
|
break;
|
||||||
case "keepLow":
|
case 'keepLow':
|
||||||
errorMsg += "Keep Lowest (kl)";
|
errorMsg += 'Keep Lowest (kl)';
|
||||||
break;
|
break;
|
||||||
case "reroll":
|
case 'reroll':
|
||||||
errorMsg += "Reroll (r)";
|
errorMsg += 'Reroll (r)';
|
||||||
break;
|
break;
|
||||||
case "critScore":
|
case 'critScore':
|
||||||
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';
|
||||||
break;
|
break;
|
||||||
case "CritScoreMinGtrMax":
|
case 'CritScoreMinGtrMax':
|
||||||
errorMsg = "Formatting Error: CritScore maximum cannot be greater than minimum, check formatting and flip min/max";
|
errorMsg = 'Formatting Error: CritScore maximum cannot be greater than minimum, check formatting and flip min/max';
|
||||||
break;
|
break;
|
||||||
case "MaxLoopsExceeded":
|
case 'MaxLoopsExceeded':
|
||||||
errorMsg = "Error: Roll is too complex or reaches infinity";
|
errorMsg = 'Error: Roll is too complex or reaches infinity';
|
||||||
break;
|
break;
|
||||||
case "UnbalancedParens":
|
case 'UnbalancedParens':
|
||||||
errorMsg = "Formatting Error: At least one of the equations contains unbalanced parenthesis";
|
errorMsg = 'Formatting Error: At least one of the equations contains unbalanced parenthesis';
|
||||||
break;
|
break;
|
||||||
case "EMDASNotNumber":
|
case 'EMDASNotNumber':
|
||||||
errorMsg = "Error: One or more operands is not a number";
|
errorMsg = 'Error: One or more operands is not a number';
|
||||||
break;
|
break;
|
||||||
case "ConfWhat":
|
case 'ConfWhat':
|
||||||
errorMsg = "Error: Not all values got processed, please report the command used";
|
errorMsg = 'Error: Not all values got processed, please report the command used';
|
||||||
break;
|
break;
|
||||||
case "OperatorWhat":
|
case 'OperatorWhat':
|
||||||
errorMsg = "Error: Something really broke with the Operator, try again";
|
errorMsg = 'Error: Something really broke with the Operator, try again';
|
||||||
break;
|
break;
|
||||||
case "OperandNaN":
|
case 'OperandNaN':
|
||||||
errorMsg = "Error: One or more operands reached NaN, check input";
|
errorMsg = 'Error: One or more operands reached NaN, check input';
|
||||||
break;
|
break;
|
||||||
case "UndefinedStep":
|
case 'UndefinedStep':
|
||||||
errorMsg = "Error: Roll became undefined, one or more operands are not a roll or a number, check input";
|
errorMsg = 'Error: Roll became undefined, one or more operands are not a roll or a number, check input';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log(LT.ERROR, `Undangled Error: ${errorName}, ${errorDetails}`);
|
log(LT.ERROR, `Undangled Error: ${errorName}, ${errorDetails}`);
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
import {
|
import {
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import { roll } from "./roller.ts";
|
import { roll } from './roller.ts';
|
||||||
import { SolvedStep } from "./solver.d.ts";
|
import { SolvedStep } from './solver.d.ts';
|
||||||
|
|
||||||
// formatRoll(rollConf, maximiseRoll, nominalRoll) returns one SolvedStep
|
// formatRoll(rollConf, maximiseRoll, nominalRoll) returns one SolvedStep
|
||||||
// formatRoll handles creating and formatting the completed rolls into the SolvedStep format
|
// formatRoll handles creating and formatting the completed rolls into the SolvedStep format
|
||||||
export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll: boolean): SolvedStep => {
|
export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll: boolean): SolvedStep => {
|
||||||
let tempTotal = 0;
|
let tempTotal = 0;
|
||||||
let tempDetails = "[";
|
let tempDetails = '[';
|
||||||
let tempCrit = false;
|
let tempCrit = false;
|
||||||
let tempFail = false;
|
let tempFail = false;
|
||||||
|
|
||||||
// Generate the roll, passing flags thru
|
// Generate the roll, passing flags thru
|
||||||
const tempRollSet = roll(rollConf, maximiseRoll, nominalRoll);
|
const tempRollSet = roll(rollConf, maximiseRoll, nominalRoll);
|
||||||
|
|
||||||
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
||||||
tempRollSet.forEach(e => {
|
tempRollSet.forEach((e) => {
|
||||||
log(LT.LOG, `Formatting roll ${rollConf} | ${JSON.stringify(e)}`);
|
log(LT.LOG, `Formatting roll ${rollConf} | ${JSON.stringify(e)}`);
|
||||||
let preFormat = "";
|
let preFormat = '';
|
||||||
let postFormat = "";
|
let postFormat = '';
|
||||||
|
|
||||||
if (!e.dropped && !e.rerolled) {
|
if (!e.dropped && !e.rerolled) {
|
||||||
// If the roll was not dropped or rerolled, add it to the stepTotal and flag the critHit/critFail
|
// If the roll was not dropped or rerolled, add it to the stepTotal and flag the critHit/critFail
|
||||||
|
@ -54,13 +55,13 @@ export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll:
|
||||||
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.substring(0, (tempDetails.length - 3));
|
tempDetails = tempDetails.substring(0, tempDetails.length - 3);
|
||||||
tempDetails += "]";
|
tempDetails += ']';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total: tempTotal,
|
total: tempTotal,
|
||||||
details: tempDetails,
|
details: tempDetails,
|
||||||
containsCrit: tempCrit,
|
containsCrit: tempCrit,
|
||||||
containsFail: tempFail
|
containsFail: tempFail,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {
|
import {
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import { RollSet, ReturnData } from "./solver.d.ts";
|
import { ReturnData, RollSet } from './solver.d.ts';
|
||||||
|
|
||||||
// MAXLOOPS determines how long the bot will attempt a roll
|
// MAXLOOPS determines how long the bot will attempt a roll
|
||||||
// Default is 5000000 (5 million), which results in at most a 10 second delay before the bot calls the roll infinite or too complex
|
// Default is 5000000 (5 million), which results in at most a 10 second delay before the bot calls the roll infinite or too complex
|
||||||
|
@ -60,7 +61,7 @@ export const escapeCharacters = (str: string, esc: string): string => {
|
||||||
for (let i = 0; i < esc.length; i++) {
|
for (let i = 0; i < esc.length; i++) {
|
||||||
log(LT.LOG, `Escaping character ${esc[i]} | ${str}, ${esc}`);
|
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;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import {
|
import {
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import { RollSet } from "./solver.d.ts";
|
import { RollSet } from './solver.d.ts';
|
||||||
import { MAXLOOPS, genRoll, compareRolls, compareOrigidx } from "./rollUtils.ts";
|
import { compareOrigidx, compareRolls, genRoll, MAXLOOPS } from './rollUtils.ts';
|
||||||
|
|
||||||
// roll(rollStr, maximiseRoll, nominalRoll) returns RollSet
|
// roll(rollStr, maximiseRoll, nominalRoll) returns RollSet
|
||||||
// roll parses and executes the rollStr, if needed it will also make the roll the maximum or average
|
// roll parses and executes the rollStr, if needed it will also make the roll the maximum or average
|
||||||
|
@ -19,7 +20,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollStr = rollStr.toLowerCase();
|
rollStr = rollStr.toLowerCase();
|
||||||
|
|
||||||
// Split the roll on the die size (and the drop if its there)
|
// Split the roll on the die size (and the drop if its there)
|
||||||
const dpts = rollStr.split("d");
|
const dpts = rollStr.split('d');
|
||||||
|
|
||||||
// Initialize the configuration to store the parsed data
|
// Initialize the configuration to store the parsed data
|
||||||
const rollConf = {
|
const rollConf = {
|
||||||
|
@ -27,47 +28,47 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
dieSize: 0,
|
dieSize: 0,
|
||||||
drop: {
|
drop: {
|
||||||
on: false,
|
on: false,
|
||||||
count: 0
|
count: 0,
|
||||||
},
|
},
|
||||||
keep: {
|
keep: {
|
||||||
on: false,
|
on: false,
|
||||||
count: 0
|
count: 0,
|
||||||
},
|
},
|
||||||
dropHigh: {
|
dropHigh: {
|
||||||
on: false,
|
on: false,
|
||||||
count: 0
|
count: 0,
|
||||||
},
|
},
|
||||||
keepLow: {
|
keepLow: {
|
||||||
on: false,
|
on: false,
|
||||||
count: 0
|
count: 0,
|
||||||
},
|
},
|
||||||
reroll: {
|
reroll: {
|
||||||
on: false,
|
on: false,
|
||||||
once: false,
|
once: false,
|
||||||
nums: <number[]>[]
|
nums: <number[]> [],
|
||||||
},
|
},
|
||||||
critScore: {
|
critScore: {
|
||||||
on: false,
|
on: false,
|
||||||
range: <number[]>[]
|
range: <number[]> [],
|
||||||
},
|
},
|
||||||
critFail: {
|
critFail: {
|
||||||
on: false,
|
on: false,
|
||||||
range: <number[]>[]
|
range: <number[]> [],
|
||||||
},
|
},
|
||||||
exploding: {
|
exploding: {
|
||||||
on: false,
|
on: false,
|
||||||
once: false,
|
once: false,
|
||||||
nums: <number[]>[]
|
nums: <number[]> [],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the dpts is not long enough, throw error
|
// If the dpts is not long enough, throw error
|
||||||
if (dpts.length < 2) {
|
if (dpts.length < 2) {
|
||||||
throw new Error("YouNeedAD");
|
throw new Error('YouNeedAD');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out the die count, first item will either be an int or empty string, short circuit execution will take care of replacing the empty string with a 1
|
// Fill out the die count, first item will either be an int or empty string, short circuit execution will take care of replacing the empty string with a 1
|
||||||
const tempDC = (dpts.shift() || "1").replace(/\D/g,'');
|
const tempDC = (dpts.shift() || '1').replace(/\D/g, '');
|
||||||
rollConf.dieCount = parseInt(tempDC);
|
rollConf.dieCount = parseInt(tempDC);
|
||||||
|
|
||||||
// Finds the end of the die size/beginnning of the additional options
|
// Finds the end of the die size/beginnning of the additional options
|
||||||
|
@ -77,7 +78,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rejoin all remaining parts
|
// Rejoin all remaining parts
|
||||||
let remains = dpts.join("d");
|
let remains = dpts.join('d');
|
||||||
// Get the die size out of the remains and into the rollConf
|
// Get the die size out of the remains and into the rollConf
|
||||||
rollConf.dieSize = parseInt(remains.slice(0, afterDieIdx));
|
rollConf.dieSize = parseInt(remains.slice(0, afterDieIdx));
|
||||||
remains = remains.slice(afterDieIdx);
|
remains = remains.slice(afterDieIdx);
|
||||||
|
@ -88,7 +89,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Finish parsing the roll
|
// Finish parsing the roll
|
||||||
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}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,42 +114,42 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
|
|
||||||
// Switch on rule name
|
// Switch on rule name
|
||||||
switch (tSep) {
|
switch (tSep) {
|
||||||
case "dl":
|
case 'dl':
|
||||||
case "d":
|
case 'd':
|
||||||
// Configure Drop (Lowest)
|
// Configure Drop (Lowest)
|
||||||
rollConf.drop.on = true;
|
rollConf.drop.on = true;
|
||||||
rollConf.drop.count = tNum;
|
rollConf.drop.count = tNum;
|
||||||
break;
|
break;
|
||||||
case "kh":
|
case 'kh':
|
||||||
case "k":
|
case 'k':
|
||||||
// Configure Keep (Highest)
|
// Configure Keep (Highest)
|
||||||
rollConf.keep.on = true;
|
rollConf.keep.on = true;
|
||||||
rollConf.keep.count = tNum;
|
rollConf.keep.count = tNum;
|
||||||
break;
|
break;
|
||||||
case "dh":
|
case 'dh':
|
||||||
// Configure Drop (Highest)
|
// Configure Drop (Highest)
|
||||||
rollConf.dropHigh.on = true;
|
rollConf.dropHigh.on = true;
|
||||||
rollConf.dropHigh.count = tNum;
|
rollConf.dropHigh.count = tNum;
|
||||||
break;
|
break;
|
||||||
case "kl":
|
case 'kl':
|
||||||
// Configure Keep (Lowest)
|
// Configure Keep (Lowest)
|
||||||
rollConf.keepLow.on = true;
|
rollConf.keepLow.on = true;
|
||||||
rollConf.keepLow.count = tNum;
|
rollConf.keepLow.count = tNum;
|
||||||
break;
|
break;
|
||||||
case "ro":
|
case 'ro':
|
||||||
case "ro=":
|
case 'ro=':
|
||||||
rollConf.reroll.once = true;
|
rollConf.reroll.once = true;
|
||||||
// falls through as ro/ro= functions the same as r/r= in this context
|
// falls through as ro/ro= functions the same as r/r= in this context
|
||||||
case "r":
|
case 'r':
|
||||||
case "r=":
|
case 'r=':
|
||||||
// Configure Reroll (this can happen multiple times)
|
// Configure Reroll (this can happen multiple times)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
rollConf.reroll.nums.push(tNum);
|
rollConf.reroll.nums.push(tNum);
|
||||||
break;
|
break;
|
||||||
case "ro>":
|
case 'ro>':
|
||||||
rollConf.reroll.once = true;
|
rollConf.reroll.once = true;
|
||||||
// falls through as ro> functions the same as r> in this context
|
// falls through as ro> functions the same as r> in this context
|
||||||
case "r>":
|
case 'r>':
|
||||||
// Configure reroll for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure reroll for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -156,10 +157,10 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.reroll.nums.push(i);
|
rollConf.reroll.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "ro<":
|
case 'ro<':
|
||||||
rollConf.reroll.once = true;
|
rollConf.reroll.once = true;
|
||||||
// falls through as ro< functions the same as r< in this context
|
// falls through as ro< functions the same as r< in this context
|
||||||
case "r<":
|
case 'r<':
|
||||||
// Configure reroll for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure reroll for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
for (let i = 1; i <= tNum; i++) {
|
for (let i = 1; i <= tNum; i++) {
|
||||||
|
@ -167,13 +168,13 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.reroll.nums.push(i);
|
rollConf.reroll.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cs":
|
case 'cs':
|
||||||
case "cs=":
|
case 'cs=':
|
||||||
// Configure CritScore for one number (this can happen multiple times)
|
// Configure CritScore for one number (this can happen multiple times)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
rollConf.critScore.range.push(tNum);
|
rollConf.critScore.range.push(tNum);
|
||||||
break;
|
break;
|
||||||
case "cs>":
|
case 'cs>':
|
||||||
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -181,7 +182,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.critScore.range.push(i);
|
rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cs<":
|
case 'cs<':
|
||||||
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
|
@ -189,13 +190,13 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.critScore.range.push(i);
|
rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cf":
|
case 'cf':
|
||||||
case "cf=":
|
case 'cf=':
|
||||||
// Configure CritFail for one number (this can happen multiple times)
|
// Configure CritFail for one number (this can happen multiple times)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
rollConf.critFail.range.push(tNum);
|
rollConf.critFail.range.push(tNum);
|
||||||
break;
|
break;
|
||||||
case "cf>":
|
case 'cf>':
|
||||||
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -203,7 +204,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.critFail.range.push(i);
|
rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cf<":
|
case 'cf<':
|
||||||
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
|
@ -211,10 +212,10 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.critFail.range.push(i);
|
rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "!o":
|
case '!o':
|
||||||
rollConf.exploding.once = true;
|
rollConf.exploding.once = true;
|
||||||
// falls through as !o functions the same as ! in this context
|
// falls through as !o functions the same as ! in this context
|
||||||
case "!":
|
case '!':
|
||||||
// Configure Exploding
|
// Configure Exploding
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
if (afterNumIdx > 0) {
|
if (afterNumIdx > 0) {
|
||||||
|
@ -225,18 +226,18 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
afterNumIdx = 1;
|
afterNumIdx = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "!o=":
|
case '!o=':
|
||||||
rollConf.exploding.once = true;
|
rollConf.exploding.once = true;
|
||||||
// falls through as !o= functions the same as != in this context
|
// falls through as !o= functions the same as != in this context
|
||||||
case "!=":
|
case '!=':
|
||||||
// Configure Exploding (this can happen multiple times)
|
// Configure Exploding (this can happen multiple times)
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
rollConf.exploding.nums.push(tNum);
|
rollConf.exploding.nums.push(tNum);
|
||||||
break;
|
break;
|
||||||
case "!o>":
|
case '!o>':
|
||||||
rollConf.exploding.once = true;
|
rollConf.exploding.once = true;
|
||||||
// falls through as !o> functions the same as !> in this context
|
// falls through as !o> functions the same as !> in this context
|
||||||
case "!>":
|
case '!>':
|
||||||
// Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -244,10 +245,10 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rollConf.exploding.nums.push(i);
|
rollConf.exploding.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "!o<":
|
case '!o<':
|
||||||
rollConf.exploding.once = true;
|
rollConf.exploding.once = true;
|
||||||
// falls through as !o< functions the same as !< in this context
|
// falls through as !o< functions the same as !< in this context
|
||||||
case "!<":
|
case '!<':
|
||||||
// Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
for (let i = 1; i <= tNum; i++) {
|
for (let i = 1; i <= tNum; i++) {
|
||||||
|
@ -266,36 +267,36 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
|
|
||||||
// Verify the parse, throwing errors for every invalid config
|
// Verify the parse, throwing errors for every invalid config
|
||||||
if (rollConf.dieCount < 0) {
|
if (rollConf.dieCount < 0) {
|
||||||
throw new Error("NoZerosAllowed_base");
|
throw new Error('NoZerosAllowed_base');
|
||||||
}
|
}
|
||||||
if (rollConf.dieCount === 0 || rollConf.dieSize === 0) {
|
if (rollConf.dieCount === 0 || rollConf.dieSize === 0) {
|
||||||
throw new Error("NoZerosAllowed_base");
|
throw new Error('NoZerosAllowed_base');
|
||||||
}
|
}
|
||||||
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
||||||
let dkdkCnt = 0;
|
let dkdkCnt = 0;
|
||||||
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach(e => {
|
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach((e) => {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Checking if drop/keep is on ${e}`);
|
log(LT.LOG, `Handling roll ${rollStr} | Checking if drop/keep is on ${e}`);
|
||||||
if (e) {
|
if (e) {
|
||||||
dkdkCnt++;
|
dkdkCnt++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (dkdkCnt > 1) {
|
if (dkdkCnt > 1) {
|
||||||
throw new Error("FormattingError_dk");
|
throw new Error('FormattingError_dk');
|
||||||
}
|
}
|
||||||
if (rollConf.drop.on && rollConf.drop.count === 0) {
|
if (rollConf.drop.on && rollConf.drop.count === 0) {
|
||||||
throw new Error("NoZerosAllowed_drop");
|
throw new Error('NoZerosAllowed_drop');
|
||||||
}
|
}
|
||||||
if (rollConf.keep.on && rollConf.keep.count === 0) {
|
if (rollConf.keep.on && rollConf.keep.count === 0) {
|
||||||
throw new Error("NoZerosAllowed_keep");
|
throw new Error('NoZerosAllowed_keep');
|
||||||
}
|
}
|
||||||
if (rollConf.dropHigh.on && rollConf.dropHigh.count === 0) {
|
if (rollConf.dropHigh.on && rollConf.dropHigh.count === 0) {
|
||||||
throw new Error("NoZerosAllowed_dropHigh");
|
throw new Error('NoZerosAllowed_dropHigh');
|
||||||
}
|
}
|
||||||
if (rollConf.keepLow.on && rollConf.keepLow.count === 0) {
|
if (rollConf.keepLow.on && rollConf.keepLow.count === 0) {
|
||||||
throw new Error("NoZerosAllowed_keepLow");
|
throw new Error('NoZerosAllowed_keepLow');
|
||||||
}
|
}
|
||||||
if (rollConf.reroll.on && rollConf.reroll.nums.indexOf(0) >= 0) {
|
if (rollConf.reroll.on && rollConf.reroll.nums.indexOf(0) >= 0) {
|
||||||
throw new Error("NoZerosAllowed_reroll");
|
throw new Error('NoZerosAllowed_reroll');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roll the roll
|
// Roll the roll
|
||||||
|
@ -331,7 +332,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
rerolled: false,
|
rerolled: false,
|
||||||
exploding: false,
|
exploding: false,
|
||||||
critHit: false,
|
critHit: false,
|
||||||
critFail: false
|
critFail: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Begin counting the number of loops to prevent from getting into an infinite loop
|
// Begin counting the number of loops to prevent from getting into an infinite loop
|
||||||
|
@ -342,7 +343,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
log(LT.LOG, `Handling roll ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > MAXLOOPS) {
|
||||||
throw new Error("MaxLoopsExceeded");
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the template to fill out for this iteration
|
// Copy the template to fill out for this iteration
|
||||||
|
@ -356,13 +357,13 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(rolling.roll) >= 0) {
|
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(rolling.roll) >= 0) {
|
||||||
rolling.critHit = true;
|
rolling.critHit = true;
|
||||||
} else if (!rollConf.critScore.on) {
|
} else if (!rollConf.critScore.on) {
|
||||||
rolling.critHit = (rolling.roll === rollConf.dieSize);
|
rolling.critHit = rolling.roll === rollConf.dieSize;
|
||||||
}
|
}
|
||||||
// If critFail arg is on, check if the roll should be a fail, if its off, check if the roll matches 1
|
// If critFail arg is on, check if the roll should be a fail, if its off, check if the roll matches 1
|
||||||
if (rollConf.critFail.on && rollConf.critFail.range.indexOf(rolling.roll) >= 0) {
|
if (rollConf.critFail.on && rollConf.critFail.range.indexOf(rolling.roll) >= 0) {
|
||||||
rolling.critFail = true;
|
rolling.critFail = true;
|
||||||
} else if (!rollConf.critFail.on) {
|
} else if (!rollConf.critFail.on) {
|
||||||
rolling.critFail = (rolling.roll === 1);
|
rolling.critFail = rolling.roll === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the newly created roll and loop again
|
// Push the newly created roll and loop again
|
||||||
|
@ -376,7 +377,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
log(LT.LOG, `Handling roll ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > MAXLOOPS) {
|
||||||
throw new Error("MaxLoopsExceeded");
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we need to reroll this roll, flag its been replaced and...
|
// If we need to reroll this roll, flag its been replaced and...
|
||||||
|
@ -393,21 +394,24 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(newRoll.roll) >= 0) {
|
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(newRoll.roll) >= 0) {
|
||||||
newRoll.critHit = true;
|
newRoll.critHit = true;
|
||||||
} else if (!rollConf.critScore.on) {
|
} else if (!rollConf.critScore.on) {
|
||||||
newRoll.critHit = (newRoll.roll === rollConf.dieSize);
|
newRoll.critHit = newRoll.roll === rollConf.dieSize;
|
||||||
}
|
}
|
||||||
// If critFail arg is on, check if the roll should be a fail, if its off, check if the roll matches 1
|
// If critFail arg is on, check if the roll should be a fail, if its off, check if the roll matches 1
|
||||||
if (rollConf.critFail.on && rollConf.critFail.range.indexOf(newRoll.roll) >= 0) {
|
if (rollConf.critFail.on && rollConf.critFail.range.indexOf(newRoll.roll) >= 0) {
|
||||||
newRoll.critFail = true;
|
newRoll.critFail = true;
|
||||||
} else if (!rollConf.critFail.on) {
|
} else if (!rollConf.critFail.on) {
|
||||||
newRoll.critFail = (newRoll.roll === 1);
|
newRoll.critFail = newRoll.roll === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slot this new roll in after the current iteration so it can be processed in the next loop
|
// Slot this new roll in after the current iteration so it can be processed in the next loop
|
||||||
rollSet.splice(i + 1, 0, newRoll);
|
rollSet.splice(i + 1, 0, newRoll);
|
||||||
} else if (rollConf.exploding.on && !rollSet[i].rerolled && (rollConf.exploding.nums.length ? rollConf.exploding.nums.indexOf(rollSet[i].roll) >= 0 : rollSet[i].critHit) && (!rollConf.exploding.once || !rollSet[i].exploding)) {
|
} else if (
|
||||||
|
rollConf.exploding.on && !rollSet[i].rerolled && (rollConf.exploding.nums.length ? rollConf.exploding.nums.indexOf(rollSet[i].roll) >= 0 : rollSet[i].critHit) &&
|
||||||
|
(!rollConf.exploding.once || !rollSet[i].exploding)
|
||||||
|
) {
|
||||||
// If we have exploding.nums set, use those to determine the exploding range, and make sure if !o is on, make sure we don't repeatedly explode
|
// If we have exploding.nums set, use those to determine the exploding range, and make sure if !o is on, make sure we don't repeatedly explode
|
||||||
// If it exploded, we keep both, so no flags need to be set
|
// If it exploded, we keep both, so no flags need to be set
|
||||||
|
|
||||||
// Copy the template to fill out for this iteration
|
// Copy the template to fill out for this iteration
|
||||||
const newRoll = JSON.parse(JSON.stringify(templateRoll));
|
const newRoll = JSON.parse(JSON.stringify(templateRoll));
|
||||||
// If maximiseRoll is on, set the roll to the dieSize, else if nominalRoll is on, set the roll to the average roll of dieSize, else generate a new random roll
|
// If maximiseRoll is on, set the roll to the dieSize, else if nominalRoll is on, set the roll to the average roll of dieSize, else generate a new random roll
|
||||||
|
@ -419,13 +423,13 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(newRoll.roll) >= 0) {
|
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(newRoll.roll) >= 0) {
|
||||||
newRoll.critHit = true;
|
newRoll.critHit = true;
|
||||||
} else if (!rollConf.critScore.on) {
|
} else if (!rollConf.critScore.on) {
|
||||||
newRoll.critHit = (newRoll.roll === rollConf.dieSize);
|
newRoll.critHit = newRoll.roll === rollConf.dieSize;
|
||||||
}
|
}
|
||||||
// If critFail arg is on, check if the roll should be a fail, if its off, check if the roll matches 1
|
// If critFail arg is on, check if the roll should be a fail, if its off, check if the roll matches 1
|
||||||
if (rollConf.critFail.on && rollConf.critFail.range.indexOf(newRoll.roll) >= 0) {
|
if (rollConf.critFail.on && rollConf.critFail.range.indexOf(newRoll.roll) >= 0) {
|
||||||
newRoll.critFail = true;
|
newRoll.critFail = true;
|
||||||
} else if (!rollConf.critFail.on) {
|
} else if (!rollConf.critFail.on) {
|
||||||
newRoll.critFail = (newRoll.roll === 1);
|
newRoll.critFail = newRoll.roll === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slot this new roll in after the current iteration so it can be processed in the next loop
|
// Slot this new roll in after the current iteration so it can be processed in the next loop
|
||||||
|
@ -444,7 +448,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
for (let i = 0; i < rollSet.length; i++) {
|
for (let i = 0; i < rollSet.length; i++) {
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > MAXLOOPS) {
|
||||||
throw new Error("MaxLoopsExceeded");
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[i])}`);
|
log(LT.LOG, `Handling roll ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[i])}`);
|
||||||
|
@ -477,9 +481,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
if (dropCount < 0) {
|
if (dropCount < 0) {
|
||||||
dropCount = 0;
|
dropCount = 0;
|
||||||
}
|
}
|
||||||
}
|
} // For inverted drop and keep, order must be flipped to greatest to least before the simple subtraction can determine how many to drop
|
||||||
|
|
||||||
// For inverted drop and keep, order must be flipped to greatest to least before the simple subtraction can determine how many to drop
|
|
||||||
// Protections are in to prevent the dropCount from going below 0 or more than the valid rolls to drop
|
// Protections are in to prevent the dropCount from going below 0 or more than the valid rolls to drop
|
||||||
else if (rollConf.dropHigh.on) {
|
else if (rollConf.dropHigh.on) {
|
||||||
rollSet.reverse();
|
rollSet.reverse();
|
||||||
|
@ -500,7 +502,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
while (dropCount > 0 && i < rollSet.length) {
|
while (dropCount > 0 && i < rollSet.length) {
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > MAXLOOPS) {
|
||||||
throw new Error("MaxLoopsExceeded");
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
log(LT.LOG, `Handling roll ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
||||||
|
|
|
@ -2,49 +2,49 @@
|
||||||
|
|
||||||
// RollSet is used to preserve all information about a calculated roll
|
// RollSet is used to preserve all information about a calculated roll
|
||||||
export type RollSet = {
|
export type RollSet = {
|
||||||
origidx: number,
|
origidx: number;
|
||||||
roll: number,
|
roll: number;
|
||||||
dropped: boolean,
|
dropped: boolean;
|
||||||
rerolled: boolean,
|
rerolled: boolean;
|
||||||
exploding: boolean,
|
exploding: boolean;
|
||||||
critHit: boolean,
|
critHit: boolean;
|
||||||
critFail: boolean
|
critFail: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SolvedStep is used to preserve information while math is being performed on the roll
|
// SolvedStep is used to preserve information while math is being performed on the roll
|
||||||
export type SolvedStep = {
|
export type SolvedStep = {
|
||||||
total: number,
|
total: number;
|
||||||
details: string,
|
details: string;
|
||||||
containsCrit: boolean,
|
containsCrit: boolean;
|
||||||
containsFail: boolean
|
containsFail: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ReturnData is the temporary internal type used before getting turned into SolvedRoll
|
// ReturnData is the temporary internal type used before getting turned into SolvedRoll
|
||||||
export type ReturnData = {
|
export type ReturnData = {
|
||||||
rollTotal: number,
|
rollTotal: number;
|
||||||
rollPostFormat: string,
|
rollPostFormat: string;
|
||||||
rollDetails: string,
|
rollDetails: string;
|
||||||
containsCrit: boolean,
|
containsCrit: boolean;
|
||||||
containsFail: boolean,
|
containsFail: boolean;
|
||||||
initConfig: string
|
initConfig: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SolvedRoll is the complete solved and formatted roll, or the error said roll created
|
// SolvedRoll is the complete solved and formatted roll, or the error said roll created
|
||||||
export type SolvedRoll = {
|
export type SolvedRoll = {
|
||||||
error: boolean,
|
error: boolean;
|
||||||
errorMsg: string,
|
errorMsg: string;
|
||||||
errorCode: string,
|
errorCode: string;
|
||||||
line1: string,
|
line1: string;
|
||||||
line2: string,
|
line2: string;
|
||||||
line3: string
|
line3: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CountDetails is the object holding the count data for creating the Count Embed
|
// CountDetails is the object holding the count data for creating the Count Embed
|
||||||
export type CountDetails = {
|
export type CountDetails = {
|
||||||
total: number,
|
total: number;
|
||||||
successful: number,
|
successful: number;
|
||||||
failed: number,
|
failed: number;
|
||||||
rerolled: number,
|
rerolled: number;
|
||||||
dropped: number,
|
dropped: number;
|
||||||
exploded: number
|
exploded: number;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,22 +5,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
LT, log
|
LT,
|
||||||
} from "../../deps.ts";
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import { SolvedStep } from "./solver.d.ts";
|
import { SolvedStep } from './solver.d.ts';
|
||||||
|
|
||||||
// fullSolver(conf, wrapDetails) returns one condensed SolvedStep
|
// fullSolver(conf, wrapDetails) returns one condensed SolvedStep
|
||||||
// fullSolver is a function that recursively solves the full roll and math
|
// fullSolver is a function that recursively solves the full roll and math
|
||||||
export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean): SolvedStep => {
|
export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean): SolvedStep => {
|
||||||
// Initialize PEMDAS
|
// Initialize PEMDAS
|
||||||
const signs = ["^", "*", "/", "%", "+", "-"];
|
const signs = ['^', '*', '/', '%', '+', '-'];
|
||||||
const stepSolve = {
|
const stepSolve = {
|
||||||
total: 0,
|
total: 0,
|
||||||
details: "",
|
details: '',
|
||||||
containsCrit: false,
|
containsCrit: false,
|
||||||
containsFail: false
|
containsFail: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// If entering with a single number, note it now
|
// If entering with a single number, note it now
|
||||||
|
@ -30,10 +31,10 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate all parenthesis
|
// Evaluate all parenthesis
|
||||||
while (conf.indexOf("(") > -1) {
|
while (conf.indexOf('(') > -1) {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for (`);
|
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for (`);
|
||||||
// Get first open parenthesis
|
// Get first open parenthesis
|
||||||
const openParen = conf.indexOf("(");
|
const openParen = conf.indexOf('(');
|
||||||
let closeParen = -1;
|
let closeParen = -1;
|
||||||
let nextParen = 0;
|
let nextParen = 0;
|
||||||
|
|
||||||
|
@ -41,12 +42,12 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
for (let i = openParen; i < conf.length; i++) {
|
for (let i = openParen; i < conf.length; i++) {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for matching ) openIdx: ${openParen} checking: ${i}`);
|
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for matching ) openIdx: ${openParen} checking: ${i}`);
|
||||||
// If we hit an open, add one (this includes the openParen we start with), if we hit a close, subtract one
|
// If we hit an open, add one (this includes the openParen we start with), if we hit a close, subtract one
|
||||||
if (conf[i] === "(") {
|
if (conf[i] === '(') {
|
||||||
nextParen++;
|
nextParen++;
|
||||||
} else if (conf[i] === ")") {
|
} else if (conf[i] === ')') {
|
||||||
nextParen--;
|
nextParen--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When nextParen reaches 0 again, we will have found the matching closing parenthesis and can safely exit the for loop
|
// When nextParen reaches 0 again, we will have found the matching closing parenthesis and can safely exit the for loop
|
||||||
if (nextParen === 0) {
|
if (nextParen === 0) {
|
||||||
closeParen = i;
|
closeParen = i;
|
||||||
|
@ -56,11 +57,11 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
|
|
||||||
// Make sure we did find the correct closing paren, if not, error out now
|
// Make sure we did find the correct closing paren, if not, error out now
|
||||||
if (closeParen === -1 || closeParen < openParen) {
|
if (closeParen === -1 || closeParen < openParen) {
|
||||||
throw new Error("UnbalancedParens");
|
throw new Error('UnbalancedParens');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the itemes between openParen and closeParen (including the parens) with its solved equilvalent by calling the solver on the items between openParen and closeParen (excluding the parens)
|
// Replace the itemes between openParen and closeParen (including the parens) with its solved equilvalent by calling the solver on the items between openParen and closeParen (excluding the parens)
|
||||||
conf.splice(openParen, (closeParen + 1), fullSolver(conf.slice((openParen + 1), closeParen), true));
|
conf.splice(openParen, closeParen + 1, fullSolver(conf.slice(openParen + 1, closeParen), true));
|
||||||
|
|
||||||
// Determing if we need to add in a multiplication sign to handle implicit multiplication (like "(4)2" = 8)
|
// Determing if we need to add in a multiplication sign to handle implicit multiplication (like "(4)2" = 8)
|
||||||
// insertedMult flags if there was a multiplication sign inserted before the parens
|
// insertedMult flags if there was a multiplication sign inserted before the parens
|
||||||
|
@ -68,20 +69,20 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
// Check if a number was directly before openParen and slip in the "*" if needed
|
// Check if a number was directly before openParen and slip in the "*" if needed
|
||||||
if (((openParen - 1) > -1) && (signs.indexOf(conf[openParen - 1].toString()) === -1)) {
|
if (((openParen - 1) > -1) && (signs.indexOf(conf[openParen - 1].toString()) === -1)) {
|
||||||
insertedMult = true;
|
insertedMult = true;
|
||||||
conf.splice(openParen, 0, "*");
|
conf.splice(openParen, 0, '*');
|
||||||
}
|
}
|
||||||
// Check if a number is directly after closeParen and slip in the "*" if needed
|
// Check if a number is directly after closeParen and slip in the "*" if needed
|
||||||
if (!insertedMult && (((openParen + 1) < conf.length) && (signs.indexOf(conf[openParen + 1].toString()) === -1))) {
|
if (!insertedMult && (((openParen + 1) < conf.length) && (signs.indexOf(conf[openParen + 1].toString()) === -1))) {
|
||||||
conf.splice((openParen + 1), 0, "*");
|
conf.splice(openParen + 1, 0, '*');
|
||||||
} else if (insertedMult && (((openParen + 2) < conf.length) && (signs.indexOf(conf[openParen + 2].toString()) === -1))) {
|
} else if (insertedMult && (((openParen + 2) < conf.length) && (signs.indexOf(conf[openParen + 2].toString()) === -1))) {
|
||||||
// insertedMult is utilized here to let us account for an additional item being inserted into the array (the "*" from before openParn)
|
// insertedMult is utilized here to let us account for an additional item being inserted into the array (the "*" from before openParn)
|
||||||
conf.splice((openParen + 2), 0, "*");
|
conf.splice(openParen + 2, 0, '*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate all EMMDAS by looping thru each teir of operators (exponential is the higehest teir, addition/subtraction the lowest)
|
// Evaluate all EMMDAS by looping thru each teir of operators (exponential is the higehest teir, addition/subtraction the lowest)
|
||||||
const allCurOps = [["^"], ["*", "/", "%"], ["+", "-"]];
|
const allCurOps = [['^'], ['*', '/', '%'], ['+', '-']];
|
||||||
allCurOps.forEach(curOps => {
|
allCurOps.forEach((curOps) => {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)}`);
|
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)}`);
|
||||||
// Iterate thru all operators/operands in the conf
|
// Iterate thru all operators/operands in the conf
|
||||||
for (let i = 0; i < conf.length; i++) {
|
for (let i = 0; i < conf.length; i++) {
|
||||||
|
@ -96,15 +97,15 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
let oper2 = NaN;
|
let oper2 = NaN;
|
||||||
const subStepSolve = {
|
const subStepSolve = {
|
||||||
total: NaN,
|
total: NaN,
|
||||||
details: "",
|
details: '',
|
||||||
containsCrit: false,
|
containsCrit: false,
|
||||||
containsFail: false
|
containsFail: false,
|
||||||
};
|
};
|
||||||
// Flag to prevent infinte loop when dealing with negative numbers (such as [[-1+20]])
|
// Flag to prevent infinte loop when dealing with negative numbers (such as [[-1+20]])
|
||||||
let shouldDecrement = true;
|
let shouldDecrement = true;
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -122,7 +123,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
if (typeof operand2 === "object") {
|
if (typeof operand2 === 'object') {
|
||||||
oper2 = operand2.total;
|
oper2 = operand2.total;
|
||||||
subStepSolve.details += operand2.details;
|
subStepSolve.details += operand2.details;
|
||||||
subStepSolve.containsCrit = subStepSolve.containsCrit || operand2.containsCrit;
|
subStepSolve.containsCrit = subStepSolve.containsCrit || operand2.containsCrit;
|
||||||
|
@ -135,42 +136,42 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
|
|
||||||
// Make sure neither operand is NaN before continuing
|
// Make sure neither operand is NaN before continuing
|
||||||
if (isNaN(oper1) || isNaN(oper2)) {
|
if (isNaN(oper1) || isNaN(oper2)) {
|
||||||
throw new Error("OperandNaN");
|
throw new Error('OperandNaN');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify a second time that both are numbers before doing math, throwing an error if necessary
|
// Verify a second time that both are numbers before doing math, throwing an error if necessary
|
||||||
if ((typeof oper1 === "number") && (typeof oper2 === "number")) {
|
if ((typeof oper1 === 'number') && (typeof oper2 === 'number')) {
|
||||||
// Finally do the operator on the operands, throw an error if the operator is not found
|
// Finally do the operator on the operands, throw an error if the operator is not found
|
||||||
switch (conf[i]) {
|
switch (conf[i]) {
|
||||||
case "^":
|
case '^':
|
||||||
subStepSolve.total = Math.pow(oper1, oper2);
|
subStepSolve.total = Math.pow(oper1, oper2);
|
||||||
break;
|
break;
|
||||||
case "*":
|
case '*':
|
||||||
subStepSolve.total = oper1 * oper2;
|
subStepSolve.total = oper1 * oper2;
|
||||||
break;
|
break;
|
||||||
case "/":
|
case '/':
|
||||||
subStepSolve.total = oper1 / oper2;
|
subStepSolve.total = oper1 / oper2;
|
||||||
break;
|
break;
|
||||||
case "%":
|
case '%':
|
||||||
subStepSolve.total = oper1 % oper2;
|
subStepSolve.total = oper1 % oper2;
|
||||||
break;
|
break;
|
||||||
case "+":
|
case '+':
|
||||||
subStepSolve.total = oper1 + oper2;
|
subStepSolve.total = oper1 + oper2;
|
||||||
break;
|
break;
|
||||||
case "-":
|
case '-':
|
||||||
subStepSolve.total = oper1 - oper2;
|
subStepSolve.total = oper1 - oper2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("OperatorWhat");
|
throw new Error('OperatorWhat');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("EMDASNotNumber");
|
throw new Error('EMDASNotNumber');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if we actually did math or just smashed a - sign onto a number
|
// Determine if we actually did math or just smashed a - sign onto a number
|
||||||
if (shouldDecrement) {
|
if (shouldDecrement) {
|
||||||
// Replace the two operands and their operator with our subStepSolve
|
// Replace the two operands and their operator with our subStepSolve
|
||||||
conf.splice((i - 1), 3, subStepSolve);
|
conf.splice(i - 1, 3, subStepSolve);
|
||||||
// Because we are messing around with the array we are iterating thru, we need to back up one idx to make sure every operator gets processed
|
// Because we are messing around with the array we are iterating thru, we need to back up one idx to make sure every operator gets processed
|
||||||
i--;
|
i--;
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,17 +185,17 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
// If we somehow have more than one item left in conf at this point, something broke, throw an error
|
// If we somehow have more than one item left in conf at this point, something broke, throw an error
|
||||||
if (conf.length > 1) {
|
if (conf.length > 1) {
|
||||||
log(LT.LOG, `ConfWHAT? ${JSON.stringify(conf)}`);
|
log(LT.LOG, `ConfWHAT? ${JSON.stringify(conf)}`);
|
||||||
throw new Error("ConfWhat");
|
throw new Error('ConfWhat');
|
||||||
} else if (singleNum && (typeof (conf[0]) === "number")) {
|
} else if (singleNum && (typeof (conf[0]) === 'number')) {
|
||||||
// If we are only left with a number, populate the stepSolve with it
|
// If we are only left with a number, populate the stepSolve with it
|
||||||
stepSolve.total = conf[0];
|
stepSolve.total = conf[0];
|
||||||
stepSolve.details = conf[0].toString();
|
stepSolve.details = conf[0].toString();
|
||||||
} else {
|
} else {
|
||||||
// Else fully populate the stepSolve with what was computed
|
// Else fully populate the stepSolve with what was computed
|
||||||
stepSolve.total = (<SolvedStep>conf[0]).total;
|
stepSolve.total = (<SolvedStep> conf[0]).total;
|
||||||
stepSolve.details = (<SolvedStep>conf[0]).details;
|
stepSolve.details = (<SolvedStep> conf[0]).details;
|
||||||
stepSolve.containsCrit = (<SolvedStep>conf[0]).containsCrit;
|
stepSolve.containsCrit = (<SolvedStep> conf[0]).containsCrit;
|
||||||
stepSolve.containsFail = (<SolvedStep>conf[0]).containsFail;
|
stepSolve.containsFail = (<SolvedStep> conf[0]).containsFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -204,7 +205,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
|
|
||||||
// If our total has reached undefined for some reason, error out now
|
// If our total has reached undefined for some reason, error out now
|
||||||
if (stepSolve.total === undefined) {
|
if (stepSolve.total === undefined) {
|
||||||
throw new Error("UndefinedStep");
|
throw new Error('UndefinedStep');
|
||||||
}
|
}
|
||||||
|
|
||||||
return stepSolve;
|
return stepSolve;
|
||||||
|
|
59
src/utils.ts
59
src/utils.ts
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
sendMessage
|
sendMessage,
|
||||||
} from "../deps.ts";
|
} from '../deps.ts';
|
||||||
|
|
||||||
// ask(prompt) returns string
|
// ask(prompt) returns string
|
||||||
// ask prompts the user at command line for message
|
// ask prompts the user at command line for message
|
||||||
|
@ -18,7 +18,7 @@ const ask = async (question: string, stdin = Deno.stdin, stdout = Deno.stdout):
|
||||||
await stdout.write(new TextEncoder().encode(question));
|
await stdout.write(new TextEncoder().encode(question));
|
||||||
|
|
||||||
// Read console's input into answer
|
// Read console's input into answer
|
||||||
const n = <number>await stdin.read(buf);
|
const n = <number> await stdin.read(buf);
|
||||||
const answer = new TextDecoder().decode(buf.subarray(0, n));
|
const answer = new TextDecoder().decode(buf.subarray(0, n));
|
||||||
|
|
||||||
return answer.trim();
|
return answer.trim();
|
||||||
|
@ -31,64 +31,55 @@ const cmdPrompt = async (logChannel: bigint, botName: string): Promise<void> =>
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
// Get a command and its args
|
// Get a command and its args
|
||||||
const fullCmd = await ask("cmd> ");
|
const fullCmd = await ask('cmd> ');
|
||||||
|
|
||||||
// Split the args off of the command and prep the command
|
// Split the args off of the command and prep the command
|
||||||
const args = fullCmd.split(" ");
|
const args = fullCmd.split(' ');
|
||||||
const command = args.shift()?.toLowerCase();
|
const command = args.shift()?.toLowerCase();
|
||||||
|
|
||||||
// All commands below here
|
// All commands below here
|
||||||
|
|
||||||
// exit or e
|
// exit or e
|
||||||
// Fully closes the bot
|
// Fully closes the bot
|
||||||
if (command === "exit" || command === "e") {
|
if (command === 'exit' || command === 'e') {
|
||||||
console.log(`${botName} Shutting down.\n\nGoodbye.`);
|
console.log(`${botName} Shutting down.\n\nGoodbye.`);
|
||||||
done = true;
|
done = true;
|
||||||
Deno.exit(0);
|
Deno.exit(0);
|
||||||
}
|
} // stop
|
||||||
|
|
||||||
// stop
|
|
||||||
// Closes the CLI only, leaving the bot running truly headless
|
// Closes the CLI only, leaving the bot running truly headless
|
||||||
else if (command === "stop") {
|
else if (command === 'stop') {
|
||||||
console.log(`Closing ${botName} CLI. Bot will continue to run.\n\nGoodbye.`);
|
console.log(`Closing ${botName} CLI. Bot will continue to run.\n\nGoodbye.`);
|
||||||
done = true;
|
done = true;
|
||||||
}
|
} // m [channel] [message]
|
||||||
|
|
||||||
// m [channel] [message]
|
|
||||||
// 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(BigInt(channelId), message).catch(reason => {
|
sendMessage(BigInt(channelId), message).catch((reason) => {
|
||||||
console.error(reason);
|
console.error(reason);
|
||||||
});
|
});
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
} // ml [message]
|
||||||
|
|
||||||
// ml [message]
|
|
||||||
// Sends a message to the specified log channel
|
// Sends a message to the specified log channel
|
||||||
else if (command === "ml") {
|
else if (command === 'ml') {
|
||||||
const message = args.join(" ");
|
const message = args.join(' ');
|
||||||
|
|
||||||
sendMessage(logChannel, message).catch(reason => {
|
sendMessage(logChannel, message).catch((reason) => {
|
||||||
console.error(reason);
|
console.error(reason);
|
||||||
});
|
});
|
||||||
}
|
} // help or h
|
||||||
|
|
||||||
// help or h
|
|
||||||
// Shows a basic help menu
|
// Shows a basic help menu
|
||||||
else if (command === "help" || command === "h") {
|
else if (command === 'help' || command === 'h') {
|
||||||
console.log(`${botName} CLI Help:\n\nAvailable Commands:\n exit - closes bot\n stop - closes the CLI\n m [ChannelID] [messgae] - sends message to specific ChannelID as the bot\n ml [message] sends a message to the specified botlog\n help - this message`);
|
console.log(
|
||||||
}
|
`${botName} CLI Help:\n\nAvailable Commands:\n exit - closes bot\n stop - closes the CLI\n m [ChannelID] [messgae] - sends message to specific ChannelID as the bot\n ml [message] sends a message to the specified botlog\n help - this message`,
|
||||||
|
);
|
||||||
// Unhandled commands die here
|
} // Unhandled commands die here
|
||||||
else {
|
else {
|
||||||
console.log("undefined command");
|
console.log('undefined command');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue