Merge remote-tracking branch 'upstream/master' into profile

merge-requests/19/head
Hiroyuki 2021-03-05 22:16:07 -04:00
commit 5a9738d560
No known key found for this signature in database
GPG Key ID: C15AC26538975A24
33 changed files with 546 additions and 310 deletions

View File

@ -2,7 +2,7 @@
We accept contributions from the community, however there's a few steps you need to do first before you're able to fork the project. We accept contributions from the community, however there's a few steps you need to do first before you're able to fork the project.
1. Join the [Discord Server](https://discord.gg/F4ztpQh). 1. Join the [Discord Server](https://loc.sh/discord).
2. Send a DM to @Ramirez in the server, provide your GitLab username. 2. Send a DM to @Ramirez in the server, provide your GitLab username.
3. We'll let you know when you'll be able to fork the project. 3. We'll let you know when you'll be able to fork the project.

View File

@ -1,5 +1,5 @@
{ {
"name": "loccommunityrelations", "name": "loccr",
"version": "1.0.0", "version": "1.0.0",
"description": "The official system for handling Community Relations in the LOC Discord server.", "description": "The official system for handling Community Relations in the LOC Discord server.",
"main": "build/main.js", "main": "build/main.js",
@ -7,7 +7,7 @@
"lint": "eslint -c ./.eslintrc.json src --ext ts" "lint": "eslint -c ./.eslintrc.json src --ext ts"
}, },
"repository": "https://gitlab.libraryofcode.org/engineering/communityrelations.git", "repository": "https://gitlab.libraryofcode.org/engineering/communityrelations.git",
"author": "Matthew R <matthew@staff.libraryofcode.org>", "author": "Matthew R, AD, FSEN <matthew@staff.libraryofcode.org>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"private": false, "private": false,
"devDependencies": { "devDependencies": {
@ -29,7 +29,8 @@
"eslint": "^7.19.0", "eslint": "^7.19.0",
"eslint-config-airbnb-base": "^14.1.0", "eslint-config-airbnb-base": "^14.1.0",
"eslint-plugin-import": "^2.20.2", "eslint-plugin-import": "^2.20.2",
"typescript": "^3.9.8" "tslib": "^2.1.0",
"typescript": "^3.9.2"
}, },
"dependencies": { "dependencies": {
"@google-cloud/text-to-speech": "^3.1.2", "@google-cloud/text-to-speech": "^3.1.2",
@ -55,7 +56,8 @@
"puppeteer": "^5.5.0", "puppeteer": "^5.5.0",
"sd-notify": "^2.8.0", "sd-notify": "^2.8.0",
"signale": "^1.4.0", "signale": "^1.4.0",
"stripe": "^8.135.0", "stock-info": "^1.2.0",
"stripe": "^8.120.0",
"uuid": "^8.0.0", "uuid": "^8.0.0",
"yaml": "^1.9.2" "yaml": "^1.9.2"
} }

View File

@ -1,9 +1,8 @@
/* eslint-disable no-bitwise */ /* eslint-disable no-bitwise */
/* eslint-disable no-continue */ /* eslint-disable no-continue */
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { v4 as uuid } from 'uuid';
import { TextChannel } from 'eris'; import { TextChannel } from 'eris';
import { LocalStorage, Route, Server, RichEmbed } from '../../../class'; import { LocalStorage, Route, Server } from '../../../class';
import { ScoreHistoricalRaw } from '../../../models/ScoreHistorical'; import { ScoreHistoricalRaw } from '../../../models/ScoreHistorical';
import { getTotalMessageCount } from '../../../intervals/score'; import { getTotalMessageCount } from '../../../intervals/score';
@ -128,11 +127,12 @@ export default class Report extends Route {
else if (member.cloudServices > 10) cloudServicesScore = 10; else if (member.cloudServices > 10) cloudServicesScore = 10;
else cloudServicesScore = Math.round(member.cloudServices); else cloudServicesScore = Math.round(member.cloudServices);
const inqs = await this.server.client.db.Inquiry.find({ userID: member.userID }).lean().exec();
const inquiries: [{ id?: string, name: string, date: Date }?] = []; const inquiries: [{ id?: string, name: string, date: Date }?] = [];
if (member.inquiries?.length > 0) { if (inqs?.length > 0) {
for (const inq of member.inquiries) { for (const inq of inqs) {
const testDate = (new Date(new Date(inq.date).setHours(1460))); const testDate = (new Date(new Date(inq.date).setHours(1460)));
if (testDate > new Date()) inquiries.push({ id: inq.id, name: inq.name, date: inq.date }); if (testDate > new Date()) inquiries.push({ id: inq.iid, name: inq.name, date: inq.date });
} }
} }
@ -173,35 +173,14 @@ export default class Report extends Route {
array.push(data); array.push(data);
} }
if (member.notify) { const inq = await this.server.client.report.createInquiry(member.userID, merchant.name, 0, req.body.reason);
const chan = await this.server.client.getDMChannel(member.userID);
try {
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:** ${merchant.name.toUpperCase()}`);
} catch (err) {
this.server.client.util.signale.error(`Unable to DM user: ${member.userID} | ${err}`);
}
}
await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 0, reason: req.body.reason, date: new Date() } } }); await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 0, reason: req.body.reason, date: new Date() } } });
const reportID = uuid();
await this.server.client.db.Score.updateOne({ userID: member.userID }, { $addToSet: { inquiries: { id: reportID, name: merchant.name, reason: req.body.reason, date: new Date(), report: member } } });
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setDescription(reportID);
embed.setColor('#800080');
embed.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${member.userID}>`, true);
embed.addField('Type', 'HARD', true);
embed.addField('Department/Service', merchant.name.toUpperCase(), true);
embed.addField('Reason', req.body.reason ?? 'N/A', true);
embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL);
const chan = <TextChannel>this.server.client.guilds.get(this.server.client.config.guildID).channels.get('611584771356622849');
chan.createMessage({ embed }).catch(() => { });
return res.status(200).json({ return res.status(200).json({
code: this.constants.codes.SUCCESS, code: this.constants.codes.SUCCESS,
message: { message: {
id: reportID, id: inq.id,
userID: member.userID, userID: member.userID,
memberInformation: { memberInformation: {
username: mem.user.username, username: mem.user.username,
@ -237,35 +216,24 @@ export default class Report extends Route {
const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec();
if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED });
const member = await this.server.client.db.Score.findOne({ userID: req.body.userID }).lean().exec(); const report = await this.server.client.db.Score.findOne({ userID: req.body.userID }).lean().exec();
if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); if (!report) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED });
let totalScore: number; let totalScore: number;
if (member.total < 200) totalScore = 0; if (report.total < 200) totalScore = 0;
else if (member.total > 800) totalScore = 800; else if (report.total > 800) totalScore = 800;
else totalScore = Math.round(member.total); else totalScore = Math.round(report.total);
await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 1, reason: 'N/A', date: new Date() } } }); await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 1, reason: 'N/A', date: new Date() } } });
await this.server.client.db.Score.updateOne({ userID: member.userID }, { $addToSet: { softInquiries: { name: merchant.name, date: new Date() } } }); const mem = this.server.client.util.resolveMember(report.userID, this.server.client.guilds.get(this.server.client.config.guildID));
const embed = new RichEmbed(); await this.server.client.report.createInquiry(report.userID, merchant.name.toUpperCase(), 1);
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
const mem = this.server.client.util.resolveMember(member.userID, this.server.client.guilds.get(this.server.client.config.guildID));
if (!mem) return res.status(404).json({ code: this.constants.codes.NOT_FOUND, message: this.constants.codes.NOT_FOUND });
embed.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${member.userID}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', merchant.name.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL);
const chan = <TextChannel>this.server.client.guilds.get(this.server.client.config.guildID).channels.get('611584771356622849');
chan.createMessage({ embed }).catch(() => { });
if (!merchant.privileged) { if (!merchant.privileged) {
return res.status(200).json({ return res.status(200).json({
code: this.constants.codes.SUCCESS, code: this.constants.codes.SUCCESS,
message: { message: {
userID: member.userID, userID: report.userID,
totalScore, totalScore,
}, },
}); });
@ -287,36 +255,38 @@ export default class Report extends Route {
if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER'); if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER');
} }
const set = []; const set = [];
const accounts = await this.server.client.db.Score.find().lean().exec(); if (req.query.p?.toString() === 'true') {
for (const sc of accounts) { const accounts = await this.server.client.db.Score.find().lean().exec();
if (sc.total < 200) { continue; } for (const sc of accounts) {
if (sc.total > 800) { set.push(800); continue; } if (sc.total < 200) { continue; }
set.push(sc.total); if (sc.total > 800) { set.push(800); continue; }
set.push(sc.total);
}
} }
let activityScore: number; let activityScore: number;
const moderationScore = Math.round(member.moderation); const moderationScore = Math.round(report.moderation);
let roleScore: number; let roleScore: number;
let cloudServicesScore: number; let cloudServicesScore: number;
const otherScore = Math.round(member.other); const otherScore = Math.round(report.other);
let miscScore: number; let miscScore: number;
if (member.activity < 10) activityScore = 0; if (report.activity < 10) activityScore = 0;
else if (member.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); else if (report.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12));
else activityScore = Math.round(member.activity); else activityScore = Math.round(report.activity);
if (member.roles <= 0) roleScore = 0; if (report.roles <= 0) roleScore = 0;
else if (member.roles > 54) roleScore = 54; else if (report.roles > 54) roleScore = 54;
else roleScore = Math.round(member.roles); else roleScore = Math.round(report.roles);
if (member.staff <= 0) miscScore = 0; if (report.staff <= 0) miscScore = 0;
else miscScore = Math.round(member.staff); else miscScore = Math.round(report.staff);
if (member.cloudServices === 0) cloudServicesScore = 0; if (report.cloudServices === 0) cloudServicesScore = 0;
else if (member.cloudServices > 10) cloudServicesScore = 10; else if (report.cloudServices > 10) cloudServicesScore = 10;
else cloudServicesScore = Math.round(member.cloudServices); else cloudServicesScore = Math.round(report.cloudServices);
const historicalData = await this.server.client.db.ScoreHistorical.find({ userID: member.userID }).lean().exec(); const historicalData = await this.server.client.db.ScoreHistorical.find({ userID: report.userID }).lean().exec();
const array: ScoreHistoricalRaw[] = []; const array: ScoreHistoricalRaw[] = [];
for (const data of historicalData) { for (const data of historicalData) {
delete data.report?.softInquiries; delete data.report?.softInquiries;
@ -357,7 +327,7 @@ export default class Report extends Route {
return res.status(200).json({ return res.status(200).json({
code: this.constants.codes.SUCCESS, code: this.constants.codes.SUCCESS,
message: { message: {
userID: member.userID, userID: report.userID,
memberInformation: { memberInformation: {
username: mem.user.username, username: mem.user.username,
discriminator: mem.user.discriminator, discriminator: mem.user.discriminator,
@ -368,7 +338,7 @@ export default class Report extends Route {
nitroBoost: mem.premiumSince === null, nitroBoost: mem.premiumSince === null,
}, },
totalScore, totalScore,
percentile: Math.round(this.server.client.util.percentile(set, member.total)), percentile: Math.round(this.server.client.util.percentile(set, report.total)),
activityScore, activityScore,
moderationScore, moderationScore,
roleScore, roleScore,
@ -403,17 +373,7 @@ export default class Report extends Route {
else totalScore = Math.round(member.total); else totalScore = Math.round(member.total);
await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 1, reason: 'N/A', date: new Date() } } }); await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 1, reason: 'N/A', date: new Date() } } });
await this.server.client.db.Score.updateOne({ userID: member.userID }, { $addToSet: { softInquiries: { name: merchant.name, date: new Date() } } }); await this.server.client.report.createInquiry(member.userID, merchant.name.toUpperCase(), 1);
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
embed.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${member.userID}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', merchant.name.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL);
const chan = <TextChannel>this.server.client.guilds.get(this.server.client.config.guildID).channels.get('611584771356622849');
chan.createMessage({ embed }).catch(() => { });
if (!merchant.privileged) { if (!merchant.privileged) {
return res.status(200).json({ return res.status(200).json({
@ -486,42 +446,12 @@ export default class Report extends Route {
this.timeout.delete(req.ip); this.timeout.delete(req.ip);
if (staffScore.userID === score.userID) { if (staffScore.userID === score.userID) {
updated = true; updated = true;
await this.server.client.db.Score.updateOne({ userID: score.userID }, { $addToSet: { softInquiries: { name: `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, date: new Date() } } }); await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1);
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${member.user.id}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', `${member.username} via report.libraryofcode.org @ IP ${req.ip}`.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL);
const chan = <TextChannel>this.server.client.guilds.get(this.server.client.config.guildID).channels.get('611584771356622849');
chan.createMessage({ embed }).catch(() => { });
} else { } else {
await this.server.client.db.Score.updateOne({ userID: score.userID }, { $addToSet: { softInquiries: { name: 'Library of Code sp-us | Staff Team via report.libraryofcode.org', date: new Date() } } }); await this.server.client.report.createInquiry(member.user.id, 'Library of Code sp-us | Staff Team via report.libraryofcode.org', 1);
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${member.user.id}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', 'Library of Code sp-us | Staff Team via report.libraryofcode.org'.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL);
const chan = <TextChannel>this.server.client.guilds.get(this.server.client.config.guildID).channels.get('611584771356622849');
chan.createMessage({ embed }).catch(() => { });
} }
} else if (!updated) { } else if (!updated) {
await this.server.client.db.Score.updateOne({ userID: score.userID }, { $addToSet: { softInquiries: { name: `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, date: new Date() } } }); await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1);
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${member.user.id}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', `${member.username} via report.libraryofcode.org @ IP ${req.ip}`.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.server.client.user.username, this.server.client.user.avatarURL);
const chan = <TextChannel>this.server.client.guilds.get(this.server.client.config.guildID).channels.get('611584771356622849');
chan.createMessage({ embed }).catch(() => { });
} }
score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec();
@ -557,7 +487,7 @@ export default class Report extends Route {
else if (score.cloudServices > 10) cloudServicesScore = '10'; else if (score.cloudServices > 10) cloudServicesScore = '10';
else cloudServicesScore = `${score.cloudServices}`; else cloudServicesScore = `${score.cloudServices}`;
const moderations = await this.server.client.db.Moderation.find({ userID: score.userID }); const moderations = await this.server.client.db.Moderation.find({ userID: score.userID }).lean().exec();
const historical = await this.server.client.db.ScoreHistorical.find({ userID: score.userID }).lean().exec(); const historical = await this.server.client.db.ScoreHistorical.find({ userID: score.userID }).lean().exec();
@ -592,6 +522,17 @@ export default class Report extends Route {
data.report.total = total; data.report.activity = activity; data.report.moderation = moderation; data.report.roles = role; data.report.cloudServices = cloud; data.report.other = other; data.report.staff = misc; data.report.total = total; data.report.activity = activity; data.report.moderation = moderation; data.report.roles = role; data.report.cloudServices = cloud; data.report.other = other; data.report.staff = misc;
} }
const inqs = await this.server.client.db.Inquiry.find({ userID: score.userID }).lean().exec();
const hardInquiries: [{ id?: string, name: string, reason: string, date: Date }?] = [];
const softInquiries: [{ id?: string, name: string, date: Date }?] = [];
for (const inq of inqs) {
if (inq.type === 0) {
hardInquiries.push({ id: inq.iid, name: inq.name, reason: inq.reason, date: inq.date });
} else if (inq.type === 1) {
softInquiries.push({ name: inq.name, date: inq.date });
}
}
return res.status(200).json({ return res.status(200).json({
name: `${member.username}#${member.discriminator}`, name: `${member.username}#${member.discriminator}`,
avatarURL: member.avatarURL, avatarURL: member.avatarURL,
@ -607,8 +548,8 @@ export default class Report extends Route {
notify: score.notify, notify: score.notify,
locked: !!score.locked, locked: !!score.locked,
totalModerations: moderations?.length > 0 ? moderations.length : 0, totalModerations: moderations?.length > 0 ? moderations.length : 0,
inquiries: score.inquiries?.length > 0 ? score.inquiries : [], inquiries: hardInquiries?.length > 0 ? hardInquiries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) : [],
softInquiries: score.softInquiries?.length > 0 ? score.softInquiries : [], softInquiries: softInquiries?.length > 0 ? softInquiries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) : [],
historical: historical ?? [], historical: historical ?? [],
lastUpdated: score.lastUpdate, lastUpdated: score.lastUpdate,
}); });

View File

@ -7,20 +7,17 @@ import { Collection, Command, LocalStorage, Queue, Util, ServerManagement, Event
import { import {
Customer, CustomerInterface, Customer, CustomerInterface,
CustomerPortal, CustomerPortalInterface, CustomerPortal, CustomerPortalInterface,
ExecutiveOrder, ExecutiveOrderInterface,
File, FileInterface, File, FileInterface,
Inquiry, InquiryInterface,
Member, MemberInterface, Member, MemberInterface,
Merchant, MerchantInterface, Merchant, MerchantInterface,
Moderation, ModerationInterface, Moderation, ModerationInterface,
Motion, MotionInterface,
NNTrainingData, NNTrainingDataInterface, NNTrainingData, NNTrainingDataInterface,
Note, NoteInterface, Note, NoteInterface,
PagerNumber, PagerNumberInterface, PagerNumber, PagerNumberInterface,
Proclamation, ProclamationInterface,
Promo, PromoInterface, Promo, PromoInterface,
Rank, RankInterface, Rank, RankInterface,
Redirect, RedirectInterface, Redirect, RedirectInterface,
Resolution, ResolutionInterface,
Score, ScoreInterface, Score, ScoreInterface,
ScoreHistorical, ScoreHistoricalInterface, ScoreHistorical, ScoreHistoricalInterface,
Staff, StaffInterface, Staff, StaffInterface,
@ -47,29 +44,7 @@ export default class Client extends eris.Client {
public stripe: Stripe; public stripe: Stripe;
public db: { public db: { Customer: mongoose.Model<CustomerInterface>, CustomerPortal: mongoose.Model<CustomerPortalInterface>, File: mongoose.Model<FileInterface>, Inquiry: mongoose.Model<InquiryInterface>, Member: mongoose.Model<MemberInterface>, Merchant: mongoose.Model<MerchantInterface>, Moderation: mongoose.Model<ModerationInterface>, NNTrainingData: mongoose.Model<NNTrainingDataInterface>, Note: mongoose.Model<NoteInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Promo: mongoose.Model<PromoInterface>, Rank: mongoose.Model<RankInterface>, Redirect: mongoose.Model<RedirectInterface>, Score: mongoose.Model<ScoreInterface>, ScoreHistorical: mongoose.Model<ScoreHistoricalInterface>, Staff: mongoose.Model<StaffInterface>, Stat: mongoose.Model<StatInterface>, local: { muted: LocalStorage } };
Customer: mongoose.Model<CustomerInterface>,
CustomerPortal: mongoose.Model<CustomerPortalInterface>,
ExecutiveOrder: mongoose.Model<ExecutiveOrderInterface>,
File: mongoose.Model<FileInterface>,
Member: mongoose.Model<MemberInterface>,
Merchant: mongoose.Model<MerchantInterface>,
Moderation: mongoose.Model<ModerationInterface>,
Motion: mongoose.Model<MotionInterface>,
NNTrainingData: mongoose.Model<NNTrainingDataInterface>,
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 }
};
constructor(token: string, options?: eris.ClientOptions) { constructor(token: string, options?: eris.ClientOptions) {
super(token, options); super(token, options);
@ -77,9 +52,18 @@ export default class Client extends eris.Client {
this.events = new Collection<Event>(); this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>(); this.intervals = new Collection<NodeJS.Timeout>();
this.queue = new Queue(this); this.queue = new Queue(this);
this.db = { Customer, CustomerPortal, ExecutiveOrder, File, Member, Merchant, Moderation, Motion, NNTrainingData, Note, PagerNumber, Proclamation, Promo, Rank, Redirect, Resolution, Score, ScoreHistorical, Staff, Stat, local: { muted: new LocalStorage('muted') } }; this.db = { Customer, CustomerPortal, File, Inquiry, Member, Merchant, Moderation, NNTrainingData, Note, PagerNumber, Promo, Rank, Redirect, Score, ScoreHistorical, Staff, Stat, local: { muted: new LocalStorage('muted') } };
} }
get report() {
return this.util.report;
}
get pbx() {
return this.util.pbx;
}
public async loadDatabase() { public async loadDatabase() {
await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 }); await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 });

View File

@ -1,9 +1,10 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-eval */ /* eslint-disable no-eval */
import Bull from 'bull'; import Bull from 'bull';
import cron from 'cron'; import cron from 'cron';
import { TextableChannel } from 'eris'; import { TextableChannel, TextChannel } from 'eris';
import { Client, RichEmbed } from '.'; import { Client, RichEmbed } from '.';
import { ScoreInterface } from '../models'; import { ScoreInterface, InqType as InquiryType } from '../models';
import { apply as Apply } from '../commands'; import { apply as Apply } from '../commands';
@ -28,12 +29,13 @@ export default class Queue {
const startDate = new Date(); const startDate = new Date();
for (const report of reports) { for (const report of reports) {
const inqs = await this.client.db.Inquiry.find({ userID: report.userID });
const data = new this.client.db.ScoreHistorical({ const data = new this.client.db.ScoreHistorical({
userID: report.userID, userID: report.userID,
report, report,
inquiries: inqs.map((inq) => inq._id),
date: startDate, date: startDate,
}); });
// eslint-disable-next-line no-await-in-loop
await data.save(); await data.save();
} }
} catch (err) { } catch (err) {
@ -77,6 +79,37 @@ export default class Queue {
} }
protected setProcessors() { 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 }>) => { 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() } }); 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) { if (!job.data.score.pin || job.data.score.pin?.length < 1) {
@ -123,8 +156,12 @@ export default class Queue {
}); });
} }
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) { 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 }); 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) { public processApplication(channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func?: string) {

97
src/class/Report.ts Normal file
View File

@ -0,0 +1,97 @@
import { v4 as uuid } from 'uuid';
import { Client } from '.';
import { InqType } from '../models';
export default class Report {
public client: Client;
constructor(client: Client) {
this.client = client;
}
public async createInquiry(userID: string, name: string, type: InqType, reason?: string) {
const report = await this.client.db.Score.findOne({ userID }).lean().exec();
const member = this.client.util.resolveMember(userID, this.client.guilds.get(this.client.config.guildID));
if (!report || !member) return null;
if (type === InqType.HARD && report.locked) return null;
const mod = await (new this.client.db.Inquiry({
iid: uuid(),
userID,
name,
type,
reason,
date: new Date(),
report,
}).save());
this.client.queue.addInquiry(mod.iid, userID, name, type, reason);
return mod;
}
/* public async soft(userID: string) {
const report = await this.client.db.Score.findOne({ userID });
if (!report) return null;
let totalScore: number;
let activityScore: number;
const moderationScore = Math.round(report.moderation);
let roleScore: number;
let cloudServicesScore: number;
const otherScore = Math.round(report.other);
let miscScore: number;
if (report.total < 200) totalScore = 0;
else if (report.total > 800) totalScore = 800;
else totalScore = Math.round(report.total);
if (report.activity < 10) activityScore = 0;
else if (report.activity > Math.floor((Math.log1p(3000 + 300 + 200 + 100) * 12))) activityScore = Math.floor((Math.log1p(3000 + 300 + 200 + 100) * 12));
else activityScore = Math.round(report.activity);
if (report.roles <= 0) roleScore = 0;
else if (report.roles > 54) roleScore = 54;
else roleScore = Math.round(report.roles);
if (report.staff <= 0) miscScore = 0;
else miscScore = Math.round(report.staff);
if (report.cloudServices === 0) cloudServicesScore = 0;
else if (report.cloudServices > 10) cloudServicesScore = 10;
else cloudServicesScore = Math.round(report.cloudServices);
const historicalData = await this.client.db.ScoreHistorical.find({ userID: member.userID }).lean().exec();
const array: ScoreHistoricalRaw[] = [];
for (const data of historicalData) {
let total: number;
let activity: number;
const moderation = Math.round(data.report.moderation);
let role: number;
let cloud: number;
const other = Math.round(data.report.other);
let misc: number;
if (data.report.total < 200) total = 0;
else if (data.report.total > 800) total = 800;
else total = Math.round(data.report.total);
if (data.report.activity < 10) activity = 0;
else if (data.report.activity > Math.floor((Math.log1p(3000 + 300 + 200 + 100) * 12))) activity = Math.floor((Math.log1p(3000 + 300 + 200 + 100) * 12));
else activity = Math.round(data.report.activity);
if (data.report.roles <= 0) role = 0;
else if (data.report.roles > 54) role = 54;
else role = Math.round(data.report.roles);
if (data.report.staff <= 0) role = 0;
else misc = Math.round(data.report.staff);
if (data.report.cloudServices === 0) cloud = 0;
else if (data.report.cloudServices > 10) cloud = 10;
else cloud = Math.round(data.report.cloudServices);
data.report.total = total; data.report.activity = activity; data.report.moderation = moderation; data.report.roles = role; data.report.cloudServices = cloud; data.report.other = other; data.report.staff = misc;
array.push(data);
}
} */
}

View File

@ -4,7 +4,7 @@ import childProcess from 'child_process';
import { promisify } from 'util'; import { promisify } from 'util';
import signale from 'signale'; import signale from 'signale';
import { Member, Message, Guild, PrivateChannel, GroupChannel, Role, AnyGuildChannel, WebhookPayload } from 'eris'; import { Member, Message, Guild, PrivateChannel, GroupChannel, Role, AnyGuildChannel, WebhookPayload } from 'eris';
import { Client, Command, Moderation, PBX, RichEmbed } from '.'; import { Client, Command, Moderation, PBX, Report, RichEmbed } from '.';
import { statusMessages as emotes } from '../configs/emotes.json'; import { statusMessages as emotes } from '../configs/emotes.json';
export default class Util { export default class Util {
@ -18,6 +18,8 @@ export default class Util {
public pbx: PBX; public pbx: PBX;
public report: Report;
constructor(client: Client) { constructor(client: Client) {
this.client = client; this.client = client;
this.moderation = new Moderation(this.client); this.moderation = new Moderation(this.client);
@ -33,6 +35,7 @@ export default class Util {
auth: { user: 'internal', pass: this.client.config.emailPass }, auth: { user: 'internal', pass: this.client.config.emailPass },
}); });
this.pbx = new PBX(this.client); this.pbx = new PBX(this.client);
this.report = new Report(this.client);
} }
get emojis() { get emojis() {
@ -43,6 +46,46 @@ export default class Util {
}; };
} }
public hrn(number: any, fixed: number, formatter: any | any[]) {
const builtInFormatters = {
en: ['KMGTPEZY'.split(''), 1e3],
zh_CN: ['百千万亿兆京垓秭'.split(''), [100, 10, 10, 1e4, 1e4, 1e4, 1e4, 1e4]],
};
number = Math.abs(number);
if (!fixed && fixed !== 0) fixed = 1;
if (typeof formatter === 'object') {
const name = `${new Date().getTime()}`;
builtInFormatters[name] = formatter;
formatter = name;
}
if (!builtInFormatters[formatter]) formatter = 'en';
formatter = builtInFormatters[formatter];
let power = 1;
const texts = formatter[0];
const powers = formatter[1];
let loop = 0;
let is_array = false;
if (typeof powers === 'object') is_array = true;
// eslint-disable-next-line no-constant-condition
while (1) {
if (is_array) power = powers[loop];
else power = powers;
if (number >= power && loop < texts.length) number /= power;
else {
number = number.toFixed(fixed);
return loop === 0 ? number : `${number} ${texts[loop - 1]}`;
}
// eslint-disable-next-line no-plusplus
++loop;
}
}
/** /**
* Resolves a command * Resolves a command
* @param query Command input * @param query Command input

View File

@ -7,6 +7,7 @@ export { default as LocalStorage } from './LocalStorage';
export { default as Moderation } from './Moderation'; export { default as Moderation } from './Moderation';
export { default as PBX } from './PBX'; export { default as PBX } from './PBX';
export { default as Queue } from './Queue'; export { default as Queue } from './Queue';
export { default as Report } from './Report';
export { default as RichEmbed } from './RichEmbed'; export { default as RichEmbed } from './RichEmbed';
export { default as Route } from './Route'; export { default as Route } from './Route';
export { default as Server } from './Server'; export { default as Server } from './Server';

View File

@ -7,7 +7,7 @@ export default class Callback extends Command {
constructor(client: Client) { constructor(client: Client) {
super(client); super(client);
this.name = 'callback'; this.name = 'callback';
this.description = 'Requests a Callback from a Technican.\nPlease use `-` to separate the number if needed. E.x. 202-750-2585.\nDo note, we are unable to dial international numbers outside of the US and Canada.'; this.description = 'Requests a Callback from a Technican.\nPlease use `-` to separate the number if needed. E.x. 202-750-2585.\nDo note, we are unable to dial international numbers outside of the US and Canada.\n\n*We recommend you run this command in your DMs for privacy.*';
this.usage = 'callback <the number you want us to call>'; this.usage = 'callback <the number you want us to call>';
this.aliases = ['cb']; this.aliases = ['cb'];
this.permissions = 0; this.permissions = 0;
@ -31,17 +31,7 @@ export default class Callback extends Command {
embed.addField('Phone Number Type', phone.getType(), true); embed.addField('Phone Number Type', phone.getType(), true);
const communityReport = await this.client.db.Score.findOne({ userID: message.author.id }).lean().exec(); const communityReport = await this.client.db.Score.findOne({ userID: message.author.id }).lean().exec();
if (communityReport) { if (communityReport) {
await this.client.db.Score.updateOne({ userID: message.author.id }, { $addToSet: { softInquiries: { name: 'LIBRARY OF CODE SP-US | VOIP/PBX MEMBER SUPPORT SVCS', date: new Date() } } }); await this.client.report.createInquiry(member.user.id, 'Library of Code sp-us | VOIP/PBX Member Support SVCS', 1);
const embed2 = new RichEmbed();
embed2.setTitle('Inquiry Notification');
embed2.setColor('#00FFFF');
embed2.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${member.user.id}>`, true);
embed2.addField('Type', 'SOFT', true);
embed2.addField('Department/Service', 'Library of Code sp-us | VOIP/PBX Member Support SVCS'.toUpperCase(), true);
embed2.setTimestamp();
embed2.setFooter(this.client.user.username, this.client.user.avatarURL);
const log = <TextChannel> this.mainGuild.channels.get('611584771356622849');
log.createMessage({ embed: embed2 }).catch(() => {});
embed.addField('PIN', `${communityReport.pin[0]}-${communityReport.pin[1]}-${communityReport.pin[2]}`, true); embed.addField('PIN', `${communityReport.pin[0]}-${communityReport.pin[1]}-${communityReport.pin[2]}`, true);
} }
try { try {

View File

@ -1,5 +1,4 @@
import { Message } from 'eris'; import { Message } from 'eris';
import { randomBytes } from 'crypto';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class DelMerchant extends Command { export default class DelMerchant extends Command {

View File

@ -21,6 +21,7 @@ export { default as info } from './info';
export { default as intercom } from './intercom'; export { default as intercom } from './intercom';
export { default as kick } from './kick'; export { default as kick } from './kick';
export { default as listredirects } from './listredirects'; export { default as listredirects } from './listredirects';
export { default as market } from './market';
export { default as members } from './members'; export { default as members } from './members';
export { default as mute } from './mute'; export { default as mute } from './mute';
export { default as notes } from './notes'; export { default as notes } from './notes';
@ -32,6 +33,7 @@ export { default as pulldata } from './pulldata';
export { default as rank } from './rank'; export { default as rank } from './rank';
export { default as roleinfo } from './roleinfo'; export { default as roleinfo } from './roleinfo';
export { default as score } from './score'; export { default as score } from './score';
export { default as sip } from './sip';
export { default as site } from './site'; export { default as site } from './site';
export { default as stats } from './stats'; export { default as stats } from './stats';
export { default as storemessages } from './storemessages'; export { default as storemessages } from './storemessages';

View File

@ -25,7 +25,7 @@ export default class Intercom extends Command {
channel: `PJSIP/${args[0]}`, channel: `PJSIP/${args[0]}`,
exten: args[0], exten: args[0],
context: 'from-internal', context: 'from-internal',
CallerID: `TTS PAGE FRM ${message.author.username} <*0>`, CallerID: `TTS INTC FRM ${message.author.username} <000>`,
application: 'PlayBack', application: 'PlayBack',
priority: '1', priority: '1',
data: `beep&${recordingLocation.split(':')[1]}`, data: `beep&${recordingLocation.split(':')[1]}`,

View File

@ -1,4 +1,4 @@
import { Message, User, Member } from 'eris'; import { Member, Message } from 'eris';
import { Client, Command } from '../class'; import { Client, Command } from '../class';
export default class Kick extends Command { export default class Kick extends Command {

59
src/commands/market.ts Normal file
View File

@ -0,0 +1,59 @@
import { Message } from 'eris';
import stockInfo from 'stock-info';
import { Client, Command, RichEmbed } from '../class';
export default class Market extends Command {
constructor(client: Client) {
super(client);
this.name = 'market';
this.description = 'Fetches information from a ticker for a stock or fund.';
this.usage = `${this.client.config.prefix}market <ticker>`;
this.permissions = 0;
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]);
let stock: stockInfo.Stock;
try {
stock = await stockInfo.getSingleStockInfo(args[0]);
} catch (err) {
return this.error(message.channel, `Unable to fetch information for that ticker. | ${err}`);
}
const embed = new RichEmbed();
embed.setTitle(stock.longName ?? stock.symbol);
let type: string;
switch (stock.quoteType) {
case 'EQUITY':
type = 'Common/Preferred Stock';
break;
case 'ETF':
type = 'Exchange Traded Fund (ETF)';
break;
case 'MUTUALFUND':
type = 'Mutual Fund';
break;
default:
type = 'N/A or Unknown';
break;
}
embed.addField('Type', type, true);
embed.addField('Market Cap', `${stock.marketCap ? this.client.util.hrn(stock.marketCap, undefined, undefined) : 'N/A'}`, true);
embed.addField('Day Quote Price', stock.regularMarketPrice ? `$${Number(stock.regularMarketPrice).toFixed(2)}` : 'N/A', true);
embed.addField('Day G/L', stock.regularMarketChange ? `$${Number(stock.regularMarketChange.toFixed(2))}` : 'N/A', true);
embed.addField('Day Range', stock.regularMarketDayRange ?? 'N/A', true);
embed.addField('Bid/Ask', `Bid: $${stock.bid?.toFixed(2) ?? 'N/A'} | Ask: $${stock.ask?.toFixed(2) ?? 'N/A'}`, true);
embed.addField('Forward P/E (Price/Earnings)', `${stock.forwardPE?.toFixed(2) ?? 'N/A'}`, true);
embed.addField('Forward EPS (Earnings Per Share)', `${stock.epsForward?.toFixed(2) ?? 'N/A'}`, true);
embed.addField('Exchange', `${stock.fullExchangeName?.toUpperCase() ?? 'N/A'}`, true);
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
return message.channel.createMessage({ embed });
} catch (err) {
return this.client.util.handleError(err, message, this, false);
}
}
}

View File

@ -205,7 +205,7 @@ export default class Page extends Command {
const chan = await this.client.util.pbx.ari.channels.originate({ const chan = await this.client.util.pbx.ari.channels.originate({
endpoint: `PJSIP/${member.extension}`, endpoint: `PJSIP/${member.extension}`,
extension: `${member.extension}`, extension: `${member.extension}`,
callerId: `LOC PBX - PAGE FRM ${senderNumber} <00>`, callerId: `PAGE FRM ${senderNumber} <000>`,
context: 'from-internal', context: 'from-internal',
priority: 1, priority: 1,
app: 'cr-zero', app: 'cr-zero',

View File

@ -27,18 +27,7 @@ export default class Score extends Command {
const report = score.inquiries.find((inq) => inq.id === args[1]); const report = score.inquiries.find((inq) => inq.id === args[1]);
if (!report) return this.error(message.channel, 'Could not find inquiry information.'); if (!report) return this.error(message.channel, 'Could not find inquiry information.');
await this.client.db.Score.updateOne({ userID: member.id }, { $addToSet: { softInquiries: { name: 'Library of Code sp-us | Bureau of Community Reports', date: new Date() } } }); await this.client.report.createInquiry(member.id, 'Library of Code sp-us | Bureau of Community Reports', 1);
const embed2 = new RichEmbed();
embed2.setTitle('Inquiry Notification');
embed2.setColor('#00FFFF');
const mem = this.client.util.resolveMember(score.userID, this.client.guilds.get(this.client.config.guildID));
embed2.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${score.userID}>`, true);
embed2.addField('Type', 'SOFT', true);
embed2.addField('Department/Service', 'Library of Code sp-us | Bureau of Community Reports'.toUpperCase(), true);
embed2.setTimestamp();
embed2.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: embed2 }).catch(() => {});
const embed = new RichEmbed(); const embed = new RichEmbed();
embed.setTitle(`Hard Inquiry Information - ${report.id}`); embed.setTitle(`Hard Inquiry Information - ${report.id}`);

View File

@ -1,8 +1,8 @@
/* eslint-disable no-plusplus */
/* eslint-disable no-continue */ /* eslint-disable no-continue */
/* eslint-disable default-case */ /* eslint-disable default-case */
import moment from 'moment'; import moment from 'moment';
import { v4 as uuid } from 'uuid'; import { Message, User } from 'eris';
import { Message, User, TextChannel } from 'eris';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command, RichEmbed } from '../class';
import { getTotalMessageCount } from '../intervals/score'; import { getTotalMessageCount } from '../intervals/score';
import Score_Hist from './score_hist'; import Score_Hist from './score_hist';
@ -15,6 +15,7 @@ export default class Score extends Command {
this.name = 'score'; this.name = 'score';
this.description = 'Retrieves your Community Report'; this.description = 'Retrieves your Community Report';
this.usage = `${this.client.config.prefix}score\n${this.client.config.prefix}score <member> <type: 'hard' | 'soft'> <reporting department: ex. Library of Code sp-us | Cloud Account Services>:<reason>`; this.usage = `${this.client.config.prefix}score\n${this.client.config.prefix}score <member> <type: 'hard' | 'soft'> <reporting department: ex. Library of Code sp-us | Cloud Account Services>:<reason>`;
this.aliases = ['report'];
this.subcmds = [Score_Hist, Score_Notify, Score_Pref]; this.subcmds = [Score_Hist, Score_Notify, Score_Pref];
this.permissions = 0; this.permissions = 0;
this.guildOnly = false; this.guildOnly = false;
@ -28,18 +29,7 @@ export default class Score extends Command {
if (!args[0] || !this.checkCustomPermissions(this.client.util.resolveMember(message.author.id, this.mainGuild), 4)) { if (!args[0] || !this.checkCustomPermissions(this.client.util.resolveMember(message.author.id, this.mainGuild), 4)) {
user = message.author; user = message.author;
if (!user) return this.error(message.channel, 'Member not found.'); if (!user) return this.error(message.channel, 'Member not found.');
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name: `${user.username} via Discord`, date: new Date() } } }); await this.client.report.createInquiry(user.id, `${user.username} via Discord`, 1);
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
const mem = this.client.util.resolveMember(user.id, this.client.guilds.get(this.client.config.guildID));
embed.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${user.id}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', `${user.username} via Discord`.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(() => { });
check = true; check = true;
} else { } else {
user = this.client.util.resolveMember(args[0], this.mainGuild)?.user; user = this.client.util.resolveMember(args[0], this.mainGuild)?.user;
@ -57,30 +47,12 @@ export default class Score extends Command {
const score = await this.client.db.Score.findOne({ userID: user.id }); const score = await this.client.db.Score.findOne({ userID: user.id });
if (!score) return this.error(message.channel, 'Score not calculated yet.'); if (!score) return this.error(message.channel, 'Score not calculated yet.');
if (score.locked) return this.error(message.channel, 'The score report you have requested has been locked.'); if (score.locked) return this.error(message.channel, 'The score report you have requested has been locked.');
const reportID = uuid(); await this.client.report.createInquiry(score.userID, name, 0, reason);
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { inquiries: { id: reportID, name, reason, date: new Date(), report: score.toObject() } } });
const embed = new RichEmbed();
embed.setTitle('Inquiry Notification');
embed.setDescription(reportID);
embed.setColor('#800080');
const mem = this.client.util.resolveMember(score.userID, this.client.guilds.get(this.client.config.guildID));
embed.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${score.userID}>`, true);
embed.addField('Type', 'HARD', true);
embed.addField('Department/Service', name.toUpperCase(), true);
embed.addField('Reason', reason ?? 'N/A', 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(() => { });
if (score.notify === true) {
await this.client.getDMChannel(user.id).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:** ${name.toUpperCase()}`);
}).catch(() => { });
}
} }
} }
if (!user) return this.error(message.channel, 'Member not found.'); if (!user) return this.error(message.channel, 'Member not found.');
const score = await this.client.db.Score.findOne({ userID: user.id }); const score = await this.client.db.Score.findOne({ userID: user.id });
const inqs = await this.client.db.Inquiry.find({ userID: user.id, type: 0 });
if (!score) return this.error(message.channel, 'Community Report has not been generated yet.'); if (!score) return this.error(message.channel, 'Community Report has not been generated yet.');
let totalScore = '0'; let totalScore = '0';
let activityScore = '0'; let activityScore = '0';
@ -134,13 +106,18 @@ export default class Score extends Command {
break; break;
} }
} */ } */
if (score?.inquiries?.length > 0) { let inqAdded = 0;
if (inqs?.length > 0) {
let desc = '__**Hard Inquiries**__\n*These inquiries will fall off your report within 2 months, try to keep your hard inquiries to a minimum. If you want to file a dispute, please DM Ramirez.*\n\n'; let desc = '__**Hard Inquiries**__\n*These inquiries will fall off your report within 2 months, try to keep your hard inquiries to a minimum. If you want to file a dispute, please DM Ramirez.*\n\n';
score.inquiries.forEach((inq) => { inqs.forEach((inq) => {
const testDate = (new Date(new Date(inq.date).setHours(1460))); const testDate = (new Date(new Date(inq.date).setHours(1460)));
// eslint-disable-next-line no-useless-escape // eslint-disable-next-line no-useless-escape
if (testDate > new Date()) desc += `${inq.id ? `__[${inq.id}]__\n` : ''}**Department/Service:** ${inq.name.replace(/\*/gmi, '')}\n**Reason:** ${inq.reason}\n**Date:** ${inq.date.toLocaleString('en-us')} ET\n**Expires:** ${moment(testDate).calendar()}\n\n`; if (testDate > new Date()) {
desc += `${inq.iid ? `__[${inq.iid}]__\n` : ''}**Department/Service:** ${inq.name.replace(/\*/gmi, '')}\n**Reason:** ${inq.reason}\n**Date:** ${moment(inq.date).format('MMMM Do YYYY, h:mm:ss')}\n**Expires:** ${moment(testDate).calendar()}\n\n`;
inqAdded++;
}
}); });
if (inqAdded <= 0) desc = '';
if (desc.length >= 1900) { if (desc.length >= 1900) {
embed.setDescription('__***Too many Hard Inquiries to show, please see https://report.libraryofcode.org***__'); embed.setDescription('__***Too many Hard Inquiries to show, please see https://report.libraryofcode.org***__');
} else { } else {
@ -183,18 +160,7 @@ export default class Score extends Command {
name = `Library of Code sp-us | ${role.name}`; name = `Library of Code sp-us | ${role.name}`;
break; break;
} }
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name, date: new Date() } } }); await this.client.report.createInquiry(user.id, name, 1);
const embed2 = new RichEmbed();
embed2.setTitle('Inquiry Notification');
embed2.setColor('#00FFFF');
const mem = this.client.util.resolveMember(score.userID, this.client.guilds.get(this.client.config.guildID));
embed2.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${score.userID}>`, true);
embed2.addField('Type', 'SOFT', true);
embed2.addField('Department/Service', name.toUpperCase(), true);
embed2.setTimestamp();
embed2.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: embed2 }).catch(() => { });
} }
} }
if (args[1] === 'hard' && this.checkCustomPermissions(this.client.util.resolveMember(message.author.id, this.mainGuild), 6)) { if (args[1] === 'hard' && this.checkCustomPermissions(this.client.util.resolveMember(message.author.id, this.mainGuild), 6)) {

View File

@ -1,3 +1,4 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-continue */ /* eslint-disable no-continue */
/* eslint-disable default-case */ /* eslint-disable default-case */
import moment from 'moment'; import moment from 'moment';
@ -6,6 +7,7 @@ import { createPaginationEmbed } from 'eris-pagination';
import { Message, User, TextChannel } from 'eris'; import { Message, User, TextChannel } from 'eris';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command, RichEmbed } from '../class';
import { getTotalMessageCount } from '../intervals/score'; import { getTotalMessageCount } from '../intervals/score';
import { InquiryInterface } from '../models';
export default class Score_Hist extends Command { export default class Score_Hist extends Command {
constructor(client: Client) { constructor(client: Client) {
@ -78,8 +80,15 @@ export default class Score_Hist extends Command {
let data = ''; let data = '';
let hardInquiries = 0; let hardInquiries = 0;
if (hist.report?.inquiries?.length > 0) { const inquiries: InquiryInterface[] = [];
hist.report.inquiries.forEach((inq) => { if (hist.inquiries?.length > 0) {
for (const h of hist.inquiries) {
const inq = await this.client.db.Inquiry.findOne({ _id: h });
inquiries.push(inq);
}
}
if (inquiries?.length > 0) {
inquiries.forEach((inq) => {
const testDate = (new Date(new Date(inq.date).setHours(1460))); const testDate = (new Date(new Date(inq.date).setHours(1460)));
// eslint-disable-next-line no-plusplus // eslint-disable-next-line no-plusplus
if (testDate > new Date()) hardInquiries++; if (testDate > new Date()) hardInquiries++;
@ -156,17 +165,7 @@ export default class Score_Hist extends Command {
return cmdPages.push(embed); return cmdPages.push(embed);
}); });
const name = `${user.username} VIA DISCORD - [HISTORICAL]`; const name = `${user.username} VIA DISCORD - [HISTORICAL]`;
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name: name.toUpperCase(), date: new Date() } } }); await this.client.report.createInquiry(user.id, name, 1);
const embed2 = new RichEmbed();
embed2.setTitle('Inquiry Notification');
embed2.setColor('#00FFFF');
embed2.addField('Member', `${user.username}#${user.discriminator} | <@${user.id}>`, true);
embed2.addField('Type', 'SOFT', true);
embed2.addField('Department/Service', name.toUpperCase(), true);
embed2.setTimestamp();
embed2.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: embed2 }).catch(() => {});
if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] });
@ -231,8 +230,15 @@ export default class Score_Hist extends Command {
let data = ''; let data = '';
let hardInquiries = 0; let hardInquiries = 0;
if (hist.report?.inquiries?.length > 0) { const inquiries: InquiryInterface[] = [];
hist.report.inquiries.forEach((inq) => { if (hist.inquiries?.length > 0) {
for (const h of hist.inquiries) {
const inq = await this.client.db.Inquiry.findOne({ _id: h });
inquiries.push(inq);
}
}
if (inquiries?.length > 0) {
inquiries.forEach((inq) => {
const testDate = (new Date(new Date(inq.date).setHours(1460))); const testDate = (new Date(new Date(inq.date).setHours(1460)));
// eslint-disable-next-line no-plusplus // eslint-disable-next-line no-plusplus
if (testDate > new Date()) hardInquiries++; if (testDate > new Date()) hardInquiries++;
@ -314,18 +320,7 @@ export default class Score_Hist extends Command {
name = `Library of Code sp-us | ${role.name} - [HISTORICAL]`; name = `Library of Code sp-us | ${role.name} - [HISTORICAL]`;
break; break;
} }
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name, date: new Date() } } }); await this.client.report.createInquiry(user.id, name, 1);
const embed2 = new RichEmbed();
embed2.setTitle('Inquiry Notification');
embed2.setColor('#00FFFF');
const mem = this.client.util.resolveMember(user.id, this.client.guilds.get(this.client.config.guildID));
embed2.addField('Member', `${mem.user.username}#${mem.user.discriminator} | <@${user.id}>`, true);
embed2.addField('Type', 'SOFT', true);
embed2.addField('Department/Service', name.toUpperCase(), true);
embed2.setTimestamp();
embed2.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: embed2 }).catch(() => {});
if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] });

81
src/commands/sip.ts Normal file
View File

@ -0,0 +1,81 @@
/* eslint-disable consistent-return */
import { Message } from 'eris';
import type { Channel } from 'ari-client';
import { Client, Command } from '../class';
import { Misc } from '../pbx';
export default class SIP extends Command {
constructor(client: Client) {
super(client);
this.name = 'sip';
this.description = 'Dials a SIP URI.';
this.usage = `${this.client.config.prefix}sip <uri>`;
this.permissions = 1;
this.guildOnly = true;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
try {
const staff = await this.client.db.Staff.findOne({ userID: message.author.id });
if (!staff || !staff?.extension) return this.error(message.channel, 'You must have an extension to complete this action.');
this.success(message.channel, 'Queued call.');
const bridge = await this.client.pbx.ari.Bridge().create();
let receiver: Channel = this.client.pbx.ari.Channel();
const sender = await this.client.pbx.ari.channels.originate({
endpoint: `PJSIP/${staff.extension}`,
extension: staff.extension,
callerId: 'LOC PBX AUTO OPERATOR <operator>',
context: 'from-internal',
priority: 1,
app: 'cr-zero',
});
sender.once('StasisStart', async () => {
await Misc.play(this.client.pbx, sender, 'sound:pls-hold-while-try');
await sender.ring();
try {
receiver = await receiver.originate({
endpoint: `SIP/${args.join(' ')}`,
callerId: 'LOC PBX AUTO OPERATOR <operator>',
context: 'from-internal',
priority: 1,
app: 'cr-zero',
});
} catch {
await Misc.play(this.client.pbx, sender, 'sound:discon-or-out-of-service');
await sender.hangup().catch(() => {});
return false;
}
// receiver.once('StasisStart', )
});
receiver.once('StasisStart', async () => {
await sender.ringStop();
await bridge.addChannel({ channel: [receiver.id, sender.id] });
await bridge.play({ media: 'sound:beep' });
});
receiver.once('ChannelDestroyed', async () => {
if (!sender.connected) return;
await Misc.play(this.client.pbx, sender, ['sound:the-number-u-dialed', 'sound:T-is-not-available', 'sound:please-try-again-later']);
await sender.hangup().catch(() => {});
await bridge.destroy().catch(() => {});
});
receiver.once('StasisEnd', async () => {
await sender.hangup().catch(() => {});
await bridge.destroy().catch(() => {});
});
sender.once('StasisEnd', async () => {
await receiver.hangup().catch(() => {});
await bridge.destroy().catch(() => {});
});
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -62,7 +62,7 @@ export default class SiteInfo extends Command {
this.aliases = ['ssl', 'cert', 'certinfo', 'ci', 'tls', 'si', 'siteinfo']; this.aliases = ['ssl', 'cert', 'certinfo', 'ci', 'tls', 'si', 'siteinfo'];
this.permissions = 0; this.permissions = 0;
this.guildOnly = true; this.guildOnly = true;
this.enabled = true; this.enabled = false;
} }
public async run(message: Message, args: string[]) { public async run(message: Message, args: string[]) {
@ -157,6 +157,7 @@ export default class SiteInfo extends Command {
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(`https://${args[0]}`); await page.goto(`https://${args[0]}`);
screenshotData = await page.screenshot(); screenshotData = await page.screenshot();
browser.close();
} catch (e) { } catch (e) {
this.client.util.signale.error(e); this.client.util.signale.error(e);
} }

View File

@ -1,8 +1,7 @@
/* eslint-disable no-bitwise */ /* eslint-disable no-bitwise */
import moment from 'moment'; import moment from 'moment';
import { Message, Member, TextChannel } from 'eris'; import { Message, Member } from 'eris';
import { Client, Command, RichEmbed } from '../class'; import { Client, Command, RichEmbed } from '../class';
// import acknowledgements from '../configs/acknowledgements.json';
import { whois as emotes } from '../configs/emotes.json'; import { whois as emotes } from '../configs/emotes.json';
export default class Whois extends Command { export default class Whois extends Command {
@ -34,7 +33,6 @@ export default class Whois extends Command {
} }
const embed = new RichEmbed(); const embed = new RichEmbed();
embed.setThumbnail(member.avatarURL); embed.setThumbnail(member.avatarURL);
// const ackResolve = this.resolveStaffInformation(member.id);
const ackResolve = await this.client.db.Staff.findOne({ userID: member.id }).lean().exec(); const ackResolve = await this.client.db.Staff.findOne({ userID: member.id }).lean().exec();
let title = `${member.user.username}#${member.user.discriminator}`; let title = `${member.user.username}#${member.user.discriminator}`;
if (ackResolve?.pn?.length > 0) title += `, ${ackResolve.pn.join(', ')}`; if (ackResolve?.pn?.length > 0) title += `, ${ackResolve.pn.join(', ')}`;
@ -53,7 +51,7 @@ export default class Whois extends Command {
} }
const pager = await this.client.db.PagerNumber.findOne({ individualAssignID: member.user.id }).lean().exec(); const pager = await this.client.db.PagerNumber.findOne({ individualAssignID: member.user.id }).lean().exec();
if (pager?.num) { if (pager?.num) {
description += `📡 ${pager.num}\n`; description += `📟 ${pager.num}\n`;
} }
if (ackResolve?.extension) { if (ackResolve?.extension) {
description += `☎️ ${ackResolve.extension}\n`; description += `☎️ ${ackResolve.extension}\n`;
@ -78,12 +76,11 @@ export default class Whois extends Command {
} }
} }
embed.addField('Status', member.status === 'dnd' ? 'Do Not Disturb' : this.capsFirstLetter(member.status) || 'Offline', true); embed.addField('Status', member.status === 'dnd' ? 'Do Not Disturb' : this.capsFirstLetter(member.status) || 'Offline', true);
// const platform = member.bot && member.status !== 'offline' ? 'API/WebSocket' : Object.entries(message.member.clientStatus).filter((a) => a[1] !== 'offline').map((a) => this.capsFirstLetter(a[0])).join(', ');
// if (platform) embed.addField('Platform', platform, true);
embed.addField('Joined At', `${moment(new Date(member.joinedAt)).format('dddd, MMMM Do YYYY, h:mm:ss A')} ET`, true); embed.addField('Joined At', `${moment(new Date(member.joinedAt)).format('dddd, MMMM Do YYYY, h:mm:ss A')} ET`, true);
embed.addField('Created At', `${moment(new Date(member.user.createdAt)).format('dddd, MMMM Do YYYY, h:mm:ss A')} ET`, true); embed.addField('Created At', `${moment(new Date(member.user.createdAt)).format('dddd, MMMM Do YYYY, h:mm:ss A')} ET`, true);
const score = await this.client.db.Score.findOne({ userID: member.id }).lean().exec(); const score = await this.client.db.Score.findOne({ userID: member.id }).lean().exec();
if (score) { if (score) {
<<<<<<< HEAD
await this.client.db.Score.updateOne({ userID: member.id }, { $addToSet: { softInquiries: { name: 'Library of Code sp-us | Bureau of Community Reports', date: new Date() } } }); await this.client.db.Score.updateOne({ userID: member.id }, { $addToSet: { softInquiries: { name: 'Library of Code sp-us | Bureau of Community Reports', date: new Date() } } });
const embed2 = new RichEmbed(); const embed2 = new RichEmbed();
embed2.setTitle('Inquiry Notification'); embed2.setTitle('Inquiry Notification');
@ -96,6 +93,9 @@ export default class Whois extends Command {
embed2.setFooter(this.client.user.username, this.client.user.avatarURL); embed2.setFooter(this.client.user.username, this.client.user.avatarURL);
const log = <TextChannel>this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849'); const log = <TextChannel>this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed: embed2 }).catch(() => { }); log.createMessage({ embed: embed2 }).catch(() => { });
=======
await this.client.report.createInquiry(member.id, 'Library of Code sp-us | Bureau of Community Reports', 1);
>>>>>>> upstream/master
let totalScore = '0'; let totalScore = '0';
if (score.total < 200) totalScore = '---'; if (score.total < 200) totalScore = '---';
else if (score.total > 800) totalScore = '800'; else if (score.total > 800) totalScore = '800';
@ -229,8 +229,8 @@ export default class Whois extends Command {
if (serverAcknowledgements.length > 0) { if (serverAcknowledgements.length > 0) {
embed.addField('Acknowledgements', serverAcknowledgements[0]); embed.addField('Acknowledgements', serverAcknowledgements[0]);
} }
if (ackResolve?.acknowledgements) { if (ackResolve?.additionalRoles?.length > 0) {
embed.addField('Bot Acknowledgements', ackResolve.acknowledgements.join(', ')); embed.addField('Additional Acknowledgements', ackResolve.additionalRoles.join(', '));
} }
embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp(); embed.setTimestamp();

View File

@ -12,8 +12,8 @@ export default class GuildMemberAdd extends Event {
public async run(_, member: Member) { public async run(_, member: Member) {
try { try {
const search = await this.client.db.local.muted.get<boolean>(`muted-${member.user.id}`); const search = await this.client.db.local.muted.get<boolean>(`muted-${member.user.id}`);
if (search) { if (search === true) {
await member.addRole('478373942638149643'); member.addRole('478373942638149643', 'muted user left server and joined back');
} }
} catch (err) { } catch (err) {
this.client.util.handleError(err); this.client.util.handleError(err);

View File

@ -11,7 +11,7 @@ export default function checkLock(client: Client): NodeJS.Timeout {
if (moderation.expiration.processed) return; if (moderation.expiration.processed) return;
if (new Date() > moderation.expiration.date) { if (new Date() > moderation.expiration.date) {
await moderation.updateOne({ 'expiration.processed': true }); await moderation.updateOne({ 'expiration.processed': true });
// const moderator = client.guilds.get(client.config.guildID).members.get(moderation.moderatorID);
const system = client.guilds.get(client.config.guildID).members.get(client.user.id); const system = client.guilds.get(client.config.guildID).members.get(client.user.id);
switch (moderation.type) { switch (moderation.type) {
case 5: case 5:

View File

@ -63,8 +63,8 @@ export default async function calculateScore(client: Client): Promise<NodeJS.Tim
staff: boolean, staff: boolean,
locked: boolean, locked: boolean,
notify: boolean, notify: boolean,
inquiries: [{ name: string, reason: string, date: Date }?], // inquiries: [{ name: string, reason: string, date: Date }?],
softInquiries: [{name: string, date: Date }?] // softInquiries: [{name: string, date: Date }?]
lastUpdated: Date, lastUpdated: Date,
pin: number[], pin: number[],
/* generalMessagesRatio: number, /* generalMessagesRatio: number,
@ -82,8 +82,8 @@ export default async function calculateScore(client: Client): Promise<NodeJS.Tim
staff: false, staff: false,
locked: false, locked: false,
notify: false, notify: false,
inquiries: [], // inquiries: [],
softInquiries: [], // softInquiries: [],
lastUpdated: new Date(), lastUpdated: new Date(),
pin: [client.util.randomNumber(100, 999), client.util.randomNumber(10, 99), client.util.randomNumber(1000, 9999)], pin: [client.util.randomNumber(100, 999), client.util.randomNumber(10, 99), client.util.randomNumber(1000, 9999)],
}; };

33
src/models/Inquiry.ts Normal file
View File

@ -0,0 +1,33 @@
import { Document, Schema, model } from 'mongoose';
import { ScoreInterfaceRaw } from '.';
export enum InqType {
HARD,
SOFT,
}
export interface InquiryInterface extends Document {
iid?: string,
userID: string,
/**
* - 0: Hard
* - 1: Soft
*/
type: InqType,
name: string,
reason?: string,
date: Date,
report?: ScoreInterfaceRaw,
}
const Inquiry: Schema = new Schema({
iid: String,
userID: String,
type: Number,
name: String,
reason: String,
date: String,
report: Object,
});
export default model<InquiryInterface>('Inquiry', Inquiry);

View File

@ -1,7 +1,7 @@
import { Document, Schema, model } from 'mongoose'; import { Document, Schema, model } from 'mongoose';
export interface MemberInterface extends Document { export interface MemberInterface extends Document {
userID: string userID: string,
additional: { additional: {
langs: ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'], langs: ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'],
operatingSystems: ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'], operatingSystems: ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'],
@ -9,6 +9,7 @@ export interface MemberInterface extends Document {
gitlab: string, gitlab: string,
bio: string, bio: string,
}, },
bio: string,
} }
const Member: Schema = new Schema({ const Member: Schema = new Schema({
@ -20,6 +21,7 @@ const Member: Schema = new Schema({
gitlab: String, gitlab: String,
bio: String, bio: String,
}, },
bio: String,
}); });
export default model<MemberInterface>('Member', Member); export default model<MemberInterface>('Member', Member);

View File

@ -49,30 +49,11 @@ export interface ScoreInterfaceRaw {
export interface ScoreInterface extends Document { export interface ScoreInterface extends Document {
userID: string userID: string
/**
* total will be between 800-200 - 0 signfies "No Score", too little information is available or other variable are too low
* - CALCULATION: `(COMBINED SUBSCORES x 5) * 5.13; Math.floor()`
*/
total: number, total: number,
/**
* 10 - 55
*/
activity: number, activity: number,
/**
* 0 - 54
*/
roles: number, roles: number,
/**
* -50 - 2
* all users start out with 2 moderation points, the number of points decreases for each moderation.
*/
moderation: number, moderation: number,
/**
* -20 - 50
* processed by CSD
*/
cloudServices: number, cloudServices: number,
// 0 or 20, 20 points are added if the user is a staff member
staff: number, staff: number,
other: number, other: number,
notify: boolean, notify: boolean,

View File

@ -1,21 +1,24 @@
import { Document, Schema, model } from 'mongoose'; import { Document, Schema, model, Types } from 'mongoose';
import { ScoreInterfaceRaw } from '.'; import { ScoreInterfaceRaw } from '.';
export interface ScoreHistoricalRaw { export interface ScoreHistoricalRaw {
userID: string, userID: string,
report: ScoreInterfaceRaw, report: ScoreInterfaceRaw,
inquiries: [ Types.ObjectId ],
date: Date, date: Date,
} }
export interface ScoreHistoricalInterface extends Document { export interface ScoreHistoricalInterface extends Document {
userID: string, userID: string,
report: ScoreInterfaceRaw, report: ScoreInterfaceRaw,
inquiries: [ Types.ObjectId ],
date: Date date: Date
} }
const ScoreHistorical: Schema = new Schema({ const ScoreHistorical: Schema = new Schema({
userID: String, userID: String,
report: Object, report: Object,
inquiries: Array,
date: Date, date: Date,
}); });

View File

@ -9,6 +9,7 @@ export interface StaffInterface extends Document {
emailAddress: string, emailAddress: string,
extension: string, extension: string,
acknowledgements: string[], acknowledgements: string[],
additionalRoles: string[]
} }
const Staff: Schema = new Schema({ const Staff: Schema = new Schema({
@ -20,6 +21,7 @@ const Staff: Schema = new Schema({
emailAddress: String, emailAddress: String,
extension: String, extension: String,
acknowledgements: Array, acknowledgements: Array,
additionalRoles: Array,
}); });
export default model<StaffInterface>('Staff', Staff); export default model<StaffInterface>('Staff', Staff);

View File

@ -1,19 +1,16 @@
export { default as Customer, CustomerInterface } from './Customer'; export { default as Customer, CustomerInterface } from './Customer';
export { default as CustomerPortal, CustomerPortalInterface } from './CustomerPortal'; export { default as CustomerPortal, CustomerPortalInterface } from './CustomerPortal';
export { default as ExecutiveOrder, ExecutiveOrderInterface } from './ExecutiveOrder';
export { default as File, FileInterface } from './File'; export { default as File, FileInterface } from './File';
export { default as Inquiry, InquiryInterface, InqType } from './Inquiry';
export { default as Member, MemberInterface } from './Member'; export { default as Member, MemberInterface } from './Member';
export { default as Merchant, MerchantInterface } from './Merchant'; export { default as Merchant, MerchantInterface } from './Merchant';
export { default as Moderation, ModerationInterface } from './Moderation'; export { default as Moderation, ModerationInterface } from './Moderation';
export { default as Motion, MotionInterface } from './Motion';
export { default as NNTrainingData, NNTrainingDataInterface } from './NNTrainingData'; export { default as NNTrainingData, NNTrainingDataInterface } from './NNTrainingData';
export { default as Note, NoteInterface } from './Note'; export { default as Note, NoteInterface } from './Note';
export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber'; export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber';
export { default as Proclamation, ProclamationInterface } from './Proclamation';
export { default as Promo, PromoInterface } from './Promo'; export { default as Promo, PromoInterface } from './Promo';
export { default as Rank, RankInterface } from './Rank'; export { default as Rank, RankInterface } from './Rank';
export { default as Redirect, RedirectInterface, RedirectRaw } from './Redirect'; export { default as Redirect, RedirectInterface, RedirectRaw } from './Redirect';
export { default as Resolution, ResolutionInterface } from './Resolution';
export { default as Score, ScoreInterface, ScoreInterfaceRaw } from './Score'; export { default as Score, ScoreInterface, ScoreInterfaceRaw } from './Score';
export { default as ScoreHistorical, ScoreHistoricalInterface } from './ScoreHistorical'; export { default as ScoreHistorical, ScoreHistoricalInterface } from './ScoreHistorical';
export { default as Staff, StaffInterface } from './Staff'; export { default as Staff, StaffInterface } from './Staff';

View File

@ -4,11 +4,17 @@ import { promises as fs } from 'fs';
import { PBX } from '../../class'; import { PBX } from '../../class';
export default class Misc { export default class Misc {
public static async accessDenied(channel: ARI.Channel) { public static accessDenied(channel: ARI.Channel) {
const playback = await channel.play({ return new Promise<void>((resolve, reject) => {
media: 'sound:access-denied', channel.play({
}, undefined); media: 'sound:access-denied',
playback.once('PlaybackFinished', () => channel.hangup()); }, undefined).then((playback) => {
playback.on('PlaybackFinished', () => {
channel.hangup().catch((err) => reject(err));
resolve();
});
}).catch((err) => reject(err));
});
} }
public static async TTS(pbx: PBX, text: string, gender: string | any): Promise<string> { public static async TTS(pbx: PBX, text: string, gender: string | any): Promise<string> {
@ -24,7 +30,7 @@ export default class Misc {
return `sound:/tmp/${fileExtension}`; return `sound:/tmp/${fileExtension}`;
} }
public static play(pbx: PBX, channel: ARI.Channel, sound: string): Promise<ARI.Playback> { public static play(pbx: PBX, channel: ARI.Channel, sound: string | string[]): Promise<ARI.Playback> {
const playback = pbx.ari.Playback(); const playback = pbx.ari.Playback();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -18,7 +18,7 @@
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
"removeComments": true, /* Do not emit comments to output. */ "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */ // "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

View File

@ -562,6 +562,14 @@ ax@0.1.8:
resolved "https://registry.yarnpkg.com/ax/-/ax-0.1.8.tgz#27ca9a73fa4c78a478d62d827cad860a24fdd497" resolved "https://registry.yarnpkg.com/ax/-/ax-0.1.8.tgz#27ca9a73fa4c78a478d62d827cad860a24fdd497"
integrity sha1-J8qac/pMeKR41i2CfK2GCiT91Jc= integrity sha1-J8qac/pMeKR41i2CfK2GCiT91Jc=
axios@^0.18.1:
version "0.18.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
dependencies:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
axios@^0.19.2: axios@^0.19.2:
version "0.19.2" version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
@ -2101,6 +2109,11 @@ is-boolean-object@^1.1.0:
dependencies: dependencies:
call-bind "^1.0.0" call-bind "^1.0.0"
is-buffer@^2.0.2:
version "2.0.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.3: is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.3:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
@ -3550,6 +3563,13 @@ standard-as-callback@^2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
stock-info@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/stock-info/-/stock-info-1.2.0.tgz#a29f54c5416deec5a08a9f3c19736a91c913c20a"
integrity sha512-GxhFrCWlibRdS/9KC1aRMBD0p4IyGj/rKD5InK/ZUOFAapJ76QhVY/ShsNT0WRkOh12Bh6NfZkWU/Ipj90NstQ==
dependencies:
axios "^0.18.1"
stream-shift@^1.0.0: stream-shift@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
@ -3652,7 +3672,7 @@ strip-json-comments@~2.0.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
stripe@^8.135.0: stripe@^8.120.0:
version "8.137.0" version "8.137.0"
resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.137.0.tgz#9344d99d96ef3a19ff4c92f2bb141c40f2b18a6a" resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.137.0.tgz#9344d99d96ef3a19ff4c92f2bb141c40f2b18a6a"
integrity sha512-UlxXjff6O+0hGY7DRZZnepZegXfi8KoYKuW4fgMlNIiyvKR/G8EjL13uaqFI31vmVm0WxNvjrBiHd9DFX9rLgA== integrity sha512-UlxXjff6O+0hGY7DRZZnepZegXfi8KoYKuW4fgMlNIiyvKR/G8EjL13uaqFI31vmVm0WxNvjrBiHd9DFX9rLgA==
@ -3781,6 +3801,11 @@ tslib@^1.8.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
tsutils@^3.17.1: tsutils@^3.17.1:
version "3.20.0" version "3.20.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.20.0.tgz#ea03ea45462e146b53d70ce0893de453ff24f698" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.20.0.tgz#ea03ea45462e146b53d70ce0893de453ff24f698"
@ -3830,7 +3855,7 @@ typed-function@^2.0.0:
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.0.0.tgz#15ab3825845138a8b1113bd89e60cd6a435739e8" resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.0.0.tgz#15ab3825845138a8b1113bd89e60cd6a435739e8"
integrity sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA== integrity sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==
typescript@^3.9.8: typescript@^3.9.2:
version "3.9.9" version "3.9.9"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
@ -3897,9 +3922,9 @@ uuid@^8.0.0, uuid@^8.3.0:
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3: v8-compile-cache@^2.0.3:
version "2.2.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q== integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
validate-npm-package-license@^3.0.1: validate-npm-package-license@^3.0.1:
version "3.0.4" version "3.0.4"