Member Profiles #32

Closed
ghost wants to merge 28 commits from profile into master
52 changed files with 1411 additions and 7287 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.

4889
package-lock.json generated

File diff suppressed because it is too large Load Diff

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",
@ -42,7 +43,7 @@
"bull": "^3.20.1", "bull": "^3.20.1",
"cheerio": "^1.0.0-rc.5", "cheerio": "^1.0.0-rc.5",
"cron": "^1.8.2", "cron": "^1.8.2",
"eris": "^0.13.3", "eris": "^0.14.0",
"eris-pagination": "github:bsian03/eris-pagination", "eris-pagination": "github:bsian03/eris-pagination",
"express": "^4.17.1", "express": "^4.17.1",
"helmet": "^3.22.0", "helmet": "^3.22.0",
@ -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,3 +0,0 @@
import { Server, ServerManagement } from '../../class';
export default (management: ServerManagement) => new Server(management, 3892, `${__dirname}/routes`);

View File

@ -1 +0,0 @@
export { default as Root } from './root';

View File

@ -1,777 +0,0 @@
import { TextChannel } from 'eris';
import { v4 as genUUID } from 'uuid';
import { Request, Response } from 'express';
import { RichEmbed, Route, Server } from '../../../class';
export default class Root extends Route {
constructor(server: Server) {
super(server);
this.conf = {
path: '/',
};
}
public bind() {
this.router.post('/eo', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
if (!director || !staffGuild.members.get(director.userID)?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 1024 || req.body.body.length > 1024) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const eoID = genUUID();
const directorDiscord = this.server.client.users.get(director.userID) || await this.server.client.getRESTUser(director.userID);
const directorInformation = await this.server.client.db.Staff.findOne({ userID: director.userID });
const embed = new RichEmbed();
embed.setTitle('Executive Order');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorInformation.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#dd3acd');
embed.addField('Subject', req.body.subject);
embed.addField('Body', req.body.body);
embed.addField('Director', directorDiscord.mention);
embed.setDescription(eoID);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const msg = await channel.createMessage({ embed });
const executiveOrder = await this.server.client.db.ExecutiveOrder.create({
issuer: director.userID,
subject: req.body.subject,
body: req.body.body,
at: new Date(),
oID: eoID,
msg: msg.id,
});
res.status(200).json({
code: this.constants.codes.SUCCESS,
message: `Created new Executive Order with ID ${executiveOrder.oID} by ${directorDiscord.username}#${directorDiscord.discriminator}, ${directorInformation.pn.join(', ')}.`,
});
});
this.router.post('/proc', async (req: Request, res: Response) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
if (!director || !staffGuild.members.get(director.userID)?.roles?.includes('662163685439045632')) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 1024 || req.body.body.length > 1024) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const proclamationID = genUUID();
const directorDiscord = this.server.client.users.get(director.userID) || await this.server.client.getRESTUser(director.userID);
const directorInformation = await this.server.client.db.Staff.findOne({ userID: director.userID });
const embed = new RichEmbed();
embed.setTitle('Proclamation');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorInformation.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#66e1ff');
embed.addField('Subject', req.body.subject);
embed.addField('Body', req.body.body);
embed.addField('ID', proclamationID);
embed.addField('Director', directorDiscord.mention);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const procMessage = await channel.createMessage({ embed });
await procMessage.addReaction(this.server.client.util.emojis.SUCCESS);
await procMessage.addReaction(this.server.client.util.emojis.ERROR);
await procMessage.getReaction('🙋');
const proclamation = await this.server.client.db.Proclamation.create({
issuer: director.userID,
subject: req.body.subject,
body: req.body.body,
at: new Date(),
oID: proclamationID,
processed: false,
msg: procMessage.id,
});
res.status(200).json({
code: this.constants.codes.SUCCESS,
message: `Created new Proclamation with ID ${proclamation.oID} by ${directorDiscord.username}#${directorDiscord.discriminator}, ${directorInformation.pn.join(', ')}.`,
});
});
this.router.delete('/eo/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
if (!director || !staffGuild.members.get(director.userID)?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.ExecutiveOrder.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const executiveOrder = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id });
if (!['278620217221971968', executiveOrder.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await executiveOrder.delete();
res.status(200).json({ message: `Executive Order with ID ${req.params.id} deleted.` });
});
this.router.delete('/motion/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
if (!director || !staffGuild.members.get(director.userID)?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Motion.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });
if (!['278620217221971968', motion.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await motion.delete();
res.status(200).json({ message: `Motion with ID ${req.params.id} deleted.` });
});
this.router.delete('/proc/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
if (!director || !staffGuild.members.get(director.userID)?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Proclamation.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const proclamation = await this.server.client.db.Proclamation.findOne({ oID: req.params.id });
if (!['278620217221971968', proclamation.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await proclamation.delete();
res.status(200).json({ message: `Proclamation with ID ${req.params.id} deleted.` });
});
this.router.get('/eo/:id', async (req, res) => {
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.ExecutiveOrder.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const executiveOrder = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id }).lean();
res.status(200).json(executiveOrder);
});
this.router.get('/motion/:id', async (req, res) => {
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Motion.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id }).lean();
res.status(200).json(motion);
});
this.router.get('/proc/:id', async (req: Request, res: Response) => {
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Proclamation.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const proclamation = await this.server.client.db.Proclamation.findOne({ oID: req.params.id }).lean();
res.status(200).json(proclamation);
});
this.router.get('/resolution/:id', async (req, res) => {
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Resolution.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const resolution = await this.server.client.db.Resolution.findOne({ oID: req.params.id }).lean();
res.status(200).json(resolution);
});
this.router.patch('/eo/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
const directorDiscord = staffGuild.members.get(director.userID);
if (!director || !directorDiscord?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.ExecutiveOrder.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 1024 || req.body.body.length > 1024) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const executiveOrder = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id });
if (!['278620217221971968', executiveOrder.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await executiveOrder.updateOne({
subject: req.body.subject || executiveOrder.subject,
body: req.body.body || executiveOrder.body,
});
if (executiveOrder.subject !== req.body.subject || executiveOrder.body !== req.body.body) {
const directorStaffProfile = await this.server.client.db.Staff.findOne({ userID: directorDiscord.id });
const embed = new RichEmbed();
embed.setTitle('Executive Order');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorStaffProfile.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#66e1ff');
embed.addField('Subject', req.body.subject || executiveOrder.subject);
embed.addField('Body', req.body.body || executiveOrder.body);
embed.addField('Director', `<@!${executiveOrder.issuer}>`);
embed.setDescription(req.params.id);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const eoMessage = await channel.getMessage(executiveOrder.msg);
await eoMessage.edit({ embed });
}
res.status(200).json({ message: `Updated Executive Order with ID ${executiveOrder.oID}.` });
});
this.router.patch('/motion/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
const directorDiscord = staffGuild.members.get(director.userID);
if (!director || !directorDiscord?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Motion.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 1024 || req.body.body.length > 1024) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });
if (!['278620217221971968', motion.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await motion.updateOne({
subject: req.body.subject || motion.subject,
body: req.body.body || motion.body,
});
if (motion.subject !== req.body.subject || motion.body !== req.body.body) {
const directorStaffProfile = await this.server.client.db.Staff.findOne({ userID: directorDiscord.id });
const embed = new RichEmbed();
embed.setTitle('Motion');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorStaffProfile.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#66e1ff');
embed.addField('Subject', req.body.subject || motion.subject);
embed.addField('Body', req.body.body || motion.body);
embed.addField('Director', `<@!${motion.issuer}>`);
embed.setDescription(req.params.id);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const motionMessage = await channel.getMessage(motion.msg);
await motionMessage.edit({ embed });
}
res.status(200).json({ message: `Updated Motion with ID ${motion.oID}.` });
});
this.router.patch('/proc/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
const directorDiscord = staffGuild.members.get(director.userID);
if (!director || !directorDiscord?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Proclamation.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 1024 || req.body.body.length > 1024) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const proclamation = await this.server.client.db.Proclamation.findOne({ oID: req.params.id });
if (!['278620217221971968', proclamation.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await proclamation.updateOne({
subject: req.body.subject || proclamation.subject,
body: req.body.body || proclamation.body,
});
if (proclamation.subject !== req.body.subject || proclamation.body !== req.body.body) {
const directorStaffProfile = await this.server.client.db.Staff.findOne({ userID: directorDiscord.id });
const embed = new RichEmbed();
embed.setTitle('Proclamation');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorStaffProfile.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#66e1ff');
embed.addField('Subject', req.body.subject || proclamation.subject);
embed.addField('Body', req.body.body || proclamation.body);
embed.addField('Director', `<@!${proclamation.issuer}>`);
embed.setDescription(req.params.id);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const procMessage = await channel.getMessage(proclamation.msg);
await procMessage.edit({ embed });
}
res.status(200).json({ message: `Updated Proclamation with ID ${proclamation.oID}.` });
});
this.router.patch('/resolution/:id', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
const directorDiscord = staffGuild.members.get(director.userID);
if (!director || !directorDiscord?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Resolution.exists({ oID: req.params.id }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 1024 || req.body.body.length > 1024) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const resolution = await this.server.client.db.Resolution.findOne({ oID: req.params.id });
if (!['278620217221971968', resolution.issuer].includes(director.userID)) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
await resolution.updateOne({
subject: req.body.subject || resolution.subject,
body: req.body.body || resolution.body,
});
if (resolution.subject !== req.body.subject || resolution.body !== req.body.body) {
const directorStaffProfile = await this.server.client.db.Staff.findOne({ userID: directorDiscord.id });
const motion = await this.server.client.db.Motion.findOne({ oID: resolution.oID });
const embed = new RichEmbed();
embed.setTitle('Resolution');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorStaffProfile.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#75b0ff');
embed.addField('Subject', req.body.subject || resolution.subject);
embed.addField('Body', req.body.body || resolution.body);
embed.addField('Director', `<@!${motion.issuer}>`);
embed.setDescription(req.params.id);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const resMessage = await channel.getMessage(resolution.msg);
await resMessage.edit({
content: `<@!${resolution.issuer}>`,
embed,
});
}
res.status(200).json({ message: `Updated Resolution with ID ${resolution.oID}.` });
});
this.router.get('/eo', async (_req, res) => {
const executiveOrders = await this.server.client.db.ExecutiveOrder.find().lean();
res.status(200).json(executiveOrders);
});
this.router.get('/motion', async (_req, res) => {
const motions = await this.server.client.db.Motion.find().lean();
res.status(200).json(motions);
});
this.router.get('/proc', async (_req: Request, res: Response) => {
const proclamations = await this.server.client.db.Proclamation.find().lean();
res.status(200).send({ proclamations });
});
this.router.get('/resolution', async (_req, res) => {
const resolutions = await this.server.client.db.Resolution.find().lean();
res.status(200).json(resolutions);
});
this.router.patch('/motion/confirm', async (req, res) => {
if (!req.body.pin) {
return res.status(401).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
const director = await this.server.client.db.Score.findOne({ pin: req.body.pin });
const staffGuild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
const directorDiscord = staffGuild.members.get(director.userID);
if (!director || !directorDiscord?.roles?.includes('662163685439045632')) {
return res.status(403).json({
code: this.constants.codes.UNAUTHORIZED,
message: this.constants.messages.UNAUTHORIZED,
});
}
if (!req.params.id) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!(await this.server.client.db.Motion.exists({ oID: req.params.id, processed: false }))) {
return res.status(404).json({
code: this.constants.codes.NOT_FOUND,
message: this.constants.messages.NOT_FOUND,
});
}
const yea = Number(req.body.yea);
const nay = Number(req.body.nay);
const present = Number(req.body.present);
const absent = Number(req.body.absent);
if (Number.isNaN(yea) || Number.isNaN(nay) || Number.isNaN(present) || Number.isNaN(absent)) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });
await motion.updateOne({
processed: true,
results: {
yea,
nay,
present,
absent,
},
});
const directorStaffProfile = await this.server.client.db.Staff.findOne({ userID: directorDiscord.id });
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const embed = new RichEmbed();
embed.setTitle('Motion Confirmed');
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorStaffProfile.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setColor('#27b17a');
embed.addField('Subject', motion.subject);
embed.addField('Body', motion.body);
embed.addField('Director', `<@!${motion.issuer}>`);
embed.setDescription(motion.oID);
embed.setFooter(motion.oID, directorDiscord.avatarURL);
embed.setTimestamp(new Date());
await channel.createMessage({ embed });
const excludingYea = nay + present + absent;
if (yea > excludingYea) {
const resolutionEmbed = new RichEmbed();
resolutionEmbed.setTitle('Resolution');
resolutionEmbed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorStaffProfile.pn.join(', ')}`, directorDiscord.avatarURL);
resolutionEmbed.setColor('#75b0ff');
resolutionEmbed.addField('Subject', motion.subject);
resolutionEmbed.addField('Body', motion.body);
resolutionEmbed.addField('Director', `<@!${motion.issuer}>`);
resolutionEmbed.setDescription(motion.oID);
resolutionEmbed.setTimestamp(new Date());
const resMsg = await channel.createMessage({
content: `<@!${motion.issuer}>`,
embed: resolutionEmbed,
});
await this.server.client.db.Resolution.create({
issuer: motion.issuer,
subject: motion.subject,
body: motion.body,
at: Date.now(),
oID: motion.oID,
results: {
yea,
nay,
present,
absent,
},
msg: resMsg.id,
});
}
res.status(200).json({ message: `Confirmed results of motion with ID ${motion.oID}.` });
});
}
}

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 = [];
if (req.query.p?.toString() === 'true') {
const accounts = await this.server.client.db.Score.find().lean().exec(); const accounts = await this.server.client.db.Score.find().lean().exec();
for (const sc of accounts) { for (const sc of accounts) {
if (sc.total < 200) { continue; } if (sc.total < 200) { continue; }
if (sc.total > 800) { set.push(800); continue; } if (sc.total > 800) { set.push(800); continue; }
set.push(sc.total); 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

@ -1,10 +1,8 @@
import locsh from './loc.sh/main'; import locsh from './loc.sh/main';
import crins from './cr.ins/main'; import crins from './cr.ins/main';
import commlibraryofcodeorg from './comm.libraryofcode.org/main'; import commlibraryofcodeorg from './comm.libraryofcode.org/main';
import boardins from './board.ins/main';
export default { export default {
'board.ins': boardins,
'loc.sh': locsh, 'loc.sh': locsh,
'cr.ins': crins, 'cr.ins': crins,
'comm.libraryofcode.org': commlibraryofcodeorg, 'comm.libraryofcode.org': commlibraryofcodeorg,

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-constant-condition */ /* eslint-disable no-constant-condition */
import { promises as fs, accessSync, constants, writeFileSync } from 'fs'; import { promises as fs, accessSync, constants, writeFileSync } from 'fs';
import { promisify } from 'util'; import { promisify } from 'util';
import { join } from 'path';
import { gzip, gzipSync, unzip } from 'zlib'; import { gzip, gzipSync, unzip } from 'zlib';
type JSONData = [{key: string, value: any}?]; type JSONData = [{ key: string, value: any }?];
/** /**
@ -18,7 +19,7 @@ export default class LocalStorage {
private locked: boolean = false; private locked: boolean = false;
constructor(dbName: string, dir = `${__dirname}/../../localstorage`) { constructor(dbName: string, dir = `${__dirname}/../../localstorage`) {
this.storagePath = `${dir}/${dbName}.json.gz`; this.storagePath = join(__dirname, '../../localstorage') || dir;
this.init(); this.init();
} }
@ -42,7 +43,7 @@ export default class LocalStorage {
*/ */
static async compress(data: string): Promise<Buffer> { static async compress(data: string): Promise<Buffer> {
const func = promisify(gzip); const func = promisify(gzip);
const comp = <Buffer> await func(data); const comp = <Buffer>await func(data);
return comp; return comp;
} }
@ -57,7 +58,7 @@ export default class LocalStorage {
*/ */
static async decompress(data: Buffer): Promise<string> { static async decompress(data: Buffer): Promise<string> {
const func = promisify(unzip); const func = promisify(unzip);
const uncomp = <Buffer> await func(data); const uncomp = <Buffer>await func(data);
return uncomp.toString(); return uncomp.toString();
} }
@ -91,7 +92,7 @@ export default class LocalStorage {
* await LocalStorage.get<type>('data-key'); * await LocalStorage.get<type>('data-key');
* @param key The key for the data entry. * @param key The key for the data entry.
*/ */
public async getMany<T>(key: string): Promise<{key: string, value: T}[]> { public async getMany<T>(key: string): Promise<{ key: string, value: T }[]> {
while (true) { while (true) {
if (!this.locked) break; if (!this.locked) break;
} }

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

@ -56,6 +56,7 @@ export default class Server {
public init() { public init() {
if (this.parse) { if (this.parse) {
this.app.use(bodyParser.json()); this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
} }
this.app.set('trust proxy', 'loopback'); this.app.set('trust proxy', 'loopback');
this.app.use(helmet({ this.app.use(helmet({

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

@ -12,42 +12,10 @@ export default class Profile extends Command {
} }
public async run(message: Message, args: string[]) { public async run(message: Message, args: string[]) {
const profile = await this.client.db.Member.findOne({ userID: message.author.id }); if (!await this.client.db.Member.exists({ userID: message.author.id })) {
if (!profile) return this.error(message.channel, 'Please try again later. We do not currently have a member profile for you.'); await this.client.db.Member.create({ userID: message.author.id });
if (!args[1]) return this.error(message.channel, 'No new value was provided.');
const newValue = args.slice(1).join(' ');
if (newValue.length >= 512) return this.error(message.channel, 'Please shorten your input.');
switch (args[0]) {
case 'github':
await profile.updateOne({
additional: {
...profile.additional,
github: args[1],
},
});
this.success(message.channel, 'Updated GitHub.');
break;
case 'gitlab':
await profile.updateOne({
additional: {
...profile.additional,
gitlab: args[1],
},
});
this.success(message.channel, 'Updated GitLab.');
break;
case 'bio':
await profile.updateOne({
additional: {
...profile.additional,
bio: newValue,
},
});
this.success(message.channel, 'Updated bio.');
break;
default:
return this.error(message.channel, 'Please specify a valid option to change.');
} }
this.error(message.channel, `Please specify a valid option to change. Choose from \`github\`, \`bio\` and \`gitlab\`. You can view your profile with \`${this.client.config.prefix}whois\`.`);
} }
} }

