add SAA, and changes to how inquiries are handled. upgrade to Yarn v2

merge-requests/25/merge
Matthew 2021-04-12 20:05:30 -04:00
parent e4a63cbf30
commit 22ac5faa22
No known key found for this signature in database
GPG Key ID: 210AF32ADE3B5C4B
19 changed files with 559 additions and 5001 deletions

7
.gitignore vendored
View File

@ -1,5 +1,12 @@
# Package Management & Libraries
node_modules
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Configuration Files
config.yaml

55
.yarn/releases/yarn-berry.cjs vendored Normal file

File diff suppressed because one or more lines are too long

1
.yarnrc.yml Normal file
View File

@ -0,0 +1 @@
yarnPath: ".yarn/releases/yarn-berry.cjs"

4889
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@
"eris-pagination": "github:bsian03/eris-pagination",
"express": "^4.17.1",
"helmet": "^3.22.0",
"ioredis": "^4.26.0",
"jsonwebtoken": "^8.5.1",
"mathjs": "^7.6.0",
"moment": "^2.25.3",

View File

@ -2,6 +2,7 @@ import Stripe from 'stripe';
import eris from 'eris';
import pluris from 'pluris';
import mongoose from 'mongoose';
import Redis from 'ioredis';
import { promises as fs } from 'fs';
import { Collection, Command, LocalStorage, Queue, Util, ServerManagement, Event } from '.';
import {
@ -21,6 +22,7 @@ import {
Rank, RankInterface,
Redirect, RedirectInterface,
Resolution, ResolutionInterface,
SAA, SAAInterface,
Score, ScoreInterface,
ScoreHistorical, ScoreHistoricalInterface,
Staff, StaffInterface,
@ -47,7 +49,32 @@ export default class Client extends eris.Client {
public stripe: Stripe;
public db: { Customer: mongoose.Model<CustomerInterface>, CustomerPortal: mongoose.Model<CustomerPortalInterface>, ExecutiveOrder: mongoose.Model<ExecutiveOrderInterface>, File: mongoose.Model<FileInterface>, Inquiry: mongoose.Model<InquiryInterface>, Member: mongoose.Model<MemberInterface>, Merchant: mongoose.Model<MerchantInterface>, Moderation: mongoose.Model<ModerationInterface>, Motion: mongoose.Model<MotionInterface>, Note: mongoose.Model<NoteInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Proclamation: mongoose.Model<ProclamationInterface>, Promo: mongoose.Model<PromoInterface>, Rank: mongoose.Model<RankInterface>, Redirect: mongoose.Model<RedirectInterface>, Resolution: mongoose.Model<ResolutionInterface>, Score: mongoose.Model<ScoreInterface>, ScoreHistorical: mongoose.Model<ScoreHistoricalInterface>, Staff: mongoose.Model<StaffInterface>, Stat: mongoose.Model<StatInterface>, local: { muted: LocalStorage } };
public db: {
Customer: mongoose.Model<CustomerInterface>,
CustomerPortal: mongoose.Model<CustomerPortalInterface>,
ExecutiveOrder: mongoose.Model<ExecutiveOrderInterface>,
File: mongoose.Model<FileInterface>,
Inquiry: mongoose.Model<InquiryInterface>,
Member: mongoose.Model<MemberInterface>,
Merchant: mongoose.Model<MerchantInterface>,
Moderation: mongoose.Model<ModerationInterface>,
Motion: mongoose.Model<MotionInterface>,
Note: mongoose.Model<NoteInterface>,
PagerNumber: mongoose.Model<PagerNumberInterface>,
Proclamation: mongoose.Model<ProclamationInterface>,
Promo: mongoose.Model<PromoInterface>,
Rank: mongoose.Model<RankInterface>,
Redirect: mongoose.Model<RedirectInterface>,
Resolution: mongoose.Model<ResolutionInterface>,
SAA: mongoose.Model<SAAInterface>,
Score: mongoose.Model<ScoreInterface>,
ScoreHistorical: mongoose.Model<ScoreHistoricalInterface>,
Staff: mongoose.Model<StaffInterface>,
Stat: mongoose.Model<StatInterface>,
local: { muted: LocalStorage }
};
constructor(token: string, options?: eris.ClientOptions) {
super(token, options);
@ -55,7 +82,30 @@ export default class Client extends eris.Client {
this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>();
this.queue = new Queue(this);
this.db = { Customer, CustomerPortal, ExecutiveOrder, File, Inquiry, Member, Merchant, Moderation, Motion, Note, PagerNumber, Promo, Proclamation, Rank, Redirect, Resolution, Score, ScoreHistorical, Staff, Stat, local: { muted: new LocalStorage('muted') } };
this.db = {
Customer,
CustomerPortal,
ExecutiveOrder,
File,
Inquiry,
Member,
Merchant,
Moderation,
Motion,
Note,
PagerNumber,
Promo,
Proclamation,
Rank,
Redirect,
Resolution,
SAA,
Score,
ScoreHistorical,
Staff,
Stat,
local: { muted: new LocalStorage('muted') },
};
}
get report() {

View File

@ -138,17 +138,27 @@ export default class Queue {
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.`);
if (chan) {
let description = `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.`;
if (application.token) description += `\n\n*This document provides detailed information about the decision given to you by EDS.*: https://eds.libraryofcode.org/dec/${application.token}`;
embed.setDescription(description);
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 });
try {
await chan.createMessage({ embed });
} catch {
await channel.createMessage('**We were not able to send the decision of your application to your DMs. Please contact the Staff Team for further information.**');
}
await channel.createMessage({ embed: new RichEmbed().setTitle('Application Decision').setDescription('The decision of your application has been sent to your DMs.').setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL)
.setTimestamp() });
} else {
await channel.createMessage('**We were not able to send the decision of your application to your DMs. Please contact the Staff Team for further information.**');
}
if (job.data.func) {
const func = eval(job.data.func);
if (application.status === 'SUCCESS' && application.decision === 'APPROVED') await func(this.client, job.data.userID);

View File

@ -18,6 +18,7 @@ export { default as eval } from './eval';
export { default as game } from './game';
export { default as help } from './help';
export { default as info } from './info';
export { default as pulldata } from './inquiry';
export { default as intercom } from './intercom';
export { default as kick } from './kick';
export { default as listredirects } from './listredirects';
@ -30,10 +31,10 @@ export { default as offer } from './offer';
export { default as page } from './page';
export { default as ping } from './ping';
export { default as profile } from './profile';
export { default as pulldata } from './pulldata';
export { default as rank } from './rank';
export { default as role } from './role';
export { default as roleinfo } from './roleinfo';
export { default as saa } from './saa';
export { default as score } from './score';
export { default as sip } from './sip';
export { default as site } from './site';

102
src/commands/inquiry.ts Normal file
View File

@ -0,0 +1,102 @@
/* eslint-disable no-continue */
/* eslint-disable default-case */
import { Message } from 'eris';
import { Client, Command, RichEmbed } from '../class';
import { getTotalMessageCount } from '../intervals/score';
import Inquiry_Remove from './inquiry_rm';
export default class Inquiry extends Command {
constructor(client: Client) {
super(client);
this.name = 'inquiry';
this.description = 'Retrieves information about a hard inquiry that was performed on a member.';
this.usage = `${this.client.config.prefix}inquiry <reportID>`;
this.aliases = ['inq', 'pulldata'];
this.permissions = 5;
this.guildOnly = true;
this.enabled = true;
this.subcmds = [Inquiry_Remove];
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const inquiry = await this.client.db.Inquiry.findOne({ iid: args[0] });
if (!inquiry) return this.error(message.channel, 'Could not locate Inquiry information.');
const currentReport = await this.client.db.Score.findOne({ userID: inquiry.userID });
if (!currentReport) return this.error(message.channel, 'Could not find Community Report for this user.');
const member = this.client.util.resolveMember(inquiry.userID, this.mainGuild);
if (!member) return this.error(message.channel, 'Could not locate member.');
const { report } = inquiry;
// if (!report) return this.error(message.channel, 'Could not find inquiry information.');
await this.client.report.createInquiry(member.id, 'Library of Code sp-us | Bureau of Community Reports', 1);
const embed = new RichEmbed();
embed.setTitle(`Hard Inquiry Information - ${inquiry.iid}`);
embed.setAuthor(member.username, member.user.avatarURL);
let currentScore = '0';
if (currentReport.total < 200) currentScore = '---';
else if (currentReport.total > 800) currentScore = '800';
else currentScore = `${currentReport.total}`;
embed.setDescription(`**Current Community Score:** ${currentScore}\n\n**Department/Service:** ${inquiry.name || 'N/A'}\n**Reason:** ${inquiry.reason || 'N/A'}`);
let totalScore = '0';
let activityScore = '0';
let moderationScore = '0';
let roleScore = '0';
let cloudServicesScore = '0';
let otherScore = '0';
let miscScore = '0';
if (report.total < 200) totalScore = '---';
else if (report.total > 800) totalScore = '800';
else totalScore = `${report.total}`;
if (report.activity < 10) activityScore = '---';
else if (report.activity > Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))) activityScore = String(Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12)));
else activityScore = `${report.activity}`;
if (report.roles <= 0) roleScore = '---';
else if (report.roles > 54) roleScore = '54';
else roleScore = `${report.roles}`;
moderationScore = `${report.moderation}`;
if (report.other === 0) otherScore = '---';
else otherScore = `${report.other}`;
if (report.staff <= 0) miscScore = '---';
else miscScore = `${report.staff}`;
if (report.cloudServices === 0) cloudServicesScore = '---';
else if (report.cloudServices > 10) cloudServicesScore = '10';
else cloudServicesScore = `${report.cloudServices}`;
let color = '🔴';
let additionalText = 'POOR';
embed.setColor('FF0000');
if (report.total >= 550) { color = '🟠'; additionalText = 'FAIR'; embed.setColor('FFA500'); }
if (report.total >= 630) { color = '🟡'; additionalText = 'GOOD'; embed.setColor('FFFF00'); }
if (report.total >= 700) { color = '🟢'; additionalText = 'EXCELLENT'; embed.setColor('66FF66'); }
if (report.total >= 770) { color = '✨'; additionalText = 'EXCEPTIONAL'; embed.setColor('#99FFFF'); }
embed.addField('Total | 200 to 800', report ? `${color} ${totalScore} | ${additionalText}` : 'N/C', true);
embed.addField(`Activity | 10 to ${Math.floor(Math.log1p(getTotalMessageCount(this.client)) * 12)}`, activityScore || 'N/C', true);
embed.addField('Roles | 1 to N/A', roleScore || 'N/C', true);
embed.addField('Moderation | N/A to 2' || 'N/C', moderationScore, true);
embed.addField('Cloud Services | N/A to 10+', cloudServicesScore || 'N/C', true);
embed.addField('Other', otherScore || 'N/C', true);
embed.addField('Misc', miscScore || 'N/C', true);
if (currentReport.pin?.length > 0) {
embed.addField('PIN', currentReport.pin.join('-'), true);
}
embed.setTimestamp(inquiry.date);
embed.setFooter('Inquiry performed on', this.client.user.avatarURL);
return message.channel.createMessage({ embed });
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -0,0 +1,55 @@
import { Message, TextChannel } from 'eris';
import { apply as Apply } from '.';
import { Client, Command, RichEmbed } from '../class';
export default class Inquiry_Remove extends Command {
public applyCommand: Apply;
constructor(client: Client) {
super(client);
this.name = 'rm';
this.description = 'Removes a Hard Inquiry.';
this.usage = `${this.client.config.prefix}inquiry rm <inquiry id>`;
this.aliases = ['remove', 'delete'];
this.permissions = 2;
this.guildOnly = true;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const inquiry = await this.client.db.Inquiry.findOne({ iid: args[0] });
if (!inquiry) return this.error(message.channel, 'Unable to find Inquiry.');
const member = await this.client.util.resolveMember(inquiry.userID, this.mainGuild);
if (!member) return this.error(message.channel, 'Unable to locate member.');
const report = await this.client.db.Score.findOne({ userID: member.id });
if (!report) return this.error(message.channel, 'Unable to locate Community Report.');
if (inquiry.type !== 0) return this.error(message.channel, 'You can only remove Hard Inquiries.');
await this.client.db.Inquiry.deleteOne({ iid: args[0] });
const embed = new RichEmbed();
embed.setTitle('Inquiry - Removed');
embed.addField('Member', `${member.username}#${member.discriminator} | <@${member.id}>`, true);
embed.addField('Department/Service', inquiry.name || 'N/A');
embed.addField('Reason', inquiry.reason || 'N/A');
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp(inquiry.date || new Date());
const log = <TextChannel> this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed });
const chan = await this.client.getDMChannel(member.id);
if (chan) {
chan.createMessage({ embed }).catch(() => {});
}
return this.success(message.channel, 'Inquiry successfully deleted.');
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -1,97 +0,0 @@
/* eslint-disable no-continue */
/* eslint-disable default-case */
import { Message, TextChannel } from 'eris';
import { Client, Command, RichEmbed } from '../class';
import { getTotalMessageCount } from '../intervals/score';
export default class Score extends Command {
constructor(client: Client) {
super(client);
this.name = 'pulldata';
this.description = 'Retrieves information about a hard inquiry that was performed on a member.';
this.usage = `${this.client.config.prefix}pulldata <userID> <reportID>`;
this.aliases = ['inq'];
this.permissions = 5;
this.guildOnly = true;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
try {
if (!args[1]) return this.client.commands.get('help').run(message, [this.name]);
const member = this.client.util.resolveMember(args[0], this.mainGuild);
if (!member) return this.error(message.channel, 'Could not locate member.');
const score = await this.client.db.Score.findOne({ userID: member.id });
if (!score) return this.error(message.channel, 'Could not find Community Report for this user.');
const report = score.inquiries.find((inq) => inq.id === args[1]);
if (!report) return this.error(message.channel, 'Could not find inquiry information.');
await this.client.report.createInquiry(member.id, 'Library of Code sp-us | Bureau of Community Reports', 1);
const embed = new RichEmbed();
embed.setTitle(`Hard Inquiry Information - ${report.id}`);
embed.setAuthor(member.username, member.user.avatarURL);
let currentScore = '0';
if (score.total < 200) currentScore = '---';
else if (score.total > 800) currentScore = '800';
else currentScore = `${score.total}`;
embed.setDescription(`**Current Community Score:** ${currentScore}\n\n**Department/Service:** ${report.name || 'N/A'}\n**Reason:** ${report.reason || 'N/A'}`);
let totalScore = '0';
let activityScore = '0';
let moderationScore = '0';
let roleScore = '0';
let cloudServicesScore = '0';
let otherScore = '0';
let miscScore = '0';
if (score.total < 200) totalScore = '---';
else if (score.total > 800) totalScore = '800';
else totalScore = `${score.total}`;
if (score.activity < 10) activityScore = '---';
else if (score.activity > Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))) activityScore = String(Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12)));
else activityScore = `${score.activity}`;
if (score.roles <= 0) roleScore = '---';
else if (score.roles > 54) roleScore = '54';
else roleScore = `${score.roles}`;
moderationScore = `${score.moderation}`;
if (score.other === 0) otherScore = '---';
else otherScore = `${score.other}`;
if (score.staff <= 0) miscScore = '---';
else miscScore = `${score.staff}`;
if (score.cloudServices === 0) cloudServicesScore = '---';
else if (score.cloudServices > 10) cloudServicesScore = '10';
else cloudServicesScore = `${score.cloudServices}`;
let color = '🔴';
let additionalText = 'POOR';
embed.setColor('FF0000');
if (score.total >= 550) { color = '🟠'; additionalText = 'FAIR'; embed.setColor('FFA500'); }
if (score.total >= 630) { color = '🟡'; additionalText = 'GOOD'; embed.setColor('FFFF00'); }
if (score.total >= 700) { color = '🟢'; additionalText = 'EXCELLENT'; embed.setColor('66FF66'); }
if (score.total >= 770) { color = '✨'; additionalText = 'EXCEPTIONAL'; embed.setColor('#99FFFF'); }
embed.addField('Total | 200 to 800', score ? `${color} ${totalScore} | ${additionalText}` : 'N/C', true);
embed.addField(`Activity | 10 to ${Math.floor(Math.log1p(getTotalMessageCount(this.client)) * 12)}`, activityScore || 'N/C', true);
embed.addField('Roles | 1 to N/A', roleScore || 'N/C', true);
embed.addField('Moderation | N/A to 2' || 'N/C', moderationScore, true);
embed.addField('Cloud Services | N/A to 10+', cloudServicesScore || 'N/C', true);
embed.addField('Other', otherScore || 'N/C', true);
embed.addField('Misc', miscScore || 'N/C', true);
if (score.pin?.length > 0) {
embed.addField('PIN', score.pin.join('-'), true);
}
embed.setTimestamp(report.date);
embed.setFooter('Inquiry performed on', this.client.user.avatarURL);
return message.channel.createMessage({ embed });
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -65,7 +65,7 @@ export default class Role extends Command {
// if (stop) return;
rolesToAdd.forEach((role) => member.addRole(role.id));
rolesToRemove.forEach((role) => member.removeRole(role.id));
return this.success(message.channel, `Changed the roles for ${member.username}#${member.discriminator}${rolesToAdd.length > 0 ? `, added \`${rolesToAdd.map((r) => r.name).join('`, `')}\`` : ''}${rolesToRemove.length > 0 ? `, removed \`${rolesToRemove.map((r) => r.name).join('`, `')}\`` : ''}`);
return this.success(message.channel, `Changed roles for ${member.username}#${member.discriminator}${rolesToAdd.length > 0 ? `, added \`${rolesToAdd.map((r) => r.name).join('`, `')}\`` : ''}${rolesToRemove.length > 0 ? `, removed \`${rolesToRemove.map((r) => r.name).join('`, `')}\`` : ''}`);
} catch (err) {
return this.client.util.handleError(err, message, this);
}

