diff --git a/src/api/comm.libraryofcode.org/routes/actions.ts b/src/api/comm.libraryofcode.org/routes/actions.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/api/comm.libraryofcode.org/routes/report.ts b/src/api/comm.libraryofcode.org/routes/report.ts index c7f1d97..2b079e0 100644 --- a/src/api/comm.libraryofcode.org/routes/report.ts +++ b/src/api/comm.libraryofcode.org/routes/report.ts @@ -1,611 +1,606 @@ -/* eslint-disable no-bitwise */ -/* eslint-disable no-continue */ -import jwt from 'jsonwebtoken'; -import { TextChannel } from 'eris'; -import { LocalStorage, Route, Server } from '../../../class'; -import { ScoreHistoricalInterface, ScoreHistoricalRaw } from '../../../models/ScoreHistorical'; -import { getTotalMessageCount } from '../../../intervals/score'; - -export default class Report extends Route { - public timeout: Map; - - public acceptedOffers: LocalStorage; - - constructor(server: Server) { - super(server); - this.timeout = new Map(); - this.acceptedOffers = new LocalStorage('accepted-offers'); - this.conf = { - path: '/report', - }; - } - - protected check(userID: string) { - if (this.timeout.has(userID)) { - if (this.timeout.get(userID) >= 3) { - return true; - } - this.timeout.set(userID, this.timeout.get(userID) + 1); - } else { - this.timeout.set(userID, 1); - } - setTimeout(() => { - if (this.timeout.has(userID)) { - this.timeout.set(userID, this.timeout.get(userID) - 1); - } else { - this.timeout.delete(userID); - } - }, 30000); - return false; - } - - public bind() { - this.router.all('*', (_req, res, next) => { - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', '*'); - res.setHeader('Access-Control-Allow-Headers', '*'); - next(); - }); - - this.router.post('/hard', async (req, res) => { - try { - if (!req.headers.authorization) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - if (!req.body.pin || !req.body.userID || !req.body.reason) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.messages.CLIENT_ERROR }); - if (req.body.reason?.length < 1) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.codes.CLIENT_ERROR }); - - const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); - if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - - const member = await this.server.client.db.Score.findOne({ userID: req.body.userID, 'pin.2': req.body.pin }).lean().exec(); - if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - - 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 }); - - if (member.locked) return res.status(403).json({ code: this.constants.codes.PERMISSION_DENIED, message: this.constants.messages.PERMISSION_DENIED }); - if (merchant?.type !== 1) return res.status(403).json({ code: this.constants.codes.PERMISSION_DENIED, message: this.constants.messages.PERMISSION_DENIED }); - - if (this.check(member.userID)) { - await this.server.client.db.Score.updateOne({ userID: member.userID }, { $set: { locked: true } }); - const chan = await this.server.client.getDMChannel(member.userID); - try { - await chan.createMessage(`__**Community Report Locked**__\nWe've detected suspicious activity on your Community Report, for the integrity of your report we have automatically locked it. To unlock your report, please run \`${this.server.client.config.prefix}score pref unlock\` in <#468759629334183956>.`); - } catch (err) { - this.server.client.util.signale.error(`Unable to DM user: ${member.userID} | ${err}`); - } - return res.status(403).json({ code: this.constants.codes.PERMISSION_DENIED, message: this.constants.messages.PERMISSION_DENIED }); - } - - const flags = []; - if (mem.user.publicFlags) { - if ((mem.user.publicFlags & (1 << 0)) === 1 << 0) flags.push('DISCORD_EMPLOYEE'); - if ((mem.user.publicFlags & (1 << 1)) === 1 << 1) flags.push('PARTNERED_SERVER_OWNER'); - if ((mem.user.publicFlags & (1 << 2)) === 1 << 2) flags.push('HYPESQUAD_EVENTS'); - if ((mem.user.publicFlags & (1 << 3)) === 1 << 3) flags.push('BUG_HUNTER_1'); - if ((mem.user.publicFlags & (1 << 6)) === 1 << 6) flags.push('HOUSE_BRAVERY'); - if ((mem.user.publicFlags & (1 << 7)) === 1 << 7) flags.push('HOUSE_BRILLIANCE'); - if ((mem.user.publicFlags & (1 << 8)) === 1 << 8) flags.push('HOUSE_BALANCE'); - if ((mem.user.publicFlags & (1 << 9)) === 1 << 9) flags.push('EARLY_SUPPORTER'); - if ((mem.user.publicFlags & (1 << 10)) === 1 << 10) flags.push('TEAM_USER'); - if ((mem.user.publicFlags & (1 << 12)) === 1 << 12) flags.push('SYSTEM'); - if ((mem.user.publicFlags & (1 << 14)) === 1 << 14) flags.push('BUG_HUNTER_2'); - if ((mem.user.publicFlags & (1 << 16)) === 1 << 16) flags.push('VERIFIED_BOT'); - if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER'); - } - const set = []; - const accounts = await this.server.client.db.Score.find().lean().exec(); - for (const sc of accounts) { - if (sc.total < 200) { continue; } - if (sc.total > 800) { set.push(800); continue; } - set.push(sc.total); - } - - let totalScore: number; - let activityScore: number; - const moderationScore = Math.round(member.moderation); - let roleScore: number; - let cloudServicesScore: number; - const otherScore = Math.round(member.other); - let miscScore: number; - - if (member.total < 200) totalScore = 0; - else if (member.total > 800) totalScore = 800; - else totalScore = Math.round(member.total); - - if (member.activity < 10) activityScore = 0; - else if (member.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); - else activityScore = Math.round(member.activity); - - if (member.roles <= 0) roleScore = 0; - else if (member.roles > 54) roleScore = 54; - else roleScore = Math.round(member.roles); - - if (member.staff <= 0) miscScore = 0; - else miscScore = Math.round(member.staff); - - if (member.cloudServices === 0) cloudServicesScore = 0; - else if (member.cloudServices > 10) cloudServicesScore = 10; - else cloudServicesScore = Math.round(member.cloudServices); - - const inqs = await this.server.client.db.Inquiry.find({ userID: member.userID }).lean().exec(); - const inquiries: [{ id?: string, name: string, date: Date }?] = []; - if (inqs?.length > 0) { - for (const inq of inqs) { - const testDate = (new Date(new Date(inq.date).setHours(1460))); - if (testDate > new Date()) inquiries.push({ id: inq.iid, name: inq.name, date: inq.date }); - } - } - - const judgements = await this.server.client.db.Judgement.find({ userID: member.userID }).lean().exec(); - - const historicalData = await this.server.client.db.ScoreHistorical.find({ userID: member.userID }).lean().exec(); - const array: ScoreHistoricalRaw[] | ScoreHistoricalInterface[] = []; - for (const data of historicalData) { - delete data.report?.softInquiries; - - 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(getTotalMessageCount(this.server.client)) * 12))) activity = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 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); - } - - const inq = await this.server.client.report.createInquiry(member.userID, merchant.name, 0, req.body.reason); - - await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 0, reason: req.body.reason, date: new Date() } } }); - - return res.status(200).json({ - code: this.constants.codes.SUCCESS, - message: { - id: inq.id, - userID: member.userID, - memberInformation: { - username: mem.user.username, - discriminator: mem.user.discriminator, - joinedServerAt: new Date(mem.joinedAt), - createdAt: new Date(mem.createdAt), - avatarURL: mem.avatarURL, - flags, - nitroBoost: mem.premiumSince === null, - }, - percentile: Math.round(this.server.client.util.percentile(set, member.total)), - totalScore, - activityScore, - roleScore, - moderationScore, - cloudServicesScore, - miscScore, - otherScore, - inquiries, - judgements, - historical: array ?? [], - }, - }); - } catch (err) { - return this.handleError(err, res); - } - }); - - this.router.post('/v2/soft', async (req, res) => { - try { - if (!req.headers.authorization) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - if (!req.body.userID) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.messages.CLIENT_ERROR }); - - const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); - if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - - const report = await this.server.client.db.Score.findOne({ userID: req.body.userID }).lean().exec(); - if (!report) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - - let totalScore: number; - - if (report.total < 200) totalScore = 0; - else if (report.total > 800) totalScore = 800; - else totalScore = Math.round(report.total); - - await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 1, reason: 'N/A', date: new Date() } } }); - const mem = this.server.client.util.resolveMember(report.userID, this.server.client.guilds.get(this.server.client.config.guildID)); - await this.server.client.report.createInquiry(report.userID, merchant.name.toUpperCase(), 1); - - if (!merchant.privileged) { - return res.status(200).json({ - code: this.constants.codes.SUCCESS, - message: { - userID: report.userID, - totalScore, - }, - }); - } - const flags = []; - if (mem.user.publicFlags) { - if ((mem.user.publicFlags & (1 << 0)) === 1 << 0) flags.push('DISCORD_EMPLOYEE'); - if ((mem.user.publicFlags & (1 << 1)) === 1 << 1) flags.push('PARTNERED_SERVER_OWNER'); - if ((mem.user.publicFlags & (1 << 2)) === 1 << 2) flags.push('HYPESQUAD_EVENTS'); - if ((mem.user.publicFlags & (1 << 3)) === 1 << 3) flags.push('BUG_HUNTER_1'); - if ((mem.user.publicFlags & (1 << 6)) === 1 << 6) flags.push('HOUSE_BRAVERY'); - if ((mem.user.publicFlags & (1 << 7)) === 1 << 7) flags.push('HOUSE_BRILLIANCE'); - if ((mem.user.publicFlags & (1 << 8)) === 1 << 8) flags.push('HOUSE_BALANCE'); - if ((mem.user.publicFlags & (1 << 9)) === 1 << 9) flags.push('EARLY_SUPPORTER'); - if ((mem.user.publicFlags & (1 << 10)) === 1 << 10) flags.push('TEAM_USER'); - if ((mem.user.publicFlags & (1 << 12)) === 1 << 12) flags.push('SYSTEM'); - if ((mem.user.publicFlags & (1 << 14)) === 1 << 14) flags.push('BUG_HUNTER_2'); - if ((mem.user.publicFlags & (1 << 16)) === 1 << 16) flags.push('VERIFIED_BOT'); - if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER'); - } - const set = []; - if (req.query.p?.toString() === 'true') { - const accounts = await this.server.client.db.Score.find().lean().exec(); - for (const sc of accounts) { - if (sc.total < 200) { continue; } - if (sc.total > 800) { set.push(800); continue; } - set.push(sc.total); - } - } - - const judgements = await this.server.client.db.Judgement.find({ userID: report.userID }).lean().exec(); - - 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.activity < 10) activityScore = 0; - else if (report.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); - else activityScore = Math.round(report.activity); - - if (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.server.client.db.ScoreHistorical.find({ userID: report.userID }).lean().exec(); - const array: ScoreHistoricalRaw[] = []; - for (const data of historicalData) { - delete data.report?.softInquiries; - delete data.report?.inquiries; - - 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(getTotalMessageCount(this.server.client)) * 12))) activity = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 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); - } - - return res.status(200).json({ - code: this.constants.codes.SUCCESS, - message: { - userID: report.userID, - memberInformation: { - username: mem.user.username, - discriminator: mem.user.discriminator, - joinedServerAt: new Date(mem.joinedAt), - createdAt: new Date(mem.createdAt), - avatarURL: mem.avatarURL, - flags, - nitroBoost: mem.premiumSince === null, - }, - totalScore, - percentile: Math.round(this.server.client.util.percentile(set, report.total)), - activityScore, - moderationScore, - roleScore, - cloudServicesScore, - otherScore, - miscScore, - judgements, - historical: array ?? [], - }, - }); - } catch (err) { - return this.handleError(err, res); - } - }); - - this.router.post('/soft', async (req, res) => { - try { - if (!req.headers.authorization) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - if (!req.body.pin || !req.body.userID) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.messages.CLIENT_ERROR }); - - const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); - if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - - const member = await this.server.client.db.Score.findOne({ userID: req.body.userID, 'pin.2': req.body.pin }).lean().exec(); - if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - 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 }); - - let totalScore: number; - - if (member.total < 200) totalScore = 0; - else if (member.total > 800) totalScore = 800; - 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.report.createInquiry(member.userID, merchant.name.toUpperCase(), 1); - - if (!merchant.privileged) { - return res.status(200).json({ - code: this.constants.codes.SUCCESS, - message: { - userID: member.userID, - totalScore, - }, - }); - } - let activityScore: number; - const moderationScore = Math.round(member.moderation); - let roleScore: number; - let cloudServicesScore: number; - const otherScore = Math.round(member.other); - let miscScore: number; - - if (member.activity < 10) activityScore = 0; - else if (member.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); - else activityScore = Math.round(member.activity); - - if (member.roles <= 0) roleScore = 0; - else if (member.roles > 54) roleScore = 54; - else roleScore = Math.round(member.roles); - - if (member.staff <= 0) miscScore = 0; - else miscScore = Math.round(member.staff); - - if (member.cloudServices === 0) cloudServicesScore = 0; - else if (member.cloudServices > 10) cloudServicesScore = 10; - else cloudServicesScore = Math.round(member.cloudServices); - - return res.status(200).json({ - code: this.constants.codes.SUCCESS, - message: { - userID: member.userID, - totalScore, - activityScore, - moderationScore, - roleScore, - cloudServicesScore, - otherScore, - miscScore, - }, - }); - } catch (err) { - return this.handleError(err, res); - } - }); - - this.router.get('/web', async (req, res) => { - try { - res.setHeader('Access-Control-Allow-Origin', '*'); - if (this.timeout.has(req.ip)) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - if (!req.query.pin) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - const args = req.query.pin.toString(); - this.timeout.set(req.ip, 1); - setTimeout(() => this.timeout.delete(req.ip), 1800000); - let score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); - if (!score) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - const member = await this.server.client.getRESTGuildMember(this.constants.discord.SERVER_ID, score.userID); - if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - let updated = false; - if (req.query.staff) { - // eslint-disable-next-line no-shadow - const args = req.query.staff.toString(); - const staffScore = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); - if (!staffScore) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - if (!staffScore.staff) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - this.timeout.delete(req.ip); - if (staffScore.userID === score.userID) { - updated = true; - await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1); - } else { - await this.server.client.report.createInquiry(member.user.id, 'Library of Code sp-us | Staff Team via report.libraryofcode.org', 1); - } - } else if (!updated) { - await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1); - } - score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); - - let totalScore = '0'; - let activityScore = '0'; - let moderationScore = '0'; - let roleScore = '0'; - let cloudServicesScore = '0'; - let otherScore = '0'; - let miscScore = '0'; - - if (score.total < 200) totalScore = '---'; - else if (score.total > 800) totalScore = '800'; - else totalScore = `${score.total}`; - - if (score.activity < 10) activityScore = '---'; - else if (score.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = String(Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))); - else activityScore = `${score.activity}`; - - if (score.roles <= 0) roleScore = '---'; - else if (score.roles > 54) roleScore = '54'; - else roleScore = `${score.roles}`; - - moderationScore = `${score.moderation}`; - - if (score.other === 0) otherScore = '---'; - else otherScore = `${score.other}`; - - if (score.staff <= 0) miscScore = '---'; - else miscScore = `${score.staff}`; - - if (score.cloudServices === 0) cloudServicesScore = '---'; - else if (score.cloudServices > 10) cloudServicesScore = '10'; - else cloudServicesScore = `${score.cloudServices}`; - - 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(); - - for (const data of historical) { - 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(getTotalMessageCount(this.server.client)) * 12))) activity = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 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; - } - - const inqs = await this.server.client.db.Inquiry.find({ userID: score.userID }).lean().exec(); - const hardInquiries: [{ id?: string, name: string, reason: string, date: Date }?] = []; - const softInquiries: [{ id?: string, name: string, date: Date }?] = []; - for (const inq of inqs) { - if (inq.type === 0) { - hardInquiries.push({ id: inq.iid, name: inq.name, reason: inq.reason, date: inq.date }); - } else if (inq.type === 1) { - softInquiries.push({ name: inq.name, date: inq.date }); - } - } - - return res.status(200).json({ - name: `${member.username}#${member.discriminator}`, - avatarURL: member.avatarURL, - userID: score.userID, - pin: score.pin?.join('-'), - score: totalScore, - activityScore, - cloudServicesScore, - moderationScore, - roleScore, - otherScore, - miscScore, - notify: score.notify, - locked: !!score.locked, - totalModerations: moderations?.length > 0 ? moderations.length : 0, - inquiries: hardInquiries?.length > 0 ? hardInquiries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) : [], - softInquiries: softInquiries?.length > 0 ? softInquiries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) : [], - historical: historical ?? [], - lastUpdated: score.lastUpdate, - }); - } catch (err) { - return this.handleError(err, res); - } - }); - - this.router.get('/offer', async (req, res) => { - try { - res.setHeader('Access-Control-Allow-Origin', '*'); - if (!req.query.code) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - if (await this.acceptedOffers.get(req.query.code.toString())) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - let offer: { - userID?: string, - staffID?: string, - channelID?: string, - messageID?: string, - pin?: string, - name?: string, - department?: string, - date?: Date, - }; - - try { - offer = <{ - userID?: string, - staffID?: string, - channelID?: string, - messageID?: string, - pin?: string, - name?: string, - department?: string, - date?: Date, - }>jwt.verify(req.query.code.toString(), this.server.client.config.internalKey); - } catch { - return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); - } - const chan = this.server.client.guilds.get(this.constants.discord.SERVER_ID).channels.get(offer.channelID); - await chan.createMessage(`__**PRE-APPROVED OFFER ACCEPTED**__\n<@${offer.staffID}>`); - const message = await chan.getMessage(offer.messageID); - const args = []; - args.push(offer.userID, 'hard'); - `${offer.department}:${offer.name}`.split(' ').forEach((item) => args.push(item)); - await this.server.client.commands.get('score').run(message, args); - await this.acceptedOffers.set(req.query.code.toString(), true); - return res.sendStatus(200); - } catch (err) { - return this.handleError(err, res); - } - }); - } -} +/* eslint-disable no-bitwise */ +/* eslint-disable no-continue */ +import jwt from 'jsonwebtoken'; +import { TextChannel } from 'eris'; +import { LocalStorage, Route, Server } from '../../../class'; +import { ScoreHistoricalInterface, ScoreHistoricalRaw } from '../../../models/ScoreHistorical'; +import { getTotalMessageCount } from '../../../intervals/score'; + +export default class Report extends Route { + public timeout: Map; + + public acceptedOffers: LocalStorage; + + constructor(server: Server) { + super(server); + this.timeout = new Map(); + this.acceptedOffers = new LocalStorage('accepted-offers'); + this.conf = { + path: '/report', + }; + } + + protected check(userID: string) { + if (this.timeout.has(userID)) { + if (this.timeout.get(userID) >= 3) { + return true; + } + this.timeout.set(userID, this.timeout.get(userID) + 1); + } else { + this.timeout.set(userID, 1); + } + setTimeout(() => { + if (this.timeout.has(userID)) { + this.timeout.set(userID, this.timeout.get(userID) - 1); + } else { + this.timeout.delete(userID); + } + }, 30000); + return false; + } + + public bind() { + this.router.all('*', (_req, res, next) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', '*'); + res.setHeader('Access-Control-Allow-Headers', '*'); + next(); + }); + + this.router.post('/hard', async (req, res) => { + try { + if (!req.headers.authorization) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + if (!req.body.pin || !req.body.userID || !req.body.reason) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.messages.CLIENT_ERROR }); + if (req.body.reason?.length < 1) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.codes.CLIENT_ERROR }); + + const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); + if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + + const member = await this.server.client.db.Score.findOne({ userID: req.body.userID, 'pin.2': req.body.pin }).lean().exec(); + if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + + 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 }); + + if (member.locked) return res.status(403).json({ code: this.constants.codes.PERMISSION_DENIED, message: this.constants.messages.PERMISSION_DENIED }); + if (merchant?.type !== 1) return res.status(403).json({ code: this.constants.codes.PERMISSION_DENIED, message: this.constants.messages.PERMISSION_DENIED }); + + if (this.check(member.userID)) { + await this.server.client.db.Score.updateOne({ userID: member.userID }, { $set: { locked: true } }); + const chan = await this.server.client.getDMChannel(member.userID); + try { + await chan.createMessage(`__**Community Report Locked**__\nWe've detected suspicious activity on your Community Report, for the integrity of your report we have automatically locked it. To unlock your report, please run \`${this.server.client.config.prefix}score pref unlock\` in <#468759629334183956>.`); + } catch (err) { + this.server.client.util.signale.error(`Unable to DM user: ${member.userID} | ${err}`); + } + return res.status(403).json({ code: this.constants.codes.PERMISSION_DENIED, message: this.constants.messages.PERMISSION_DENIED }); + } + + const flags = []; + if (mem.user.publicFlags) { + if ((mem.user.publicFlags & (1 << 0)) === 1 << 0) flags.push('DISCORD_EMPLOYEE'); + if ((mem.user.publicFlags & (1 << 1)) === 1 << 1) flags.push('PARTNERED_SERVER_OWNER'); + if ((mem.user.publicFlags & (1 << 2)) === 1 << 2) flags.push('HYPESQUAD_EVENTS'); + if ((mem.user.publicFlags & (1 << 3)) === 1 << 3) flags.push('BUG_HUNTER_1'); + if ((mem.user.publicFlags & (1 << 6)) === 1 << 6) flags.push('HOUSE_BRAVERY'); + if ((mem.user.publicFlags & (1 << 7)) === 1 << 7) flags.push('HOUSE_BRILLIANCE'); + if ((mem.user.publicFlags & (1 << 8)) === 1 << 8) flags.push('HOUSE_BALANCE'); + if ((mem.user.publicFlags & (1 << 9)) === 1 << 9) flags.push('EARLY_SUPPORTER'); + if ((mem.user.publicFlags & (1 << 10)) === 1 << 10) flags.push('TEAM_USER'); + if ((mem.user.publicFlags & (1 << 12)) === 1 << 12) flags.push('SYSTEM'); + if ((mem.user.publicFlags & (1 << 14)) === 1 << 14) flags.push('BUG_HUNTER_2'); + if ((mem.user.publicFlags & (1 << 16)) === 1 << 16) flags.push('VERIFIED_BOT'); + if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER'); + } + const set = []; + const accounts = await this.server.client.db.Score.find().lean().exec(); + for (const sc of accounts) { + if (sc.total < 200) { continue; } + if (sc.total > 800) { set.push(800); continue; } + set.push(sc.total); + } + + let totalScore: number; + let activityScore: number; + const moderationScore = Math.round(member.moderation); + let roleScore: number; + let cloudServicesScore: number; + const otherScore = Math.round(member.other); + let miscScore: number; + + if (member.total < 200) totalScore = 0; + else if (member.total > 800) totalScore = 800; + else totalScore = Math.round(member.total); + + if (member.activity < 10) activityScore = 0; + else if (member.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); + else activityScore = Math.round(member.activity); + + if (member.roles <= 0) roleScore = 0; + else if (member.roles > 54) roleScore = 54; + else roleScore = Math.round(member.roles); + + if (member.staff <= 0) miscScore = 0; + else miscScore = Math.round(member.staff); + + if (member.cloudServices === 0) cloudServicesScore = 0; + else if (member.cloudServices > 10) cloudServicesScore = 10; + else cloudServicesScore = Math.round(member.cloudServices); + + const inqs = await this.server.client.db.Inquiry.find({ userID: member.userID }).lean().exec(); + const inquiries: [{ id?: string, name: string, date: Date }?] = []; + if (inqs?.length > 0) { + for (const inq of inqs) { + const testDate = (new Date(new Date(inq.date).setHours(1460))); + if (testDate > new Date()) inquiries.push({ id: inq.iid, name: inq.name, date: inq.date }); + } + } + + const judgements = await this.server.client.db.Judgement.find({ userID: member.userID }).lean().exec(); + + const historicalData = await this.server.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(getTotalMessageCount(this.server.client)) * 12))) activity = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 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); + } + + const inq = await this.server.client.report.createInquiry(member.userID, merchant.name, 0, req.body.reason); + + await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 0, reason: req.body.reason, date: new Date() } } }); + + return res.status(200).json({ + code: this.constants.codes.SUCCESS, + message: { + id: inq.id, + userID: member.userID, + memberInformation: { + username: mem.user.username, + discriminator: mem.user.discriminator, + joinedServerAt: new Date(mem.joinedAt), + createdAt: new Date(mem.createdAt), + avatarURL: mem.avatarURL, + flags, + nitroBoost: mem.premiumSince === null, + }, + percentile: Math.round(this.server.client.util.percentile(set, member.total)), + totalScore, + activityScore, + roleScore, + moderationScore, + cloudServicesScore, + miscScore, + otherScore, + inquiries, + judgements, + historical: array ?? [], + }, + }); + } catch (err) { + return this.handleError(err, res); + } + }); + + this.router.post('/v2/soft', async (req, res) => { + try { + if (!req.headers.authorization) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + if (!req.body.userID) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.messages.CLIENT_ERROR }); + + const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); + if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + + const report = await this.server.client.db.Score.findOne({ userID: req.body.userID }).lean().exec(); + if (!report) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + + let totalScore: number; + + if (report.total < 200) totalScore = 0; + else if (report.total > 800) totalScore = 800; + else totalScore = Math.round(report.total); + + await this.server.client.db.Merchant.updateOne({ key: req.headers.authorization }, { $addToSet: { pulls: { type: 1, reason: 'N/A', date: new Date() } } }); + const mem = this.server.client.util.resolveMember(report.userID, this.server.client.guilds.get(this.server.client.config.guildID)); + await this.server.client.report.createInquiry(report.userID, merchant.name.toUpperCase(), 1); + + if (!merchant.privileged) { + return res.status(200).json({ + code: this.constants.codes.SUCCESS, + message: { + userID: report.userID, + totalScore, + }, + }); + } + const flags = []; + if (mem.user.publicFlags) { + if ((mem.user.publicFlags & (1 << 0)) === 1 << 0) flags.push('DISCORD_EMPLOYEE'); + if ((mem.user.publicFlags & (1 << 1)) === 1 << 1) flags.push('PARTNERED_SERVER_OWNER'); + if ((mem.user.publicFlags & (1 << 2)) === 1 << 2) flags.push('HYPESQUAD_EVENTS'); + if ((mem.user.publicFlags & (1 << 3)) === 1 << 3) flags.push('BUG_HUNTER_1'); + if ((mem.user.publicFlags & (1 << 6)) === 1 << 6) flags.push('HOUSE_BRAVERY'); + if ((mem.user.publicFlags & (1 << 7)) === 1 << 7) flags.push('HOUSE_BRILLIANCE'); + if ((mem.user.publicFlags & (1 << 8)) === 1 << 8) flags.push('HOUSE_BALANCE'); + if ((mem.user.publicFlags & (1 << 9)) === 1 << 9) flags.push('EARLY_SUPPORTER'); + if ((mem.user.publicFlags & (1 << 10)) === 1 << 10) flags.push('TEAM_USER'); + if ((mem.user.publicFlags & (1 << 12)) === 1 << 12) flags.push('SYSTEM'); + if ((mem.user.publicFlags & (1 << 14)) === 1 << 14) flags.push('BUG_HUNTER_2'); + if ((mem.user.publicFlags & (1 << 16)) === 1 << 16) flags.push('VERIFIED_BOT'); + if ((mem.user.publicFlags & (1 << 17)) === 1 << 17) flags.push('EARLY_VERIFIED_BOT_DEVELOPER'); + } + const set = []; + if (req.query.p?.toString() === 'true') { + const accounts = await this.server.client.db.Score.find().lean().exec(); + for (const sc of accounts) { + if (sc.total < 200) { continue; } + if (sc.total > 800) { set.push(800); continue; } + set.push(sc.total); + } + } + + const judgements = await this.server.client.db.Judgement.find({ userID: report.userID }).lean().exec(); + + 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.activity < 10) activityScore = 0; + else if (report.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); + else activityScore = Math.round(report.activity); + + if (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.server.client.db.ScoreHistorical.find({ userID: report.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(getTotalMessageCount(this.server.client)) * 12))) activity = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 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); + } + + return res.status(200).json({ + code: this.constants.codes.SUCCESS, + message: { + userID: report.userID, + memberInformation: { + username: mem.user.username, + discriminator: mem.user.discriminator, + joinedServerAt: new Date(mem.joinedAt), + createdAt: new Date(mem.createdAt), + avatarURL: mem.avatarURL, + flags, + nitroBoost: mem.premiumSince === null, + }, + totalScore, + percentile: Math.round(this.server.client.util.percentile(set, report.total)), + activityScore, + moderationScore, + roleScore, + cloudServicesScore, + otherScore, + miscScore, + judgements, + historical: array ?? [], + }, + }); + } catch (err) { + return this.handleError(err, res); + } + }); + + this.router.post('/soft', async (req, res) => { + try { + if (!req.headers.authorization) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + if (!req.body.pin || !req.body.userID) return res.status(400).json({ code: this.constants.codes.CLIENT_ERROR, message: this.constants.messages.CLIENT_ERROR }); + + const merchant = await this.server.client.db.Merchant.findOne({ key: req.headers.authorization }).lean().exec(); + if (!merchant) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + + const member = await this.server.client.db.Score.findOne({ userID: req.body.userID, 'pin.2': req.body.pin }).lean().exec(); + if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + 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 }); + + let totalScore: number; + + if (member.total < 200) totalScore = 0; + else if (member.total > 800) totalScore = 800; + 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.report.createInquiry(member.userID, merchant.name.toUpperCase(), 1); + + if (!merchant.privileged) { + return res.status(200).json({ + code: this.constants.codes.SUCCESS, + message: { + userID: member.userID, + totalScore, + }, + }); + } + let activityScore: number; + const moderationScore = Math.round(member.moderation); + let roleScore: number; + let cloudServicesScore: number; + const otherScore = Math.round(member.other); + let miscScore: number; + + if (member.activity < 10) activityScore = 0; + else if (member.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12)); + else activityScore = Math.round(member.activity); + + if (member.roles <= 0) roleScore = 0; + else if (member.roles > 54) roleScore = 54; + else roleScore = Math.round(member.roles); + + if (member.staff <= 0) miscScore = 0; + else miscScore = Math.round(member.staff); + + if (member.cloudServices === 0) cloudServicesScore = 0; + else if (member.cloudServices > 10) cloudServicesScore = 10; + else cloudServicesScore = Math.round(member.cloudServices); + + return res.status(200).json({ + code: this.constants.codes.SUCCESS, + message: { + userID: member.userID, + totalScore, + activityScore, + moderationScore, + roleScore, + cloudServicesScore, + otherScore, + miscScore, + }, + }); + } catch (err) { + return this.handleError(err, res); + } + }); + + this.router.get('/web', async (req, res) => { + try { + res.setHeader('Access-Control-Allow-Origin', '*'); + if (this.timeout.has(req.ip)) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + if (!req.query.pin) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + const args = req.query.pin.toString(); + this.timeout.set(req.ip, 1); + setTimeout(() => this.timeout.delete(req.ip), 1800000); + let score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); + if (!score) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + const member = await this.server.client.getRESTGuildMember(this.constants.discord.SERVER_ID, score.userID); + if (!member) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + let updated = false; + if (req.query.staff) { + // eslint-disable-next-line no-shadow + const args = req.query.staff.toString(); + const staffScore = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); + if (!staffScore) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + if (!staffScore.staff) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + this.timeout.delete(req.ip); + if (staffScore.userID === score.userID) { + updated = true; + await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1); + } else { + await this.server.client.report.createInquiry(member.user.id, 'Library of Code sp-us | Staff Team via report.libraryofcode.org', 1); + } + } else if (!updated) { + await this.server.client.report.createInquiry(member.user.id, `${member.username} via report.libraryofcode.org @ IP ${req.ip}`, 1); + } + score = await this.server.client.db.Score.findOne({ pin: [Number(args.split('-')[0]), Number(args.split('-')[1]), Number(args.split('-')[2])] }).lean().exec(); + + let totalScore = '0'; + let activityScore = '0'; + let moderationScore = '0'; + let roleScore = '0'; + let cloudServicesScore = '0'; + let otherScore = '0'; + let miscScore = '0'; + + if (score.total < 200) totalScore = '---'; + else if (score.total > 800) totalScore = '800'; + else totalScore = `${score.total}`; + + if (score.activity < 10) activityScore = '---'; + else if (score.activity > Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))) activityScore = String(Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 12))); + else activityScore = `${score.activity}`; + + if (score.roles <= 0) roleScore = '---'; + else if (score.roles > 54) roleScore = '54'; + else roleScore = `${score.roles}`; + + moderationScore = `${score.moderation}`; + + if (score.other === 0) otherScore = '---'; + else otherScore = `${score.other}`; + + if (score.staff <= 0) miscScore = '---'; + else miscScore = `${score.staff}`; + + if (score.cloudServices === 0) cloudServicesScore = '---'; + else if (score.cloudServices > 10) cloudServicesScore = '10'; + else cloudServicesScore = `${score.cloudServices}`; + + 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(); + + for (const data of historical) { + 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(getTotalMessageCount(this.server.client)) * 12))) activity = Math.floor((Math.log1p(getTotalMessageCount(this.server.client)) * 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; + } + + const inqs = await this.server.client.db.Inquiry.find({ userID: score.userID }).lean().exec(); + const hardInquiries: [{ id?: string, name: string, reason: string, date: Date }?] = []; + const softInquiries: [{ id?: string, name: string, date: Date }?] = []; + for (const inq of inqs) { + if (inq.type === 0) { + hardInquiries.push({ id: inq.iid, name: inq.name, reason: inq.reason, date: inq.date }); + } else if (inq.type === 1) { + softInquiries.push({ name: inq.name, date: inq.date }); + } + } + + return res.status(200).json({ + name: `${member.username}#${member.discriminator}`, + avatarURL: member.avatarURL, + userID: score.userID, + pin: score.pin?.join('-'), + score: totalScore, + activityScore, + cloudServicesScore, + moderationScore, + roleScore, + otherScore, + miscScore, + notify: score.notify, + locked: !!score.locked, + totalModerations: moderations?.length > 0 ? moderations.length : 0, + inquiries: hardInquiries?.length > 0 ? hardInquiries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) : [], + softInquiries: softInquiries?.length > 0 ? softInquiries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) : [], + historical: historical ?? [], + lastUpdated: score.lastUpdate, + }); + } catch (err) { + return this.handleError(err, res); + } + }); + + this.router.get('/offer', async (req, res) => { + try { + res.setHeader('Access-Control-Allow-Origin', '*'); + if (!req.query.code) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + if (await this.acceptedOffers.get(req.query.code.toString())) return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + let offer: { + userID?: string, + staffID?: string, + channelID?: string, + messageID?: string, + pin?: string, + name?: string, + department?: string, + date?: Date, + }; + + try { + offer = <{ + userID?: string, + staffID?: string, + channelID?: string, + messageID?: string, + pin?: string, + name?: string, + department?: string, + date?: Date, + }>jwt.verify(req.query.code.toString(), this.server.client.config.internalKey); + } catch { + return res.status(401).json({ code: this.constants.codes.UNAUTHORIZED, message: this.constants.messages.UNAUTHORIZED }); + } + const chan = this.server.client.guilds.get(this.constants.discord.SERVER_ID).channels.get(offer.channelID); + await chan.createMessage(`__**PRE-APPROVED OFFER ACCEPTED**__\n<@${offer.staffID}>`); + const message = await chan.getMessage(offer.messageID); + const args = []; + args.push(offer.userID, 'hard'); + `${offer.department}:${offer.name}`.split(' ').forEach((item) => args.push(item)); + await this.server.client.commands.get('score').run(message, args); + await this.acceptedOffers.set(req.query.code.toString(), true); + return res.sendStatus(200); + } catch (err) { + return this.handleError(err, res); + } + }); + } +} diff --git a/src/class/Queue.ts b/src/class/Queue.ts index 79f5811..70b4d1d 100644 --- a/src/class/Queue.ts +++ b/src/class/Queue.ts @@ -1,185 +1,193 @@ -/* eslint-disable no-await-in-loop */ -/* eslint-disable no-eval */ -import Bull from 'bull'; -import cron from 'cron'; -import { TextableChannel, TextChannel } from 'eris'; -import { Client, RichEmbed } from '.'; -import { ScoreInterface, InqType as InquiryType } from '../models'; - -import { apply as Apply } from '../commands'; - -export default class Queue { - public client: Client; - - public queues: { score: Bull.Queue }; - - constructor(client: Client) { - this.client = client; - this.queues = { - score: new Bull('score', { prefix: 'queue::score' }), - }; - this.setProcessors(); - this.setCronJobs(); - } - - protected setCronJobs() { - const historialCommunityReportJob = new cron.CronJob('0 20 * * *', async () => { - try { - const reports = await this.client.db.Score.find().lean().exec(); - const startDate = new Date(); - - for (const report of reports) { - const inqs = await this.client.db.Inquiry.find({ userID: report.userID }); - const data = new this.client.db.ScoreHistorical({ - userID: report.userID, - report, - inquiries: inqs.map((inq) => inq._id), - date: startDate, - }); - await data.save(); - } - } catch (err) { - this.client.util.handleError(err); - } - }); - - const clearOldHistoricalReportsJob = new cron.CronJob('0 22 * * *', async () => { - this.client.db.ScoreHistorical.remove({ date: { $lt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) } }); - }); - - historialCommunityReportJob.start(); - clearOldHistoricalReportsJob.start(); - } - - public async jobCounts() { - const data = { - waiting: 0, - active: 0, - completed: 0, - failed: 0, - delayed: 0, - }; - for (const entry of Object.entries(this.queues)) { - // eslint-disable-next-line no-await-in-loop - const counts = await entry[1].getJobCounts(); - data.waiting += counts.waiting; - data.active += counts.active; - data.completed += counts.completed; - data.failed += counts.failed; - data.delayed += counts.delayed; - } - return data; - } - - protected listeners() { - this.queues.score.on('active', (job) => { - this.client.util.signale.pending(`${job.id} has become active.`); - }); - this.queues.score.on('completed', (job) => { - this.client.util.signale.success(`Job with id ${job.id} has been completed`); - }); - this.queues.score.on('error', async (err) => { - this.client.util.handleError(err); - }); - } - - protected setProcessors() { - this.queues.score.process('score::inquiry', async (job: Bull.Job<{ inqID: string, userID: string, name: string, type: InquiryType, reason?: string }>) => { - const member = this.client.util.resolveMember(job.data.userID, this.client.guilds.get(this.client.config.guildID)); - const report = await this.client.db.Score.findOne({ userID: job.data.userID }).lean().exec(); - const embed = new RichEmbed(); - if (job.data.type === InquiryType.HARD) { - embed.setTitle('Inquiry Notification'); - embed.setDescription(job.data.inqID); - embed.setColor('#800080'); - embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true); - embed.addField('Type', 'HARD', true); - embed.addField('Department/Service', job.data.name.toUpperCase(), true); - embed.addField('Reason', job.data.reason ?? 'N/A', true); - embed.setTimestamp(); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - if (report.notify === true) { - await this.client.getDMChannel(job.data.userID).then((chan) => { - chan.createMessage(`__**Community Score - Hard Pull Notification**__\n*You have signed up to be notified whenever your hard score has been pulled. See \`?score\` for more information.*\n\n**Department/Service:** ${job.data.name.toUpperCase()}`); - }).catch(() => {}); - } - } else { - embed.setTitle('Inquiry Notification'); - embed.setColor('#00FFFF'); - embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true); - embed.addField('Type', 'SOFT', true); - embed.addField('Department/Service', job.data.name.toUpperCase(), true); - embed.setTimestamp(); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - } - const log = this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849'); - log.createMessage({ embed }).catch(() => {}); - }); - this.queues.score.process('score::update', async (job: Bull.Job<{ score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number }>) => { - await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { total: job.data.total, activity: job.data.activity, roles: job.data.roles, moderation: job.data.moderation, cloudServices: job.data.cloudServices, other: job.data.other, staff: job.data.staff, lastUpdate: new Date() } }); - if (!job.data.score.pin || job.data.score.pin?.length < 1) { - await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { pin: [this.client.util.randomNumber(100, 999), this.client.util.randomNumber(10, 99), this.client.util.randomNumber(1000, 9999)] } }); - } - }); - this.queues.score.process('score::apply', async (job: Bull.Job<{ channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func?: string }>) => { - const application = await Apply.apply(this.client, job.data.url, job.data.userID); - const guild = this.client.guilds.get(job.data.channelInformation.guildID); - const channel = guild.channels.get(job.data.channelInformation.channelID); - const message = await channel.getMessage(job.data.channelInformation.messageID); - const member = guild.members.get(job.data.userID); - await message.delete(); - const embed = new RichEmbed(); - embed.setTitle('Application Decision'); - if (member) { - embed.setAuthor(member.username, member.avatarURL); - } - if (application.decision === 'APPROVED') { - embed.setColor('#50c878'); - } else if (application.decision === 'DECLINED') { - embed.setColor('#fe0000'); - } else if (application.decision === 'PRE-DECLINE') { - embed.setColor('#ffa500'); - } else { - embed.setColor('#eeeeee'); - } - const chan = await this.client.getDMChannel(job.data.userID); - if (chan) { - let description = `This application was processed by __${application.processedBy}__ on behalf of the vendor, department, or service who operates this application. Please contact the vendor for further information about your application if needed.`; - if (application.token) description += `\n\n*This document provides detailed information about the decision given to you by EDS.*: https://eds.libraryofcode.org/dec/${application.token}`; - embed.setDescription(description); - embed.addField('Status', application.decision, true); - embed.addField('User ID', job.data.userID, true); - embed.addField('Application ID', application.id, true); - embed.addField('Job ID', job.id.toString(), true); - embed.setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL); - embed.setTimestamp(); - try { - await chan.createMessage({ embed }); - } catch { - await channel.createMessage('**We were not able to send the decision of your application to your DMs. Please contact the Staff Team for further information.**'); - } - - await channel.createMessage({ embed: new RichEmbed().setTitle('Application Decision').setDescription('The decision of your application has been sent to your DMs.\n\n*Please view the PDF document for further information regarding the decision. For reconsiderations or questions, please contact us.*').setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL) - .setTimestamp() }); - } else { - await channel.createMessage('**We were not able to send the decision of your application to your DMs. Please contact the Staff Team for further information.**'); - } - if (job.data.func) { - const func = eval(job.data.func); - if (application.status === 'SUCCESS' && application.decision === 'APPROVED') await func(this.client, job.data.userID); - } - }); - } - - public addInquiry(inqID: string, userID: string, name: string, type: InquiryType, reason?: string) { - return this.queues.score.add('score::inquiry', { inqID, userID, name, type, reason }); - } - - public updateScore(score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number) { - return this.queues.score.add('score::update', { score, total, activity, roles, moderation, cloudServices, other, staff }); - } - - public processApplication(channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func?: string) { - return this.queues.score.add('score::apply', { channelInformation, url, userID, func }); - } -} +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-eval */ +import Bull from 'bull'; +import cron from 'cron'; +import { TextableChannel, TextChannel } from 'eris'; +import { Client, RichEmbed } from '.'; +import { ScoreInterface, InqType as InquiryType } from '../models'; + +import { apply as Apply } from '../commands'; + +export default class Queue { + public client: Client; + + public queues: { score: Bull.Queue }; + + constructor(client: Client) { + this.client = client; + this.queues = { + score: new Bull('score', { prefix: 'queue::score' }), + }; + this.setProcessors(); + this.setCronJobs(); + } + + protected setCronJobs() { + const historialCommunityReportJob = new cron.CronJob('0 20 * * *', async () => { + try { + const reports = await this.client.db.Score.find().lean().exec(); + const startDate = new Date(); + + for (const report of reports) { + const inqs = await this.client.db.Inquiry.find({ userID: report.userID }); + const data = new this.client.db.ScoreHistorical({ + userID: report.userID, + report: { + total: report.total, + activity: report.activity, + roles: report.roles, + moderation: report.moderation, + cloudServices: report.cloudServices, + staff: report.staff, + other: report.other, + }, + inquiries: inqs.map((inq) => inq._id), + date: startDate, + }); + await data.save(); + } + } catch (err) { + this.client.util.handleError(err); + } + }); + + const clearOldHistoricalReportsJob = new cron.CronJob('0 22 * * *', async () => { + this.client.db.ScoreHistorical.remove({ date: { $lt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) } }); + }); + + historialCommunityReportJob.start(); + clearOldHistoricalReportsJob.start(); + } + + public async jobCounts() { + const data = { + waiting: 0, + active: 0, + completed: 0, + failed: 0, + delayed: 0, + }; + for (const entry of Object.entries(this.queues)) { + // eslint-disable-next-line no-await-in-loop + const counts = await entry[1].getJobCounts(); + data.waiting += counts.waiting; + data.active += counts.active; + data.completed += counts.completed; + data.failed += counts.failed; + data.delayed += counts.delayed; + } + return data; + } + + protected listeners() { + this.queues.score.on('active', (job) => { + this.client.util.signale.pending(`${job.id} has become active.`); + }); + this.queues.score.on('completed', (job) => { + this.client.util.signale.success(`Job with id ${job.id} has been completed`); + }); + this.queues.score.on('error', async (err) => { + this.client.util.handleError(err); + }); + } + + protected setProcessors() { + this.queues.score.process('score::inquiry', async (job: Bull.Job<{ inqID: string, userID: string, name: string, type: InquiryType, reason?: string }>) => { + const member = this.client.util.resolveMember(job.data.userID, this.client.guilds.get(this.client.config.guildID)); + const report = await this.client.db.Score.findOne({ userID: job.data.userID }).lean().exec(); + const embed = new RichEmbed(); + if (job.data.type === InquiryType.HARD) { + embed.setTitle('Inquiry Notification'); + embed.setDescription(job.data.inqID); + embed.setColor('#800080'); + embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true); + embed.addField('Type', 'HARD', true); + embed.addField('Department/Service', job.data.name.toUpperCase(), true); + embed.addField('Reason', job.data.reason ?? 'N/A', true); + embed.setTimestamp(); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + if (report.notify === true) { + await this.client.getDMChannel(job.data.userID).then((chan) => { + chan.createMessage(`__**Community Score - Hard Pull Notification**__\n*You have signed up to be notified whenever your hard score has been pulled. See \`?score\` for more information.*\n\n**Department/Service:** ${job.data.name.toUpperCase()}`); + }).catch(() => {}); + } + } else { + embed.setTitle('Inquiry Notification'); + embed.setColor('#00FFFF'); + embed.addField('Member', `${member.user.username}#${member.user.discriminator} | <@${job.data.userID}>`, true); + embed.addField('Type', 'SOFT', true); + embed.addField('Department/Service', job.data.name.toUpperCase(), true); + embed.setTimestamp(); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + } + const log = this.client.guilds.get(this.client.config.guildID).channels.get('611584771356622849'); + log.createMessage({ embed }).catch(() => {}); + }); + this.queues.score.process('score::update', async (job: Bull.Job<{ score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number }>) => { + await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { total: job.data.total, activity: job.data.activity, roles: job.data.roles, moderation: job.data.moderation, cloudServices: job.data.cloudServices, other: job.data.other, staff: job.data.staff, lastUpdate: new Date() } }); + if (!job.data.score.pin || job.data.score.pin?.length < 1) { + await this.client.db.Score.updateOne({ userID: job.data.score.userID }, { $set: { pin: [this.client.util.randomNumber(100, 999), this.client.util.randomNumber(10, 99), this.client.util.randomNumber(1000, 9999)] } }); + } + }); + this.queues.score.process('score::apply', async (job: Bull.Job<{ channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func?: string }>) => { + const application = await Apply.apply(this.client, job.data.url, job.data.userID); + const guild = this.client.guilds.get(job.data.channelInformation.guildID); + const channel = guild.channels.get(job.data.channelInformation.channelID); + const message = await channel.getMessage(job.data.channelInformation.messageID); + const member = guild.members.get(job.data.userID); + await message.delete(); + const embed = new RichEmbed(); + embed.setTitle('Application Decision'); + if (member) { + embed.setAuthor(member.username, member.avatarURL); + } + if (application.decision === 'APPROVED') { + embed.setColor('#50c878'); + } else if (application.decision === 'DECLINED') { + embed.setColor('#fe0000'); + } else if (application.decision === 'PRE-DECLINE') { + embed.setColor('#ffa500'); + } else { + embed.setColor('#eeeeee'); + } + const chan = await this.client.getDMChannel(job.data.userID); + if (chan) { + let description = `This application was processed by __${application.processedBy}__ on behalf of the vendor, department, or service who operates this application. Please contact the vendor for further information about your application if needed.`; + if (application.token) description += `\n\n*This document provides detailed information about the decision given to you by EDS.*: https://eds.libraryofcode.org/dec/${application.token}`; + embed.setDescription(description); + embed.addField('Status', application.decision, true); + embed.addField('User ID', job.data.userID, true); + embed.addField('Application ID', application.id, true); + embed.addField('Job ID', job.id.toString(), true); + embed.setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL); + embed.setTimestamp(); + try { + await chan.createMessage({ embed }); + } catch { + await channel.createMessage('**We were not able to send the decision of your application to your DMs. Please contact the Staff Team for further information.**'); + } + + await channel.createMessage({ embed: new RichEmbed().setTitle('Application Decision').setDescription('The decision of your application has been sent to your DMs.\n\n*Please view the PDF document for further information regarding the decision. For reconsiderations or questions, please contact us.*').setFooter(`${this.client.user.username} via Electronic Decision Service [EDS]`, this.client.user.avatarURL) + .setTimestamp() }); + } else { + await channel.createMessage('**We were not able to send the decision of your application to your DMs. Please contact the Staff Team for further information.**'); + } + if (job.data.func) { + const func = eval(job.data.func); + if (application.status === 'SUCCESS' && application.decision === 'APPROVED') await func(this.client, job.data.userID); + } + }); + } + + public addInquiry(inqID: string, userID: string, name: string, type: InquiryType, reason?: string) { + return this.queues.score.add('score::inquiry', { inqID, userID, name, type, reason }); + } + + public updateScore(score: ScoreInterface, total: number, activity: number, roles: number, moderation: number, cloudServices: number, other: number, staff: number) { + return this.queues.score.add('score::update', { score, total, activity, roles, moderation, cloudServices, other, staff }); + } + + public processApplication(channelInformation: { messageID: string, guildID: string, channelID: string }, url: string, userID: string, func?: string) { + return this.queues.score.add('score::apply', { channelInformation, url, userID, func }); + } +} diff --git a/src/commands/score_hist.ts b/src/commands/score_hist.ts index acb635f..b641ec6 100644 --- a/src/commands/score_hist.ts +++ b/src/commands/score_hist.ts @@ -1,184 +1,185 @@ -/* eslint-disable no-await-in-loop */ -/* eslint-disable no-continue */ -/* eslint-disable default-case */ -import moment from 'moment'; -import { median, mode, mean } from 'mathjs'; -import { createPaginationEmbed } from 'eris-pagination'; -import { Message } from 'eris'; -import { Client, Command, RichEmbed } from '../class'; -import { getTotalMessageCount } from '../intervals/score'; -import { InquiryInterface } from '../models'; - -export default class Score_Hist extends Command { - constructor(client: Client) { - super(client); - this.name = 'hist'; - this.description = 'Pulls a Community Report history for a user.'; - this.usage = `${this.client.config.prefix}score hist `; - this.permissions = 4; - this.guildOnly = false; - 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 user = this.client.util.resolveMember(args[0], this.mainGuild)?.user; - if (!user) { - const sc = await this.client.db.Score.findOne({ pin: [Number(args[0].split('-')[0]), Number(args[0].split('-')[1]), Number(args[0].split('-')[2])] }); - user = this.client.util.resolveMember(sc.userID, this.mainGuild)?.user; - } - if (!user) return this.error(message.channel, 'Member not found.'); - const hists = await this.client.db.ScoreHistorical.find({ userID: user.id }).limit(31).lean().exec(); - if (!hists) return this.error(message.channel, 'No history found.'); - if (hists.length < 1) return this.error(message.channel, 'No history found.'); - const histArray: [{ name: string, value: string }?] = []; - const totalArray: number[] = []; - const activityArray: number[] = []; - const moderationArray: number[] = []; - const roleArray: number[] = []; - const cloudServicesArray: number[] = []; - const otherArray: number[] = []; - const miscArray: number[] = []; - for (const hist of hists.reverse()) { - totalArray.push(hist.report.total); - activityArray.push(hist.report.activity); - moderationArray.push(hist.report.moderation); - roleArray.push(hist.report.roles); - cloudServicesArray.push(hist.report.cloudServices); - otherArray.push(hist.report.other); - miscArray.push(hist.report.staff); - let totalScore = '0'; - let activityScore = '0'; - let moderationScore = '0'; - let roleScore = '0'; - let cloudServicesScore = '0'; - let otherScore = '0'; - let miscScore = '0'; - - if (hist.report.total < 200) totalScore = '---'; - else if (hist.report.total > 800) totalScore = '800'; - else totalScore = `${hist.report.total}`; - - if (hist.report.activity < 10) activityScore = '---'; - else if (hist.report.activity > Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))) activityScore = String(Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))); - else activityScore = `${hist.report.activity}`; - - if (hist.report.roles <= 0) roleScore = '---'; - else if (hist.report.roles > 54) roleScore = '54'; - else roleScore = `${hist.report.roles}`; - - moderationScore = `${hist.report.moderation}`; - - if (hist.report.other === 0) otherScore = '---'; - else otherScore = `${hist.report.other}`; - - if (hist.report.staff <= 0) miscScore = '---'; - else miscScore = `${hist.report.staff}`; - - if (hist.report.cloudServices === 0) cloudServicesScore = '---'; - else if (hist.report.cloudServices > 10) cloudServicesScore = '10'; - else cloudServicesScore = `${hist.report.cloudServices}`; - - let data = ''; - let hardInquiries = 0; - const inquiries: InquiryInterface[] = []; - if (hist.inquiries?.length > 0) { - for (const h of hist.inquiries) { - const inq = await this.client.db.Inquiry.findOne({ _id: h }); - inquiries.push(inq); - } - } - if (inquiries?.length > 0) { - inquiries.forEach((inq) => { - const testDate = (new Date(new Date(inq.date).setHours(1460))); - // eslint-disable-next-line no-plusplus - if (testDate > new Date()) hardInquiries++; - }); - data += `__CommScore™:__ ${totalScore}\n__Activity:__ ${activityScore}\n__Roles:__ ${roleScore}\n__Moderation:__ ${moderationScore}\n__Cloud Services:__ ${cloudServicesScore}\n__Other:__ ${otherScore}\n__Misc:__ ${miscScore}\n\n__Hard Inquiries:__ ${hardInquiries}\n__Soft Inquiries:__ ${hist.report.softInquiries?.length ?? '0'}`; - histArray.push({ name: moment(hist.date).calendar(), value: data }); - } - } - - const stat = { - totalMean: mean(totalArray), - totalMode: mode(totalArray), - totalMedian: median(totalArray), - activityMean: mean(activityArray), - rolesMean: mean(roleArray), - moderationMean: mean(moderationArray), - cloudServicesMean: mean(cloudServicesArray), - otherMean: mean(otherArray), - miscMean: mean(miscArray), - }; - const splitHist = this.client.util.splitFields(histArray); - const cmdPages: RichEmbed[] = []; - splitHist.forEach((split) => { - const embed = new RichEmbed(); - embed.setTitle('Historical Community Report'); - let totalMean = '0'; - let totalMedian = '0'; - let totalMode = '0'; - let activityMean = '0'; - let moderationMean = '0'; - let roleMean = '0'; - let cloudServicesMean = '0'; - let otherMean = '0'; - let miscMean = '0'; - - if (stat.totalMean < 200) totalMean = '---'; - else if (stat.totalMean > 800) totalMean = '800'; - else totalMean = `${stat.totalMean}`; - - if (stat.totalMedian < 200) totalMedian = '---'; - else if (stat.totalMedian > 800) totalMedian = '800'; - else totalMedian = `${stat.totalMedian}`; - - if (stat.totalMode < 200) totalMode = '---'; - else if (stat.totalMode > 800) totalMode = '800'; - else totalMode = `${stat.totalMode}`; - - if (stat.activityMean < 10) activityMean = '---'; - else if (stat.activityMean > Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))) activityMean = String(Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))); - else activityMean = `${stat.activityMean}`; - - if (stat.rolesMean <= 0) roleMean = '---'; - else if (stat.rolesMean > 54) roleMean = '54'; - else roleMean = `${stat.rolesMean}`; - - moderationMean = `${stat.moderationMean}`; - - if (stat.otherMean === 0) otherMean = '---'; - else otherMean = `${stat.otherMean}`; - - if (stat.miscMean <= 0) miscMean = '---'; - else miscMean = `${stat.miscMean}`; - - if (stat.cloudServicesMean === 0) cloudServicesMean = '---'; - else if (stat.cloudServicesMean > 10) cloudServicesMean = '10'; - else cloudServicesMean = `${stat.cloudServicesMean}`; - - embed.setDescription(`__**Statistical Averages**__\n**CommScore™ Mean:** ${totalMean} | **CommScore™ Mode:** ${totalMode} | **CommScore™ Median:** ${totalMedian}\n\n**Activity Mean:** ${activityMean}\n**Roles Mean:** ${roleMean}\n**Moderation Mean:** ${moderationMean}\n**Cloud Services Mean:** ${cloudServicesMean}\n**Other Mean:** ${otherMean}\n**Misc Mean:** ${miscMean}`); - embed.setAuthor(user.username, user.avatarURL); - embed.setThumbnail(user.avatarURL); - embed.setTimestamp(); - embed.setFooter(this.client.user.username, this.client.user.avatarURL); - split.forEach((c) => embed.addField(c.name, c.value)); - return cmdPages.push(embed); - }); - - let name = ''; - for (const role of this.client.util.resolveMember(message.author.id, this.mainGuild).roles.map((r) => this.mainGuild.roles.get(r)).sort((a, b) => b.position - a.position)) { - name = `Library of Code sp-us | ${role.name} - [HISTORICAL]`; - break; - } - await this.client.report.createInquiry(user.id, name, 1); - - - if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); - return createPaginationEmbed(message, cmdPages); - } catch (err) { - return this.client.util.handleError(err, message, this); - } - } -} +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-continue */ +/* eslint-disable default-case */ +import moment from 'moment'; +import { median, mode, mean } from 'mathjs'; +import { createPaginationEmbed } from 'eris-pagination'; +import { Message } from 'eris'; +import { Client, Command, RichEmbed } from '../class'; +import { getTotalMessageCount } from '../intervals/score'; +import { InquiryInterface } from '../models'; + +export default class Score_Hist extends Command { + constructor(client: Client) { + super(client); + this.name = 'hist'; + this.description = 'Pulls a Community Report history for a user.'; + this.usage = `${this.client.config.prefix}score hist `; + this.permissions = 4; + this.guildOnly = false; + 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 user = this.client.util.resolveMember(args[0], this.mainGuild)?.user; + if (!user) { + const sc = await this.client.db.Score.findOne({ pin: [Number(args[0].split('-')[0]), Number(args[0].split('-')[1]), Number(args[0].split('-')[2])] }); + user = this.client.util.resolveMember(sc.userID, this.mainGuild)?.user; + } + const score = await this.client.db.Score.findOne({ userID: user.id }).lean().exec(); + if (!user) return this.error(message.channel, 'Member not found.'); + const hists = await this.client.db.ScoreHistorical.find({ userID: user.id }).limit(31).lean().exec(); + if (!hists) return this.error(message.channel, 'No history found.'); + if (hists.length < 1) return this.error(message.channel, 'No history found.'); + const histArray: [{ name: string, value: string }?] = []; + const totalArray: number[] = []; + const activityArray: number[] = []; + const moderationArray: number[] = []; + const roleArray: number[] = []; + const cloudServicesArray: number[] = []; + const otherArray: number[] = []; + const miscArray: number[] = []; + for (const hist of hists.reverse()) { + totalArray.push(hist.report.total); + activityArray.push(hist.report.activity); + moderationArray.push(hist.report.moderation); + roleArray.push(hist.report.roles); + cloudServicesArray.push(hist.report.cloudServices); + otherArray.push(hist.report.other); + miscArray.push(hist.report.staff); + let totalScore = '0'; + let activityScore = '0'; + let moderationScore = '0'; + let roleScore = '0'; + let cloudServicesScore = '0'; + let otherScore = '0'; + let miscScore = '0'; + + if (hist.report.total < 200) totalScore = '---'; + else if (hist.report.total > 800) totalScore = '800'; + else totalScore = `${hist.report.total}`; + + if (hist.report.activity < 10) activityScore = '---'; + else if (hist.report.activity > Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))) activityScore = String(Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))); + else activityScore = `${hist.report.activity}`; + + if (hist.report.roles <= 0) roleScore = '---'; + else if (hist.report.roles > 54) roleScore = '54'; + else roleScore = `${hist.report.roles}`; + + moderationScore = `${hist.report.moderation}`; + + if (hist.report.other === 0) otherScore = '---'; + else otherScore = `${hist.report.other}`; + + if (hist.report.staff <= 0) miscScore = '---'; + else miscScore = `${hist.report.staff}`; + + if (hist.report.cloudServices === 0) cloudServicesScore = '---'; + else if (hist.report.cloudServices > 10) cloudServicesScore = '10'; + else cloudServicesScore = `${hist.report.cloudServices}`; + + let data = ''; + let hardInquiries = 0; + const inquiries: InquiryInterface[] = []; + if (hist.inquiries?.length > 0) { + for (const h of hist.inquiries) { + const inq = await this.client.db.Inquiry.findOne({ _id: h }); + inquiries.push(inq); + } + } + if (inquiries?.length > 0) { + inquiries.forEach((inq) => { + const testDate = (new Date(new Date(inq.date).setHours(1460))); + // eslint-disable-next-line no-plusplus + if (testDate > new Date()) hardInquiries++; + }); + data += `__CommScore™:__ ${totalScore}\n__Activity:__ ${activityScore}\n__Roles:__ ${roleScore}\n__Moderation:__ ${moderationScore}\n__Cloud Services:__ ${cloudServicesScore}\n__Other:__ ${otherScore}\n__Misc:__ ${miscScore}\n\n__Hard Inquiries:__ ${hardInquiries}\n__Soft Inquiries:__ ${score.softInquiries?.length ?? '0'}`; + histArray.push({ name: moment(hist.date).calendar(), value: data }); + } + } + + const stat = { + totalMean: mean(totalArray), + totalMode: mode(totalArray), + totalMedian: median(totalArray), + activityMean: mean(activityArray), + rolesMean: mean(roleArray), + moderationMean: mean(moderationArray), + cloudServicesMean: mean(cloudServicesArray), + otherMean: mean(otherArray), + miscMean: mean(miscArray), + }; + const splitHist = this.client.util.splitFields(histArray); + const cmdPages: RichEmbed[] = []; + splitHist.forEach((split) => { + const embed = new RichEmbed(); + embed.setTitle('Historical Community Report'); + let totalMean = '0'; + let totalMedian = '0'; + let totalMode = '0'; + let activityMean = '0'; + let moderationMean = '0'; + let roleMean = '0'; + let cloudServicesMean = '0'; + let otherMean = '0'; + let miscMean = '0'; + + if (stat.totalMean < 200) totalMean = '---'; + else if (stat.totalMean > 800) totalMean = '800'; + else totalMean = `${stat.totalMean}`; + + if (stat.totalMedian < 200) totalMedian = '---'; + else if (stat.totalMedian > 800) totalMedian = '800'; + else totalMedian = `${stat.totalMedian}`; + + if (stat.totalMode < 200) totalMode = '---'; + else if (stat.totalMode > 800) totalMode = '800'; + else totalMode = `${stat.totalMode}`; + + if (stat.activityMean < 10) activityMean = '---'; + else if (stat.activityMean > Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))) activityMean = String(Math.floor((Math.log1p(getTotalMessageCount(this.client)) * 12))); + else activityMean = `${stat.activityMean}`; + + if (stat.rolesMean <= 0) roleMean = '---'; + else if (stat.rolesMean > 54) roleMean = '54'; + else roleMean = `${stat.rolesMean}`; + + moderationMean = `${stat.moderationMean}`; + + if (stat.otherMean === 0) otherMean = '---'; + else otherMean = `${stat.otherMean}`; + + if (stat.miscMean <= 0) miscMean = '---'; + else miscMean = `${stat.miscMean}`; + + if (stat.cloudServicesMean === 0) cloudServicesMean = '---'; + else if (stat.cloudServicesMean > 10) cloudServicesMean = '10'; + else cloudServicesMean = `${stat.cloudServicesMean}`; + + embed.setDescription(`__**Statistical Averages**__\n**CommScore™ Mean:** ${totalMean} | **CommScore™ Mode:** ${totalMode} | **CommScore™ Median:** ${totalMedian}\n\n**Activity Mean:** ${activityMean}\n**Roles Mean:** ${roleMean}\n**Moderation Mean:** ${moderationMean}\n**Cloud Services Mean:** ${cloudServicesMean}\n**Other Mean:** ${otherMean}\n**Misc Mean:** ${miscMean}`); + embed.setAuthor(user.username, user.avatarURL); + embed.setThumbnail(user.avatarURL); + embed.setTimestamp(); + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + split.forEach((c) => embed.addField(c.name, c.value)); + return cmdPages.push(embed); + }); + + let name = ''; + for (const role of this.client.util.resolveMember(message.author.id, this.mainGuild).roles.map((r) => this.mainGuild.roles.get(r)).sort((a, b) => b.position - a.position)) { + name = `Library of Code sp-us | ${role.name} - [HISTORICAL]`; + break; + } + await this.client.report.createInquiry(user.id, name, 1); + + + if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); + return createPaginationEmbed(message, cmdPages); + } catch (err) { + return this.client.util.handleError(err, message, this); + } + } +}