View File

@ -0,0 +1,30 @@
import { Message } from 'eris';
import { Client, Command } from '../class';
export default class Profile_Bio extends Command {
constructor(client: Client) {
super(client);
this.name = 'bio';
this.description = 'Updates your bio on your profile.';
this.usage = `${this.client.config.prefix}bio <new bio>`;
this.permissions = 0;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
if (!await this.client.db.Member.exists({ userID: message.author.id })) {
await this.client.db.Member.create({ userID: message.author.id });
}
if (!args[0]) return this.error(message.channel, 'No new bio content was provided.');
const bio = args.join(' ');
if (bio.length >= 256) return this.error(message.channel, 'Bio too long. It must be less than or equal to 256 characters.');
const member = await this.client.db.Member.findOne({ userID: message.author.id });
await member.updateOne({
additional: {
...member.additional,
bio,
},
});
}
}

View File

@ -0,0 +1,38 @@
import { Message } from 'eris';
import { Client, Command } from '../class';
export default class Profile_GitHub extends Command {
constructor(client: Client) {
super(client);
this.name = 'github';
this.description = 'Updates your GitHub information on your profile.';
this.usage = `${this.client.config.prefix}github <GitHub profile URL>`;
this.permissions = 0;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
if (!await this.client.db.Member.exists({ userID: message.author.id })) {
await this.client.db.Member.create({ userID: message.author.id });
}
if (!args[0]) return this.error(message.channel, 'No GitHub profile URL was provided.');
const urlRegex = new RegExp(
'^(https?:\\/\\/)?'
+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'
+ '((\\d{1,3}\\.){3}\\d{1,3}))'
+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'
+ '(\\?[;&a-z\\d%_.~+=-]*)?'
+ '(\\#[-a-z\\d_]*)?$',
'i',
);
if (!urlRegex.test(args[0]) || !args[0].startsWith('https://github.com/')) return this.error(message.channel, 'Invalid GitHub profile URL.');
const member = await this.client.db.Member.findOne({ userID: message.author.id });
await member.updateOne({
additional: {
...member.additional,
github: args[0],
},
});
}
}

