merge-requests/17/head
Hiroyuki 2021-02-06 23:04:18 -04:00
parent d83c35b256
commit eebd5d1e4c
No known key found for this signature in database
GPG Key ID: C15AC26538975A24
10 changed files with 225 additions and 55 deletions

View File

@ -1,47 +1,45 @@
{
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"env": {
"es6": true,
"node": true
},
"extends": [
"airbnb-base"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"linebreak-style": "off",
"no-unused-vars": "off",
"max-len": "off",
"import/no-dynamic-require": "off",
"global-require": "off",
"class-methods-use-this":"off",
"no-restricted-syntax": "off",
"camelcase": "off",
"indent": "warn",
"object-curly-newline": "off",
"import/prefer-default-export": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": 2,
"import/extensions": "off",
"no-param-reassign": "off",
"no-underscore-dangle": "off"
},
"ignorePatterns": "**/*.js"
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"env": {
"es6": true,
"node": true
},
"extends": ["airbnb-base"],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {
"linebreak-style": "off",
"no-unused-vars": "off",
"max-len": "off",
"import/no-dynamic-require": "off",
"global-require": "off",
"class-methods-use-this": "off",
"no-restricted-syntax": "off",
"camelcase": "off",
"indent": "warn",
"object-curly-newline": "off",
"import/prefer-default-export": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": 2,
"import/extensions": "off",
"no-param-reassign": "off",
"no-underscore-dangle": "off",
"keyword-spacing": "off",
"no-multiple-empty-lines": "off"
},
"ignorePatterns": "**/*.js"
}

View File

@ -68,7 +68,74 @@ export default class Root extends Route {
return res.status(200).json({
code: this.constants.codes.SUCCESS,
message: `Created new Executive Order with ID ${executiveOrder.oID} by the ${staffDiscord.username}#${staffDiscord.discriminator}, ${staffInformation.pn.join(', ')}.`,
message: `Created new Executive Order with ID ${executiveOrder.oID} by ${staffDiscord.username}#${staffDiscord.discriminator}, ${staffInformation.pn.join(', ')}.`,
});
});
this.router.post('/motions/new', 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('446067825673633794') || await this.server.client.getRESTGuild('446067825673633794');
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 (!req.body.subject) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
if (!req.body.body) {
return res.status(400).json({
code: this.constants.codes.CLIENT_ERROR,
message: this.constants.messages.CLIENT_ERROR,
});
}
const motionID = genUUID();
const staffDiscord = this.server.client.users.get(director.userID) || await this.server.client.getRESTUser(director.userID);
const staffInformation = await this.server.client.db.Staff.findOne({ userID: director.userID });
const embed = new RichEmbed();
embed.setTitle('Motion');
embed.setAuthor(`${staffDiscord.username}#${staffDiscord.discriminator}, ${staffInformation.pn.join(', ')}`, staffDiscord.avatarURL);
embed.setColor('#66e1ff');
embed.addField('Subject', req.body.subject);
embed.addField('Body', req.body.body);
embed.addField('ID', motionID);
embed.setTimestamp(new Date());
const channel = <TextChannel>this.server.client.getChannel('807444198969835550');
const motionMessage = await channel.createMessage({ embed });
await motionMessage.addReaction(this.server.client.util.emojis.SUCCESS);
await motionMessage.addReaction(this.server.client.util.emojis.ERROR);
const motion = await this.server.client.db.Motion.create({
issuedBy: director.userID,
subject: req.body.subject,
body: req.body.body,
at: new Date(),
oID: motionID,
motionMessage: motionMessage.id,
processed: false,
});
return res.status(200).json({
code: this.constants.codes.SUCCESS,
message: `Created new Motion with ID ${motion.oID} by ${staffDiscord.username}#${staffDiscord.discriminator}, ${staffInformation.pn.join(', ')}.`,
});
});
}

View File

