diff --git a/src/api/board.ins/routes/root.ts b/src/api/board.ins/routes/root.ts index d53b99e..959f587 100644 --- a/src/api/board.ins/routes/root.ts +++ b/src/api/board.ins/routes/root.ts @@ -38,7 +38,7 @@ export default class Root extends Route { } const executiveOrder = await this.server.client.db.ExecutiveOrder.create({ - issuedBy: director.userID, + issuer: director.userID, subject: req.body.subject, body: req.body.body, at: new Date(), @@ -106,17 +106,14 @@ export default class Root extends Route { embed.setTimestamp(new Date()); const channel = 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); + await channel.createMessage({ embed }); const motion = await this.server.client.db.Motion.create({ - issuedBy: director.userID, + issuer: director.userID, subject: req.body.subject, body: req.body.body, at: new Date(), oID: motionID, - motionMessage: motionMessage.id, processed: false, }); @@ -173,22 +170,23 @@ export default class Root extends Route { embed.setTimestamp(new Date()); const channel = 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 procMessage = await channel.createMessage({ embed }); + await procMessage.addReaction(this.server.client.util.emojis.SUCCESS); + await procMessage.addReaction(this.server.client.util.emojis.ERROR); - const motion = await this.server.client.db.Proclamation.create({ - issuedBy: director.userID, + const proc = await this.server.client.db.Proclamation.create({ + issuer: director.userID, subject: req.body.subject, body: req.body.body, at: new Date(), oID: proclamationID, processed: false, + msg: procMessage.id, }); res.status(200).json({ code: this.constants.codes.SUCCESS, - message: `Created new Proclamation with ID ${motion.oID} by ${staffDiscord.username}#${staffDiscord.discriminator}, ${staffInformation.pn.join(', ')}.`, + message: `Created new Proclamation with ID ${proc.oID} by ${staffDiscord.username}#${staffDiscord.discriminator}, ${staffInformation.pn.join(', ')}.`, }); }); @@ -232,7 +230,7 @@ export default class Root extends Route { embed.setTimestamp(new Date()); const resolution = await this.server.client.db.Resolution.create({ - issuedBy: director.userID, + issuer: director.userID, subject: req.body.subject, body: req.body.body, at: new Date(), @@ -408,7 +406,7 @@ export default class Root extends Route { const executiveOrder = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id }); res.status(200).json({ - issuedBy: executiveOrder.issuedBy, + issuer: executiveOrder.issuer, id: executiveOrder.oID, subject: executiveOrder.subject, body: executiveOrder.body, @@ -433,7 +431,7 @@ export default class Root extends Route { const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id }); res.status(200).json({ - issuedBy: motion.issuedBy, + issuer: motion.issuer, id: motion.oID, subject: motion.subject, body: motion.body, @@ -458,13 +456,13 @@ export default class Root extends Route { const resolution = await this.server.client.db.Resolution.findOne({ oID: req.params.id }); res.status(200).json({ - issuedBy: resolution.issuedBy, + issuer: resolution.issuer, id: resolution.oID, subject: resolution.subject, body: resolution.body, at: new Date(resolution.at), approvedAt: resolution.acceptedAt || null, - voteResults: resolution.voteResults || null, + results: resolution.results || null, }); }); diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index 0d750f0..8dbf502 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -13,7 +13,7 @@ export default class GuildMemberAdd extends Event { try { const search = await this.client.db.local.muted.get(`muted-${member.user.id}`); if (search) { - member.addRole('478373942638149643'); + await member.addRole('478373942638149643'); } } catch (err) { this.client.util.handleError(err); diff --git a/src/events/messageReactionAdd.ts b/src/events/messageReactionAdd.ts new file mode 100644 index 0000000..c00fcbf --- /dev/null +++ b/src/events/messageReactionAdd.ts @@ -0,0 +1,57 @@ +import { Emoji, GuildTextableChannel, Member, Message } from 'eris'; +import { Client, Event } from '../class'; + +export default class MessageReactionAdd extends Event { + public client: Client; + + constructor(client: Client) { + super(client); + this.event = 'messageReactionAdd'; + } + + public async run(message: Message, emoji: Emoji, reactor: Member) { + if (message.channel.id !== '807444198969835550') return; + if (message.author.id !== this.client.user.id) return; + + if (!reactor.roles[0]) { + reactor = await message.channel.guild.getRESTMember(reactor.id); + } + + if (!reactor.roles.includes('662163685439045632')) return; + + if ((await this.client.db.Proclamation.exists({ msg: message.id, processed: false }))) { + const yea = await message.getReaction(this.client.util.emojis.SUCCESS); + const nay = await message.getReaction(this.client.util.emojis.ERROR); + const present = await message.getReaction('🙋'); + const totalDirectors = 6; + const proc = await this.client.db.Proclamation.findOne({ msg: message.id }); + const processed = totalDirectors === (yea.length + nay.length + present.length) || Date.now() - proc.at > 604800000; + const absent = totalDirectors - (yea.length + nay.length + present.length); + + await this.client.db.Proclamation.updateOne({ msg: message.id }, { + results: { + yea: yea.length, + nay: nay.length, + present: present.length, + absent, + }, + processed, + }); + const inTheMajority = yea.length > nay.length + present.length; + + if (processed) { + const author = this.client.users.get(proc.issuer) || await this.client.getRESTUser(proc.issuer); + + if (inTheMajority) { + await author.createMessage(`__**Proclamation Majority Vote Received**__\nThe Proclamation you created at Library of Code sp-us, titled **${proc.subject}** (\`${proc.oID}\`) received the majority vote.`); + await message.channel.createMessage(`__**Proclamation Results**__\nProclamation issued by ${author.mention} **received** the majority vote. Proclamation ID: ${proc.oID}\n\n__Results:__\n**Yea:** ${yea.length}\n**Nay:** ${nay.length}\n**Present:** ${present.length}\n**Absent:** ${absent}`); + } else { + await author.createMessage(`__**Proclamation Majority Vote Lost**__\nThe Proclamation you created at Library of Code sp-us, titled **${proc.subject}** (\`${proc.oID}\`) lost the majority vote.`); + await message.channel.createMessage(`__**Proclamation Results**__\nProclamation issued by ${author.mention} **lost** the majority vote. Proclamation ID: ${proc.oID}\n\n__Results:__\n**Yea:** ${yea.length}\n**Nay:** ${nay.length}\n**Present:** ${present.length}\n**Absent:** ${absent}`); + } + } + + await reactor.user.createMessage(`__**Vote Recorded**\nYour vote on the proclamation with ID \`${proc.id}\` at Library of Code sp-us was successfully recorded.`); + } + } +} diff --git a/src/intervals/motions.ts b/src/intervals/motions.ts deleted file mode 100644 index 4c9d74a..0000000 --- a/src/intervals/motions.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* 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 = 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, - }, - }); - await client.db.Resolution.create({ - issuedBy: motion.issuedBy, - subject: motion.subject, - body: motion.body, - at: motion.at, - oID: motion.oID, - voteResults: { - yea: yea.length, - Nay: nay.length, - present, - absent, - }, - acceptedAt: Date.now(), - }); - - 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.setTitle('Resolution'); - embed.setFooter(`${directorProfile.title} | 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.setDescription(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; -}; diff --git a/src/models/ExecutiveOrder.ts b/src/models/ExecutiveOrder.ts index be4127a..c4c7bca 100644 --- a/src/models/ExecutiveOrder.ts +++ b/src/models/ExecutiveOrder.ts @@ -1,7 +1,7 @@ import { Document, model, Schema } from 'mongoose'; export interface ExecutiveOrderInterface extends Document { - issuedBy: string; + issuer: string; subject: string; body: string; at: Date; @@ -9,7 +9,7 @@ export interface ExecutiveOrderInterface extends Document { } const ExecutiveOrder = new Schema({ - issuedBy: { type: String, required: true }, + issuer: { type: String, required: true }, subject: { type: String, required: true }, body: { type: String, required: true }, at: { type: Date, required: true }, diff --git a/src/models/Motion.ts b/src/models/Motion.ts index d2f9711..d75c6d8 100644 --- a/src/models/Motion.ts +++ b/src/models/Motion.ts @@ -1,33 +1,32 @@ import { Document, model, Schema } from 'mongoose'; export interface MotionInterface extends Document { - issuedBy: string; + issuer: string; subject: string; body: string; at: Date; oID: string; - voteResults: { + results: { yea: number; nay: number; present: number; absent: number; }; - motionMessage: string; + processed: boolean; } const Motion = new Schema({ - issuedBy: { type: String, required: true }, + issuer: { type: String, required: true }, subject: { type: String, required: true }, body: { type: String, required: true }, at: { type: Date, required: true }, oID: { type: String, required: true, unique: true }, - voteResults: { + results: { yea: Number, - Nay: Number, + nay: Number, present: Number, absent: Number, }, - motionMessage: { type: String, required: true, unique: true }, processed: Boolean, }); diff --git a/src/models/Proclamation.ts b/src/models/Proclamation.ts index df3cc6b..e681da9 100644 --- a/src/models/Proclamation.ts +++ b/src/models/Proclamation.ts @@ -1,29 +1,37 @@ import { Document, model, Schema } from 'mongoose'; export interface ProclamationInterface extends Document { - issuedBy: string; + issuer: string; subject: string; body: string; - at: Date; + at: number; oID: string; - voteResults: { + results: { yea: number; nay: number; + present: number; + absent: number; }; acceptedAt: number; + msg: string; + processed: boolean; } const Proclamation = new Schema({ - issuedBy: { type: String, required: true }, + issuer: { type: String, required: true }, subject: { type: String, required: true }, body: { type: String, required: true }, - at: { type: Date, required: true }, + at: { type: Number, required: true }, oID: { type: String, required: true, unique: true }, - voteResults: { + results: { yea: Number, nay: Number, + present: Number, + absent: Number, }, acceptedAt: Number, + msg: { type: String, required: true, unique: true }, + processed: Boolean, }); export default model('Proclamations', Proclamation); diff --git a/src/models/Resolution.ts b/src/models/Resolution.ts index 45b3245..2f32c46 100644 --- a/src/models/Resolution.ts +++ b/src/models/Resolution.ts @@ -1,12 +1,12 @@ import { Document, model, Schema } from 'mongoose'; export interface ResolutionInterface extends Document { - issuedBy: string; + issuer: string; subject: string; body: string; at: Date; oID: string; - voteResults: { + results: { yea: number; nay: number; present: number; @@ -16,12 +16,12 @@ export interface ResolutionInterface extends Document { } const Resolution = new Schema({ - issuedBy: { type: String, required: true }, + issuer: { type: String, required: true }, subject: { type: String, required: true }, body: { type: String, required: true }, at: { type: Date, required: true }, oID: { type: String, required: true, unique: true }, - voteResults: { + results: { yea: Number, Nay: Number, present: Number,