View File

@ -0,0 +1,38 @@
import { Message } from 'eris';
import { Client, Command } from '../class';
export default class Profile_GitLab extends Command {
constructor(client: Client) {
super(client);
this.name = 'gitlab';
this.description = 'Updates your GitLab information on your profile.';
this.usage = `${this.client.config.prefix}gitlab <GitLab profile URL>`;
this.permissions = 0;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
if (!await this.client.db.Member.exists({ userID: message.author.id })) {
await this.client.db.Member.create({ userID: message.author.id });
}
if (!args[0]) return this.error(message.channel, 'No GitLab profile URL was provided.');
const urlRegex = new RegExp(
'^(https?:\\/\\/)?'
+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'
+ '((\\d{1,3}\\.){3}\\d{1,3}))'
+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'
+ '(\\?[;&a-z\\d%_.~+=-]*)?'
+ '(\\#[-a-z\\d_]*)?$',
'i',
);
if (!urlRegex.test(args[0]) || !args[0].startsWith('https://gitlab.com/')) return this.error(message.channel, 'Invalid GitLab profile URL.');
const member = await this.client.db.Member.findOne({ userID: message.author.id });
await member.updateOne({
additional: {
...member.additional,
gitlab: args[0],
},
});
}
}

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,14 +51,12 @@ 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`;
} }
const memberProfile = await this.client.db.Member.findOne({ userID: message.author.id }); const memberProfile = await this.client.db.Member.findOne({ userID: message.author.id });
if (memberProfile?.additional?.gitlab) { if (memberProfile?.additional?.gitlab) {
description += `${emotes.gitlab} ${memberProfile?.additional.gitlab}\n`; description += `${emotes.gitlab} ${memberProfile?.additional.gitlab}\n`;
} }
@ -80,24 +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) {
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(() => { });
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';
@ -231,8 +214,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

@ -1,6 +1,5 @@
export { default as CallBackHandler } from './CallBackHandler'; export { default as CallBackHandler } from './CallBackHandler';
export { default as CommandHandler } from './CommandHandler'; export { default as CommandHandler } from './CommandHandler';
export { default as guildMemberAdd } from './guildMemberAdd'; export { default as guildMemberAdd } from './guildMemberAdd';
export { default as messageReactionAdd } from './messageReactionAdd';
export { default as ready } from './ready'; export { default as ready } from './ready';
export { default as Training } from './Training'; export { default as Training } from './Training';

View File

@ -1,57 +0,0 @@
import { Emoji, GuildTextableChannel, Member, Message } from 'eris';
import { Client, Event } from '../class';
export default class MessageReactionAdd extends Event {
public client: Client;
constructor(client: Client) {
super(client);
this.event = 'messageReactionAdd';
}
public async run(message: Message<GuildTextableChannel>, _emoji: Emoji, reactor: Member) {
if (message.channel.id !== '807444198969835550') return;
if (message.author.id !== this.client.user.id) return;
if (!reactor.roles[0]) {
reactor = await message.channel.guild.getRESTMember(reactor.id);
}
if (!reactor.roles.includes('662163685439045632')) return;
if ((await this.client.db.Proclamation.exists({ msg: message.id, processed: false }))) {
const yea = await message.getReaction(this.client.util.emojis.SUCCESS);
const nay = await message.getReaction(this.client.util.emojis.ERROR);
const present = await message.getReaction('🙋');
const totalDirectors = 6;
const proclamation = await this.client.db.Proclamation.findOne({ msg: message.id });
const processed = totalDirectors === (yea.length + nay.length + present.length) || Date.now() - proclamation.at > 604800000;
const absent = totalDirectors - (yea.length + nay.length + present.length);
await this.client.db.Proclamation.updateOne({ msg: message.id }, {
results: {
yea: yea.length,
nay: nay.length,
present: present.length,
absent,
},
processed,
});
const inTheMajority = yea.length > nay.length + present.length;
if (processed) {
const author = this.client.users.get(proclamation.issuer) || await this.client.getRESTUser(proclamation.issuer);
if (inTheMajority) {
await author.createMessage(`__**Proclamation Majority Vote Received**__\nThe Proclamation you created at Library of Code sp-us, titled **${proclamation.subject}** (\`${proclamation.oID}\`) received the majority vote.`);
await message.channel.createMessage(`__**Proclamation Results**__\nProclamation issued by ${author.mention} **received** the majority vote. Proclamation ID: ${proclamation.oID}\n\n__Results:__\n**Yea:** ${yea.length}\n**Nay:** ${nay.length}\n**Present:** ${present.length}\n**Absent:** ${absent}`);
} else {
await author.createMessage(`__**Proclamation Majority Vote Lost**__\nThe Proclamation you created at Library of Code sp-us, titled **${proclamation.subject}** (\`${proclamation.oID}\`) lost the majority vote.`);
await message.channel.createMessage(`__**Proclamation Results**__\nProclamation issued by ${author.mention} **lost** the majority vote. Proclamation ID: ${proclamation.oID}\n\n__Results:__\n**Yea:** ${yea.length}\n**Nay:** ${nay.length}\n**Present:** ${present.length}\n**Absent:** ${absent}`);
}
}
await reactor.user.createMessage(`__**Vote Recorded**\nYour vote on the proclamation with ID \`${proclamation.id}\` at Library of Code sp-us was successfully recorded.`);
}
}
}

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

