pin functionality
This commit is contained in:
parent
b399aab2da
commit
047083d126
6 changed files with 307 additions and 44 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
config.json
|
||||
extset/
|
||||
|
||||
# ---> Node
|
||||
# Logs
|
||||
|
|
65
bot.js
65
bot.js
|
@ -14,6 +14,11 @@ if (!fs.existsSync('./whitelist.json')) {
|
|||
}
|
||||
|
||||
const whitelist = require('./whitelist.json');
|
||||
|
||||
if (!fs.existsSync('./extset')) {
|
||||
fs.mkdirSync('./extset');
|
||||
}
|
||||
|
||||
const dir = dirname(import.meta.url);
|
||||
|
||||
const bot = new Eris(cfg.token);
|
||||
|
@ -25,6 +30,45 @@ global.ctx = {
|
|||
global.ctx[key] = value;
|
||||
},
|
||||
};
|
||||
|
||||
let extension_settings = {};
|
||||
|
||||
const loadSettings = (guild) => {
|
||||
extension_settings[guild] = {};
|
||||
if (!fs.existsSync(`./extset/${guild}.json`)) {
|
||||
fs.writeFileSync(`./extset/${guild}.json`, '{}');
|
||||
}
|
||||
let settings = require(`./extset/${guild}.json`);
|
||||
if (settings != undefined) {
|
||||
extension_settings[guild] = settings;
|
||||
}
|
||||
};
|
||||
const saveSettings = (guild) => {
|
||||
let data = JSON.stringify(extension_settings[guild]);
|
||||
fs.writeFileSync(`./extset/${guild}.json`, data);
|
||||
};
|
||||
|
||||
global.ctx.settings = {};
|
||||
global.ctx.settings.getSetting = (guild, extensionId, key) => {
|
||||
if (!extension_settings[guild]) {
|
||||
loadSettings(guild);
|
||||
}
|
||||
if (!extension_settings[guild][extensionId]) {
|
||||
extension_settings[guild][extensionId] = {};
|
||||
}
|
||||
return extension_settings[guild][extensionId][key];
|
||||
};
|
||||
global.ctx.settings.setSetting = (guild, extensionId, key, value) => {
|
||||
if (!extension_settings[guild]) {
|
||||
loadSettings(guild);
|
||||
}
|
||||
if (!extension_settings[guild][extensionId]) {
|
||||
extension_settings[guild][extensionId] = {};
|
||||
}
|
||||
extension_settings[guild][extensionId][key] = value;
|
||||
saveSettings(guild);
|
||||
};
|
||||
|
||||
const log = new Logger(filename(import.meta.url), global.ctx.log_level);
|
||||
const parse = new CommandParser(global.ctx, cfg.prefix || undefined);
|
||||
|
||||
|
@ -55,7 +99,7 @@ global.ctx.whitelist = {
|
|||
wl: whitelist,
|
||||
};
|
||||
|
||||
const listeners = {}
|
||||
const listeners = {};
|
||||
|
||||
bot.on('ready', () => {
|
||||
log.info('ready recieved.');
|
||||
|
@ -64,7 +108,7 @@ bot.on('ready', () => {
|
|||
|
||||
bot.on('messageCreate', (msg) => parse.parseMsg(msg, global.ctx));
|
||||
|
||||
bot.on('error', (err) => log.error(err.toString()));
|
||||
bot.on('error', (err) => log.error(err.stack));
|
||||
|
||||
bot.connect();
|
||||
|
||||
|
@ -83,6 +127,7 @@ async function load_commands() {
|
|||
if (obj.default.constructor.name == 'CommandInitializer') {
|
||||
obj.default.initialize(global.ctx);
|
||||
let cmds = obj.default.getCommands();
|
||||
let aliases = obj.default.getAliases();
|
||||
if (parse.isCmd(cmds)) {
|
||||
parse.addCommand(cmds);
|
||||
} else if (cmds.constructor.name == 'Array') {
|
||||
|
@ -90,13 +135,25 @@ async function load_commands() {
|
|||
parse.addCommand(cmd);
|
||||
}
|
||||
}
|
||||
if (aliases != undefined) {
|
||||
parse.addAliases(aliases);
|
||||
}
|
||||
let events = obj.default.getEvents();
|
||||
if (events != undefined) {
|
||||
for (let event in events) {
|
||||
if (!listeners[event]) {
|
||||
listeners[event] = []
|
||||
listeners[event] = [];
|
||||
}
|
||||
listeners[event].push(events[event])
|
||||
log.trace(events[event]);
|
||||
listeners[event] = listeners[event].concat(events[event]);
|
||||
log.debug(`added ${events[event].length} events for ${event} from ${file}`);
|
||||
bot.on(event, (...args) => {
|
||||
for (let handler of listeners[event]) {
|
||||
log.trace(event);
|
||||
log.trace(handler);
|
||||
handler.func(global.ctx, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
124
cmd/pin.js
Normal file
124
cmd/pin.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
import { CommandInitializer, Command, Event } from '../parser.js';
|
||||
import Logger, { levels } from '../logger.js';
|
||||
import { filename } from '../utils.js';
|
||||
|
||||
const initializer = new CommandInitializer();
|
||||
const log = new Logger(filename(import.meta.url), global.ctx.log_level);
|
||||
|
||||
let activePins = {};
|
||||
|
||||
let defaultSettings = { threshold: 3, emoji: '📌' };
|
||||
|
||||
class PinEvent extends Event {
|
||||
event = 'messageReactionAdd';
|
||||
async func(ctx, args) {
|
||||
const msg = args[0];
|
||||
const fullMsg = await ctx.bot.getMessage(msg.channel.id, msg.id);
|
||||
const reaction = args[1];
|
||||
const reactor = args[2];
|
||||
log.trace(msg);
|
||||
log.trace(reaction);
|
||||
log.trace(reactor);
|
||||
let threshold = ctx.settings.getSetting(msg.channel.guild.id, 'pin', 'threshold');
|
||||
if (threshold == undefined) {
|
||||
threshold = defaultSettings.threshold;
|
||||
ctx.settings.setSetting(msg.channel.guild.id, 'pin', 'threshold', threshold);
|
||||
}
|
||||
let emoji = ctx.settings.getSetting(msg.channel.guild.id, 'pin', 'emoji');
|
||||
if (emoji == undefined) {
|
||||
emoji = defaultSettings.emoji;
|
||||
ctx.settings.setSetting(msg.channel.guild.id, 'pin', 'emoji', emoji);
|
||||
}
|
||||
if (reaction.name === emoji) {
|
||||
const fullReaction = await ctx.bot.getMessageReaction(msg.channel.id, msg.id, emoji);
|
||||
log.debug('reaction matched');
|
||||
log.trace(fullReaction);
|
||||
if (fullReaction.length >= threshold) {
|
||||
if (fullMsg.author.bot || fullReaction.filter((reaction) => reaction.id == fullMsg.author.id).length > 0) {
|
||||
if (activePins[fullMsg.id]) {
|
||||
activePins[fullMsg.id].delete();
|
||||
}
|
||||
fullMsg.pin().catch(async (err) => {
|
||||
let sn = await fullMsg.channel.createMessage('could not pin the message: ' + err.toString());
|
||||
if (err.toString().includes('Missing Permissions')) {
|
||||
sn.edit(
|
||||
'could not pin the message: ' +
|
||||
err.toString() +
|
||||
'\n(requires the manage messages or pin messages permission)'
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let text = '';
|
||||
text += fullMsg.author.mention + ', ';
|
||||
if (fullReaction.length == 1) {
|
||||
text += fullReaction[0].username + ' wants ';
|
||||
} else {
|
||||
for (let i = 0; i < fullReaction.length; i++) {
|
||||
text += (i == fullReaction.length - 1) ? 'and ' + fullReaction[i].username : fullReaction[i].username + ', ';
|
||||
}
|
||||
text += ' want ';
|
||||
}
|
||||
text += 'to pin your message. react with ' + emoji + ' to pin it.';
|
||||
let message = await fullMsg.channel.createMessage(text);
|
||||
activePins[fullMsg.id] = message;
|
||||
}
|
||||
}
|
||||
} else if (emoji.contains(reaction.name) && reaction.emoji(reaction.id)) {
|
||||
// good luck
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializer.addEvent(new PinEvent());
|
||||
|
||||
function settingsSubcommand(msg, args, ctx) {
|
||||
if (args[1] == undefined) {
|
||||
msg.channel.createMessage('not enough arguments given');
|
||||
return;
|
||||
}
|
||||
if (defaultSettings[args[1].trim()] == undefined) {
|
||||
msg.channel.createMessage(
|
||||
args[1] +
|
||||
' is not a valid setting.\navailable settings are:\n```\n' +
|
||||
Object.keys(defaultSettings).join('\n') +
|
||||
'\n```'
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (args[2] == undefined) {
|
||||
let setting = ctx.settings.getSetting(msg.channel.guild.id, 'pin', args[1]);
|
||||
if (setting == undefined) {
|
||||
setting = defaultSettings[args[1]];
|
||||
ctx.settings.setSetting(msg.channel.guild.id, 'pin', args[1], defaultSettings[args[1]]);
|
||||
}
|
||||
msg.channel.createMessage(args[1] + ' is currently set to ' + setting);
|
||||
} else {
|
||||
ctx.settings.setSetting(msg.channel.guild.id, 'pin', args[1], args[2]);
|
||||
msg.channel.createMessage('set the value of ' + args[1] + ' to ' + args[2]);
|
||||
}
|
||||
}
|
||||
|
||||
class PinCommand extends Command {
|
||||
name = 'pin';
|
||||
perms = 32;
|
||||
description = 'manage the pin module';
|
||||
helptext = '';
|
||||
func(msg, args, ctx) {
|
||||
switch (args[0]) {
|
||||
case 'settings':
|
||||
case 'setting':
|
||||
settingsSubcommand(msg, args, ctx);
|
||||
break;
|
||||
case undefined:
|
||||
msg.channel.createMessage('no arguments given');
|
||||
break;
|
||||
default:
|
||||
msg.channel.createMessage('unknown argument ' + args[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializer.addCommand(new PinCommand());
|
||||
|
||||
export default initializer;
|
30
cmd/reg.js
30
cmd/reg.js
|
@ -7,12 +7,13 @@ const log = new Logger(filename(import.meta.url), global.ctx.log_level);
|
|||
|
||||
class PingCommand extends Command {
|
||||
name = 'ping';
|
||||
aliases = ['p'];
|
||||
func(msg, args, ctx) {
|
||||
msg.channel.createMessage('p').then((m) => {
|
||||
m.edit(
|
||||
`rtt: ${Math.floor(m.timestamp - msg.timestamp)}, gateway: ${
|
||||
`rtt: ${Math.floor(m.timestamp - msg.timestamp)}ms, gateway: ${
|
||||
ctx.bot.shards.get(ctx.bot.guildShardMap[ctx.bot.channelGuildMap[msg.channel.id]] || 0).latency
|
||||
}`
|
||||
}ms`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -36,17 +37,30 @@ class EvalCommand extends Command {
|
|||
whitelist = true;
|
||||
func(msg, args, ctx) {
|
||||
log.debug('evaluating ' + args[0]);
|
||||
let result = eval(args[0]);
|
||||
log.debug('result is: \n' + result);
|
||||
if (result.length <= 1999) {
|
||||
msg.channel.createMessage(result);
|
||||
let result;
|
||||
try {
|
||||
result = eval(args[0]);
|
||||
} catch (e) {
|
||||
result = e.stack;
|
||||
}
|
||||
else {
|
||||
msg.channel.createMessage("result too long, see logs");
|
||||
log.debug('result is: \n' + result);
|
||||
if (String.valueOf(result).length <= 1999) {
|
||||
msg.channel.createMessage('```\n' + result + '```\n');
|
||||
} else {
|
||||
msg.channel.createMessage('result too long, see logs');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializer.addCommand(new EvalCommand());
|
||||
|
||||
class HelpCommand extends Command {
|
||||
name = 'help';
|
||||
description = 'get help for commands';
|
||||
helptext = '```md\nhelp\nshows this text\n\nhelp <command>\nshows the helptext for <command>';
|
||||
func(msg, args, ctx) {}
|
||||
}
|
||||
|
||||
initializer.addCommand(new HelpCommand());
|
||||
|
||||
export default initializer;
|
||||
|
|
72
parser.js
72
parser.js
|
@ -1,5 +1,5 @@
|
|||
import Logger, { levels } from './logger.js';
|
||||
import { filename } from './utils.js';
|
||||
import { filename, getPerms, hasPerms } from './utils.js';
|
||||
|
||||
export class Command {
|
||||
init(ctx, log) {
|
||||
|
@ -7,17 +7,31 @@ export class Command {
|
|||
}
|
||||
log;
|
||||
name = 'DEFAULT';
|
||||
description = 'No description';
|
||||
helptext = 'No helptext';
|
||||
aliases = '';
|
||||
whitelist = false;
|
||||
perms = 0;
|
||||
func() {}
|
||||
}
|
||||
|
||||
export class Event {
|
||||
event = 'NONE';
|
||||
func(...args) {}
|
||||
}
|
||||
|
||||
export class CommandInitializer {
|
||||
ctx;
|
||||
log;
|
||||
commands = [];
|
||||
aliases = {};
|
||||
uninitialized = [];
|
||||
events = {};
|
||||
|
||||
initialize(ctx) {
|
||||
for (let index in this.uninitialized) {
|
||||
this.ctx = ctx;
|
||||
this.log = new Logger('parser', ctx.log_level);
|
||||
for (const index in this.uninitialized) {
|
||||
this.initCommand(this.uninitialized[index], ctx);
|
||||
delete this.uninitialized[index];
|
||||
}
|
||||
|
@ -26,24 +40,34 @@ export class CommandInitializer {
|
|||
initCommand(cmd, ctx) {
|
||||
cmd.init(ctx, new Logger(`cmd.${cmd.name}`, ctx.log_level));
|
||||
this.commands.push(cmd);
|
||||
for (const alias of cmd.aliases) {
|
||||
this.aliases[alias] = cmd.name;
|
||||
}
|
||||
}
|
||||
|
||||
addCommand(cmd) {
|
||||
this.uninitialized.push(cmd);
|
||||
}
|
||||
|
||||
addEvent(event, func) {
|
||||
if (!events[event]) {
|
||||
events[event] = [];
|
||||
addEvent(handler) {
|
||||
console.log(handler);
|
||||
const event = handler.event;
|
||||
if (!this.events[event]) {
|
||||
this.events[event] = [];
|
||||
}
|
||||
events[event].push(func);
|
||||
this.events[event].push(handler);
|
||||
}
|
||||
|
||||
getCommands() {
|
||||
return this.commands;
|
||||
}
|
||||
|
||||
getAliases() {
|
||||
return this.aliases;
|
||||
}
|
||||
|
||||
getEvents() {
|
||||
console.log(this.events);
|
||||
return this.events;
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +80,7 @@ export default class CommandParser {
|
|||
log;
|
||||
prefix;
|
||||
commands = [];
|
||||
aliases = {};
|
||||
|
||||
addCommand(cmd) {
|
||||
this.log.trace(`cmd to add: ${JSON.stringify(cmd)}`);
|
||||
|
@ -64,8 +89,20 @@ export default class CommandParser {
|
|||
}
|
||||
}
|
||||
|
||||
addAliases(aliases) {
|
||||
this.log.debug('added ' + Object.keys(aliases).length + ' aliases');
|
||||
this.aliases = {
|
||||
...this.aliases,
|
||||
...aliases,
|
||||
};
|
||||
}
|
||||
|
||||
hasCmd(str) {
|
||||
let results = this.commands.filter((c) => c.name == str);
|
||||
if (this.aliases && this.aliases[str] != undefined) {
|
||||
str = this.aliases[str];
|
||||
}
|
||||
|
||||
const results = this.commands.filter((c) => c.name == str);
|
||||
|
||||
return results.length ? results[0] : undefined;
|
||||
}
|
||||
|
@ -75,7 +112,7 @@ export default class CommandParser {
|
|||
}
|
||||
|
||||
getArgsList(split) {
|
||||
let parsed_args = [];
|
||||
const parsed_args = [];
|
||||
let join_index = -1;
|
||||
let add = true;
|
||||
for (let index in split) {
|
||||
|
@ -112,18 +149,29 @@ export default class CommandParser {
|
|||
this.log.trace(msg.content[0]);
|
||||
this.log.trace(this.prefix);
|
||||
if (msg.content.startsWith(this.prefix)) {
|
||||
let snip = msg.content.slice(this.prefix.length);
|
||||
let unsep = snip.split(' ');
|
||||
let res = this.hasCmd(unsep[0]);
|
||||
let args = this.getArgsList(unsep.slice(1));
|
||||
const snip = msg.content.slice(this.prefix.length);
|
||||
const unsep = snip.split(' ');
|
||||
const res = this.hasCmd(unsep[0]);
|
||||
const args = this.getArgsList(unsep.slice(1));
|
||||
this.log.trace(snip);
|
||||
this.log.trace(res);
|
||||
this.log.trace(args);
|
||||
|
||||
if (res != undefined) {
|
||||
this.log.debug(`execute function ${res.name}`);
|
||||
const perms = msg.channel.guild.members.get(msg.author.id).permissions;
|
||||
const resolvedPerms = res.perms.toString();
|
||||
this.log.trace(resolvedPerms);
|
||||
this.log.trace(perms);
|
||||
if (res.whitelist && !ctx.whitelist.user(msg.author)) {
|
||||
msg.channel.createMessage('not whitelisted');
|
||||
} else if (resolvedPerms && !hasPerms(perms, resolvedPerms)) {
|
||||
const required = getPerms(perms.allow.toString() & res.perms).join(', ');
|
||||
msg.channel.createMessage('not enough permissions.').then((sent) => {
|
||||
if (required.length <= 1000) {
|
||||
sent.edit('not enough permissions. needs: `' + required + '`');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.func(msg, args, ctx);
|
||||
}
|
||||
|
|
37
utils.js
37
utils.js
|
@ -1,15 +1,34 @@
|
|||
import path from "path";
|
||||
import {platform} from "process";
|
||||
import path from 'path';
|
||||
import { platform } from 'process';
|
||||
import { Constants } from 'eris';
|
||||
|
||||
export function filename(url) {
|
||||
let __filename = new URL(url).pathname;
|
||||
return path.basename(__filename, ".js");
|
||||
const __filename = new URL(url).pathname;
|
||||
return path.basename(__filename, '.js');
|
||||
}
|
||||
|
||||
export function dirname(url) {
|
||||
let __filename = new URL(url).pathname;
|
||||
let __dirname = path.dirname(__filename);
|
||||
return platform == "win32"
|
||||
? __dirname.slice(1)
|
||||
: __dirname;
|
||||
const __filename = new URL(url).pathname;
|
||||
const __dirname = path.dirname(__filename);
|
||||
return platform == 'win32' ? __dirname.slice(1) : __dirname;
|
||||
}
|
||||
|
||||
export function getPerms(perms) {
|
||||
const result = [];
|
||||
for (const key in Constants.Permissions) {
|
||||
if (Constants.Permissions[key].toString() & perms) {
|
||||
result.push(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function hasPerms(perms, test) {
|
||||
let testPerms = getPerms(test);
|
||||
for (const tp of testPerms) {
|
||||
if (!perms.has(tp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
Loading…
Reference in a new issue