add flag system, new argument parser, kick blocked
This commit is contained in:
parent
e95d452e89
commit
ff4d6eda69
145
src/index.ts
145
src/index.ts
|
@ -8,18 +8,44 @@ config();
|
|||
|
||||
type Db = {
|
||||
probation: string[];
|
||||
blocked: string[];
|
||||
blocked: { [key: string]: { blocked: boolean, kick: boolean } };
|
||||
}
|
||||
|
||||
type CommandFlag = {
|
||||
name: string;
|
||||
} & (
|
||||
{
|
||||
type: 'string';
|
||||
value?: string;
|
||||
} | {
|
||||
type: 'boolean';
|
||||
value?: boolean;
|
||||
}
|
||||
);
|
||||
|
||||
const CommandFlags: CommandFlag[] = [
|
||||
{
|
||||
name: 'kick',
|
||||
type: 'boolean',
|
||||
}
|
||||
];
|
||||
|
||||
const PREFIX_WORD = '/kibbydev';
|
||||
const RE_COMMAND_ARGS = /(?<!\\)"[^(?<!\\)"\n]*"|[\S]+/g;
|
||||
const RE_COMMAND_ARG_QUOTED = /^".*(?<!\\)"$/g;
|
||||
const RE_QUOTE_BACKSLASH = /\\"/g;
|
||||
const RE_FLAG = /^--\S+(=.*)?$/g;
|
||||
const RE_FLAG_NAME = /^--[^=\s]+(=*?|$)/g;
|
||||
const DB_FILE = process.env.DB_FILE || './db.json';
|
||||
const RE_USER_MENTION = /^<@[0-9A-HJ-KM-NP-TV-Z]{26}>$/i;
|
||||
const PUBLIC_COMMANDS = ['suicide', 'status', 'help'];
|
||||
const COMMANDS = {
|
||||
'help': 'List available commands',
|
||||
'approve': 'Release users from probation',
|
||||
'unapprove': 'Send users to probation',
|
||||
'status': 'Edit the bot\'s status',
|
||||
'suicide': 'This will make you commit suicide',
|
||||
'debug': 'Debug command',
|
||||
'approve': 'Release users from probation',
|
||||
'unapprove': 'Send users to probation',
|
||||
'block': 'Troll a user',
|
||||
'unblock': 'Untroll a user',
|
||||
}
|
||||
|
@ -34,9 +60,20 @@ const client = new Client({ });
|
|||
client.loginBot(process.env.TOKEN);
|
||||
|
||||
db.read().then(() => {
|
||||
db.data ||= { probation: [], blocked: [] };
|
||||
db.data ||= { probation: [], blocked: {} };
|
||||
db.data.probation ||= [];
|
||||
db.data.blocked ||= [];
|
||||
db.data.blocked ||= {};
|
||||
|
||||
if (db.data.blocked instanceof Array) {
|
||||
console.log('Running migration: db.blocked');
|
||||
|
||||
const blocked = db.data.blocked as unknown as string[];
|
||||
db.data.blocked = {};
|
||||
for (const id of blocked) {
|
||||
db.data.blocked[id] = { blocked: true, kick: false };
|
||||
}
|
||||
}
|
||||
|
||||
db.write();
|
||||
});
|
||||
|
||||
|
@ -210,14 +247,75 @@ const setProbation = async (member: Member, probation: boolean) => {
|
|||
client.on('message', async (message) => {
|
||||
try {
|
||||
if (!message.content || typeof message.content != 'string') return;
|
||||
const args = message.content.replace(/ +/g, ' ').split(' ');
|
||||
if (args.shift()?.toLowerCase() != '/kibby') return;
|
||||
let args: string[] = Array.from(message.content.match(RE_COMMAND_ARGS) ?? []);
|
||||
if (args.shift()?.toLowerCase() != PREFIX_WORD) return;
|
||||
|
||||
// Remove quotes
|
||||
args = args.map(arg => arg.match(RE_COMMAND_ARG_QUOTED) ? arg.substring(1, arg.length - 1) : arg);
|
||||
args = args.map(arg => arg.replace(RE_QUOTE_BACKSLASH, '"'));
|
||||
|
||||
// Parse flags
|
||||
let flags = [...CommandFlags];
|
||||
for (let i = args.length - 1; i >= 0; i--) {
|
||||
const arg = args[i];
|
||||
if (arg.match(RE_FLAG)) {
|
||||
const name = arg.match(RE_FLAG_NAME)?.[0].substring(2);
|
||||
console.log('name', name)
|
||||
if (!name) continue;
|
||||
const flag = CommandFlags.find(flag => flag.name == name);
|
||||
console.log('flag', flag)
|
||||
if (!flag) continue;
|
||||
|
||||
let value: string | boolean | null = null;
|
||||
const argValue = arg.includes('=')
|
||||
? arg.substring(arg.indexOf('=') + 1) // Makes sure we only split at the first =
|
||||
: null;
|
||||
|
||||
console.log(argValue);
|
||||
|
||||
if (flag.type == 'boolean') {
|
||||
if (!argValue) value = true;
|
||||
else if (['true', 't', 'yes', 'y', '1'].includes(argValue.toLowerCase())) value = true;
|
||||
else if (['false', 'f', 'no', 'n', '0'].includes(argValue.toLowerCase())) value = false;
|
||||
else {
|
||||
await message.reply({ embeds: [
|
||||
embed(
|
||||
`The flag \`--${flag.name}\` is of type boolean, but no suitable value was provided.`,
|
||||
'Argument error',
|
||||
'ERROR',
|
||||
),
|
||||
] });
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (flag.type == 'string') {
|
||||
if (argValue == null) {
|
||||
await message.reply({ embeds: [
|
||||
embed(
|
||||
`The flag \`--${flag.name}\` is of type string, but no value was provided.`,
|
||||
'Argument error',
|
||||
'ERROR',
|
||||
),
|
||||
] });
|
||||
return;
|
||||
}
|
||||
value = argValue;
|
||||
}
|
||||
|
||||
args.splice(i, 1);
|
||||
flags = flags.map(f => f.name == flag.name ? { ...f, value: value as any } : f);
|
||||
}
|
||||
}
|
||||
|
||||
const logs = client.channels.get(process.env.LOGS!);
|
||||
const privileged = message.member?.hasPermission(message.channel?.server!, 'ManageMessages');
|
||||
|
||||
if (!privileged && db.data?.blocked.includes(message.author_id)) {
|
||||
if (!privileged && db.data?.blocked[message.author_id]?.blocked) {
|
||||
console.log('Ignoring nerd');
|
||||
if (db.data?.blocked[message.author_id]?.kick && message.member?.kickable) {
|
||||
console.log('Also kicking the nerd');
|
||||
await message.member?.kick();
|
||||
}
|
||||
try {
|
||||
await message.react('01G7PX5GVMPQD35FQE15H2T08S');
|
||||
} catch(e) { console.error(e) }
|
||||
|
@ -237,7 +335,27 @@ client.on('message', async (message) => {
|
|||
console.log('Got command: ' + args.join(' '));
|
||||
if (message.channel?.server_id != process.env.SERVER) return console.log('Command received in wrong server');
|
||||
|
||||
const getFlag = (input: string) => {
|
||||
const flag = flags.find(f => f.name == input);
|
||||
if (!flag) throw 'Tried to get unknown flag';
|
||||
return flag.value;
|
||||
}
|
||||
|
||||
switch(args.shift()?.toLowerCase()) {
|
||||
case 'debug': {
|
||||
console.log(args.map(arg => `- ${arg}`).join('\n'))
|
||||
return await message.reply({ embeds: [
|
||||
args.length
|
||||
? embed(args.map(arg => `- ${arg}`).join('\n'), 'Command arguments', 'INFO')
|
||||
: embed('No arguments', 'Command arguments', 'WARN'),
|
||||
embed(
|
||||
flags.map(flag => `- (${flag.type}) ${flag.name}=${flag.value ?? '*(unset)*'}`).join('\n'),
|
||||
'Command flags',
|
||||
'INFO'
|
||||
),
|
||||
] });
|
||||
}
|
||||
|
||||
case 'approve': {
|
||||
const users = await extractUsers(message, args);
|
||||
if (!users?.length) return console.log('No users received');
|
||||
|
@ -330,7 +448,9 @@ client.on('message', async (message) => {
|
|||
const users = await extractUsers(message, args);
|
||||
if (!users?.length) return await message.reply('User(s) not found or no users provided');
|
||||
for (const user of users) {
|
||||
if (!db.data?.blocked.includes(user._id)) db.data?.blocked.push(user._id);
|
||||
if (!db.data?.blocked[user._id]?.blocked) {
|
||||
db.data!.blocked[user._id] = { blocked: true, kick: !!getFlag('kick') }
|
||||
}
|
||||
}
|
||||
|
||||
await db.write();
|
||||
|
@ -346,7 +466,10 @@ client.on('message', async (message) => {
|
|||
const users = await extractUsers(message, args);
|
||||
if (!users?.length) return await message.reply('User(s) not found or no users provided');
|
||||
for (const user of users) {
|
||||
if (db.data?.blocked.includes(user._id)) db.data.blocked = db.data.blocked.filter(u => u != user._id);
|
||||
if (db.data?.blocked[user._id]?.blocked) {
|
||||
db.data.blocked[user._id].blocked = false;
|
||||
db.data.blocked[user._id].kick = false;
|
||||
}
|
||||
}
|
||||
|
||||
await db.write();
|
||||
|
@ -363,7 +486,7 @@ client.on('message', async (message) => {
|
|||
|
||||
return await message.reply({ embeds: [
|
||||
embed("Kibby is this server's personal maid!"),
|
||||
embed(`### Commands\n${commands.map(c => `- **/kibby ${c[0]}:** ${c[1]}`).join('\n')}`),
|
||||
embed(`### Commands\n${commands.map(c => `- **${PREFIX_WORD} ${c[0]}:** ${c[1]}`).join('\n')}`),
|
||||
] });
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue