Motions
parent
d83c35b256
commit
eebd5d1e4c
|
@ -1,47 +1,45 @@
|
||||||
{
|
{
|
||||||
"settings": {
|
"settings": {
|
||||||
"import/resolver": {
|
"import/resolver": {
|
||||||
"node": {
|
"node": {
|
||||||
"extensions": [".js", ".jsx", ".ts", ".tsx"]
|
"extensions": [".js", ".jsx", ".ts", ".tsx"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": ["airbnb-base"],
|
||||||
"airbnb-base"
|
"globals": {
|
||||||
],
|
"Atomics": "readonly",
|
||||||
"globals": {
|
"SharedArrayBuffer": "readonly"
|
||||||
"Atomics": "readonly",
|
},
|
||||||
"SharedArrayBuffer": "readonly"
|
"parser": "@typescript-eslint/parser",
|
||||||
},
|
"parserOptions": {
|
||||||
"parser": "@typescript-eslint/parser",
|
"ecmaVersion": 2020,
|
||||||
"parserOptions": {
|
"sourceType": "module"
|
||||||
"ecmaVersion": 2020,
|
},
|
||||||
"sourceType": "module"
|
"plugins": ["@typescript-eslint"],
|
||||||
},
|
"rules": {
|
||||||
"plugins": [
|
"linebreak-style": "off",
|
||||||
"@typescript-eslint"
|
"no-unused-vars": "off",
|
||||||
],
|
"max-len": "off",
|
||||||
"rules": {
|
"import/no-dynamic-require": "off",
|
||||||
"linebreak-style": "off",
|
"global-require": "off",
|
||||||
"no-unused-vars": "off",
|
"class-methods-use-this": "off",
|
||||||
"max-len": "off",
|
"no-restricted-syntax": "off",
|
||||||
"import/no-dynamic-require": "off",
|
"camelcase": "off",
|
||||||
"global-require": "off",
|
"indent": "warn",
|
||||||
"class-methods-use-this":"off",
|
"object-curly-newline": "off",
|
||||||
"no-restricted-syntax": "off",
|
"import/prefer-default-export": "off",
|
||||||
"camelcase": "off",
|
"no-useless-constructor": "off",
|
||||||
"indent": "warn",
|
"@typescript-eslint/no-useless-constructor": 2,
|
||||||
"object-curly-newline": "off",
|
"import/extensions": "off",
|
||||||
"import/prefer-default-export": "off",
|
"no-param-reassign": "off",
|
||||||
"no-useless-constructor": "off",
|
"no-underscore-dangle": "off",
|
||||||
"@typescript-eslint/no-useless-constructor": 2,
|
"keyword-spacing": "off",
|
||||||
"import/extensions": "off",
|
"no-multiple-empty-lines": "off"
|
||||||
"no-param-reassign": "off",
|
},
|
||||||
"no-underscore-dangle": "off"
|
"ignorePatterns": "**/*.js"
|
||||||
},
|
|
||||||
"ignorePatterns": "**/*.js"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(', ')}.`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -105,7 +104,7 @@ export default class Util {
|
||||||
* @param query Command input
|
* @param query Command input
|
||||||
* @param message Only used to check for errors
|
* @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 {
|
try {
|
||||||
let resolvedCommand: Command;
|
let resolvedCommand: Command;
|
||||||
if (typeof query === 'string') query = query.split(' ');
|
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 }[][] {
|
public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
const array: {name: string, value: string, inline?: boolean}[][] = [[]];
|
const array: { name: string, value: string, inline?: boolean }[][] = [[]];
|
||||||
while (fields.length) {
|
while (fields.length) {
|
||||||
if (array[index].length >= 25) { index += 1; array[index] = []; }
|
if (array[index].length >= 25) { index += 1; array[index] = []; }
|
||||||
array[index].push(fields[0]); fields.shift();
|
array[index].push(fields[0]); fields.shift();
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default class Apply extends Command {
|
||||||
validation: (member: Member) => member.roles.includes('546457886440685578'),
|
validation: (member: Member) => member.roles.includes('546457886440685578'),
|
||||||
func: async (client: Client, ...data: any[]) => {
|
func: async (client: Client, ...data: any[]) => {
|
||||||
const member = await client.guilds.get(client.config.guildID).getRESTMember(data[0]);
|
const member = await client.guilds.get(client.config.guildID).getRESTMember(data[0]);
|
||||||
const ax = <AxiosStatic> require('axios');
|
const ax = <AxiosStatic>require('axios');
|
||||||
await ax({
|
await ax({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: `https://api.cloud.libraryofcode.org/wh/t2?userID=${member.id}&auth=${client.config.internalKey}`,
|
url: `https://api.cloud.libraryofcode.org/wh/t2?userID=${member.id}&auth=${client.config.internalKey}`,
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default class Billing_T3 extends Command {
|
||||||
emailAddress?: string,
|
emailAddress?: string,
|
||||||
tier?: number,
|
tier?: number,
|
||||||
supportKey?: string,
|
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.');
|
if (!response.found) return this.error(message.channel, 'CS Account not found.');
|
||||||
|
|
||||||
const customer = await this.client.db.Customer.findOne({ userID: message.author.id });
|
const customer = await this.client.db.Customer.findOne({ userID: message.author.id });
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
|
@ -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';
|
||||||
|
|
Loading…
Reference in New Issue