the initial stuff
This commit is contained in:
parent
e0116c565c
commit
e3b28826f4
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/out
|
||||||
|
*.sqlite
|
||||||
|
config.json
|
2775
package-lock.json
generated
Normal file
2775
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
package.json
Normal file
22
package.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "2023Collectabot",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "stupid",
|
||||||
|
"main": "out/mud.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "node ./out/mud.js"
|
||||||
|
},
|
||||||
|
"author": "Collectabot Team",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.15.11",
|
||||||
|
"@types/validator": "^13.7.14",
|
||||||
|
"typescript": "^5.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"discord.js": "^14.8.0",
|
||||||
|
"sequelize": "^6.30.0",
|
||||||
|
"sqlite3": "^5.1.6"
|
||||||
|
}
|
||||||
|
}
|
13
src/clientstrings.json
Normal file
13
src/clientstrings.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"command": {
|
||||||
|
"guildOnly": "that command doesn't work in DMs!",
|
||||||
|
"ownerOnly": "you can't use that command if you don't own this bot...",
|
||||||
|
"noPermission": "you aren't allowed to use that command!",
|
||||||
|
"noArguments": "i can't do anything without the command arguments!",
|
||||||
|
"missingArguments": "you're missing arguments!",
|
||||||
|
"invalidArgument": "`{1}` is invalid!",
|
||||||
|
"usagePrefix": "the proper usage would be: ",
|
||||||
|
"onCooldown": "you need to wait {1} more seconds before reusing the `{2}` command!"
|
||||||
|
},
|
||||||
|
"error": "there was an error, shout at hexugory and hope he hears you!"
|
||||||
|
}
|
249
src/commandclient.ts
Normal file
249
src/commandclient.ts
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
import { Client, ClientOptions, Collection, GuildChannel, GuildMember, Message } from "discord.js";
|
||||||
|
import config from "./config.json";
|
||||||
|
import strings from "./clientstrings.json";
|
||||||
|
import { Sequelize } from "sequelize";
|
||||||
|
import { CommandList } from "./commands/commandlist";
|
||||||
|
import { Command } from "./commands/command";
|
||||||
|
import { BlacklistUsers } from "./models/blacklistusers";
|
||||||
|
import { CommandBlacklist } from "./models/commandblacklist";
|
||||||
|
import { SlashCommand } from "./slash/slash";
|
||||||
|
import { SlashCommandList } from "./slash/commandlist";
|
||||||
|
|
||||||
|
export class CommandClient extends Client {
|
||||||
|
constructor (options: ClientOptions, db: Sequelize) {
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
process.on('exit', this.destroy);
|
||||||
|
|
||||||
|
process.on('SIGINT', this.destroy);
|
||||||
|
|
||||||
|
this.db = db;
|
||||||
|
|
||||||
|
for (const command of CommandList) {
|
||||||
|
this.commands.set(command.name, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const command of SlashCommandList) {
|
||||||
|
this.slashCommands.set(command.name, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.on('messageCreate', async (msg: Message) => {
|
||||||
|
if (!msg.content.startsWith(config.prefix) || msg.author.bot) return;
|
||||||
|
|
||||||
|
if (msg.author.id != config.owner && (await BlacklistUsers.findOne({ where: { user_id: msg.author.id } }))) return;
|
||||||
|
|
||||||
|
this.parseCommand(msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('ready', () => {
|
||||||
|
console.log(`Logged in as ${this.user!.tag}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('interactionCreate', async (int) => {
|
||||||
|
if (int.isCommand()) {
|
||||||
|
if (!int.channel) return;
|
||||||
|
|
||||||
|
const command = this.slashCommands.get(int.commandName);
|
||||||
|
|
||||||
|
if (!command) throw new Error('Slash command does not exist');
|
||||||
|
|
||||||
|
if (!int.guild && command.guildOnly) {
|
||||||
|
int.reply({ content: strings.command.guildOnly, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.permission && int.user.id != config.owner) {
|
||||||
|
if (!(int.channel instanceof GuildChannel)) {
|
||||||
|
int.reply({ content: strings.command.guildOnly, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const permission of command.permission) {
|
||||||
|
if (!(int.member as GuildMember).permissionsIn(int.channel).has(permission)){
|
||||||
|
int.reply({ content: strings.command.noPermission, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command.execute(int).catch(error => {
|
||||||
|
int.reply({ content: strings.error, ephemeral: true })
|
||||||
|
.catch(error => console.error(error));
|
||||||
|
return console.error(error);
|
||||||
|
});
|
||||||
|
return console.info(`${int.user.tag} (${int.user.id}) used ${command.name} in ${'name' in int.channel ? int.channel.name : 'DM CHANNEL'} (${int.channel.id})`);
|
||||||
|
}
|
||||||
|
else if (int.isAutocomplete()) {
|
||||||
|
if (!int.channel) return;
|
||||||
|
|
||||||
|
const command = this.slashCommands.get(int.commandName);
|
||||||
|
|
||||||
|
if (!command) throw new Error('Slash command does not exist');
|
||||||
|
|
||||||
|
command.autocomplete?.(int).catch(error => {
|
||||||
|
return console.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.login(config.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives an array of single or multi-word arguments
|
||||||
|
* @param msg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
static formatArgs (msg: string): string[] {
|
||||||
|
const args = msg.match(/("[^"]+")|(\S+)/g);
|
||||||
|
if (args === null) return [];
|
||||||
|
for (let [i, arg] of args.entries()) {
|
||||||
|
args[i] = arg.replace(/(^"|"$)/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
async parseCommand (msg: Message): Promise<Command | undefined> {
|
||||||
|
const args = CommandClient.formatArgs(msg.content.slice(config.prefix.length));
|
||||||
|
|
||||||
|
if (args.length < 1) return;
|
||||||
|
const commandName = args.shift()!.toLowerCase();
|
||||||
|
|
||||||
|
const command: Command | undefined = this.commands.get(commandName)
|
||||||
|
|| this.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
|
||||||
|
|
||||||
|
if (!command) {
|
||||||
|
this.nonCommandParse();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (command.ownerOnly && msg.author.id != config.owner) {
|
||||||
|
msg.reply(strings.command.ownerOnly);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.channel instanceof GuildChannel) {
|
||||||
|
if (!msg.member) throw new Error('Command sending member does not exist');
|
||||||
|
|
||||||
|
if (msg.author.id != config.owner) {
|
||||||
|
if (command.permission) {
|
||||||
|
for (const permission of command.permission) {
|
||||||
|
if (!msg.member.permissionsIn(msg.channel).has(permission)) {
|
||||||
|
msg.reply(strings.command.noPermission);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = (await CommandBlacklist.findOrCreate({ where: { user_id: msg.author.id, guild_id: msg.guild!.id } }))[0];
|
||||||
|
if (JSON.parse(member.blacklist)[command.name]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(command.guildOnly && !(msg.channel instanceof GuildChannel)) {
|
||||||
|
msg.reply(strings.command.guildOnly);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.args.length > 0 && !command.args[0].optional && args.length === 0) {
|
||||||
|
let reply = strings.command.noArguments;
|
||||||
|
|
||||||
|
if (command.usage) {
|
||||||
|
reply += `\n${strings.command.usagePrefix} \`${config.prefix}${command.name} ${command.usage}\``;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.channel.send(reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < command.args.filter(arg => {return !arg.optional}).length) {
|
||||||
|
let reply = strings.command.missingArguments;
|
||||||
|
|
||||||
|
if (command.usage) {
|
||||||
|
reply += `\n${strings.command.usagePrefix} \`${config.prefix}${command.name} ${command.usage}\``;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.channel.send(reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.cooldown && msg.author.id != config.owner) {
|
||||||
|
if (!this.cooldowns.has(command.name)) {
|
||||||
|
this.cooldowns.set(command.name, new Collection());
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const timestamps = this.cooldowns.get(command.name);
|
||||||
|
|
||||||
|
if (!timestamps) throw new Error('Command lacks cooldown collection');
|
||||||
|
|
||||||
|
if (timestamps.has(msg.author.id)) {
|
||||||
|
const expirationTime = (timestamps.get(msg.author.id) as number) + command.cooldown;
|
||||||
|
const timeLeft = (expirationTime - now) / 1000;
|
||||||
|
msg.reply(strings.command.onCooldown.replace('{1}', timeLeft.toFixed(1)).replace('{2}', command.name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamps.set(msg.author.id, now);
|
||||||
|
setTimeout(() => timestamps.delete(msg.author.id), command.cooldown);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return this.runCommand(msg, command, args);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
msg.reply(strings.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonCommandParse () {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runCommand (msg: Message, command: Command, args: string[]): Command | undefined {
|
||||||
|
if (command.args.length > 0 && !command.args[command.args.length-1].infinite) {
|
||||||
|
args[command.args.length-1] = args.slice(command.args.length-1, args.length).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedArgs: any[] = [];
|
||||||
|
for(var i = 0; i < command.args.length; i++) {
|
||||||
|
try {
|
||||||
|
if (!command.args[i].infinite) {
|
||||||
|
if (!command.args[i].type.validate(args[i], msg)) throw new Error('Argument is invalid');
|
||||||
|
parsedArgs[i] = command.args[i].type.parse(args[i], msg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const infinite = [];
|
||||||
|
for (var j = i; j < args.length; j++) {
|
||||||
|
if (!command.args[i].type.validate(args[j], msg)) throw new Error('Argument is invalid');
|
||||||
|
infinite.push(command.args[i].type.parse(args[j], msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedArgs[i] = infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.args[i].validator && !command.args[i].validator?.(args[i], msg)) throw new Error('Argument is invalid');
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
msg.reply(strings.command.invalidArgument.replace('{1}', args[i]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const keyedArgs: { [key: string]: any } = {};
|
||||||
|
for (var i = 0; i < command.args.length; i++) {
|
||||||
|
keyedArgs[command.args[i].key] = parsedArgs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info(`${msg.author.tag} (${msg.author.id}) used ${command.name} in ${'name' in msg.channel ? msg.channel.name : 'DM CHANNEL'} (${msg.channel.id})`);
|
||||||
|
command.execute(msg, keyedArgs);
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly commands = new Collection<string, Command>();
|
||||||
|
readonly slashCommands = new Collection<string, SlashCommand>();
|
||||||
|
readonly cooldowns = new Collection<string, Collection<string, number>>();
|
||||||
|
db: Sequelize
|
||||||
|
}
|
54
src/commands/blacklist.ts
Normal file
54
src/commands/blacklist.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { GuildMember, Message, PermissionFlagsBits } from "discord.js"
|
||||||
|
import { CommandClient } from "../commandclient"
|
||||||
|
import { CommandBlacklist } from "../models/commandblacklist"
|
||||||
|
import { MemberArgument } from "../types/member"
|
||||||
|
import { StringArgument } from "../types/string"
|
||||||
|
import { Command } from "./command"
|
||||||
|
|
||||||
|
interface BlacklistCommandArguments {
|
||||||
|
member: GuildMember
|
||||||
|
command: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BlacklistCommand implements Command {
|
||||||
|
name = 'blacklist'
|
||||||
|
aliases = []
|
||||||
|
description = 'Blacklist a member from a command'
|
||||||
|
usage = 'blacklist <command> <member>'
|
||||||
|
permission = [PermissionFlagsBits.ManageMessages]
|
||||||
|
guildOnly = true
|
||||||
|
ownerOnly = false
|
||||||
|
args = [
|
||||||
|
{
|
||||||
|
key: 'member',
|
||||||
|
type: MemberArgument,
|
||||||
|
infinite: false,
|
||||||
|
optional: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'command',
|
||||||
|
type: StringArgument,
|
||||||
|
infinite: false,
|
||||||
|
optional: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
async execute(msg: Message, arglist: {}) {
|
||||||
|
const args = arglist as BlacklistCommandArguments;
|
||||||
|
const { commands } = msg.client as CommandClient;
|
||||||
|
if (!commands.get(args.command)) {
|
||||||
|
return msg.reply(`there's no \`${args.command}\` command`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = (await CommandBlacklist.findOrCreate({ where: { user_id: args.member.id, guild_id: msg.guild!.id } }))[0];
|
||||||
|
|
||||||
|
const blacklist = JSON.parse(member.blacklist);
|
||||||
|
blacklist[args.command] = !blacklist[args.command];
|
||||||
|
|
||||||
|
member.set({
|
||||||
|
blacklist: JSON.stringify(blacklist)
|
||||||
|
});
|
||||||
|
await member.save();
|
||||||
|
|
||||||
|
return msg.reply(`${blacklist[args.command] ? '' : 'un'}blacklisted **${args.member.user.tag}** from \`${args.command}\``);
|
||||||
|
}
|
||||||
|
};
|
21
src/commands/command.ts
Normal file
21
src/commands/command.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Message, PermissionResolvable } from "discord.js"
|
||||||
|
import { Argument } from "../types/arg"
|
||||||
|
|
||||||
|
export interface Command {
|
||||||
|
name: string
|
||||||
|
aliases: string[]
|
||||||
|
description: string
|
||||||
|
cooldown?: number
|
||||||
|
usage: string
|
||||||
|
permission: PermissionResolvable[]
|
||||||
|
guildOnly: boolean
|
||||||
|
ownerOnly: boolean
|
||||||
|
args: {
|
||||||
|
key: string
|
||||||
|
type: Argument
|
||||||
|
validator?(arg: string | any[], msg: Message): boolean
|
||||||
|
infinite: boolean
|
||||||
|
optional: boolean
|
||||||
|
}[]
|
||||||
|
execute(msg: Message, arglist: {}): Promise<any>
|
||||||
|
}
|
13
src/commands/commandlist.ts
Normal file
13
src/commands/commandlist.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { BlacklistCommand } from "./blacklist";
|
||||||
|
import { DeploySlashCommand } from "./deployslash";
|
||||||
|
import { GlobalBlacklistCommand } from "./gblacklist";
|
||||||
|
import { KillCommand } from "./kill";
|
||||||
|
import { RandomCaseCommand } from "./randomcase";
|
||||||
|
|
||||||
|
export const CommandList = [
|
||||||
|
new GlobalBlacklistCommand(),
|
||||||
|
new BlacklistCommand(),
|
||||||
|
new RandomCaseCommand(),
|
||||||
|
new KillCommand(),
|
||||||
|
new DeploySlashCommand()
|
||||||
|
];
|
38
src/commands/deployslash.ts
Normal file
38
src/commands/deployslash.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Message } from "discord.js"
|
||||||
|
import { CommandClient } from "../commandclient"
|
||||||
|
import { Command } from "./command"
|
||||||
|
|
||||||
|
export class DeploySlashCommand implements Command{
|
||||||
|
name = 'deployslash'
|
||||||
|
aliases = []
|
||||||
|
description = 'Deploys slash commands'
|
||||||
|
usage = ''
|
||||||
|
permission = []
|
||||||
|
guildOnly = false
|
||||||
|
ownerOnly = true
|
||||||
|
args = []
|
||||||
|
|
||||||
|
async execute(msg: Message) {
|
||||||
|
const client = msg.client as CommandClient;
|
||||||
|
|
||||||
|
client.slashCommands.forEach(async (command) => {
|
||||||
|
console.log(command);
|
||||||
|
if (command.guildID) {
|
||||||
|
const data = {
|
||||||
|
name: command.name,
|
||||||
|
description: command.description,
|
||||||
|
options: command.args
|
||||||
|
}
|
||||||
|
console.log(await client.application!.commands.create(data, command.guildID));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const data = {
|
||||||
|
name: command.name,
|
||||||
|
description: command.description,
|
||||||
|
options: command.args
|
||||||
|
}
|
||||||
|
console.log(await client.application!.commands.create(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
46
src/commands/gblacklist.ts
Normal file
46
src/commands/gblacklist.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { Message, User } from "discord.js"
|
||||||
|
import { Command } from "./command"
|
||||||
|
import { UserArgument } from "../types/user"
|
||||||
|
import { BlacklistUsers } from "../models/blacklistusers"
|
||||||
|
|
||||||
|
interface GlobalBlacklistArguments {
|
||||||
|
users: User[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GlobalBlacklistCommand implements Command {
|
||||||
|
name = 'gblacklist'
|
||||||
|
aliases = []
|
||||||
|
description = 'banish to the shadow realm'
|
||||||
|
usage = 'no'
|
||||||
|
permission = []
|
||||||
|
guildOnly = false
|
||||||
|
ownerOnly = true
|
||||||
|
args = [
|
||||||
|
{
|
||||||
|
key: 'users',
|
||||||
|
type: UserArgument,
|
||||||
|
infinite: true,
|
||||||
|
optional: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
async execute(msg: Message, arglist: {}) {
|
||||||
|
const args = arglist as GlobalBlacklistArguments;
|
||||||
|
let replystr = '';
|
||||||
|
|
||||||
|
for (const user of args.users){
|
||||||
|
const row = (await BlacklistUsers.findOne({ where: { user_id: user.id } }));
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
row.destroy()
|
||||||
|
replystr += `${user.tag}: removed\n`
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await BlacklistUsers.create({ user_id: user.id });
|
||||||
|
replystr += `${user.tag}: added\n`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.reply(replystr);
|
||||||
|
}
|
||||||
|
};
|
19
src/commands/kill.ts
Normal file
19
src/commands/kill.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Message, PermissionResolvable } from "discord.js";
|
||||||
|
import { Command } from "./command";
|
||||||
|
|
||||||
|
export class KillCommand implements Command {
|
||||||
|
name = 'kill'
|
||||||
|
aliases = []
|
||||||
|
description = 'no'
|
||||||
|
usage = 'no'
|
||||||
|
permission = []
|
||||||
|
guildOnly = false
|
||||||
|
ownerOnly = true
|
||||||
|
args = []
|
||||||
|
|
||||||
|
async execute(msg: Message) {
|
||||||
|
console.info('dying');
|
||||||
|
msg.client.destroy();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
};
|
35
src/commands/randomcase.ts
Normal file
35
src/commands/randomcase.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Message } from "discord.js"
|
||||||
|
import { Command } from "./command"
|
||||||
|
import { StringArgument } from "../types/string"
|
||||||
|
|
||||||
|
interface RandomCaseArguments {
|
||||||
|
string: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RandomCaseCommand implements Command {
|
||||||
|
name = 'randomcase'
|
||||||
|
aliases = []
|
||||||
|
description = 'dOEs thIs'
|
||||||
|
usage = 'some words'
|
||||||
|
permission = []
|
||||||
|
guildOnly = false
|
||||||
|
ownerOnly = false
|
||||||
|
args = [
|
||||||
|
{
|
||||||
|
key: 'string',
|
||||||
|
type: StringArgument,
|
||||||
|
infinite: false,
|
||||||
|
optional: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
async execute(msg: Message, arglist: {}) {
|
||||||
|
const args = (arglist as RandomCaseArguments);
|
||||||
|
var strSplit = args.string.toLowerCase().split('');
|
||||||
|
for(let [i, char] of strSplit.entries()){
|
||||||
|
if (Math.random() > 0.5) strSplit[i] = char.toUpperCase();
|
||||||
|
}
|
||||||
|
msg.channel.send(strSplit.join(''));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
37
src/database.ts
Normal file
37
src/database.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { DataTypes, Sequelize } from "sequelize";
|
||||||
|
import { BlacklistUsers } from "./models/blacklistusers";
|
||||||
|
import { CommandBlacklist } from "./models/commandblacklist";
|
||||||
|
|
||||||
|
export const db = new Sequelize({
|
||||||
|
dialect: 'sqlite',
|
||||||
|
storage: './database.sqlite',
|
||||||
|
logging: false
|
||||||
|
});
|
||||||
|
|
||||||
|
BlacklistUsers.init({
|
||||||
|
user_id: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
primaryKey: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: 'BlacklistUsers',
|
||||||
|
sequelize: db
|
||||||
|
});
|
||||||
|
|
||||||
|
CommandBlacklist.init({
|
||||||
|
user_id: DataTypes.TEXT,
|
||||||
|
guild_id: DataTypes.TEXT,
|
||||||
|
blacklist: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
defaultValue: '{}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: 'CommandBlacklist',
|
||||||
|
sequelize: db
|
||||||
|
});
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await db.sync();
|
||||||
|
})();
|
5
src/models/blacklistusers.ts
Normal file
5
src/models/blacklistusers.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { InferAttributes, InferCreationAttributes, Model } from "sequelize";
|
||||||
|
|
||||||
|
export class BlacklistUsers extends Model<InferAttributes<BlacklistUsers>, InferCreationAttributes<BlacklistUsers>> {
|
||||||
|
declare readonly user_id: string
|
||||||
|
}
|
7
src/models/commandblacklist.ts
Normal file
7
src/models/commandblacklist.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { CreationOptional, InferAttributes, InferCreationAttributes, Model } from "sequelize";
|
||||||
|
|
||||||
|
export class CommandBlacklist extends Model<InferAttributes<CommandBlacklist>, InferCreationAttributes<CommandBlacklist>> {
|
||||||
|
declare user_id: string
|
||||||
|
declare guild_id: string
|
||||||
|
declare blacklist: CreationOptional<string>
|
||||||
|
}
|
0
src/mud.ts
Normal file
0
src/mud.ts
Normal file
4
src/slash/commandlist.ts
Normal file
4
src/slash/commandlist.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
export const SlashCommandList = [
|
||||||
|
//new Command()
|
||||||
|
];
|
24
src/slash/slash.ts
Normal file
24
src/slash/slash.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ApplicationCommandOptionData, AutocompleteInteraction, CommandInteraction, PermissionResolvable, CommandInteractionOption, CacheType } from "discord.js"
|
||||||
|
|
||||||
|
export interface SlashCommand {
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
cooldown?: number
|
||||||
|
permission: PermissionResolvable[]
|
||||||
|
guildID?: string
|
||||||
|
ownerOnly: boolean
|
||||||
|
guildOnly: boolean
|
||||||
|
args: ApplicationCommandOptionData[]
|
||||||
|
autocomplete?(int: AutocompleteInteraction): Promise<void>
|
||||||
|
execute(int: CommandInteraction): Promise<any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createArgumentsObject(data: readonly CommandInteractionOption<CacheType>[]) {
|
||||||
|
var a: {
|
||||||
|
[key: string]: any
|
||||||
|
} = {};
|
||||||
|
for (const arg of data) {
|
||||||
|
a[arg.name] = arg.value;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
7
src/types/arg.ts
Normal file
7
src/types/arg.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Message } from "discord.js"
|
||||||
|
|
||||||
|
export interface Argument {
|
||||||
|
name: string
|
||||||
|
validate (arg: string, msg: Message): boolean
|
||||||
|
parse (arg: string, msg: Message): any
|
||||||
|
}
|
48
src/types/duration.ts
Normal file
48
src/types/duration.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { Argument } from "./arg";
|
||||||
|
|
||||||
|
export interface Duration {
|
||||||
|
period: "minute" | "hour" | "day" | "week" | "month" | "year"
|
||||||
|
amount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
class HumanTimeArgumentClass implements Argument {
|
||||||
|
name = 'humantime'
|
||||||
|
|
||||||
|
validate (arg: string) {
|
||||||
|
return arg.match(/\d+ ?((minute|hour|day|week|month|year)|(m|h|d|w|y))/ig) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse (arg: string): Duration[] {
|
||||||
|
const timeMatches = arg.match(/\d+ ?((minute|hour|day|week|month|year)|(m|h|d|w|y))/ig);
|
||||||
|
|
||||||
|
const durations: Duration[] = [];
|
||||||
|
for (const time of timeMatches!) {
|
||||||
|
const duration = time.match(/(\d+) ?((minute|hour|day|week|month|year)|(m|h|d|w|y))/i);
|
||||||
|
switch (duration![2]) {
|
||||||
|
case 'm':
|
||||||
|
duration![2] = "minute";
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
duration![2] = "hour";
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
duration![2] = "day";
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
duration![2] = "week";
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
duration![2] = "year";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const period = duration![2] as "minute" | "hour" | "day" | "week" | "month" | "year"
|
||||||
|
durations.push({
|
||||||
|
period: period,
|
||||||
|
amount: parseInt(duration![1], 10)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return durations;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HumanTimeArgument = new HumanTimeArgumentClass();
|
32
src/types/member.ts
Normal file
32
src/types/member.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Message } from "discord.js";
|
||||||
|
import { Argument } from "./arg";
|
||||||
|
|
||||||
|
class MemberArgumentClass implements Argument {
|
||||||
|
name = 'user'
|
||||||
|
|
||||||
|
validate (arg: string, msg: Message) {
|
||||||
|
var idMatch = arg.match(/<@!?(\d+)>/);
|
||||||
|
|
||||||
|
if (!idMatch) {
|
||||||
|
return msg.guild!.members.cache.filter(member => {return member.user.username.toLowerCase().startsWith(arg.toLowerCase())}).size === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = idMatch[1];
|
||||||
|
if (!msg.client.users.resolve(id)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse (arg: string, msg: Message) {
|
||||||
|
var idMatch = arg.match(/<@!?(\d+)>/);
|
||||||
|
|
||||||
|
if (!idMatch) {
|
||||||
|
return msg.guild!.members.cache.find(member => {return member.user.username.toLowerCase().startsWith(arg.toLowerCase())});
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = idMatch[1];
|
||||||
|
return msg.guild!.members.resolve(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MemberArgument = new MemberArgumentClass();
|
15
src/types/string.ts
Normal file
15
src/types/string.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Argument } from "./arg";
|
||||||
|
|
||||||
|
class StringArgumentClass implements Argument {
|
||||||
|
name = 'string'
|
||||||
|
|
||||||
|
validate (arg: string): arg is string {
|
||||||
|
return typeof arg === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
parse (arg: string): string {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StringArgument = new StringArgumentClass();
|
32
src/types/user.ts
Normal file
32
src/types/user.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Message } from "discord.js";
|
||||||
|
import { Argument } from "./arg";
|
||||||
|
|
||||||
|
class UserArgumentClass implements Argument {
|
||||||
|
name = 'user'
|
||||||
|
|
||||||
|
validate (arg: any, msg: Message) {
|
||||||
|
var id = arg.match(/<@!?(\d+)>/);
|
||||||
|
if (id) id = id[1];
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
return msg.client.users.cache.filter(user => {return user.username.toLowerCase().startsWith(arg.toLowerCase())}).size === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msg.client.users.resolve(id)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse (arg: any, msg: Message) {
|
||||||
|
var id = arg.match(/<@!?(\d+)>/);
|
||||||
|
if (id) id = id[1];
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
return msg.client.users.cache.find(user => {return user.username.toLowerCase().startsWith(arg.toLowerCase())});
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg.client.users.resolve(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserArgument = new UserArgumentClass();
|
102
tsconfig.json
Normal file
102
tsconfig.json
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||||
|
|
||||||
|
/* Projects */
|
||||||
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
|
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||||
|
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
||||||
|
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
||||||
|
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||||
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
|
/* Language and Environment */
|
||||||
|
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||||
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||||
|
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
||||||
|
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||||
|
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
||||||
|
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
||||||
|
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||||
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||||
|
|
||||||
|
/* Modules */
|
||||||
|
"module": "commonjs", /* Specify what module code is generated. */
|
||||||
|
"rootDir": "./src", /* Specify the root folder within your source files. */
|
||||||
|
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
|
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||||
|
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
"resolveJsonModule": true, /* Enable importing .json files */
|
||||||
|
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||||
|
|
||||||
|
/* JavaScript Support */
|
||||||
|
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
|
||||||
|
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||||
|
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
||||||
|
|
||||||
|
/* Emit */
|
||||||
|
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||||
|
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||||
|
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||||
|
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||||
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
||||||
|
"outDir": "./out", /* Specify an output folder for all emitted files. */
|
||||||
|
// "removeComments": true, /* Disable emitting comments. */
|
||||||
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||||
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||||
|
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
||||||
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||||
|
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||||
|
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||||
|
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||||
|
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||||
|
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
||||||
|
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
||||||
|
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||||
|
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
||||||
|
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||||
|
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||||
|
|
||||||
|
/* Interop Constraints */
|
||||||
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||||
|
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
|
||||||
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||||
|
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||||
|
|
||||||
|
/* Type Checking */
|
||||||
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||||
|
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||||
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||||
|
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
||||||
|
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||||
|
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
||||||
|
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||||
|
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||||
|
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
||||||
|
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
||||||
|
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||||
|
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||||
|
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||||
|
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||||
|
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
||||||
|
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||||
|
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||||
|
|
||||||
|
/* Completeness */
|
||||||
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user