quality of life updates

merge-requests/15/merge
Matthew 2021-02-02 01:45:03 -05:00
parent 743970730b
commit d0dfe0e730
No known key found for this signature in database
GPG Key ID: 210AF32ADE3B5C4B
30 changed files with 373 additions and 434 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.
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.
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",
"description": "The official system for handling Community Relations in the LOC Discord server.",
"main": "build/main.js",
@ -7,7 +7,7 @@
"lint": "eslint -c ./.eslintrc.json src --ext ts"
},
"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",
"private": false,
"devDependencies": {
@ -29,6 +29,7 @@
"eslint": "^7.0.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-plugin-import": "^2.20.2",
"tslib": "^2.1.0",
"typescript": "^3.9.2"
},
"dependencies": {
@ -55,6 +56,7 @@
"puppeteer": "^5.5.0",
"sd-notify": "^2.8.0",
"signale": "^1.4.0",
"stock-info": "^1.2.0",
"stripe": "^8.120.0",
"uuid": "^8.0.0",
"yaml": "^1.9.2"

View File

@ -1,9 +1,8 @@
/* eslint-disable no-bitwise */
/* eslint-disable no-continue */
import jwt from 'jsonwebtoken';
import { v4 as uuid } from 'uuid';
import { TextChannel } from 'eris';
import { LocalStorage, Route, Server, RichEmbed } from '../../../class';
import { LocalStorage, Route, Server } from '../../../class';
import { ScoreHistoricalRaw } from '../../../models/ScoreHistorical';
import { getTotalMessageCount } from '../../../intervals/score';
@ -129,11 +128,12 @@ export default class Report extends Route {
else if (member.cloudServices > 10) cloudServicesScore = 10;
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 }?] = [];
if (member.inquiries?.length > 0) {
for (const inq of member.inquiries) {
if (inqs?.length > 0) {
for (const inq of inqs) {
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 });
}
}
@ -174,35 +174,14 @@ export default class Report extends Route {
array.push(data);
}
if (member.notify) {
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}`);
}
}
const inq = await this.server.client.report.createInquiry(member.userID, merchant.name, 0, req.body.reason);
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({
code: this.constants.codes.SUCCESS,
message: {
id: reportID,
id: inq.id,
userID: member.userID,
memberInformation: {
username: mem.user.username,
@ -238,35 +217,24 @@ export default class Report extends Route {
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 });
const member = 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 });
const report = await this.server.client.db.Score.findOne({ userID: req.body.userID }).lean().exec();
if (!report) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED });
let totalScore: number;
if (member.total < 200) totalScore = 0;
else if (member.total > 800) totalScore = 800;
else totalScore = Math.round(member.total);
if (report.total < 200) totalScore = 0;
else if (report.total > 800) totalScore = 800;
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.Score.updateOne({ userID: member.userID }, { $addToSet: { softInquiries: { name: merchant.name, date: new Date() } } });
const embed = new RichEmbed();
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(() => {});
const mem = this.server.client.util.resolveMember(report.userID, this.server.client.guilds.get(this.server.client.config.guildID));
await this.server.client.report.createInquiry(report.userID, merchant.name.toUpperCase(), 1);
if (!merchant.privileged) {
return res.status(200).json({
code: this.constants.codes.SUCCESS,
message: {
userID: member.userID,
userID: report.userID,
totalScore,
},
});
@ -288,36 +256,38 @@ export default class Report extends Route {
if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER');
}
const set = [];
const accounts = await this.server.client.db.Score.find().lean().exec();
for (const sc of accounts) {
if (sc.total < 200) { continue; }
if (sc.total > 800) { set.push(800); continue; }
set.push(sc.total);
if (req.query.p?.toString() === 'true') {
const accounts = await this.server.client.db.Score.find().lean().exec();
for (const sc of accounts) {
if (sc.total < 200) { continue; }
if (sc.total > 800) { set.push(800); continue; }
set.push(sc.total);
}
}
let activityScore: number;
const moderationScore = Math.round(member.moderation);
const moderationScore = Math.round(report.moderation);
let roleScore: number;
let cloudServicesScore: number;
const otherScore = Math.round(member.other);
const otherScore = Math.round(report.other);
let miscScore: number;
if (member.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 activityScore = Math.round(member.activity);
if (report.activity < 10) activityScore = 0;
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(report.activity);
if (member.roles <= 0) roleScore = 0;
else if (member.roles > 54) roleScore = 54;
else roleScore = Math.round(member.roles);
if (report.roles <= 0) roleScore = 0;
else if (report.roles > 54) roleScore = 54;
else roleScore = Math.round(report.roles);
if (member.staff <= 0) miscScore = 0;
else miscScore = Math.round(member.staff);
if (report.staff <= 0) miscScore = 0;
else miscScore = Math.round(report.staff);
if (member.cloudServices === 0) cloudServicesScore = 0;
else if (member.cloudServices > 10) cloudServicesScore = 10;
else cloudServicesScore = Math.round(member.cloudServices);
if (report.cloudServices === 0) cloudServicesScore = 0;
else if (report.cloudServices > 10) cloudServicesScore = 10;
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[] = [];
for (const data of historicalData) {
delete data.report?.softInquiries;
@ -359,7 +329,7 @@ export default class Report extends Route {
return res.status(200).json({
code: this.constants.codes.SUCCESS,
message: {
userID: member.userID,
userID: report.userID,
memberInformation: {
username: mem.user.username,
discriminator: mem.user.discriminator,
@ -370,7 +340,7 @@ export default class Report extends Route {
nitroBoost: mem.premiumSince === null,
},
totalScore,
percentile: Math.round(this.server.client.util.percentile(set, member.total)),
percentile: Math.round(this.server.client.util.percentile(set, report.total)),
activityScore,
moderationScore,
roleScore,
@ -405,17 +375,7 @@ export default class Report extends Route {
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.Score.updateOne({ userID: member.userID }, { $addToSet: { softInquiries: { name: merchant.name, date: new Date() } } });
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(() => {});
await this.server.client.report.createInquiry(member.userID, merchant.name.toUpperCase(), 1);
if (!merchant.privileged) {
return res.status(200).json({
@ -489,42 +449,12 @@ export default class Report extends Route {
this.timeout.delete(req.ip);
if (staffScore.userID === score.userID) {
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() } } });
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(() => {});
await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1);
} 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() } } });
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(() => {});
await this.server.client.report.createInquiry(member.user.id, 'Library of Code sp-us | Staff Team via report.libraryofcode.org', 1);
}
} 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() } } });
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(() => {});
await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1);
}
score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec();
@ -560,7 +490,7 @@ export default class Report extends Route {
else if (score.cloudServices > 10) cloudServicesScore = '10';
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();
@ -595,6 +525,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;
}
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({
name: `${member.username}#${member.discriminator}`,
avatarURL: member.avatarURL,
@ -610,8 +551,8 @@ export default class Report extends Route {
notify: score.notify,
locked: !!score.locked,
totalModerations: moderations?.length > 0 ? moderations.length : 0,
inquiries: score.inquiries?.length > 0 ? score.inquiries : [],
softInquiries: score.softInquiries?.length > 0 ? score.softInquiries : [],
inquiries: hardInquiries?.length > 0 ? hardInquiries : [],
softInquiries: softInquiries?.length > 0 ? softInquiries : [],
historical: historical ?? [],
lastUpdated: score.lastUpdate,
});