@ -71,7 +71,7 @@ async function setupDepartmentCodes(client: Client): Promise<void> {
function logNewPager(client: Client, num: string, member: Member): void { function logNewPager(client: Client, num: string, member: Member): void {
client.util.signale.log(`Pager Number '${num}' created for '${member.user.username}#${member.user.discriminator}'.`); client.util.signale.log(`Pager Number '${num}' created for '${member.user.username}#${member.user.discriminator}'.`);
const channel = <TextableChannel> client.guilds.get(client.config.guildID).channels.get('722636436716781619'); const channel = <TextableChannel>client.guilds.get(client.config.guildID).channels.get('722636436716781619');
channel.createMessage(`__**'${member.user.username}#${member.user.discriminator}' assigned to pager number '${num}'.**__`); channel.createMessage(`__**'${member.user.username}#${member.user.discriminator}' assigned to pager number '${num}'.**__`);
} }

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)],
}; };

View File

@ -4,6 +4,7 @@
import sdNotify from 'sd-notify'; import sdNotify from 'sd-notify';
import { parse } from 'yaml'; import { parse } from 'yaml';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import { join } from 'path';
import { Client } from './class'; import { Client } from './class';
import * as eventFiles from './events'; import * as eventFiles from './events';
import * as commandFiles from './commands'; import * as commandFiles from './commands';
@ -14,7 +15,7 @@ async function main(): Promise<void> {
sdNotify.ready(); sdNotify.ready();
sdNotify.startWatchdogMode(2500); sdNotify.startWatchdogMode(2500);
} }
const read = await fs.readFile('../config.yaml', 'utf8'); const read = await fs.readFile(join(__dirname, '../config.yaml'), 'utf8');
const config: Config = parse(read); const config: Config = parse(read);
const client = new Client(config.token, { defaultImageFormat: 'png', restMode: true, intents: ['guildBans', 'guildEmojis', 'guildInvites', 'guildMembers', 'guildMessageReactions', 'guildMessages', 'guildPresences', 'guildWebhooks', 'guilds', 'directMessages'] }); const client = new Client(config.token, { defaultImageFormat: 'png', restMode: true, intents: ['guildBans', 'guildEmojis', 'guildInvites', 'guildMembers', 'guildMessageReactions', 'guildMessages', 'guildPresences', 'guildWebhooks', 'guilds', 'directMessages'] });
client.config = config; client.config = config;

View File

@ -1,21 +0,0 @@
import { Document, model, Schema } from 'mongoose';
export interface ExecutiveOrderInterface extends Document {
issuer: string;
subject: string;
body: string;
at: Date;
oID: string;
msg: string;
}
const ExecutiveOrder = new Schema({
issuer: { type: String, required: true },
subject: { type: String, required: true },
body: { type: String, required: true },
at: { type: Date, required: true },
oID: { type: String, required: true, unique: true },
msg: { type: String, required: true, unique: true },
});
export default model<ExecutiveOrderInterface>('ExecutiveOrders', ExecutiveOrder);

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,14 +1,15 @@
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'],
github: string; github: string,
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

@ -1,35 +0,0 @@
import { Document, model, Schema } from 'mongoose';
export interface MotionInterface extends Document {
issuer: string;
subject: string;
body: string;
at: Date;
oID: string;
results: {
yea: number;
nay: number;
present: number;
absent: number;
};
processed: boolean;
msg: string;
}
const Motion = new Schema({
issuer: { type: String, required: true },
subject: { type: String, required: true },
body: { type: String, required: true },
at: { type: Date, required: true },
oID: { type: String, required: true, unique: true },
results: {
yea: Number,
nay: Number,
present: Number,
absent: Number,
},
processed: Boolean,
msg: { required: true, unique: true, type: String },
});
export default model<MotionInterface>('Motions', Motion);