View File

@ -1,5 +1,5 @@
import moment from 'moment';
import { Message, Role } from 'eris';
import { Message } from 'eris';
import { Client, Command, RichEmbed } from '../class';
export default class Roleinfo extends Command {

112
src/commands/saa.ts Normal file
View File

@ -0,0 +1,112 @@
import { Message, TextChannel } from 'eris';
import { apply as Apply } from '.';
import { Client, Command, RichEmbed } from '../class';
import SAA_Approve from './saa_approve';
import SAA_Decline from './saa_decline';
export default class StaffAssistedApplication extends Command {
public applyCommand: Apply;
constructor(client: Client) {
super(client);
this.name = 'saa';
this.description = 'Executes a Staff-assisted Application (SAA).';
this.usage = `${this.client.config.prefix}saa <memberID> <serviceName>`;
this.permissions = 2;
this.guildOnly = true;
this.enabled = true;
this.subcmds = [SAA_Approve, SAA_Decline];
this.applyCommand = <Apply> this.client.commands.get('apply');
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const member = this.client.util.resolveMember(args[0], this.mainGuild);
if (!member) return this.error(message.channel, 'Unable to locate member.');
const report = await this.client.db.Score.findOne({ userID: member.id }).lean().exec();
if (!report) return this.error(message.channel, 'Unable to locate Community Report.');
const staff = await this.client.db.Staff.findOne({ userID: message.author.id }).lean().exec();
if (!staff) return this.error(message.channel, 'Unable to locate Staff information.');
const service = this.applyCommand.services.get(args[1]);
if (!service) return this.error(message.channel, 'Invalid service code.');
if (service.type !== 'HARD') return this.error(message.channel, 'SAAs cannot be ran for services that do not require a Hard Inquiry or pre-approvals.');
const preValidationTest = await service.validation(member);
if (!preValidationTest) return this.error(message.channel, 'This member does not meet pre-validation requirements. A SAA cannot be executed.');
const loading = await this.loading(message.channel, 'Processing application with EDS. Please hold on a moment.');
const application = await Apply.apply(this.client, service.url, member.id);
await (new this.client.db.SAA({
userID: member.id,
applicationID: application.id,
serviceCode: args[1],
edsToken: application.token,
})).save();
await this.client.commands.get('score').run(message, [message.author.id, 'soft']);
const edsEmbed = new RichEmbed();
edsEmbed.setTitle('Decision from EDS');
if (member) {
edsEmbed.setAuthor(member.username, member.avatarURL);
}
if (application.decision === 'APPROVED') {
edsEmbed.setColor('#50c878');
} else if (application.decision === 'DECLINED') {
edsEmbed.setColor('#fe0000');
} else if (application.decision === 'PRE-DECLINE') {
edsEmbed.setColor('#ffa500');
} else {
edsEmbed.setColor('#eeeeee');
}
let description = `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 this application if needed.`;
if (application.token) description += `\n\n*This document provides detailed information about the decision given by EDS.*: https://eds.libraryofcode.org/dec/${application.token}`;
edsEmbed.setDescription(description);
edsEmbed.addField('Status', application.decision, true);
edsEmbed.addField('User ID', member.id, true);
edsEmbed.addField('Application ID', application.id, true);
edsEmbed.setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL);
edsEmbed.setTimestamp();
await message.channel.createMessage({ embed: edsEmbed });
const embed = new RichEmbed();
embed.setTitle('Information Panel');
embed.setDescription('You have been provided with a full report as well as a recommendation from EDS. You should use the information from the Community Report as well as EDS\' recommendation, and other information (such as ?whois, historical report, notes, ect.) to make your decision. If you need assistance, please page a Director.');
embed.addField('Approve', `Run \`${this.client.config.prefix}saa approve ${application.id}\``);
embed.addField('Decline', `Run \`${this.client.config.prefix}saa decline ${application.id}\``);
embed.setFooter(`${this.client.user.username} | Staff-assisted Application via Electronic Decision Service [EDS]`, this.client.user.avatarURL);
embed.setTimestamp();
await message.channel.createMessage({ embed });
const notificationEmbed = new RichEmbed();
notificationEmbed.setTitle('Staff Assisted Application - Queued');
notificationEmbed.setColor('#50c878');
// eslint-disable-next-line no-useless-escape
notificationEmbed.addField('User', `${member.username}#${member.discriminator} | XXX-XX-${report.pin[2]}`);
notificationEmbed.addField('Decision', 'PROCESSING');
notificationEmbed.addField('Initiated by', `${message.author.username}, ${staff.pn.slice(0, 2).join(', ')} *on behalf of Library of Code sp-us*`);
notificationEmbed.addField('Application ID', application.id);
notificationEmbed.addField('Service Code', args[1]);
notificationEmbed.setFooter(this.client.user.username, this.client.user.avatarURL);
notificationEmbed.setTimestamp();
const log = <TextChannel> this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed: notificationEmbed });
notificationEmbed.setDescription('*A Staff Assisted Application has been queued in your name. If you didn\'t request a SAA to be ran, please contact the Staff Team as soon as possible.\nYou should receive a decision soon, if you do not receive a decision within 72 hours please contact the Staff Team for further information.*');
const chan = await this.client.getDMChannel(member.id);
chan.createMessage({ embed: notificationEmbed }).then(() => this.success(message.channel, 'SAA successfully queued.')).catch(() => this.error(message.channel, 'Unable to deliver notification to user.'));
loading.delete().catch(() => {});
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -0,0 +1,59 @@
import { Message, TextChannel } from 'eris';
import { apply as Apply } from '.';
import { Client, Command, RichEmbed } from '../class';
export default class SAA_Approve extends Command {
public applyCommand: Apply;
constructor(client: Client) {
super(client);
this.name = 'approve';
this.description = 'Approves a Staff-assisted Application (SAA).';
this.usage = `${this.client.config.prefix}saa approve <applicationID>`;
this.permissions = 4;
this.guildOnly = true;
this.enabled = true;
this.applyCommand = <Apply> this.client.commands.get('apply');
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const saa = await this.client.db.SAA.findOne({ applicationID: args[0] }).lean().exec();
if (!saa) return this.error(message.channel, 'Unable to locate SAA.');
const member = this.client.util.resolveMember(saa.userID, this.mainGuild);
if (!member) return this.error(message.channel, 'Unable to locate member.');
const report = await this.client.db.Score.findOne({ userID: saa.userID }).lean().exec();
if (!report) return this.error(message.channel, 'Unable to locate Community Report.');
const staff = await this.client.db.Staff.findOne({ userID: message.author.id }).lean().exec();
if (!staff) return this.error(message.channel, 'Unable to locate Staff information.');
await this.applyCommand.services.get(saa.serviceCode).func(this.client, member.id);
const embed = new RichEmbed();
embed.setTitle('Staff Assisted Application - Decision');
embed.setColor('#50c878');
// eslint-disable-next-line no-useless-escape
embed.addField('User', `${member.username}#${member.discriminator} | XXX-XX-${report.pin[2]}`);
embed.addField('Decision', 'APPROVED');
embed.addField('Underwriter', `${message.author.username}, ${staff.pn.slice(0, 2).join(', ')} *on behalf of Library of Code sp-us*`);
embed.addField('Application ID', saa.applicationID);
embed.addField('Service Code', saa.serviceCode);
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
const log = <TextChannel> this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed });
embed.setDescription(`*A SAA has been ran in your name for a service, this embed contains the information about the result of that decision.*\n\nAccess link to the EDS recommendation for this decision: https://eds.libraryofcode.org/dec/${saa.edsToken}`);
const chan = await this.client.getDMChannel(saa.userID);
chan.createMessage({ embed }).then(() => this.success(message.channel, 'SAA successfully processed.')).catch(() => this.error(message.channel, 'Unable to deliver decision to user.'));
await this.client.db.SAA.deleteOne({ _id: saa._id }).lean().exec();
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -0,0 +1,57 @@
import { Message, TextChannel } from 'eris';
import { apply as Apply } from '.';
import { Client, Command, RichEmbed } from '../class';
export default class SAA_Decline extends Command {
public applyCommand: Apply;
constructor(client: Client) {
super(client);
this.name = 'decline';
this.description = 'Declines a Staff-assisted Application (SAA).';
this.usage = `${this.client.config.prefix}saa decline <applicationID>`;
this.permissions = 4;
this.guildOnly = true;
this.enabled = true;
this.applyCommand = <Apply> this.client.commands.get('apply');
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const saa = await this.client.db.SAA.findOne({ applicationID: args[0] }).lean().exec();
if (!saa) return this.error(message.channel, 'Unable to locate SAA.');
const member = this.client.util.resolveMember(saa.userID, this.mainGuild);
if (!member) return this.error(message.channel, 'Unable to locate member.');
const report = await this.client.db.Score.findOne({ userID: saa.userID }).lean().exec();
if (!report) return this.error(message.channel, 'Unable to locate Community Report.');
const staff = await this.client.db.Staff.findOne({ userID: message.author.id }).lean().exec();
if (!staff) return this.error(message.channel, 'Unable to locate Staff information.');
const embed = new RichEmbed();
embed.setTitle('Staff Assisted Application - Decision');
embed.setColor('#fe0000');
// eslint-disable-next-line no-useless-escape
embed.addField('User', `${member.username}#${member.discriminator} | XXX-XX-${report.pin[2]}`);
embed.addField('Decision', 'DECLINED');
embed.addField('Underwriter', `${message.author.username}, ${staff.pn.slice(0, 2).join(', ')} *on behalf of Library of Code sp-us*`);
embed.addField('Application ID', saa.applicationID);
embed.addField('Service Code', saa.serviceCode);
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
const log = <TextChannel> this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed });
embed.setDescription(`*A SAA has been ran in your name for a service, this embed contains the information about the result of that decision.*\n\nAccess link to the EDS recommendation for this decision: https://eds.libraryofcode.org/dec/${saa.edsToken}`);
const chan = await this.client.getDMChannel(saa.userID);
chan.createMessage({ embed }).then(() => this.success(message.channel, 'SAA successfully processed.')).catch(() => this.error(message.channel, 'Unable to deliver decision to user.'));
await this.client.db.SAA.deleteOne({ _id: saa._id }).lean().exec();
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