View File

@ -8,6 +8,7 @@ import {
Customer, CustomerInterface,
CustomerPortal, CustomerPortalInterface,
File, FileInterface,
Inquiry, InquiryInterface,
Member, MemberInterface,
Merchant, MerchantInterface,
Moderation, ModerationInterface,
@ -43,7 +44,7 @@ export default class Client extends eris.Client {
public stripe: Stripe;
public db: { Customer: mongoose.Model<CustomerInterface>, CustomerPortal: mongoose.Model<CustomerPortalInterface>, File: mongoose.Model<FileInterface>, 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 } };
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 } };
constructor(token: string, options?: eris.ClientOptions) {
super(token, options);
@ -51,7 +52,15 @@ 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, File, Member, Merchant, Moderation, NNTrainingData, Note, PagerNumber, Promo, Rank, Redirect, 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;
}

View File

@ -1,9 +1,10 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-eval */
import Bull from 'bull';
import cron from 'cron';
import { TextableChannel } from 'eris';
import { TextableChannel, TextChannel } from 'eris';
import { Client, RichEmbed } from '.';
import { ScoreInterface } from '../models';
import { ScoreInterface, InqType as InquiryType } from '../models';
import { apply as Apply } from '../commands';
@ -28,12 +29,13 @@ export default class Queue {
const startDate = new Date();
for (const report of reports) {
const inqs = await this.client.db.Inquiry.find({ userID: report.userID });
const data = new this.client.db.ScoreHistorical({
userID: report.userID,
report,
inquiries: inqs.map((inq) => inq._id),
date: startDate,
});
// eslint-disable-next-line no-await-in-loop
await data.save();
}
} catch (err) {
@ -77,6 +79,37 @@ export default class Queue {
}
protected setProcessors() {
this.queues.score.process('score::inquiry', async (job: Bull.Job<{ inqID: string, userID: string, name: string, type: InquiryType, reason?: string }>) => {
const member = this.client.util.resolveMember(job.data.userID, this.client.guilds.get(this.client.config.guildID));
const report = await this.client.db.Score.findOne({ userID: job.data.userID }).lean().exec();
const embed = new RichEmbed();
if (job.data.type === InquiryType.HARD) {
embed.setTitle('Inquiry Notification');
embed.setDescription(job.data.inqID);
embed.setColor('#800080');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true);
embed.addField('Type', 'HARD', true);
embed.addField('Department/Service', job.data.name.toUpperCase(), true);
embed.addField('Reason', job.data.reason ?? 'N/A', true);
embed.setTimestamp();
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
if (report.notify === true) {
await this.client.getDMChannel(job.data.userID).then((chan) => {
chan.createMessage(`__**Community Score - Hard Pull Notification**__\n*You have signed up to be notified whenever your hard score has been pulled. See \`?score\` for more information.*\n\n**Department/Service:** ${job.data.name.toUpperCase()}`);
}).catch(() => {});
}
} else {
embed.setTitle('Inquiry Notification');
embed.setColor('#00FFFF');
embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true);
embed.addField('Type', 'SOFT', true);
embed.addField('Department/Service', job.data.name.toUpperCase(), true);
embed.setTimestamp();
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
}
const log = <TextChannel> this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849');
log.createMessage({ embed }).catch(() => {});
});
this.queues.score.process('score::update', async (job: Bull.Job<{ score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number }>) => {
await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { total: job.data.total, activity: job.data.activity, roles: job.data.roles, moderation: job.data.moderation, cloudServices: job.data.cloudServices, other: job.data.other, staff: job.data.staff, lastUpdate: new Date() } });
if (!job.data.score.pin || job.data.score.pin?.length < 1) {
@ -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) {
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) {

View File

@ -1,6 +1,6 @@
import { EventEmitter } from 'events';
import { Client, RichEmbed } from '.';
import { ScoreHistoricalRaw } from '../models/ScoreHistorical';
import { v4 as uuid } from 'uuid';
import { Client } from '.';
import { InqType } from '../models';
export default class Report {
public client: Client;
@ -9,7 +9,27 @@ export default class Report {
this.client = client;
}
public async soft(userID: string) {
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;
@ -73,5 +93,5 @@ export default class Report {
array.push(data);
}
}
} */
}

