mirror of
https://github.com/chenasraf/venom.git
synced 2026-05-17 17:28:08 +00:00
refactor: re-implement old commands
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright © 2020 Chen Asraf, John Deaves, Lance Krasniqi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -3,6 +3,15 @@ import tseslint from 'typescript-eslint'
|
||||
|
||||
export default [
|
||||
...tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended),
|
||||
{
|
||||
rules: {
|
||||
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn',
|
||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ['node_modules/', 'build/', 'dist/', 'gen/'],
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import HttpService from './core/services/http.service';
|
||||
import LoggerService from './core/services/logger.service';
|
||||
import MongoService from './core/services/mongo.service';
|
||||
|
||||
import Dependencies from './core/types/Dependencies';
|
||||
import Dependencies from '../../src/types/Dependencies';
|
||||
|
||||
import Bot from './bot/Bot';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Discord from 'discord.js';
|
||||
|
||||
import Dependencies from '../core/types/Dependencies';
|
||||
import Dependencies from '../../../src/types/Dependencies';
|
||||
|
||||
import Command from './commands/Command';
|
||||
import AddGreetingCommand from './commands/add-greeting.command';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Discord from 'discord.js';
|
||||
|
||||
import Dependencies from '../../core/types/Dependencies';
|
||||
import Dependencies from '../../../../src/types/Dependencies';
|
||||
|
||||
export default abstract class Command {
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Config from '../types/Config';
|
||||
import Environment from '../types/Environment';
|
||||
import LogLevel from '../types/LogLevel';
|
||||
import Config from '../../../../src/types/Config';
|
||||
import Environment from '../../../../src/types/Environment';
|
||||
import LogLevel from '../../../../src/types/LogLevel';
|
||||
|
||||
export default class ConfigService {
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import winston from 'winston';
|
||||
|
||||
import LogLevel from '../types/LogLevel';
|
||||
import LogLevel from '../../../../src/types/LogLevel';
|
||||
|
||||
import ConfigService from './config.service';
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import Environment from './Environment';
|
||||
import LogLevel from './LogLevel';
|
||||
|
||||
export default interface Config {
|
||||
BOT_TRIGGER: string;
|
||||
DISCORD_BOT_TOKEN: string;
|
||||
MONGODB_URI: string;
|
||||
MONGODB_DB_NAME: string;
|
||||
DATABASE_URL: string;
|
||||
NODE_ENV: Environment;
|
||||
LOG_LEVEL: LogLevel;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import ConfigService from '../services/config.service';
|
||||
import DatabaseService from '../services/database.service';
|
||||
import HttpService from '../services/http.service';
|
||||
import LoggerService from '../services/logger.service';
|
||||
import MongoService from '../services/mongo.service';
|
||||
|
||||
export default interface Dependencies {
|
||||
configService: ConfigService;
|
||||
databaseService: DatabaseService;
|
||||
httpService: HttpService;
|
||||
loggerService: LoggerService;
|
||||
mongoService: MongoService;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
type Environment = 'production' | 'development' | 'test';
|
||||
|
||||
export default Environment;
|
||||
@@ -1,3 +0,0 @@
|
||||
type LogLevel = 'error' | 'warn' | 'info' | 'verbose' | 'debug' | 'silly';
|
||||
|
||||
export default LogLevel;
|
||||
@@ -1,11 +0,0 @@
|
||||
export default interface Quote {
|
||||
author: string;
|
||||
quote: string;
|
||||
shortId: string;
|
||||
meta: {
|
||||
authorCachedName: string;
|
||||
createdBy: string;
|
||||
createdByCachedName: string;
|
||||
createdAt: Date;
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"discord.js": "^14.15.3",
|
||||
"dotenv": "^16.4.5"
|
||||
"dotenv": "^16.4.5",
|
||||
"mongodb": "^6.8.0",
|
||||
"nanoid": "^5.0.7"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"ignore": [
|
||||
|
||||
114
pnpm-lock.yaml
generated
114
pnpm-lock.yaml
generated
@@ -14,6 +14,12 @@ importers:
|
||||
dotenv:
|
||||
specifier: ^16.4.5
|
||||
version: 16.4.5
|
||||
mongodb:
|
||||
specifier: ^6.8.0
|
||||
version: 6.8.0
|
||||
nanoid:
|
||||
specifier: ^5.0.7
|
||||
version: 5.0.7
|
||||
devDependencies:
|
||||
'@eslint/js':
|
||||
specifier: ^9.8.0
|
||||
@@ -231,6 +237,9 @@ packages:
|
||||
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
|
||||
deprecated: Use @eslint/object-schema instead
|
||||
|
||||
'@mongodb-js/saslprep@1.1.8':
|
||||
resolution: {integrity: sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -258,6 +267,12 @@ packages:
|
||||
'@types/node@22.0.0':
|
||||
resolution: {integrity: sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==}
|
||||
|
||||
'@types/webidl-conversions@7.0.3':
|
||||
resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
|
||||
|
||||
'@types/whatwg-url@11.0.5':
|
||||
resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==}
|
||||
|
||||
'@types/ws@8.5.12':
|
||||
resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==}
|
||||
|
||||
@@ -375,6 +390,10 @@ packages:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
bson@6.8.0:
|
||||
resolution: {integrity: sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==}
|
||||
engines: {node: '>=16.20.1'}
|
||||
|
||||
callsites@3.1.0:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -632,6 +651,9 @@ packages:
|
||||
magic-bytes.js@1.10.0:
|
||||
resolution: {integrity: sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==}
|
||||
|
||||
memory-pager@1.5.0:
|
||||
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -647,9 +669,44 @@ packages:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
mongodb-connection-string-url@3.0.1:
|
||||
resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==}
|
||||
|
||||
mongodb@6.8.0:
|
||||
resolution: {integrity: sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==}
|
||||
engines: {node: '>=16.20.1'}
|
||||
peerDependencies:
|
||||
'@aws-sdk/credential-providers': ^3.188.0
|
||||
'@mongodb-js/zstd': ^1.1.0
|
||||
gcp-metadata: ^5.2.0
|
||||
kerberos: ^2.0.1
|
||||
mongodb-client-encryption: '>=6.0.0 <7'
|
||||
snappy: ^7.2.2
|
||||
socks: ^2.7.1
|
||||
peerDependenciesMeta:
|
||||
'@aws-sdk/credential-providers':
|
||||
optional: true
|
||||
'@mongodb-js/zstd':
|
||||
optional: true
|
||||
gcp-metadata:
|
||||
optional: true
|
||||
kerberos:
|
||||
optional: true
|
||||
mongodb-client-encryption:
|
||||
optional: true
|
||||
snappy:
|
||||
optional: true
|
||||
socks:
|
||||
optional: true
|
||||
|
||||
ms@2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
|
||||
nanoid@5.0.7:
|
||||
resolution: {integrity: sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==}
|
||||
engines: {node: ^18 || >=20}
|
||||
hasBin: true
|
||||
|
||||
natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
||||
@@ -759,6 +816,9 @@ packages:
|
||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
sparse-bitfield@3.0.3:
|
||||
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -786,6 +846,10 @@ packages:
|
||||
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
|
||||
hasBin: true
|
||||
|
||||
tr46@4.1.1:
|
||||
resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
ts-api-utils@1.3.0:
|
||||
resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
|
||||
engines: {node: '>=16'}
|
||||
@@ -839,6 +903,14 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
webidl-conversions@7.0.0:
|
||||
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
whatwg-url@13.0.0:
|
||||
resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -1022,6 +1094,10 @@ snapshots:
|
||||
|
||||
'@humanwhocodes/object-schema@2.0.3': {}
|
||||
|
||||
'@mongodb-js/saslprep@1.1.8':
|
||||
dependencies:
|
||||
sparse-bitfield: 3.0.3
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
@@ -1047,6 +1123,12 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.11.1
|
||||
|
||||
'@types/webidl-conversions@7.0.3': {}
|
||||
|
||||
'@types/whatwg-url@11.0.5':
|
||||
dependencies:
|
||||
'@types/webidl-conversions': 7.0.3
|
||||
|
||||
'@types/ws@8.5.12':
|
||||
dependencies:
|
||||
'@types/node': 22.0.0
|
||||
@@ -1181,6 +1263,8 @@ snapshots:
|
||||
dependencies:
|
||||
fill-range: 7.1.1
|
||||
|
||||
bson@6.8.0: {}
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
chalk@4.1.2:
|
||||
@@ -1497,6 +1581,8 @@ snapshots:
|
||||
|
||||
magic-bytes.js@1.10.0: {}
|
||||
|
||||
memory-pager@1.5.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
micromatch@4.0.7:
|
||||
@@ -1512,8 +1598,21 @@ snapshots:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
mongodb-connection-string-url@3.0.1:
|
||||
dependencies:
|
||||
'@types/whatwg-url': 11.0.5
|
||||
whatwg-url: 13.0.0
|
||||
|
||||
mongodb@6.8.0:
|
||||
dependencies:
|
||||
'@mongodb-js/saslprep': 1.1.8
|
||||
bson: 6.8.0
|
||||
mongodb-connection-string-url: 3.0.1
|
||||
|
||||
ms@2.1.2: {}
|
||||
|
||||
nanoid@5.0.7: {}
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
nodemon@3.1.4:
|
||||
@@ -1606,6 +1705,10 @@ snapshots:
|
||||
|
||||
slash@3.0.0: {}
|
||||
|
||||
sparse-bitfield@3.0.3:
|
||||
dependencies:
|
||||
memory-pager: 1.5.0
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
@@ -1628,6 +1731,10 @@ snapshots:
|
||||
|
||||
touch@3.1.1: {}
|
||||
|
||||
tr46@4.1.1:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
ts-api-utils@1.3.0(typescript@5.5.4):
|
||||
dependencies:
|
||||
typescript: 5.5.4
|
||||
@@ -1672,6 +1779,13 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
webidl-conversions@7.0.0: {}
|
||||
|
||||
whatwg-url@13.0.0:
|
||||
dependencies:
|
||||
tr46: 4.1.1
|
||||
webidl-conversions: 7.0.0
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
@@ -1,39 +1,42 @@
|
||||
import Discord from 'discord.js';
|
||||
import Command from './Command';
|
||||
import { command } from '@/core/commands'
|
||||
import { db } from '@/core/db'
|
||||
import { BOT_PREFIX } from '@/env'
|
||||
|
||||
export default class AddGreetingCommand extends Command {
|
||||
async execute(message: Discord.Message, args: string[]): Promise<Discord.Message> {
|
||||
export default command({
|
||||
command: 'addgreeting',
|
||||
aliases: ['ag', 'add-greeting'],
|
||||
description:
|
||||
'Adds a string to the list greetings used when new users connect to server! Include `{name}` in your message to replace with the new users name.',
|
||||
examples: [`\`${BOT_PREFIX}addgreeting Welcome to the club {name}\``],
|
||||
async execute(message, args) {
|
||||
// Only certain users can use this command
|
||||
// TODO: Better handling of permissions for commands in a generic way
|
||||
const permittedRoles = new Set(['staff', 'mod', 'bot-devs']);
|
||||
const isPermitted = message.member.roles.cache.some((r) => permittedRoles.has(r.name));
|
||||
const permittedRoles = new Set(['staff', 'mod', 'bot-devs'])
|
||||
const isPermitted = message.member?.roles.cache.some((r) => permittedRoles.has(r.name))
|
||||
|
||||
if (!isPermitted) {
|
||||
return message.author.send("Sorry but I can't let you add greetings!");
|
||||
return message.author.send("Sorry but I can't let you add greetings!")
|
||||
}
|
||||
|
||||
// Can't do much without a message
|
||||
if (args.length === 0) {
|
||||
return message.author.send('When adding a greeting you need to also provide a message!');
|
||||
return message.author.send('When adding a greeting you need to also provide a message!')
|
||||
}
|
||||
|
||||
// Check for dupes
|
||||
const greetingStr = args.join(' ');
|
||||
const matchedMessages = await this.dependencies.mongoService.find(message.author.id, 'greetings', {
|
||||
message: greetingStr,
|
||||
});
|
||||
if (matchedMessages.length > 0) {
|
||||
return message.author.send('That greeting has already been added!');
|
||||
const greetingStr = args.join(' ')
|
||||
const collection = db.collection('greetings')
|
||||
const matchedMessages = await collection.countDocuments({ message: greetingStr })
|
||||
if (matchedMessages > 0) {
|
||||
return message.author.send('That greeting has already been added!')
|
||||
}
|
||||
|
||||
const result = await this.dependencies.mongoService.insert(message.author.id, 'greetings', [
|
||||
{ message: greetingStr },
|
||||
]);
|
||||
const result = await collection.insertOne({ message: greetingStr })
|
||||
|
||||
if (!result) {
|
||||
return message.author.send("Uh-oh! Couldn't add that greeting!");
|
||||
return message.author.send("Uh-oh! Couldn't add that greeting!")
|
||||
}
|
||||
|
||||
return message.author.send("I've added the greeting you told me about!");
|
||||
}
|
||||
}
|
||||
return message.author.send("I've added the greeting you told me about!")
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
import Discord from 'discord.js';
|
||||
import Discord from 'discord.js'
|
||||
|
||||
import Character from '../../carp/character/character.entity';
|
||||
import { db } from '@/core/db'
|
||||
import { command } from '@/core/commands'
|
||||
|
||||
import Command from './Command';
|
||||
// TODO move to types file
|
||||
export interface Character {
|
||||
uid: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export default class CharacterCommand extends Command {
|
||||
export default command({
|
||||
command: 'character',
|
||||
aliases: ['c'],
|
||||
description: 'Get information about your character',
|
||||
examples: ['`!character`'],
|
||||
async execute(message: Discord.Message): Promise<Discord.Message> {
|
||||
// Just testing db stuff
|
||||
const matchedChar = await this.dependencies.databaseService.manager.findOne(Character, message.author.id);
|
||||
|
||||
const matchedChar = await db
|
||||
.collection<Character>('characters')
|
||||
.findOne({ userId: message.author.id })
|
||||
|
||||
if (!matchedChar) {
|
||||
return message.reply(`Doesn't look like you have joined this campaign`);
|
||||
return message.reply(`Doesn't look like you have joined this campaign`)
|
||||
}
|
||||
|
||||
return message.reply(`Welcome back ${matchedChar.name}`);
|
||||
}
|
||||
}
|
||||
return message.reply(`Welcome back ${matchedChar.name}`)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import Discord from 'discord.js';
|
||||
import Command from './Command';
|
||||
import { command } from '@/core/commands'
|
||||
import { BOT_PREFIX } from '@/env'
|
||||
import Discord from 'discord.js'
|
||||
|
||||
export default class EightBallCommand extends Command {
|
||||
export default command({
|
||||
command: '8ball',
|
||||
aliases: ['eightball', 'magicball', 'ball', 'wisdomball'],
|
||||
description: 'Ask the magic eightball for advice.',
|
||||
examples: [`\`${BOT_PREFIX} 8ball will I be awesome today?\``],
|
||||
async execute(message: Discord.Message, args: string[]): Promise<Discord.Message> {
|
||||
if (args.length === 0) {
|
||||
return message.reply("where's the question?");
|
||||
return message.reply("where's the question?")
|
||||
}
|
||||
|
||||
const responses = [
|
||||
@@ -32,8 +37,8 @@ export default class EightBallCommand extends Command {
|
||||
'yes.',
|
||||
'yes - definitely.',
|
||||
'yeah, you can rely on it.',
|
||||
];
|
||||
]
|
||||
|
||||
return message.reply(responses[Math.floor(Math.random() * responses.length - 1)]);
|
||||
}
|
||||
}
|
||||
return message.reply(responses[Math.floor(Math.random() * responses.length - 1)])
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
import Discord from 'discord.js';
|
||||
import Command from './Command';
|
||||
import Discord from 'discord.js'
|
||||
import { command, commands } from '@/core/commands'
|
||||
import { BOT_PREFIX } from '@/env'
|
||||
|
||||
export default class HelpCommand extends Command {
|
||||
public commandData: {
|
||||
commandList: Discord.Collection<string, Command>;
|
||||
prefix: string;
|
||||
};
|
||||
export default command({
|
||||
command: 'help',
|
||||
aliases: ['h'],
|
||||
description: 'Lists available commands and their usage.',
|
||||
examples: ['`!help`', '`!help ping`'],
|
||||
|
||||
async execute(message: Discord.Message, args: string[]): Promise<Discord.Message> {
|
||||
const data = [];
|
||||
const data = []
|
||||
|
||||
const commandList = Object.values(commands())
|
||||
if (!args || args.length === 0) {
|
||||
// Get for all commands
|
||||
data.push("here's a list of all my commands:\n");
|
||||
data.push("here's a list of all my commands:\n")
|
||||
|
||||
const cmds = this.commandData.commandList.map((c) => c.name);
|
||||
cmds.forEach((element) => {
|
||||
const cmd =
|
||||
this.commandData.commandList.get(element) ||
|
||||
this.commandData.commandList.find((c) => c.aliases && c.aliases.includes(element));
|
||||
let response = `\`${this.commandData.prefix}${cmd.name}\` `;
|
||||
for (const cmd of commandList) {
|
||||
let response = `\`${BOT_PREFIX}${cmd.command}\` `
|
||||
if (cmd.description) {
|
||||
response += `**${cmd.description}** `;
|
||||
response += `**${cmd.description}** `
|
||||
}
|
||||
if (cmd.aliases) {
|
||||
response += `\n\t\t\t*alternatively:* \`${this.commandData.prefix}${cmd.aliases.join(
|
||||
`\`, \`${this.commandData.prefix}`,
|
||||
)}\``;
|
||||
response += `\n\t\t\t*alternatively:* \`${BOT_PREFIX}${cmd.aliases.join(
|
||||
`\`, \`${BOT_PREFIX}`,
|
||||
)}\``
|
||||
}
|
||||
data.push(response);
|
||||
data.push(response)
|
||||
|
||||
cmd.examples.forEach((example) => {
|
||||
data.push(`\t\t\t*for example:* ${example}`);
|
||||
});
|
||||
data.push(`\t\t\t*for example:* ${example}`)
|
||||
})
|
||||
|
||||
data.push('\n');
|
||||
});
|
||||
data.push(`You can send \`${this.commandData.prefix}help [command name]\` to get info on a specific command!`);
|
||||
data.push('\n')
|
||||
}
|
||||
data.push(
|
||||
`You can send \`${BOT_PREFIX}help [command name]\` to get info on a specific command!`,
|
||||
)
|
||||
} else {
|
||||
// Get description of single command
|
||||
const name = args[0].toLowerCase();
|
||||
const cmd =
|
||||
this.commandData.commandList.get(name) ||
|
||||
this.commandData.commandList.find((c) => c.aliases && c.aliases.includes(name));
|
||||
const name = args[0].toLowerCase()
|
||||
const cmd = commandList.find(
|
||||
(cmd) => cmd.command === name || (cmd.aliases && cmd.aliases.includes(name)),
|
||||
)
|
||||
|
||||
if (!cmd) {
|
||||
message.reply("that's not a valid command!");
|
||||
message.reply("that's not a valid command!")
|
||||
} else {
|
||||
data.push(`**Name:** ${cmd.name}`);
|
||||
data.push(`**Name:** ${cmd.command}`)
|
||||
|
||||
if (cmd.aliases) {
|
||||
data.push(`**Aliases:** ${cmd.aliases.join(', ')}`);
|
||||
data.push(`**Aliases:** ${cmd.aliases.join(', ')}`)
|
||||
}
|
||||
|
||||
if (cmd.description) {
|
||||
data.push(`**Description:** ${cmd.description}`);
|
||||
data.push(`**Description:** ${cmd.description}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return message.reply(data, { split: true });
|
||||
return message.reply(data.join('\n'))
|
||||
} catch (error) {
|
||||
this.dependencies.loggerService.log('error', `Could not send help DM to ${message.author.tag}.\n`, error);
|
||||
console.log('error', `Could not send help DM to ${message.author.tag}.\n`, error)
|
||||
|
||||
return message.reply("it seems like I can't DM you! Do you have DMs disabled?");
|
||||
return message.reply("it seems like I can't DM you! Do you have DMs disabled?")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import Discord from 'discord.js';
|
||||
import Command from './Command';
|
||||
import Discord from 'discord.js'
|
||||
import { command } from '@/core/commands'
|
||||
|
||||
export default class PingCommand extends Command {
|
||||
export default command({
|
||||
command: 'ping',
|
||||
aliases: [],
|
||||
description: 'ping',
|
||||
examples: [],
|
||||
async execute(message: Discord.Message): Promise<Discord.Message> {
|
||||
return message.reply('Pong!');
|
||||
}
|
||||
}
|
||||
return message.reply('Pong!')
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,88 +1,117 @@
|
||||
import Discord from 'discord.js';
|
||||
import shortid from 'shortid';
|
||||
import { command } from '@/core/commands'
|
||||
import { db } from '@/core/db'
|
||||
import Discord from 'discord.js'
|
||||
import { nanoid } from 'nanoid'
|
||||
|
||||
import MongoService from '../../core/services/mongo.service';
|
||||
export interface Quote {
|
||||
author: string
|
||||
quote: string
|
||||
uid: string
|
||||
meta: {
|
||||
authorCachedName: string
|
||||
createdBy: string
|
||||
createdByCachedName: string
|
||||
createdAt: Date
|
||||
}
|
||||
}
|
||||
|
||||
import Quote from '../../core/types/Quote';
|
||||
const collection = db.collection<Quote>('quotes')
|
||||
|
||||
import Command from './Command';
|
||||
|
||||
export default class QuotesCommand extends Command {
|
||||
async execute(message: Discord.Message, args: string[]): Promise<Discord.Message> {
|
||||
export default command({
|
||||
command: 'quote',
|
||||
aliases: ['quotes', 'q'],
|
||||
description: 'Manage quotes',
|
||||
examples: [
|
||||
'`!quote` - Get a random quote',
|
||||
'`!quote search <query>` - Search for a quote',
|
||||
'`!quote add <quote>` - Add a new quote',
|
||||
'`!quote <id>` - Get a specific quote',
|
||||
],
|
||||
async execute(message, args) {
|
||||
// Get random quote
|
||||
if (args.filter((s) => s.trim().length).length === 0) {
|
||||
getRandomQuote(message, args, this.dependencies.mongoService);
|
||||
return;
|
||||
getRandomQuote(message, args)
|
||||
return
|
||||
}
|
||||
|
||||
const first = args[0].trim().toLowerCase();
|
||||
const first = args[0].trim().toLowerCase()
|
||||
|
||||
switch (first) {
|
||||
// Search quotes
|
||||
case 'search':
|
||||
searchQuotes(message, args.slice(1), this.dependencies.mongoService);
|
||||
return;
|
||||
searchQuotes(message, args.slice(1))
|
||||
return
|
||||
|
||||
// Add quote
|
||||
case 'add':
|
||||
default:
|
||||
if (first.startsWith('#')) {
|
||||
getSingleQuote(message, args, this.dependencies.mongoService);
|
||||
getSingleQuote(message, args)
|
||||
} else {
|
||||
addNewQuote(message, args.slice(first === 'add' ? 1 : 0), this.dependencies.mongoService);
|
||||
addNewQuote(message, args.slice(first === 'add' ? 1 : 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const clean = (str: string): string => str.replace(/[\t\n|]+/g, ' ').replace(/\s+/g, ' ');
|
||||
const getQuoteStr = ({ author, quote, shortId }: Quote): string => `"${quote}" - ${author} (#${shortId})`;
|
||||
const clean = (str: string): string => str.replace(/[\t\n|]+/g, ' ').replace(/\s+/g, ' ')
|
||||
const getQuoteStr = ({ author, quote, uid }: Quote): string => `"${quote}" - ${author} (#${uid})`
|
||||
|
||||
async function getRandomQuote(message: Discord.Message, args: string[], mongoService: MongoService): Promise<void> {
|
||||
const count = await mongoService.count(message.author.id, 'quotes', {});
|
||||
const r = Math.floor(Math.random() * count);
|
||||
const q = await mongoService.dbInstance.collection('quotes').find().skip(r).limit(1).toArray();
|
||||
async function getRandomQuote(message: Discord.Message, _args: string[]): Promise<void> {
|
||||
const count = await collection.countDocuments()
|
||||
const r = Math.floor(Math.random() * count)
|
||||
const q = await collection.find().skip(r).limit(1).toArray()
|
||||
|
||||
if (q.length > 0) {
|
||||
const quote: Quote = q[0];
|
||||
message.reply(getQuoteStr(quote));
|
||||
const quote: Quote = q[0]
|
||||
message.reply(getQuoteStr(quote))
|
||||
} else {
|
||||
message.reply("This is where I would usually put a quote. I can't remember any, for some reason...");
|
||||
message.reply(
|
||||
"This is where I would usually put a quote. I can't remember any, for some reason...",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function searchQuotes(message: Discord.Message, args: string[], mongoService: MongoService): Promise<void> {
|
||||
const q = await mongoService.find<Quote>(message.author.id, 'quotes', {
|
||||
quote: {
|
||||
$regex: `${args.join(' ')}`,
|
||||
$options: 'i',
|
||||
},
|
||||
});
|
||||
async function searchQuotes(message: Discord.Message, args: string[]): Promise<void> {
|
||||
const q = await collection
|
||||
.find<Quote>({
|
||||
quote: {
|
||||
$regex: `${args.join(' ')}`,
|
||||
$options: 'i',
|
||||
},
|
||||
})
|
||||
.toArray()
|
||||
|
||||
if (q.length > 0) {
|
||||
let responseTxt = '';
|
||||
let responseTxt = ''
|
||||
q.forEach((quote) => {
|
||||
responseTxt += `\n${getQuoteStr(quote)}`;
|
||||
});
|
||||
message.reply("Found a few, I'll DM you what I got!");
|
||||
message.author.send(`Found ${q.length} quote${q.length !== 1 ? 's' : ''}:\n${responseTxt}`);
|
||||
responseTxt += `\n${getQuoteStr(quote)}`
|
||||
})
|
||||
message.reply("Found a few, I'll DM you what I got!")
|
||||
message.author.send(`Found ${q.length} quote${q.length !== 1 ? 's' : ''}:\n${responseTxt}`)
|
||||
} else {
|
||||
message.reply("Sorry, didn't find anything that matches that.");
|
||||
message.reply("Sorry, didn't find anything that matches that.")
|
||||
}
|
||||
}
|
||||
|
||||
async function addNewQuote(message: Discord.Message, args: string[], mongoService: MongoService): Promise<void> {
|
||||
const [authorRaw, ...restRaw] = args;
|
||||
const hasAuthor = /<@!\d+>/.test(authorRaw) || authorRaw.startsWith('@');
|
||||
const author = hasAuthor ? (authorRaw.startsWith('@') ? authorRaw.slice(1) : authorRaw) : 'Anonymous';
|
||||
async function addNewQuote(message: Discord.Message, args: string[]): Promise<void> {
|
||||
const [authorRaw, ...restRaw] = args
|
||||
const hasAuthor = /<@!\d+>/.test(authorRaw) || authorRaw.startsWith('@')
|
||||
const author = hasAuthor
|
||||
? authorRaw.startsWith('@')
|
||||
? authorRaw.slice(1)
|
||||
: authorRaw
|
||||
: 'Anonymous'
|
||||
|
||||
const differentAuthor = hasAuthor && author !== `<@!${message.author.id}>`;
|
||||
const differentAuthor = hasAuthor && author !== `<@!${message.author.id}>`
|
||||
const authorName = differentAuthor
|
||||
? authorRaw.startsWith('@')
|
||||
? authorRaw.slice(1)
|
||||
: message.mentions.guild.members.cache.find((u) => u.user.id === message.mentions.users.first().id)?.displayName
|
||||
: message.member.displayName;
|
||||
const quote = (hasAuthor ? restRaw : [authorRaw, ...restRaw]).join(' ');
|
||||
: message.mentions.guild!.members.cache.find(
|
||||
(u) => u.user.id === message.mentions.users.first()!.id,
|
||||
)?.displayName
|
||||
: message.member!.displayName
|
||||
const quote = (hasAuthor ? restRaw : [authorRaw, ...restRaw]).join(' ')
|
||||
|
||||
const replies = [
|
||||
`wow! How inspiring. I'll forever remember this${differentAuthor ? `, ${author}` : ''}.`,
|
||||
@@ -105,33 +134,33 @@ async function addNewQuote(message: Discord.Message, args: string[], mongoServic
|
||||
} and I will refer to this moment precisely.`),
|
||||
clean(`you're not serious. Are you serious? You can't be serious. It's impossible there's **this** good a quote just floating around
|
||||
out there. It's probably fictional. Yeah.`),
|
||||
];
|
||||
]
|
||||
|
||||
const quoteObj: Quote = {
|
||||
quote,
|
||||
author,
|
||||
shortId: shortid.generate(),
|
||||
uid: nanoid(),
|
||||
meta: {
|
||||
authorCachedName: authorName,
|
||||
authorCachedName: authorName!,
|
||||
createdAt: new Date(),
|
||||
createdBy: message.author.id,
|
||||
createdByCachedName: message.member.displayName,
|
||||
createdByCachedName: message.member!.displayName,
|
||||
},
|
||||
};
|
||||
|
||||
const quoteStr = getQuoteStr(quoteObj);
|
||||
mongoService.insert(message.author.id, 'quotes', [quoteObj]);
|
||||
message.reply(`${replies[Math.floor(Math.random() * replies.length)]}\n${quoteStr}`);
|
||||
}
|
||||
|
||||
async function getSingleQuote(message: Discord.Message, args: string[], mongoService: MongoService): Promise<void> {
|
||||
const id = args[0].slice(1);
|
||||
const quote = await mongoService.findOne<Quote>(message.author.id, 'quotes', { shortId: id });
|
||||
|
||||
if (!quote) {
|
||||
message.reply("I'm sorry, I couldn't find a quote with that id!");
|
||||
return;
|
||||
}
|
||||
|
||||
message.reply(getQuoteStr(quote));
|
||||
const quoteStr = getQuoteStr(quoteObj)
|
||||
collection.insertOne(quoteObj)
|
||||
message.reply(`${replies[Math.floor(Math.random() * replies.length)]}\n${quoteStr}`)
|
||||
}
|
||||
|
||||
async function getSingleQuote(message: Discord.Message, args: string[]): Promise<void> {
|
||||
const id = args[0].slice(1)
|
||||
const quote = await collection.findOne({ uid: id })
|
||||
|
||||
if (!quote) {
|
||||
message.reply("I'm sorry, I couldn't find a quote with that id!")
|
||||
return
|
||||
}
|
||||
|
||||
message.reply(getQuoteStr(quote))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import Discord from 'discord.js';
|
||||
import Command from './Command';
|
||||
import { command } from '@/core/commands'
|
||||
import Discord from 'discord.js'
|
||||
|
||||
export default class SeeCommand extends Command {
|
||||
export default command({
|
||||
command: 'see',
|
||||
aliases: ['s'],
|
||||
description: 'See your username and ID',
|
||||
examples: ['`!s`'],
|
||||
async execute(message: Discord.Message): Promise<Discord.Message> {
|
||||
return message.author.send(
|
||||
`Server: ${message.guild.name}\nYour username: ${message.author.username}\nYour ID: ${message.author.id}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
`Server: ${message.guild!.name}\nYour username: ${message.author.username}\nYour ID: ${message.author.id}`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -7,7 +7,8 @@ export interface Command {
|
||||
command: string
|
||||
aliases: string[]
|
||||
description: string
|
||||
execute(message: Message, args: string[]): void
|
||||
examples: string[]
|
||||
execute(_message: Message, _args: string[]): void
|
||||
}
|
||||
|
||||
let _commands: Record<string, Command> = {}
|
||||
@@ -50,3 +51,11 @@ export function parseCommand(message: string): Command | null {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function command(conf: Command): Command {
|
||||
return conf
|
||||
}
|
||||
|
||||
export function commands(): Record<string, Command> {
|
||||
return _commands
|
||||
}
|
||||
|
||||
5
src/core/db.ts
Normal file
5
src/core/db.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { MONGODB_URI } from '@/env'
|
||||
import { MongoClient } from 'mongodb'
|
||||
|
||||
const client = new MongoClient(MONGODB_URI)
|
||||
export const db = client.db()
|
||||
@@ -8,8 +8,10 @@ if (env === 'development') {
|
||||
}
|
||||
dotenv.config({ path: path.resolve(process.cwd(), '.env') })
|
||||
|
||||
export const BOT_TRIGGERS = process.env.BOT_TRIGGERS!.split("|")
|
||||
export const BOT_TRIGGERS = process.env.BOT_TRIGGERS!.split('|')
|
||||
export const BOT_PREFIX = BOT_TRIGGERS[0]
|
||||
export const DISCORD_APP_ID = process.env.DISCORD_APP_ID!
|
||||
export const DISCORD_PUBLIC_KEY = process.env.DISCORD_PUBLIC_KEY!
|
||||
export const DISCORD_TOKEN = process.env.DISCORD_TOKEN!
|
||||
export const LOG_LEVEL = process.env.LOG_LEVEL!
|
||||
export const MONGODB_URI = process.env.MONGODB_URI!
|
||||
|
||||
Reference in New Issue
Block a user