Skip to content
43 changes: 43 additions & 0 deletions src/commands/Builds/AddBuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';

const Command = require('../../Command.js');
const BuildEmbed = require('../../embeds/BuildEmbed');

/**
* Create temporary voice/text channels (can be expanded in the future)
*/
class AddBuild extends Command {
/**
* Constructs a callable command
* @param {Genesis} bot The bot object
*/
constructor(bot) {
super(bot, 'builds.add', 'add build', 'Create a temporary room.');
this.regex = new RegExp(`^${this.call}\\s?(.+)?`, 'i');

this.usages = [
{ description: 'Display instructions for creating a new build with Genesis', parameters: [] },
];

this.allowDM = false;
}

async run(message) {
const matches = message.strippedContent.match(this.regex)[1];
const params = (matches || '').split('|');
if (params.length < 1) {
// let them know there's not enough params
return this.messageManager.statuses.FAILURE;
}
// save params based on order
const title = params[0] || 'My Build';
const body = params[1] || 'My Build Body';
const image = params[2] || 'https://i.imgur.com/31xCos6.png';
const build = await this.bot.settings.addNewBuild(title, body, image, message.author);
const embed = new BuildEmbed(this.bot, build);
this.messageManager.embed(message, embed, true, true);
return this.messageManager.statuses.SUCCESS;
}
}

module.exports = AddBuild;
41 changes: 41 additions & 0 deletions src/commands/Builds/DeleteBuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

const Command = require('../../Command.js');

/**
* Create temporary voice/text channels (can be expanded in the future)
*/
class DeleteBuild extends Command {
/**
* Constructs a callable command
* @param {Genesis} bot The bot object
*/
constructor(bot) {
super(bot, 'builds.delete', 'delete build', 'Create a temporary room.');
this.regex = new RegExp(`^${this.call}\\s?(.+)?`, 'i');

this.usages = [
{ description: 'Display information on an existing build from Genesis', parameters: [] },
];
}

async run(message) {
const buildId = message.strippedContent.match(this.regex)[1];
if (buildId.length < 1) {
// let them know it's not a valid build id
return this.messageManager.statuses.FAILURE;
}
const build = await this.bot.settings.getBuild(buildId);
const owner = typeof build.owner === 'object' ? build.owner.id : build.owner;
if (owner === message.author.id || owner === this.bot.owner) {
this.logger.debug('owner matched author');
await this.bot.settings.deleteBuild(buildId);
this.messageManager.embed(message, { title: `Build ${buildId} deleted.`, color: 0xcda2a3 }, true, true);
return this.messageManager.statuses.SUCCESS;
}
this.messageManager.embed(message, { title: `You couldn't delete build ${buildId}.`, color: 0x83181b }, true, true);
return this.messageManager.statuses.FAILURE;
}
}

module.exports = DeleteBuild;
36 changes: 36 additions & 0 deletions src/commands/Builds/GetBuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

const Command = require('../../Command.js');
const BuildEmbed = require('../../embeds/BuildEmbed');

/**
* Create temporary voice/text channels (can be expanded in the future)
*/
class GetBuild extends Command {
/**
* Constructs a callable command
* @param {Genesis} bot The bot object
*/
constructor(bot) {
super(bot, 'builds.get', 'get build', 'Create a temporary room.');
this.regex = new RegExp(`^${this.call}\\s?(.+)?`, 'i');

this.usages = [
{ description: 'Display information on an existing build from Genesis', parameters: [] },
];
}

async run(message) {
const buildId = message.strippedContent.match(this.regex)[1];
if (buildId.length < 1) {
// let them know it's not a valid build id
return this.messageManager.statuses.FAILURE;
}
const build = await this.bot.settings.getBuild(buildId);
const embed = new BuildEmbed(this.bot, build);
this.messageManager.embed(message, embed, true, true);
return this.messageManager.statuses.SUCCESS;
}
}

module.exports = GetBuild;
52 changes: 52 additions & 0 deletions src/commands/Builds/ListBuilds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';

const Command = require('../../Command.js');

function createGroupedArray(arr, chunkSize) {
const groups = [];
for (let i = 0; i < arr.length; i += chunkSize) {
groups.push(arr.slice(i, i + chunkSize));
}
return groups;
}