View File

@ -4,7 +4,7 @@ import childProcess from 'child_process';
import { promisify } from 'util';
import signale from 'signale';
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';
export default class Util {
@ -18,6 +18,8 @@ export default class Util {
public pbx: PBX;
public report: Report;
constructor(client: Client) {
this.client = client;
this.moderation = new Moderation(this.client);
@ -33,6 +35,7 @@ export default class Util {
auth: { user: 'internal', pass: this.client.config.emailPass },
});
this.pbx = new PBX(this.client);
this.report = new Report(this.client);
}
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
* @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 PBX } from './PBX';
export { default as Queue } from './Queue';
export { default as Report } from './Report';
export { default as RichEmbed } from './RichEmbed';
export { default as Route } from './Route';
export { default as Server } from './Server';

View File

@ -7,7 +7,7 @@ export default class Callback extends Command {
constructor(client: Client) {
super(client);
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.aliases = ['cb'];
this.permissions = 0;
@ -31,17 +31,7 @@ export default class Callback extends Command {
embed.addField('Phone Number Type', phone.getType(), true);
const communityReport = await this.client.db.Score.findOne({ userID: message.author.id }).lean().exec();
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() } } });
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(() => {});
await this.client.report.createInquiry(member.user.id, 'Library of Code sp-us | VOIP/PBX Member Support SVCS', 1);
embed.addField('PIN', `${communityReport.pin[0]}-${communityReport.pin[1]}-${communityReport.pin[2]}`, true);
}
try {

View File

@ -1,5 +1,4 @@
import { Message } from 'eris';
import { randomBytes } from 'crypto';
import { Client, Command } from '../class';
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 kick } from './kick';
export { default as listredirects } from './listredirects';
export { default as market } from './market';
export { default as members } from './members';
export { default as mute } from './mute';
export { default as notes } from './notes';