View File

@ -1,37 +0,0 @@
import { Document, model, Schema } from 'mongoose';
export interface ProclamationInterface extends Document {
issuer: string;
subject: string;
body: string;
at: number;
oID: string;
results: {
yea: number;
nay: number;
present: number;
absent: number;
};
acceptedAt: number;
msg: string;
processed: boolean;
}
const Proclamation = new Schema({
issuer: { type: String, required: true },
subject: { type: String, required: true },
body: { type: String, required: true },
at: { type: Number, required: true },
oID: { type: String, required: true, unique: true },
results: {
yea: Number,
nay: Number,
present: Number,
absent: Number,
},
acceptedAt: Number,
msg: { type: String, required: true, unique: true },
processed: Boolean,
});
export default model<ProclamationInterface>('Proclamations', Proclamation);

View File

@ -1,33 +0,0 @@
import { Document, model, Schema } from 'mongoose';
export interface ResolutionInterface extends Document {
issuer: string;
subject: string;
body: string;
at: number;
oID: string;
results: {
yea: number;
nay: number;
present: number;
absent: number;
};
msg: string;
}
const Resolution = new Schema({
issuer: { type: String, required: true },
subject: { type: String, required: true },
body: { type: String, required: true },
at: { type: Number, required: true },
oID: { type: String, required: true, unique: true },
results: {
yea: Number,
Nay: Number,
present: Number,
absent: Number,
},
msg: { type: String, required: true, unique: true },
});
export default model<ResolutionInterface>('Resolutions', Resolution);

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) => {
channel.play({
media: 'sound:access-denied', media: 'sound:access-denied',
}, undefined); }, undefined).then((playback) => {
playback.once('PlaybackFinished', () => channel.hangup()); 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'). */

1839
yarn.lock

File diff suppressed because it is too large Load Diff