This commit is contained in:
JandereDev 2021-10-09 22:20:06 +02:00
parent e23e128850
commit 3e1da96360
Signed by: Lea
GPG key ID: 5D5E18ACB990F57A
10 changed files with 182 additions and 8 deletions

14
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"command": "yarn dev",
"name": "Debug",
"request": "launch",
"type": "node-terminal"
}
]
}

17
src/bot/commands/debug.ts Normal file
View file

@ -0,0 +1,17 @@
import Command from "../../struct/Command";
import { Message } from "revolt.js/dist/maps/Messages";
import { hasPerm } from "../util";
export default {
name: 'debug',
aliases: null,
description: 'give info helpful for development and debugging',
serverOnly: false,
run: (message: Message, args: string[]) => {
message.reply(`Server ID: ${message.channel?.server_id || 'None'}\n`
+ `Channel ID: ${message.channel_id}\n`
+ `User ID: ${message.author_id}`);
console.log(hasPerm(message.member!, 'BanMembers'));
}
} as Command;

20
src/bot/commands/ping.ts Normal file
View file

@ -0,0 +1,20 @@
import Command from "../../struct/Command";
import { Message } from "revolt.js/dist/maps/Messages";
import { client } from "../..";
export default {
name: 'ping',
aliases: null,
description: 'ping pong',
serverOnly: false,
run: async (message: Message, args: string[]) => {
let now = Date.now();
message.reply(`Measuring...`)
?.catch(console.error)
.then(msg => {
msg?.edit({ content: `## Ping Pong!\n`
+ `WS: \`${client.websocket.ping ?? '--'}ms\`\n`
+ `Msg: \`${Math.round(Date.now() - now) / 2}ms\`` });
});
}
} as Command;

View file

@ -0,0 +1,74 @@
import Command from "../../struct/Command";
import { Message } from "revolt.js/dist/maps/Messages";
import { client } from "../..";
import ServerConfig from "../../struct/ServerConfig";
import { DEFAULT_PREFIX } from "../modules/command_handler";
import { hasPerm } from "../util";
const SYNTAX = '/prefix set [new prefix]; /prefix get; prefix clear';
const MENTION_TEXT = 'You can also @mention me instead of using the prefix.';
export default {
name: 'prefix',
aliases: null,
description: 'modify prefix',
syntax: SYNTAX,
serverOnly: true,
run: async (message: Message, args: string[]) => {
let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.channel?.server_id })) ?? {};
switch(args[0]?.toLowerCase()) {
case 'set':
if (!hasPerm(message.member!, 'ManageServer')) return message.reply('You need ManageServer permission for this.');
args.shift();
if (args.length == 0) return message.reply('You need to specify a prefix.');
let newPrefix = args.join(' ').trim();
let oldPrefix = config.prefix ?? DEFAULT_PREFIX;
let val = validatePrefix(newPrefix);
if (typeof val != 'boolean') {
return message.reply(val);
}
await client.db.get('servers').update({ 'id': message.channel?.server_id }, { $set: { 'prefix': newPrefix } });
message.reply(`✅ Prefix has been changed from \`${oldPrefix}\` to \`${newPrefix}\`.\n${MENTION_TEXT}`);
break;
case 'get':
case undefined:
if (config.prefix) message.reply(`This server's prefix is \`${config.prefix}\`.\n${MENTION_TEXT}`);
else message.reply(`This server uses the default prefix \`${DEFAULT_PREFIX}\`.\n${MENTION_TEXT}`);
break;
case 'clear':
case 'reset':
if (!hasPerm(message.member!, 'ManageServer')) return message.reply('You need ManageServer permission for this.');
if (config.prefix != null) {
await client.db.get('servers').update({ 'id': message.channel?.server_id }, { $set: { 'prefix': null } });
}
message.reply(`✅ Prefix has been reset to the default: \`${DEFAULT_PREFIX}\`.`);
break;
default:
message.reply(`Unknown action. Correct syntax: \`${SYNTAX}\``);
}
}
} as Command;
function validatePrefix(prefix: string): string|true {
// Check length
if (prefix.length > 32) return 'Prefix may not be longer than 32 characters';
// Check for forbidden characters
let matched = [];
for (const char of ['`', '\n', '#']) {
if (prefix.indexOf(char) > -1) matched.push(char);
}
if (matched.length > 0) return `Prefix may not contain the following characters: `
+ `${matched.map(char => char).join(', ')
.replace(new RegExp('\n', 'g'), '\\n')}`;
return true;
}

View file

