diff --git a/src/class/Queue.ts b/src/class/Queue.ts index daf587f..0209c4c 100644 --- a/src/class/Queue.ts +++ b/src/class/Queue.ts @@ -1,7 +1,11 @@ +/* eslint-disable no-eval */ import Bull from 'bull'; -import { Client } from '.'; +import { TextableChannel } from 'eris'; +import { Client, RichEmbed } from '.'; import { ScoreInterface } from '../models'; +import { apply as Apply } from '../commands'; + export default class Queue { public client: Client; @@ -42,6 +46,9 @@ export default class Queue { this.queues.score.on('completed', (job) => { this.client.util.signale.success(`Job with id ${job.id} has been completed`); }); + this.queues.score.on('error', async (err) => { + this.client.util.handleError(err); + }); } protected setProcessors() { @@ -51,9 +58,30 @@ export default class Queue { await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { pin: [this.client.util.randomNumber(100, 999), this.client.util.randomNumber(10, 99), this.client.util.randomNumber(1000, 9999)] } }); } }); + this.queues.score.process('score::apply', async (job: Bull.Job<{ channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func: string }>) => { + const application = await Apply.apply(this.client, job.data.url, job.data.userID); + const guild = this.client.guilds.get(job.data.channelInformation.guildID); + const channel = guild.channels.get(job.data.channelInformation.channelID); + const message = await channel.getMessage(job.data.channelInformation.messageID); + await message.delete(); + const embed = new RichEmbed(); + embed.setTitle('Application Decision'); + embed.addField('Status', application.decision, true); + embed.addField('UserID', job.data.userID, true); + embed.addField('Job ID', job.id.toString(), true); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + await channel.createMessage({ content: `<@${job.data.userID}>`, embed }); + const func = eval(job.data.func); + if (application.status === 'SUCCESS' && application.decision === 'APPROVED') await func(this.client, job.data.userID); + }); } public updateScore(score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number) { this.queues.score.add('score::update', { score, total, activity, roles, moderation, cloudServices, other, staff }); } + + public processApplication(channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func: string) { + return this.queues.score.add('score::apply', { channelInformation, url, userID, func }); + } } diff --git a/src/commands/addmerchant.ts b/src/commands/addmerchant.ts index f07a253..091ad36 100644 --- a/src/commands/addmerchant.ts +++ b/src/commands/addmerchant.ts @@ -18,10 +18,12 @@ export default class AddMerchant extends Command { try { if (!args[1]) return this.client.commands.get('help').run(message, [this.name]); if ((Number(args[0]) !== 0) && (Number(args[0]) !== 1)) return this.error(message.channel, 'Invalid permissions.'); + if ((Number(args[1]) !== 0) && (Number(args[1]) !== 1)) return this.error(message.channel, 'Invalid permissions.'); const key = randomBytes(20).toString('hex'); const merchant = await (new this.client.db.Merchant({ name: args.slice(2).join(' '), privileged: Number(args[0]), + type: Number(args[1]), key, pulls: [], })).save(); diff --git a/src/commands/apply.ts b/src/commands/apply.ts new file mode 100644 index 0000000..d326fb4 --- /dev/null +++ b/src/commands/apply.ts @@ -0,0 +1,74 @@ +import type { AxiosError } from 'axios'; +import axios from 'axios'; +import { Member, Message } from 'eris'; +import { Client, Command, RichEmbed } from '../class'; + +export default class Apply extends Command { + public services: Map Promise | boolean, func: Function }>; + + constructor(client: Client) { + super(client); + this.name = 'apply'; + this.description = 'apply'; + this.usage = `${this.client.config.prefix}apply [serviceName]`; + this.permissions = 0; + this.guildOnly = true; + this.enabled = true; + this.setServices(); + } + + protected setServices() { + this.services = new Map(); + this.services.set('role::constants', { + description: 'Constants role assignment.', + url: 'https://eds.libraryofcode.org/roles/constants', + validation: (member: Member) => !member.roles.includes('511771731891847168'), + func: async (client: Client, ...data: any[]) => { + const member = await client.guilds.get('446067825673633794').getRESTMember(data[0]); + await member.addRole('511771731891847168'); + }, + }); + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) { + const embed = new RichEmbed(); + embed.setTitle('Available Instant Applications'); + for (const service of this.services) { + embed.addField(service[0], `${service[1].description} | Run \`${this.client.config.prefix}apply ${service[0]}\` to apply.`, true); + } + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + return message.channel.createMessage({ embed }); + } + + if (!this.services.has(args[0])) return this.error(message.channel, 'Invalid service/product name.'); + const service = this.services.get(args[0]); + const test = await this.services.get(args[0]).validation(message.member); + if (!test) return this.error(message.channel, 'A condition exists which prevents you from applying, please try again later.'); + const msg = await this.loading(message.channel, 'Thank you for submitting an application. We are currently processing it, you will be pinged here shortly with the decision.'); + return await this.client.queue.processApplication({ channelID: message.channel.id, guildID: this.mainGuild.id, messageID: msg.id }, service.url, message.author.id, service.func.toString()); + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } + + public static async apply(client: Client, url: string, userID: string) { + try { + const { data } = await axios({ + method: 'get', + url: `${url}?userID=${userID}&auth=${client.config.internalKey}`, + }); + + return { + status: 'SUCCESS', + decision: data.decision, + }; + } catch (err) { + const error = err; + if (error.response?.status === 404 || error.response.status === 400 || error.response.status === 401) return { status: 'CLIENT_ERROR', decision: 'PRE-DECLINED' }; + return { status: 'SERVER_ERROR', decision: 'PRE-DECLINED' }; + } + } +} diff --git a/src/commands/index.ts b/src/commands/index.ts index 59c802a..06013fc 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -3,6 +3,7 @@ export { default as addmerchant } from './addmerchant'; export { default as addnote } from './addnote'; export { default as addrank } from './addrank'; export { default as addredirect } from './addredirect'; +export { default as apply } from './apply'; export { default as ban } from './ban'; export { default as delitem } from './delitem'; export { default as delmerchant } from './delmerchant';