community-relations/src/class/Queue.ts

171 lines
8.2 KiB
TypeScript

/* eslint-disable no-await-in-loop */
/* eslint-disable no-eval */
import Bull from 'bull';
import cron from 'cron';
import { TextableChannel, TextChannel } from 'eris';
import { Client, RichEmbed } from '.';
import { ScoreInterface, InqType as InquiryType } from '../models';
import { apply as Apply } from '../commands';
export default class Queue {
public client: Client;
public queues: { score: Bull.Queue };
constructor(client: Client) {
this.client = client;
this.queues = {
score: new Bull('score', { prefix: 'queue::score' }),
};
this.setProcessors();
this.setCronJobs();
}
protected setCronJobs() {
const historialCommunityReportJob = new cron.CronJob('0 20 * * *', async () => {
try {
const reports = await this.client.db.Score.find().lean().exec();
const startDate = new Date();
for (const report of reports) {
const inqs = await this.client.db.Inquiry.find({ userID: report.userID });
const data = new this.client.db.ScoreHistorical({
userID: report.userID,
report,
inquiries: inqs.map((inq) => inq._id),
date: startDate,
});
await data.save();
}
} catch (err) {
this.client.util.handleError(err);
}
});
historialCommunityReportJob.start();
}
public async jobCounts() {
const data = {
waiting: 0,
active: 0,
completed: 0,
failed: 0,
delayed: 0,
};
for (const entry of Object.entries(this.queues)) {
// eslint-disable-next-line no-await-in-loop
const counts = await entry[1].getJobCounts();
data.waiting += counts.waiting;
data.active += counts.active;
data.completed += counts.completed;
data.failed += counts.failed;
data.delayed += counts.delayed;
}
return data;
}
protected listeners() {
this.queues.score.on('active', (job) => {
this.client.util.signale.pending(`${job.id} has become active.`);
});
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() {
this.queues.score.process('score::inquiry', async (job: Bull.Job<{ inqID: string, userID: string, name: string, type: InquiryType, reason?: string }>) => {
const member = this.client.util.resolveMember(job.data.userID, this.client.guilds.get(this.client.config.guildID));
const report = await this.client.db.Score.findOne({ userID: job.data.userID }).lean().exec();
const embed = new RichEmbed();
if (job.data.type === InquiryType.HARD) {
embed.setTitle('Inquiry Notification');
embed.setDescription(job.data.inqID);
embed.setColor('#800080');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true);
embed.addField('Type', 'HARD', true);
embed.addField('Department/Service', job.data.name.toUpperCase(), true);
embed.addField('Reason', job.data.reason ?? 'N/A', true);
embed.setTimestamp();
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
if (report.notify === true) {
await this.client.getDMChannel(job.data.userID).then((chan) => {
chan.createMessage(`__**Community Score - Hard Pull Notification**__\n*You have signed up to be notified whenever your hard score has been pulled. See \`?score\` for more information.*\n\n**Department/Service:** ${job.data.name.toUpperCase()}`);
}).catch(() => {});
}
} else {
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', job.data.name.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
}
const log = <TextChannel> this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed }).catch(() => {});
});
this.queues.score.process('score::update', async (job: Bull.Job<{ score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number }>) => {
await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { total: job.data.total, activity: job.data.activity, roles: job.data.roles, moderation: job.data.moderation, cloudServices: job.data.cloudServices, other: job.data.other, staff: job.data.staff, lastUpdate: new Date() } });
if (!job.data.score.pin || job.data.score.pin?.length < 1) {
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 = <TextableChannel> guild.channels.get(job.data.channelInformation.channelID);
const message = await channel.getMessage(job.data.channelInformation.messageID);
const member = guild.members.get(job.data.userID);
await message.delete();
const embed = new RichEmbed();
embed.setTitle('Application Decision');
if (member) {
embed.setAuthor(member.username, member.avatarURL);
}
if (application.decision === 'APPROVED') {
embed.setColor('#50c878');
} else if (application.decision === 'DECLINED') {
embed.setColor('#fe0000');
} else if (application.decision === 'PRE-DECLINE') {
embed.setColor('#ffa500');
} else {
embed.setColor('#eeeeee');
}
const chan = await this.client.getDMChannel(job.data.userID);
if (chan && application.token) {
chan.createMessage(`__**Application Decision Document**__\n*This document provides detailed information about the decision given to you by EDS.*\n\nhttps://eds.libraryofcode.org/dec/${application.token}`);
}
embed.setDescription(`This application was processed by __${application.processedBy}__ on behalf of the vendor, department, or service who operates this application. Please contact the vendor for further information about your application if needed.`);
embed.addField('Status', application.decision, true);
embed.addField('User ID', job.data.userID, true);
embed.addField('Application ID', application.id, true);
embed.addField('Job ID', job.id.toString(), true);
embed.setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL);
embed.setTimestamp();
await channel.createMessage({ content: `<@${job.data.userID}>`, embed });
if (job.data.func) {
const func = eval(job.data.func);
if (application.status === 'SUCCESS' && application.decision === 'APPROVED') await func(this.client, job.data.userID);
}
});
}
public addInquiry(inqID: string, userID: string, name: string, type: InquiryType, reason?: string) {
return this.queues.score.add('score::inquiry', { inqID, userID, name, type, reason });
}
public updateScore(score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number) {
return 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 });
}
}