@ -1,5 +1,4 @@
import Command from "../../struct/Command";
import { client } from "../..";
import { Message } from "revolt.js/dist/maps/Messages";
export default {
@ -10,4 +9,4 @@ export default {
run: (message: Message, args: string[]) => {
message.reply('I am here');
}
} as Command;
} as Command;

View file

@ -20,9 +20,9 @@ function getDBUrl() {
// mongodb://username:password@hostname:port/dbname
let dburl = 'mongodb://';
dburl += env['DB_USERNAME'] ?? 'root';
if (env['DB_PASSWORD']) dburl += `:${env['DB_PASSWORD']}`;
dburl += `@${env['DB_HOST']}`; // DB_HOST is assumed to contain the port
if (env['DB_USERNAME']) dburl += env['DB_USERNAME'];
if (env['DB_PASS']) dburl += `:${env['DB_PASS']}`;
dburl += `${process.env['DB_USERNAME'] ? '@' : ''}${env['DB_HOST']}`; // DB_HOST is assumed to contain the port
dburl += `/${env['DB_NAME'] ?? 'automod'}`;
return dburl;

View file

@ -3,6 +3,7 @@ import logger from "../logger";
import { client } from "../../index";
import fs from 'fs';
import path from 'path';
import ServerConfig from "../../struct/ServerConfig";
const DEFAULT_PREFIX = process.env['PREFIX'] ?? '/';
@ -12,17 +13,29 @@ let commands: Command[] = fs.readdirSync(path.join(__dirname, '..', 'commands'))
client.on('message', async message => {
logger.debug(`Message -> ${message.content}`);
if (typeof message.content != 'string') return; // Ignore system messages
if (typeof message.content != 'string' || message.author_id == client.user?._id || !message.channel) return;
if (!message.content.startsWith(DEFAULT_PREFIX)) return;
let config: ServerConfig = (await client.db.get('servers').findOne({ 'id': message.channel?.server_id })) ?? {};
let guildPrefix = config.prefix ?? DEFAULT_PREFIX;
let args = message.content.split(' ');
let cmdName = args.shift()?.substr(DEFAULT_PREFIX.length);
let cmdName = args.shift() ?? '';
if (cmdName.startsWith(`<@${client.user?._id}>`)) {
cmdName = cmdName.substr(`<@${client.user?._id}>`.length);
if (!cmdName) cmdName = args.shift() ?? ''; // Space between mention and command name
} else if (cmdName.startsWith(guildPrefix)) {
cmdName = cmdName.substr(guildPrefix.length);
if (config.spaceAfterPrefix && !cmdName) cmdName = args.shift() ?? '';
}
if (!cmdName) return;
let cmd = commands.find(c => c.name == cmdName || (c.aliases?.indexOf(cmdName!) ?? -1) > -1);
if (!cmd) return;
logger.info(`Command: ${message.author?.username} in ${message.channel?.server?.name}: ${message.content}`);
if (cmd.serverOnly && !message.channel?.server) {
return message.reply('This command is not available in direct messages.');
}
@ -33,3 +46,5 @@ client.on('message', async message => {
message.reply(`### An error has occurred:\n\`\`\`js\n${e}\n\`\`\``);
}
});
export { DEFAULT_PREFIX }

27
src/bot/util.ts Normal file
View file

@ -0,0 +1,27 @@
import { Member } from "revolt.js/dist/maps/Members";
let ServerPermissions = {
['View' as string]: 1 << 0,
['ManageRoles' as string]: 1 << 1,
['ManageChannels' as string]: 1 << 2,
['ManageServer' as string]: 1 << 3,
['KickMembers' as string]: 1 << 4,
['BanMembers' as string]: 1 << 5,
['ChangeNickname' as string]: 1 << 12,
['ManageNicknames' as string]: 1 << 13,
['ChangeAvatar' as string]: 1 << 14,
['RemoveAvatars' as string]: 1 << 15,
}
function hasPerm(member: Member, perm: 'View'|'ManageRoles'|'ManageChannels'|'ManageServer'| // its late and im tired
'KickMembers'|'BanMembers'|'ChangeNickname'| // dont judge my code
'ManageNicknames'|'ChangeAvatar'|'RemoveAvatars') {
let p = ServerPermissions[perm];
if (member.server?.owner == member.user?._id) return true;
// TODO how the fuck do bitfields work
return false;
}
export { hasPerm }

View file

@ -2,6 +2,7 @@ class Command {
name: string;
aliases: string[] | null;
description: string | null;
syntax?: string | null;
run: Function;
serverOnly: boolean;
}

View file

@ -0,0 +1,7 @@
class ServerConfig {
id: string | undefined;
prefix: string | undefined;
spaceAfterPrefix: boolean | undefined;
}
export default ServerConfig;