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

@ -10,9 +10,7 @@
"es6": true, "es6": true,
"node": true "node": true
}, },
"extends": [ "extends": ["airbnb-base"],
"airbnb-base"
],
"globals": { "globals": {
"Atomics": "readonly", "Atomics": "readonly",
"SharedArrayBuffer": "readonly" "SharedArrayBuffer": "readonly"
@ -22,9 +20,7 @@
"ecmaVersion": 2020, "ecmaVersion": 2020,
"sourceType": "module" "sourceType": "module"
}, },
"plugins": [ "plugins": ["@typescript-eslint"],
"@typescript-eslint"
],
"rules": { "rules": {
"linebreak-style": "off", "linebreak-style": "off",
"no-unused-vars": "off", "no-unused-vars": "off",
@ -41,7 +37,9 @@
"@typescript-eslint/no-useless-constructor": 2, "@typescript-eslint/no-useless-constructor": 2,
"import/extensions": "off", "import/extensions": "off",
"no-param-reassign": "off", "no-param-reassign": "off",
"no-underscore-dangle": "off" "no-underscore-dangle": "off",
"keyword-spacing": "off",
"no-multiple-empty-lines": "off"
}, },
"ignorePatterns": "**/*.js" "ignorePatterns": "**/*.js"
} }

View File

@ -68,7 +68,74 @@ export default class Root extends Route {
return res.status(200).json({ return res.status(200).json({
code: this.constants.codes.SUCCESS, 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, Member, MemberInterface,
Merchant, MerchantInterface, Merchant, MerchantInterface,
Moderation, ModerationInterface, Moderation, ModerationInterface,
Motion, MotionInterface,
NNTrainingData, NNTrainingDataInterface, NNTrainingData, NNTrainingDataInterface,
Note, NoteInterface, Note, NoteInterface,
PagerNumber, PagerNumberInterface, PagerNumber, PagerNumberInterface,
@ -44,7 +45,27 @@ export default class Client extends eris.Client {
public stripe: Stripe; 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) { constructor(token: string, options?: eris.ClientOptions) {
super(token, options); super(token, options);
@ -52,10 +73,9 @@ export default class Client extends eris.Client {
this.events = new Collection<Event>(); this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>(); this.intervals = new Collection<NodeJS.Timeout>();
this.queue = new Queue(this); this.queue = new Queue(this);
this.db = { Customer, CustomerPortal, ExecutiveOrder, File, Member, Merchant, Moderation, 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() { public async loadDatabase() {
await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 }); await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 });

View File

@ -72,7 +72,6 @@ export default class Util {
return `${(bytes / 1024 ** i).toFixed(2)} ${sizes[i]}`; return `${(bytes / 1024 ** i).toFixed(2)} ${sizes[i]}`;
} }
public async exec(command: string, _options: childProcess.ExecOptions = {}): Promise<string> { public async exec(command: string, _options: childProcess.ExecOptions = {}): Promise<string> {
const ex = promisify(childProcess.exec); const ex = promisify(childProcess.exec);
try { try {

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 }, subject: { type: String, required: true },
body: { type: String, required: true }, body: { type: String, required: true },
at: { type: Date, 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); 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 Member, MemberInterface } from './Member';
export { default as Merchant, MerchantInterface } from './Merchant'; export { default as Merchant, MerchantInterface } from './Merchant';
export { default as Moderation, ModerationInterface } from './Moderation'; export { default as Moderation, ModerationInterface } from './Moderation';
export { default as Motion, MotionInterface } from './Motion';
export { default as NNTrainingData, NNTrainingDataInterface } from './NNTrainingData'; export { default as NNTrainingData, NNTrainingDataInterface } from './NNTrainingData';
export { default as Note, NoteInterface } from './Note'; export { default as Note, NoteInterface } from './Note';
export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber'; export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber';