Added cmdsequence saving

- Sequences of commands can be saved with ~savecmd
- When saving the semicolon must be escaped by backslash
- saved commands can be listed with ~savedcmd
- saved commands can be executed with ~execute [name]
- renamed ~save to ~savemedia and ~saved to ~savedmedia
- added a command to delete saved entries
pull/36/head
Trivernis 6 years ago
parent dd2a49209f
commit 4921ee243c

@ -160,7 +160,7 @@ class Bot {
*/
registerCommands() {
// useless test command
cmd.createGlobalCommand(prefix + 'repeatafterme', (msg, argv, args) => {
cmd.createGlobalCommand(prefix + 'say', (msg, argv, args) => {
return args.join(' ');
}, [], "Repeats what you say");
@ -333,10 +333,7 @@ class Bot {
let resolvedAnswer = await answer;
await this.answerMessage(msg, resolvedAnswer);
} else if (answer instanceof Array) {
let answerPromises = [];
for (let answerPart of answer)
answerPromises.push(async () => await this.answerMessage(msg, answerPart));
await waterfall(answerPromises);
await waterfall(answer.map((x) => async () => await this.answerMessage(msg, x))); // execute each after another
} else if ({}.toString.call(answer) === '[object Function]') {
await this.answerMessage(msg, answer());
} else if (answer) {

@ -5,6 +5,42 @@
"permission": "all",
"description": "Shows the roles used for commands on the server.",
"category": "Utility"
},
"savecmd": {
"name": "savecmd",
"permission": "moderator",
"description": "Saves a sequence of commands under a new name. ~save [cmdsequence] [cmdname]. Semicoli must be escaped with \\ (Backslash)",
"category": "Utility"
},
"savedcmd": {
"name": "savedcmd",
"permission": "all",
"description": "Displays the saved commands.",
"category": "Utility",
"response": {
"no_commands": "There are no saved commands."
}
},
"deletecmd": {
"name": "deletecmd",
"permission": "moderator",
"description": "Delete a saved command.",
"args": [
"cmdname"
],
"category": "Utility"
},
"execute": {
"name": "execute",
"permission": "all",
"args": [
"cmdname"
],
"description": "Execute saved commands.",
"category": "Utility",
"response": {
"not_found": "This command could not be found."
}
}
},
"music": {
@ -132,8 +168,8 @@
"repeat_false": "Not listening on repeat anymore."
}
},
"save": {
"name": "save",
"savemedia": {
"name": "savemedia",
"permission": "dj",
"args": [
"url"
@ -141,14 +177,23 @@
"description": "Saves the YouTube song/playlist with a specific name",
"category": "Music"
},
"saved": {
"name": "saved",
"savedmedia": {
"name": "savedmedia",
"permission": "all",
"description": "Prints out all saved playlists.",
"description": "Prints out all saved playlists and songs.",
"category": "Music",
"response": {
"no_saved": "There are no saved songs/playlists :("
}
},
"deletemedia": {
"name": "deletemedia",
"permission": "dj",
"description": "Deletes a saved media entry. ~deletemedia [name]",
"category": "Music",
"response": {
"no_name": "You must provide a name for the media that shall be deleted."
}
}
}
}

@ -35,7 +35,9 @@ exports.Servant = class {
} else {
let helpEmbed = new Discord.RichEmbed()
.setTitle('Commands');
.setTitle('Commands')
.setDescription('Create a sequence of commands with `;` (semicolon).')
.setTimestamp();
let globHelp = '';
Object.entries(globCommands).sort().forEach(([key, value]) => {
if (value.role !== 'owner' || checkPermission(msg, 'owner'))
@ -107,12 +109,19 @@ exports.Servant = class {
* @param msg
* @param globResult
* @param content
* @param returnFunction Boolean if the return value should be a function.
* @param fallback
* @returns {*}
*/
processCommand(msg, globResult, content, returnFunction) {
processCommand(msg, globResult, content, returnFunction, fallback) {
let command = (content.match(/^.\w+/) || [])[0];
if (!command || !this.commands[command])
return globResult;
if (fallback && !globResult) {
command = fallback;
content = `${fallback} ${content}`;
} else {
return globResult;
}
let cmd = this.commands[command];
if (!checkPermission(msg, cmd.role))
return 'No Permission';
@ -143,14 +152,18 @@ exports.Servant = class {
let globResult = parseGlobalCommand(msg);
logger.debug(`Global command result is ${globResult}`);
let content = msg.content;
let commands = content.split(';').map(x => x.replace(/^ +/, ''));
let commands = content.split(/(?<!\\);/).map(x => x.replace(/^ +/, ''));
if (commands.length === 1) {
return this.processCommand(msg, globResult, content);
} else {
let answers = [];
for (let i = 0; i < commands.length; i++)
let previousCommand = (commands[0].match(/^.\w+/) || [])[0];;
for (let i = 0; i < commands.length; i++) {
answers.push(this.processCommand(msg, globResult[i], commands[i],
true)); // return function to avoid "race conditions"
true, previousCommand)); // return function to avoid "race conditions"
let commandMatch = (commands[i].match(/^.\w+/) || [])[0];
previousCommand = this.commands[commandMatch]? commandMatch : previousCommand;
}
return answers;
}
@ -215,6 +228,7 @@ exports.init = function (prefix) {
} else {
let helpEmbed = new Discord.RichEmbed()
.setTitle('Global Commands')
.setDescription('Create a sequence of commands with `;` (semicolon).')
.setTimestamp();
let description = '';
Object.entries(globCommands).sort().forEach(([key, value]) => {
@ -248,7 +262,7 @@ function processCommand(cmd, msg, content, returnFunction) {
*/
function parseGlobalCommand(msg) {
let content = msg.content;
let commands = content.split(';').map(x => x.replace(/^ +/, ''));
let commands = content.split(/(?<!\\);/).map(x => x.replace(/^ +/, ''));
if (commands.length === 1) {
let command = (content.match(/^.\w+/) || [])[0];
if (!command || !globCommands[command])
@ -260,15 +274,25 @@ function parseGlobalCommand(msg) {
return processCommand(cmd, msg, content);
} else {
let answers = [];
let previousCommand = '';
for (let commandPart of commands) {
let command = (commandPart.match(/^.\w+/) || [])[0];
let command = (commandPart.match(/^.\w+/) || [])[0] || previousCommand;
previousCommand = globCommands[command]? command : previousCommand;
if (!commandPart || !globCommands[command]) {
commandPart = `${previousCommand} ${commandPart}`;
command = previousCommand;
}
if (command && globCommands[command]) {
let cmd = globCommands[command];
if (checkPermission(msg, cmd.role)) {
logger.debug(`Permission <${cmd.role}> granted for command ${command} for user <${msg.author.tag}>`);
answers.push(processCommand(cmd, msg, commandPart,
true)); // return an function to avoid "race conditions"
} else {
answers.push(false);
}
} else {
answers.push(false);
}
}
return answers;
@ -285,8 +309,9 @@ function checkPermission(msg, rolePerm) {
return true;
if (msg.author.tag === args.owner || config.owners.includes(msg.author.tag))
return true;
else
if (msg.member && rolePerm && msg.member.roles.some(role => role.name.toLowerCase() === rolePerm.toLowerCase()))
else
if (msg.member && rolePerm && rolePerm !== 'owner' && msg.member.roles
.some(role => (role.name.toLowerCase() === rolePerm.toLowerCase() || role.name.toLowerCase() === 'botcommander')))
return true;
return false;

@ -36,7 +36,7 @@ exports.GuildHandler = class {
logger.debug(`Connected to the database for ${this.guild}`);
await this.createTables();
// register commands
this.registerMusicCommands();
this.registerCommands();
}
/**
@ -66,6 +66,11 @@ exports.GuildHandler = class {
name VARCHAR(32) UNIQUE NOT NULL,
url VARCHAR(255) NOT NULL
)`);
await this.db.run(`${utils.sql.tableExistCreate} commands (
${utils.sql.pkIdSerial},
name VARCHAR(32) UNIQUE NOT NULL,
command VARCHAR(255) NOT NULL
)`);
}
/**
@ -81,10 +86,7 @@ exports.GuildHandler = class {
let resolvedAnswer = await answer;
await this.answerMessage(msg, resolvedAnswer);
} else if (answer instanceof Array) {
let answerPromises = [];
for (let answerPart of answer)
answerPromises.push(async () => await this.answerMessage(msg, answerPart));
await waterfall(answerPromises);
await waterfall(answer.map((x) => async () => await this.answerMessage(msg, x)));
} else if ({}.toString.call(answer) === '[object Function]') { // check if the answer is of type function
await this.answerMessage(msg, answer());
} else {
@ -124,7 +126,7 @@ exports.GuildHandler = class {
/**
* registers all music commands and initializes a dj
*/
registerMusicCommands() {
registerCommands() {
this.dj = new music.DJ();
let playCb = async (msg, kwargs, argv, template, next) => {
@ -261,8 +263,8 @@ exports.GuildHandler = class {
}
});
// saves playlists
this.servant.createCommand(servercmd.music.save, async (msg, kwargs, argv) => {
// saves playlists and videos
this.servant.createCommand(servercmd.music.savemedia, async (msg, kwargs, argv) => {
let saveName = argv.join(' ');
let row = await this.db.get('SELECT COUNT(*) count FROM playlists WHERE name = ?', [saveName]);
if (!row || row.count === 0)
@ -272,19 +274,75 @@ exports.GuildHandler = class {
return `Saved song/playlist as ${saveName}`;
});
// saved command - prints out saved playlists
this.servant.createCommand(servercmd.music.saved, async (msg) => {
// savedmedia command - prints out saved playlists and videos
this.servant.createCommand(servercmd.music.savedmedia, async () => {
let response = '';
let rows = await this.db.all('SELECT name, url FROM playlists');
for (let row of rows)
response += `[${row.name}](${row.url})\n`;
if (rows.length === 0)
msg.channel.send(servercmd.music.saved.response.no_saved);
return servercmd.music.savedmedia.response.no_saved;
else
return new Discord.RichEmbed()
.setTitle('Saved Songs and Playlists')
.setDescription(response);
.setDescription(response)
.setFooter(`Play a saved entry with ${this.prefix}play [Entryname]`)
.setTimestamp();
});
this.servant.createCommand(servercmd.music.deletemedia, async (msg, kwargs, argv) => {
let saveName = argv.join(' ');
if (!saveName) {
return servercmd.music.deletemedia.response.no_name;
} else {
await this.db.run('DELETE FROM playlists WHERE name = ?', [saveName]);
return `Deleted ${saveName} from saved media`;
}
});
// savecmd - saves a command sequence with a name
this.servant.createCommand(servercmd.utils.savecmd, async (msg, kwargs, argv) => {
let saveName = argv.pop();
let cmdsequence = argv.join(' ').replace(/\\/g, '');
let row = await this.db.get('SELECT COUNT(*) count FROM commands WHERE name = ?', [saveName]);
if (!row || row.count === 0)
await this.db.run('INSERT INTO commands (name, command) VALUES (?, ?)', [saveName, cmdsequence]);
else
await this.db.run('UPDATE commands SET sequence = ? WHERE name = ?', [cmdsequence, saveName]);
return `saved command sequence as ${saveName}`;
});
// savedcmd - prints saved commands
this.servant.createCommand(servercmd.utils.savedcmd, async () => {
let response = new Discord.RichEmbed()
.setTitle('Saved Commands')
.setFooter(`Execute a saved entry with ${this.prefix}execute [Entryname]`)
.setTimestamp();
let rows = await this.db.all('SELECT name, command FROM commands');
if (rows.length === 0)
return servercmd.utils.savedcmd.response.no_commands;
else
for (let row of rows)
response.addField(row.name, '`' + row.command + '`');
return response;
});
// deletecmd - deletes a command from saved commands
this.servant.createCommand(servercmd.utils.deletecmd, async (msg, kwargs) => {
await this.db.run('DELETE FROM commands WHERE name = ?', [kwargs.cmdname]);
return `Deleted command ${kwargs.cmdname}`;
});
// execute - executes a saved command
this.servant.createCommand(servercmd.utils.execute, async (msg, kwargs) => {
let row = await this.db.get('SELECT command FROM commands WHERE name = ?', [kwargs.cmdname]);
if (row) {
msg.content = row.command;
await this.handleMessage(msg);
} else {
return servercmd.utils.execute.response.not_found;
}
});
}
};

Loading…
Cancel
Save