View File

@ -1,4 +1,4 @@
import { Message, User, Member } from 'eris';
import { Member, Message } from 'eris';
import { Client, Command } from '../class';
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

@ -27,18 +27,7 @@ export default class Score extends Command {
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.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();
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(() => {});
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}`);

View File

@ -1,3 +1,4 @@
/* eslint-disable no-plusplus */
/* eslint-disable no-continue */
/* eslint-disable default-case */
import moment from 'moment';
@ -13,8 +14,9 @@ export default class Score extends Command {
constructor(client: Client) {
super(client);
this.name = 'score';
this.description = 'Retreives 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.aliases = ['report'];
this.subcmds = [Score_Hist, Score_Notify, Score_Pref];
this.permissions = 0;
this.guildOnly = false;
@ -28,18 +30,7 @@ export default class Score extends Command {
if (!args[0] || !this.checkCustomPermissions(this.client.util.resolveMember(message.author.id, this.mainGuild), 4)) {
user = message.author;
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() } } });
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(() => {});
await this.client.report.createInquiry(user.id, `${user.username} via Discord`, 1);
check = true;
} else {
user = this.client.util.resolveMember(args[0], this.mainGuild)?.user;
@ -57,30 +48,12 @@ export default class Score extends Command {
const score = await this.client.db.Score.findOne({ userID: user.id });
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.');
const reportID = uuid();
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(() => {});
}
await this.client.report.createInquiry(score.userID, name, 0, reason);
}
}
if (!user) return this.error(message.channel, 'Member not found.');
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.');
let totalScore = '0';
let activityScore = '0';
@ -134,13 +107,16 @@ export default class Score extends Command {
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';
score.inquiries.forEach((inq) => {
inqs.forEach((inq) => {
const testDate = (new Date(new Date(inq.date).setHours(1460)));
// 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:** ${inq.date.toLocaleString('en-us')} ET\n**Expires:** ${moment(testDate).calendar()}\n\n`;
inqAdded++;
});
if (inqAdded <= 0) desc = '';
if (desc.length >= 1900) {
embed.setDescription('__***Too many Hard Inquiries to show, please see https://report.libraryofcode.org***__');
} else {
@ -183,18 +159,7 @@ export default class Score extends Command {
name = `Library of Code sp-us | ${role.name}`;
break;
}
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name, date: new Date() } } });
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(() => {});
await this.client.report.createInquiry(user.id, name, 1);
}
}
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 default-case */
import moment from 'moment';
@ -6,6 +7,7 @@ import { createPaginationEmbed } from 'eris-pagination';
import { Message, User, TextChannel } from 'eris';
import { Client, Command, RichEmbed } from '../class';
import { getTotalMessageCount } from '../intervals/score';
import { InquiryInterface } from '../models';
export default class Score_Hist extends Command {
constructor(client: Client) {
@ -78,8 +80,15 @@ export default class Score_Hist extends Command {
let data = '';
let hardInquiries = 0;
if (hist.report?.inquiries?.length > 0) {
hist.report.inquiries.forEach((inq) => {
const inquiries: InquiryInterface[] = [];
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)));
// eslint-disable-next-line no-plusplus
if (testDate > new Date()) hardInquiries++;
@ -156,17 +165,7 @@ export default class Score_Hist extends Command {
return cmdPages.push(embed);
});
const name = `${user.username} VIA DISCORD - [HISTORICAL]`;
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name: name.toUpperCase(), date: new Date() } } });
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(() => {});
await this.client.report.createInquiry(user.id, name, 1);
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 hardInquiries = 0;
if (hist.report?.inquiries?.length > 0) {
hist.report.inquiries.forEach((inq) => {
const inquiries: InquiryInterface[] = [];
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)));
// eslint-disable-next-line no-plusplus
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]`;
break;
}
await this.client.db.Score.updateOne({ userID: user.id }, { $addToSet: { softInquiries: { name, date: new Date() } } });
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(() => {});
await this.client.report.createInquiry(user.id, name, 1);
if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] });

View File

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

View File

@ -1,8 +1,7 @@
/* eslint-disable no-bitwise */
import moment from 'moment';
import { Message, Member, TextChannel } from 'eris';
import { Message, Member } from 'eris';
import { Client, Command, RichEmbed } from '../class';
// import acknowledgements from '../configs/acknowledgements.json';
import { whois as emotes } from '../configs/emotes.json';
export default class Whois extends Command {
@ -34,7 +33,6 @@ export default class Whois extends Command {
}
const embed = new RichEmbed();
embed.setThumbnail(member.avatarURL);
// const ackResolve = this.resolveStaffInformation(member.id);
const ackResolve = await this.client.db.Staff.findOne({ userID: member.id }).lean().exec();
let title = `${member.user.username}#${member.user.discriminator}`;
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();
if (pager?.num) {
description += `📡 ${pager.num}\n`;
description += `📟 ${pager.num}\n`;
}
if (ackResolve?.extension) {
description += `☎️ ${ackResolve.extension}\n`;
@ -77,24 +75,11 @@ export default class Whois extends Command {
}
}
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('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();
if (score) {
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();
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(() => {});
await this.client.report.createInquiry(member.id, 'Library of Code sp-us | Bureau of Community Reports', 1);
let totalScore = '0';
if (score.total < 200) totalScore = '---';
else if (score.total > 800) totalScore = '800';
@ -228,7 +213,7 @@ export default class Whois extends Command {
if (serverAcknowledgements.length > 0) {
embed.addField('Acknowledgements', serverAcknowledgements[0]);
}
if (ackResolve?.acknowledgements) {
if (ackResolve?.acknowledgements?.length > 0) {
embed.addField('Bot Acknowledgements', ackResolve.acknowledgements.join(', '));
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);

View File

@ -1,149 +0,0 @@
[
{
"name": "Matthew",
"id": "278620217221971968",
"title": "Chief Director of Engineering",
"pn": ["AD", "FSEN", "FSO", "FSCR", "FSCE", "FSED"],
"dept": "Board of Directors",
"emailAddress": "matthew@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/matthew",
"github": "https://github.com/matthew119427",
"bio": "so baby come light me up, and maybe ill let you on it. a little bit dangerous, but baby thats how i want it. a little less conversation and a little more touch my body. cuz im so into you... ~ Ariana Grande, Into You - Dangerous Woman",
"acknowledgements": ["Maintainer & Lead Developer"]
},
{
"name": "Bsian",
"id": "253600545972027394",
"title": "Director of Engineering",
"pn": ["AD", "FSEN", "FSCR", "FSED"],
"dept": "Board of Directors",
"emailAddress": "bsian@staff.libraryofcode.org",
"bio": "I also like trains",
"acknowledgements": ["Maintainer & Assistant Lead Developer"]
},
{
"name": "NightRaven",
"id": "239261547959025665",
"title": "Director of Information Security",
"pn": ["AD", "FSEN", "FSO", "FSCR", "FSED"],
"dept": "Board of Directors",
"emailAddress": "nightraven@staff.libraryofcode.org",
"bio": "I like trains"
},
{
"name": "Unknown",
"id": "143414786913206272",
"title": "Director of Operations",
"pn": ["AD", "FSO", "FSM", "FSCR"],
"dept": "Board of Directors",
"emailAddress": "unknown@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/unknown",
"bio": "im not a proffesional developer or anything, i just enjoy it as a hobby."
},
{
"name": "TheSkele27",
"id": "213632190557192192",
"title": "Director of Community Engagement",
"pn": ["AD", "FSCE"],
"dept": "Board of Directors",
"emailAddress": "theskele27@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/TheSkele27",
"github": "https://github.com/TheSkele27",
"bio": "Is water wet?"
},
{
"name": "Catbirby",
"id": "131953641371205632",
"pn": ["SP", "FSO", "FSM"],
"dept": "Supervisor",
"emailAddress": "catbirby@staff.libraryofcode.org",
"github": "https://github.com/catbirby",
"bio": "Computer Tech/Networking Nerd/SysADin/Graphic Designer/Audiophile. I don't do much coding but know my way around most languages."
},
{
"name": "D3XTER",
"id": "468009964263178262",
"pn": ["ST", "CE-I"],
"dept": "Core Team",
"emailAddress": "dexter@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/D3XTER",
"bio": "Hi I'm D3XTER how are ya?"
},
{
"name": "DedShotTM",
"id": "402154763363418142",
"pn": ["ST", "FSCR"],
"dept": "Technician & Moderator",
"emailAddress": "dedshot@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/DedShotTM",
"github": "https://github.com/DedShotTM",
"bio": "Imagine having a bio",
"acknowledgements": ["Contributor"]
},
{
"name": "EdgyBoi2414",
"id": "397432516010835970",
"pn": ["ST"],
"dept": "Core Team",
"emailAddress": "edgyboi2414@gmail.com",
"gitlab": "https://gitlab.libraryofcode.org/EdgyBoi2414",
"github": "https://github.com/EdgyBoi2414",
"bio": "\"If teardrops could be bottled, there'd be swimming pools, built by model..\" - Some Philosopher"
},
{
"name": "Hector",
"id": "377781496292835339",
"pn": ["ST", "CRS-I"],
"dept": "Technician",
"emailAddress": "hector@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/Hector",
"github": "https://github.com/Hector6704",
"bio": "Hi there, I'm the developer of Delta, the Discord bot. I'm a free-time French JavASript developer. I hope you'll enjoy LOC!",
"acknowledgements": ["Contributor"]
},
{
"name": "KhaaZ",
"id": "179908288337412096",
"pn": ["ST", "FSEN"],
"dept": "Core Team",
"emailAddress": "khaaz@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/KhaaZ",
"github": "https://github.com/Khaazz",
"bio": "I baguette for a living and eat code for breakfast.",
"acknowledgements": ["Assistant Maintainer"]
},
{
"name": "PlayerVMachine",
"id": "273999507174195203",
"pn": ["ST", "ED-I"],
"dept": "Instructor & Core Team",
"emailAddress": "nicolas@staff.libraryofcode.org",
"bio": "I write C++ to pay off my student loans"
},
{
"name": "Sterben",
"id": "241361691730903040",
"pn": ["ST", "CRS-I", "ENG-I"],
"dept": "Core Team",
"emailAddress": "sterben@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/Sterben",
"github": "https://github.com/sterben6",
"bio": "im bored"
},
{
"name": "Raymond",
"id": "314564798992089090",
"pn": ["AS"],
"dept": "Associate",
"emailAddress": "smashjarchive@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/javaarchive",
"github": "https://github.com/javaarchive",
"bio": "I don't like reinventing the wheel and don't like coding on small screens like laptops as much"
},
{
"name": "Null",
"id": "323673862971588609",
"gitlab": "https://gitlab.libraryofcode.org/null",
"acknowledgements": ["Contributor"]
}
]

View File

@ -13,7 +13,7 @@ export default class GuildMemberAdd extends Event {
try {
const search = await this.client.db.local.muted.get<boolean>(`muted-${member.user.id}`);
if (search === true) {
member.addRole('478373942638149643');
member.addRole('478373942638149643', 'muted user left server and joined back');
}
} catch (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 (new Date() > moderation.expiration.date) {
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);
switch (moderation.type) {
case 5:

View File

@ -63,8 +63,8 @@ export default async function calculateScore(client: Client): Promise<NodeJS.Tim
staff: boolean,
locked: boolean,
notify: boolean,
inquiries: [{ name: string, reason: string, date: Date }?],
softInquiries: [{name: string, date: Date }?]
// inquiries: [{ name: string, reason: string, date: Date }?],
// softInquiries: [{name: string, date: Date }?]
lastUpdated: Date,
pin: number[],
/* generalMessagesRatio: number,
@ -82,8 +82,8 @@ export default async function calculateScore(client: Client): Promise<NodeJS.Tim
staff: false,
locked: false,
notify: false,
inquiries: [],
softInquiries: [],
// inquiries: [],
// softInquiries: [],
lastUpdated: new Date(),
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,11 +1,12 @@
import { Document, Schema, model } from 'mongoose';
export interface MemberInterface extends Document {
userID: string
userID: string,
additional: {
langs: ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'],
operatingSystems: ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'],
},
bio: string,
}
const Member: Schema = new Schema({
@ -14,6 +15,7 @@ const Member: Schema = new Schema({
langs: Array,
operatingSystems: Array,
},
bio: String,
});
export default model<MemberInterface>('Member', Member);

View File

@ -49,30 +49,11 @@ export interface ScoreInterfaceRaw {
export interface ScoreInterface extends Document {
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,
/**
* 10 - 55
*/
activity: number,
/**
* 0 - 54
*/
roles: number,
/**
* -50 - 2
* all users start out with 2 moderation points, the number of points decreases for each moderation.
*/
moderation: number,
/**
* -20 - 50
* processed by CSD
*/
cloudServices: number,
// 0 or 20, 20 points are added if the user is a staff member
staff: number,
other: number,
notify: boolean,

View File

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

View File

@ -1,6 +1,7 @@
export { default as Customer, CustomerInterface } from './Customer';
export { default as CustomerPortal, CustomerPortalInterface } from './CustomerPortal';
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 Merchant, MerchantInterface } from './Merchant';
export { default as Moderation, ModerationInterface } from './Moderation';

View File

@ -4,11 +4,17 @@ import { promises as fs } from 'fs';
import { PBX } from '../../class';
export default class Misc {
public static async accessDenied(channel: ARI.Channel) {
const playback = await channel.play({
media: 'sound:access-denied',
}, undefined);
playback.once('PlaybackFinished', () => channel.hangup());
public static accessDenied(channel: ARI.Channel) {
return new Promise<void>((resolve, reject) => {
channel.play({
media: 'sound:access-denied',
}, 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> {

View File

@ -18,7 +18,7 @@
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
"removeComments": true, /* Do not emit comments to output. */
// "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'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

View File

@ -596,6 +596,14 @@ ax@0.1.8:
resolved "https://registry.yarnpkg.com/ax/-/ax-0.1.8.tgz#27ca9a73fa4c78a478d62d827cad860a24fdd497"
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:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
@ -2229,6 +2237,11 @@ is-arrayish@^0.2.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
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.4, is-callable@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
@ -3773,6 +3786,13 @@ standard-as-callback@^2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
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:
version "1.0.1"
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
@ -4051,6 +4071,11 @@ tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.12.0.tgz#d1fc9cacd06a1456c62f2902b361573e83d66473"
integrity sha512-5rxCQkP0kytf4H1T4xz1imjxaUUPMvc5aWp0rJ/VMIN7ClRiH1FwFvBt8wOeMasp/epeUnmSW6CixSIePtiLqA==
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:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"