/**
* Create temporary voice/text channels (can be expanded in the future)
*/
class ListBuilds extends Command {
/**
* Constructs a callable command
* @param {Genesis} bot The bot object
*/
constructor(bot) {
super(bot, 'builds.list', 'list builds', 'Create a temporary room.');
this.regex = new RegExp(`^${this.call}\\s?(.+)?`, 'i');

this.usages = [
{ description: 'Display information on an existing build from Genesis. `|` separates title, body, and image. `;` separates sections in the body.', parameters: ['title | body | image'] },
];
}

async run(message) {
const useAll = message.strippedContent.match(this.regex)[1] === 'all' && this.bot.owner === message.author.id;
const builds = await this.bot.settings.getBuilds(useAll, message.author);
if (builds.length > 0) {
const buildGroups = createGroupedArray(builds, 20);
const tokens = buildGroups.map(buildGroup => ({ name: '_ _', value: buildGroup.map(build => `\`${build.id} | ${build.title} | Owned by ${typeof build.owner === 'object' ? build.owner.tag : build.owner}\``).join('\n') }));
const tokenGroups = createGroupedArray(tokens, 6);
await Promise.all(tokenGroups.map(tokenGroup => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expected parentheses around arrow function argument having a body with curly braces. (arrow-parens)

tokenGroup[0].fields.value = `\`Build ID | Title | Owner\`\n${tokenGroup[0].fields.value}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assignment to property of function parameter 'tokenGroup'. (no-param-reassign)

return this.messageManager.embed(message, {
color: 0xcda2a3,
fields: tokenGroup,
}, true, true);
}));
return this.messageManager.statuses.SUCCESS;
}
await this.messageManager.embed(message, { color: 0xcda2a3, title: 'No builds for user' }, true, true);
return this.messageManager.statuses.FAILURE;
}
}

module.exports = ListBuilds;
71 changes: 71 additions & 0 deletions src/commands/Builds/SetField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use strict';

const Command = require('../../Command.js');
const BuildEmbed = require('../../embeds/BuildEmbed');

/**
* Create temporary voice/text channels (can be expanded in the future)
*/
class AddBuild extends Command {
/**
* Constructs a callable command
* @param {Genesis} bot The bot object
*/
constructor(bot) {
super(bot, 'builds.set', 'set build', 'Create a temporary room.');
this.regex = new RegExp(`^${this.call}(?:\\s?(all|title|body|image)\\s?(.+))?`, 'i');

this.usages = [
{ description: 'Display instructions for creating a new build with Genesis', parameters: [] },
];

this.allowDM = false;
}

async run(message) {
const type = message.strippedContent.match(this.regex)[1];
const params = (message.strippedContent.match(this.regex)[2] || '').split('|');
if (!type) {
// let them know there's not enough params
return this.messageManager.statuses.FAILURE;
}
const buildId = (params[0] || '').trim();
const build = await this.bot.settings.getBuild(buildId);
let title;
let body;
let image;
if (build && (build.owner_id === message.author.id || message.author.id === this.bot.owner)) {
if (type === 'all') {
title = params[1];
body = params[2];
image = params[3];
} else if (type === 'title') {
title = params[1];
} else if (type === 'body') {
body = params[1];
} else if (type === 'image') {
image = params[1];
} else {
return this.failure(message, buildId);
}
} else {
return this.failure(message, buildId);
}

// save params based on order
const status = await this.bot.settings.setBuildFields(buildId, { title, body, image });
if (status) {
this.messageManager.embed(message, new BuildEmbed(this.bot,
await this.bot.settings.getBuild(buildId)), true, true);
return this.messageManager.statuses.SUCCESS;
}
return this.failure(message, buildId);
}

async failure(message, buildId) {
this.messageManager.embed(message, { title: `You couldn't edit build ${buildId}.`, color: 0x83181b }, true, true);
return this.messageManager.statuses.FAILURE;
}
}

module.exports = AddBuild;
13 changes: 4 additions & 9 deletions src/commands/Utilities/PollInline.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class PollInline extends Command {
*/
constructor(bot) {
super(bot, 'poll', 'poll:', 'Create a simple poll');
this.regex = new RegExp('poll\:.+', 'ig');
this.regex = new RegExp('poll:.+', 'ig');
this.usages = [
{
description: 'Create a simple poll',
Expand All @@ -29,14 +29,9 @@ class PollInline extends Command {
async run(message) {
if (message.channel.permissionsFor(this.bot.client.user.id)
.has(['USE_EXTERNAL_EMOJIS', 'ADD_REACTIONS'])) {
message.react('👍')
.then(() => {
return message.react('👎');
})
.then(() => {
return message.react('🤷');
})
.catch(this.logger.error);
await message.react('👍');
await message.react('👎');
await message.react('🤷');
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/embeds/BuildEmbed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';

const BaseEmbed = require('./BaseEmbed.js');

/**
* Generates alert embeds
*/
class AlertEmbed extends BaseEmbed {
/**
* @param {Genesis} bot - An instance of Genesis
* @param {Build} build - The alerts to be included in the embed
*/
constructor(bot, build) {
super();
this.color = 0xF1C40F;
this.title = build.title;
this.fields = [].concat(build.body.split(';').map(section => ({ name: '_ _', value: section })));
this.image = { url: build.url };
this.footer.text = `${build.id} | Owned by ${typeof build.owner === 'object' ? build.owner.tag : build.owner}`;
}
}

module.exports = AlertEmbed;
80 changes: 79 additions & 1 deletion src/settings/Database.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ const CustomCommand = require('../CustomCommand.js');
* @property {string} database - The database to use
*/

const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const makeId = () => {
const tokens = [];
for (let i = 0; i < 8; i += 1) {
tokens.push(possible.charAt(Math.floor(Math.random() * possible.length)));
}
return tokens.join('');
};

/**
* Persistent storage for the bot
*/
Expand Down Expand Up @@ -817,7 +826,7 @@ class Database {

async getWelcomes(guild) {
if (guild) {
const query = SQL`SELECT * FROM welcome_messages WHERE guild_id = ${guild.id}`;
const query = SQL`SELECT * FROM welcome_messages WHERE guild_id=${guild.id}`;
const res = await this.db.query(query);
if (res[0]) {
return res[0].map(value =>
Expand All @@ -831,6 +840,75 @@ class Database {
}
return [];
}

async addNewBuild(title, body, image, owner) {
const buildId = makeId();
const query = SQL`INSERT INTO builds VALUES (${buildId}, ${title}, ${body}, ${image}, ${owner.id})
ON DUPLICATE KEY UPDATE title=${title}, body=${body}, image=${image};`;
await this.db.query(query);
return { id: buildId, title, body, url: image, owner };
}

async getBuild(buildId) {
if (buildId) {
const query = SQL`SELECT * FROM builds WHERE build_id=${buildId};`;
const res = await this.db.query(query);
if (res[0] && res[0][0]) {
const result = res[0][0];
return {
title: result.title,
body: result.body,
url: result.image,
id: result.build_id,
owner: this.bot.client.users.get(result.owner_id) || result.owner_id,
owner_id: result.owner_id,
};
}
}
return {
id: '',
title: 'No Such Build',
body: '',
url: '',
owner: '',
};
}

async deleteBuild(buildId) {
const query = SQL`DELETE FROM builds WHERE build_id=${buildId};`;
return this.db.query(query);
}

async getBuilds(owner, author) {
const query = SQL`SELECT * FROM builds WHERE owner_id LIKE ${owner ? '%' : author.id};`;
const res = await this.db.query(query);
if (res[0]) {
return res[0].map(build => ({
id: build.build_id,
owner: this.bot.client.users.get(build.owner_id) || build.owner_id,
title: build.title

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing trailing comma. (comma-dangle)

}));
}
return [];
}

async setBuildFields(buildId, { title = undefined, body = undefined, image = undefined }) {
const setTokens = [];
if (title) {
setTokens.push(`title = '${title.trim().replace(/'/ig, '\\\'')}'`);
}
if (body) {
setTokens.push(`body = '${body.trim().replace(/'/ig, '\\\'')}'`);
}
if (image) {
setTokens.push(`image = '${image.trim().replace(/'/ig, '\\\'')}'`);
}
if (setTokens.length > 0) {
const query = `UPDATE builds SET ${setTokens.join(', ')} WHERE build_id='${buildId}';`;
return this.db.query(query);
}
return false;
}
}

module.exports = Database;
Loading