17
src/models/SAA.ts Normal file
View File

@ -0,0 +1,17 @@
import { Document, Schema, model } from 'mongoose';
export interface SAAInterface extends Document {
userID: string,
applicationID: string,
serviceCode: string,
edsToken: string,
}
const SAA: Schema = new Schema({
userID: String,
applicationID: String,
serviceCode: String,
edsToken: String,
});
export default model<SAAInterface>('SAA', SAA);

View File

@ -14,6 +14,7 @@ export { default as Proclamation, ProclamationInterface } from './Proclamation';
export { default as Rank, RankInterface } from './Rank';
export { default as Redirect, RedirectInterface, RedirectRaw } from './Redirect';
export { default as Resolution, ResolutionInterface } from './Resolution';
export { default as SAA, SAAInterface } from './SAA';
export { default as Score, ScoreInterface, ScoreInterfaceRaw } from './Score';
export { default as ScoreHistorical, ScoreHistoricalInterface } from './ScoreHistorical';
export { default as Staff, StaffInterface } from './Staff';

View File

@ -2094,6 +2094,22 @@ ioredis@^4.22.0:
redis-parser "^3.0.0"
standard-as-callback "^2.1.0"
ioredis@^4.26.0:
version "4.26.0"
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.26.0.tgz#dbbfb5e5da085fc2b1de8174db50fa42f9fed66a"
integrity sha512-nh39okWezWWZ35/RxXXzHksMFt4WCaev8SNO2kozRDeVdEAJj16EarqPP3JeHz8IEjEXN5CiVtbWMk62Z0eveQ==
dependencies:
cluster-key-slot "^1.1.0"
debug "^4.3.1"
denque "^1.1.0"
lodash.defaults "^4.2.0"
lodash.flatten "^4.4.0"
p-map "^2.1.0"
redis-commands "1.7.0"
redis-errors "^1.2.0"
redis-parser "^3.0.0"
standard-as-callback "^2.1.0"
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"