@ -12,6 +12,7 @@ import {
Member, MemberInterface,
Merchant, MerchantInterface,
Moderation, ModerationInterface,
Motion, MotionInterface,
NNTrainingData, NNTrainingDataInterface,
Note, NoteInterface,
PagerNumber, PagerNumberInterface,
@ -44,7 +45,27 @@ export default class Client extends eris.Client {
public stripe: Stripe;
public db: { Customer: mongoose.Model<CustomerInterface>, CustomerPortal: mongoose.Model<CustomerPortalInterface>, ExecutiveOrder: mongoose.Model<ExecutiveOrderInterface>, File: mongoose.Model<FileInterface>, Member: mongoose.Model<MemberInterface>, Merchant: mongoose.Model<MerchantInterface>, Moderation: mongoose.Model<ModerationInterface>, NNTrainingData: mongoose.Model<NNTrainingDataInterface>, Note: mongoose.Model<NoteInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Promo: mongoose.Model<PromoInterface>, Rank: mongoose.Model<RankInterface>, Redirect: mongoose.Model<RedirectInterface>, Score: mongoose.Model<ScoreInterface>, ScoreHistorical: mongoose.Model<ScoreHistoricalInterface>, Staff: mongoose.Model<StaffInterface>, Stat: mongoose.Model<StatInterface>, local: { muted: LocalStorage } };
public db: {
Customer: mongoose.Model<CustomerInterface>,
CustomerPortal: mongoose.Model<CustomerPortalInterface>,
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>,
Promo: mongoose.Model<PromoInterface>,
Rank: mongoose.Model<RankInterface>,
Redirect: mongoose.Model<RedirectInterface>,
Score: mongoose.Model<ScoreInterface>,
ScoreHistorical: mongoose.Model<ScoreHistoricalInterface>,
Staff: mongoose.Model<StaffInterface>,
Stat: mongoose.Model<StatInterface>,
local: { muted: LocalStorage }
};
constructor(token: string, options?: eris.ClientOptions) {
super(token, options);
@ -52,10 +73,9 @@ export default class Client extends eris.Client {
this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>();
this.queue = new Queue(this);
this.db = { Customer, CustomerPortal, ExecutiveOrder, File, Member, Merchant, Moderation, NNTrainingData, Note, PagerNumber, Promo, Rank, Redirect, Score, ScoreHistorical, Staff, Stat, local: { muted: new LocalStorage('muted') } };
this.db = { Customer, CustomerPortal, ExecutiveOrder, File, Member, Merchant, Moderation, Motion, NNTrainingData, Note, PagerNumber, Promo, Rank, Redirect, Score, ScoreHistorical, Staff, Stat, local: { muted: new LocalStorage('muted') } };
}
public async loadDatabase() {
await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 });

View File

@ -71,7 +71,6 @@ export default class Util {
}
return `${(bytes / 1024 ** i).toFixed(2)} ${sizes[i]}`;
}
public async exec(command: string, _options: childProcess.ExecOptions = {}): Promise<string> {
const ex = promisify(childProcess.exec);
@ -105,7 +104,7 @@ export default class Util {
* @param query Command input
* @param message Only used to check for errors
*/
public resolveCommand(query: string | string[], message?: Message): Promise<{cmd: Command, args: string[] }> {
public resolveCommand(query: string | string[], message?: Message): Promise<{ cmd: Command, args: string[] }> {
try {
let resolvedCommand: Command;
if (typeof query === 'string') query = query.split(' ');
@ -195,7 +194,7 @@ export default class Util {
public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] {
let index = 0;
const array: {name: string, value: string, inline?: boolean}[][] = [[]];
const array: { name: string, value: string, inline?: boolean }[][] = [[]];
while (fields.length) {
if (array[index].length >= 25) { index += 1; array[index] = []; }
array[index].push(fields[0]); fields.shift();

View File

@ -38,7 +38,7 @@ export default class Apply extends Command {
validation: (member: Member) => member.roles.includes('546457886440685578'),
func: async (client: Client, ...data: any[]) => {
const member = await client.guilds.get(client.config.guildID).getRESTMember(data[0]);
const ax = <AxiosStatic> require('axios');
const ax = <AxiosStatic>require('axios');
await ax({
method: 'get',
url: `https://api.cloud.libraryofcode.org/wh/t2?userID=${member.id}&auth=${client.config.internalKey}`,

View File

@ -23,7 +23,7 @@ export default class Billing_T3 extends Command {
emailAddress?: string,
tier?: number,
supportKey?: string,
}> (await axios.get(`https://api.cloud.libraryofcode.org/wh/info?id=${message.author.id}&authorization=${this.client.config.internalKey}`)).data;
}>(await axios.get(`https://api.cloud.libraryofcode.org/wh/info?id=${message.author.id}&authorization=${this.client.config.internalKey}`)).data;
if (!response.found) return this.error(message.channel, 'CS Account not found.');
const customer = await this.client.db.Customer.findOne({ userID: message.author.id });

51
src/intervals/motions.ts Normal file
View File

@ -0,0 +1,51 @@
/* eslint-disable no-await-in-loop */
import type { TextChannel } from 'eris';
import { Client, RichEmbed } from '../class';
export default (client: Client) => {
const interval = setInterval(async () => {
const motions = await client.db.Motion.find({ processed: false });
const directorLogs = <TextChannel>client.getChannel('807444198969835550');
for (const motion of motions) {
const motionMessage = await directorLogs.getMessage(motion.motionMessage);
if ((Date.now() - motionMessage.createdAt) > 86400) {
const yea = await motionMessage.getReaction(client.util.emojis.SUCCESS);
const nay = await motionMessage.getReaction(client.util.emojis.ERROR);
const present = yea.length + nay.length;
const totalDirectors = 5;
const absent = totalDirectors - present;
await client.db.Motion.updateOne({ oID: motion.oID }, {
processed: true,
voteResults: {
yea: yea.length,
nay: nay.length,
present,
absent,
},
});
const directorDiscord = client.users.get(motion.issuedBy);
const directorProfile = await client.db.Staff.findOne({ userID: motion.issuedBy });
const embed = new RichEmbed();
embed.setAuthor(`${directorDiscord.username}#${directorDiscord.discriminator}, ${directorProfile.pn.join(', ')}`, directorDiscord.avatarURL);
embed.setFooter(`${directorProfile.position} | Library of Code sp-us | Board of Directors`, 'https://static.libraryofcode.org/loccommunityadmin.png');
let colour;
if (yea.length > nay.length) colour = '#27b17a';
else if (yea.length === nay.length) colour = '#ffb34d';
else colour = '#ff474a';
embed.setColor(colour);
embed.addField('Motion ID', motion.oID);
embed.addField('Result', `- **Yea:** ${yea.length}\n**Nay:** ${nay.length}\n**Present:** ${present}\n**Absent:** ${absent}\n**Total:** ${present + absent}`);
embed.setTimestamp();
await directorLogs.createMessage({ content: directorDiscord.mention, embed });
}
}
}, 300000);
return interval;
};

View File

@ -13,7 +13,7 @@ const ExecutiveOrder = new Schema({
subject: { type: String, required: true },
body: { type: String, required: true },
at: { type: Date, required: true },
oID: { type: String, required: true, unique: true }
oID: { type: String, required: true, unique: true },
});
export default model<ExecutiveOrderInterface>('ExecutiveOrders', ExecutiveOrder);

34
src/models/Motion.ts Normal file
View File

@ -0,0 +1,34 @@
import { Document, model, Schema } from 'mongoose';
export interface MotionInterface extends Document {
issuedBy: string;
subject: string;
body: string;
at: Date;
oID: string;
voteResults: {
yea: number;
nay: number;
present: number;
absent: number;
};
motionMessage: string;
}
const Motion = new Schema({
issuedBy: { 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 },
voteResults: {
yea: Number,
Nay: Number,
present: Number,
absent: Number,
},
motionMessage: { type: String, required: true, unique: true },
processed: Boolean,
});
export default model<MotionInterface>('Motions', Motion);

View File

@ -5,6 +5,7 @@ export { default as File, FileInterface } from './File';
export { default as Member, MemberInterface } from './Member';
export { default as Merchant, MerchantInterface } from './Merchant';
export { default as Moderation, ModerationInterface } from './Moderation';
export { default as Motion, MotionInterface } from './Motion';
export { default as NNTrainingData, NNTrainingDataInterface } from './NNTrainingData';
export { default as Note, NoteInterface } from './Note';
export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber';