From 9c119691a414755da386db73aada8843bad2aa52 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Thu, 9 Jul 2020 04:41:29 -0400 Subject: [PATCH] mute command, local storage class, and additional improvements --- .gitignore | 1 + src/class/Client.ts | 6 +- src/class/Command.ts | 6 +- src/class/LocalStorage.ts | 120 +++++++++++++++++++++++++++++++++++ src/class/Moderation.ts | 79 +++++++++++++++++++++++ src/class/index.ts | 1 + src/commands/addrank.ts | 2 +- src/commands/ban.ts | 2 +- src/commands/delrank.ts | 2 +- src/commands/game.ts | 2 +- src/commands/index.ts | 2 + src/commands/kick.ts | 2 +- src/commands/mute.ts | 45 +++++++++++++ src/commands/page.ts | 10 +-- src/commands/rank.ts | 24 ++++--- src/commands/roleinfo.ts | 5 +- src/commands/unmute.ts | 34 ++++++++++ src/commands/whois.ts | 2 +- src/events/guildMemberAdd.ts | 22 +++++++ src/intervals/autoRelease.ts | 17 ++++- src/models/Moderation.ts | 2 +- 21 files changed, 356 insertions(+), 30 deletions(-) create mode 100644 src/class/LocalStorage.ts create mode 100644 src/commands/mute.ts create mode 100644 src/commands/unmute.ts create mode 100644 src/events/guildMemberAdd.ts diff --git a/.gitignore b/.gitignore index 36f0a06..a2ae0aa 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ build/config.yaml # Build/Distribution Files build dist +localstorage diff --git a/src/class/Client.ts b/src/class/Client.ts index ae68b2b..5a733f1 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -1,7 +1,7 @@ import eris from 'eris'; import mongoose from 'mongoose'; import { promises as fs } from 'fs'; -import { Collection, Command, Util, ServerManagement, Event } from '.'; +import { Collection, Command, LocalStorage, Util, ServerManagement, Event } from '.'; import { Member, MemberInterface, Moderation, ModerationInterface, PagerNumber, PagerNumberInterface, Rank, RankInterface, Redirect, RedirectInterface } from '../models'; export default class Client extends eris.Client { @@ -17,14 +17,14 @@ export default class Client extends eris.Client { public serverManagement: ServerManagement; - public db: { Member: mongoose.Model, Moderation: mongoose.Model, PagerNumber: mongoose.Model, Rank: mongoose.Model, Redirect: mongoose.Model }; + public db: { Member: mongoose.Model, Moderation: mongoose.Model, PagerNumber: mongoose.Model, Rank: mongoose.Model, Redirect: mongoose.Model, local: LocalStorage }; constructor(token: string, options?: eris.ClientOptions) { super(token, options); this.commands = new Collection(); this.events = new Collection(); this.intervals = new Collection(); - this.db = { Member, Moderation, PagerNumber, Rank, Redirect }; + this.db = { Member, Moderation, PagerNumber, Rank, Redirect, local: new LocalStorage(this) }; } public async loadDatabase() { diff --git a/src/class/Command.ts b/src/class/Command.ts index 739f7fa..47cee7f 100644 --- a/src/class/Command.ts +++ b/src/class/Command.ts @@ -1,4 +1,4 @@ -import { Member, Message, TextableChannel } from 'eris'; +import { Guild, Member, Message, TextableChannel } from 'eris'; import { Client } from '.'; export default class Command { @@ -54,6 +54,10 @@ export default class Command { this.aliases = []; } + get mainGuild() { + return this.client.guilds.get(this.client.config.guildID); + } + public checkPermissions(member: Member): boolean { if (member.id === '278620217221971968' || member.id === '253600545972027394') return true; switch (this.permissions) { diff --git a/src/class/LocalStorage.ts b/src/class/LocalStorage.ts new file mode 100644 index 0000000..99765e6 --- /dev/null +++ b/src/class/LocalStorage.ts @@ -0,0 +1,120 @@ +/* eslint-disable no-constant-condition */ +import { promises as fs, constants } from 'fs'; +import { Client } from '.'; + +type JSONData = [{key: string, value: any}?]; + + +/** + * Persistant local JSON-based storage. + * Auto-locking system to prevent corrupted data. + * @author Matthew + */ +export default class LocalStorage { + private client: Client; + + protected storagePath: string; + + private locked: boolean = false; + + constructor(client: Client, storagePath = `${__dirname}/../../localstorage`) { + this.client = client; + this.storagePath = storagePath; + this.init(); + } + + private async init() { + try { + await fs.access(`${this.storagePath}/1.json`, constants.F_OK); + } catch { + const setup = []; + await fs.writeFile(`${this.storagePath}/1.json`, JSON.stringify(setup), { encoding: 'utf8' }); + } + } + + /** + * Retrieves one data from the store. + * If the store has multiple entries for the same key, this function will only return the first entry. + * ```ts + * await LocalStorage.get('data-key'); + * ``` + * @param key The key for the data entry. + */ + public async get(key: string): Promise { + while (true) { + if (!this.locked) break; + } + this.locked = true; + + const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' }); + this.locked = false; + const json: JSONData = JSON.parse(file); + const result = json.filter((data) => data.key === key); + if (!result[0]) return null; + return result[0].value; + } + + /** + * Retrieves multiple data keys/values from the store. + * This function will return all of the values matching the key you provided exactly. Use `LocalStorage.get();` if possible. + * ```ts + * await LocalStorage.get('data-key'); + * @param key The key for the data entry. + */ + public async getMany(key: string): Promise<{key: string, value: T}[]> { + while (true) { + if (!this.locked) break; + } + this.locked = true; + + const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' }); + this.locked = false; + const json: JSONData = JSON.parse(file); + const result = json.filter((data) => data.key === key); + if (result.length < 1) return null; + return result; + } + + /** + * Sets a key/value pair and creates a new data entry. + * @param key The key for the data entry. + * @param value The value for the data entry, can be anything that is valid JSON. + * @param options.override [DEPRECATED] By default, this function will error if the key you're trying to set already exists. Set this option to true to override that setting. + * ```ts + * await LocalStorage.set('data-key', 'test'); + * ``` + */ + public async set(key: string, value: any): Promise { + while (true) { + if (!this.locked) break; + } + this.locked = true; + + const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' }); + const json: JSONData = JSON.parse(file); + json.push({ key, value }); + await fs.writeFile(`${this.storagePath}/1.json`, JSON.stringify(json), { encoding: 'utf8' }); + this.locked = false; + } + + /** + * Deletes the data for the specified key. + * **Warning:** This function will delete ALL matching entries. + * ```ts + * await LocalStorage.del('data-key'); + * ``` + * @param key The key for the data entry. + */ + public async del(key: string): Promise { + while (true) { + if (!this.locked) break; + } + this.locked = true; + + const file = await fs.readFile(`${this.storagePath}/1.json`, { encoding: 'utf8' }); + const json: JSONData = JSON.parse(file); + const filtered = json.filter((data) => data.key !== key); + await fs.writeFile(`${this.storagePath}/1.json`, JSON.stringify(filtered), { encoding: 'utf8' }); + this.locked = false; + } +} diff --git a/src/class/Moderation.ts b/src/class/Moderation.ts index 29ac32e..f796997 100644 --- a/src/class/Moderation.ts +++ b/src/class/Moderation.ts @@ -111,6 +111,85 @@ export default class Moderation { return mod.save(); } + public async mute(user: User, moderator: Member, duration: number, reason?: string): Promise { + if (reason && reason.length > 512) throw new Error('Mute reason cannot be longer than 512 characters'); + const member = await this.client.getRESTGuildMember(this.client.config.guildID, user.id); + if (!member) throw new Error('Cannot find member.'); + await member.addRole('478373942638149643', `Muted by ${moderator.username}#${moderator.discriminator}`); + const logID = randomBytes(2).toString('hex'); + const mod = new ModerationModel({ + userID: user.id, + logID, + moderatorID: moderator.id, + reason: reason || null, + type: 2, + date: new Date(), + }); + const now: number = Date.now(); + let date: Date; + let processed = true; + if (duration > 0) { + date = new Date(now + duration); + processed = false; + } else date = null; + const expiration = { date, processed }; + mod.expiration = expiration; + await this.client.db.local.set(`muted-${member.id}`, true); + + const embed = new RichEmbed(); + embed.setTitle(`Case ${logID} | Mute`); + embed.setColor('#ffff00'); + embed.setAuthor(user.username, user.avatarURL); + embed.setThumbnail(user.avatarURL); + embed.addField('User', `<@${user.id}>`, true); + embed.addField('Moderator', `<@${moderator.id}>`, true); + if (reason) { + embed.addField('Reason', reason, true); + } + if (date) { + embed.addField('Expiration', moment(date).calendar(), true); + } + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + this.client.createMessage(this.logChannels.modlogs, { embed }); + return mod.save(); + } + + public async unmute(userID: string, moderator: Member, reason?: string): Promise { + const member = await this.client.getRESTGuildMember(this.client.config.guildID, userID); + if (!member) { + await this.client.db.local.del(`muted-${userID}`); + throw new Error('Member doesn\'t exist.'); + } + await member.removeRole('478373942638149643'); + const logID = randomBytes(2).toString('hex'); + const mod = new ModerationModel({ + userID, + logID, + moderatorID: moderator.id, + reason: reason || null, + type: 1, + date: new Date(), + }); + + await this.client.db.local.del(`muted-${member.id}`); + + const embed = new RichEmbed(); + embed.setTitle(`Case ${logID} | Unmute`); + embed.setColor('#1abc9c'); + embed.setAuthor(member.user.username, member.user.avatarURL); + embed.setThumbnail(member.user.avatarURL); + embed.addField('User', `<@${member.user.id}>`, true); + embed.addField('Moderator', `<@${moderator.id}>`, true); + if (reason) { + embed.addField('Reason', reason, true); + } + embed.setFooter(this.client.user.username, this.client.user.avatarURL); + embed.setTimestamp(); + this.client.createMessage(this.logChannels.modlogs, { embed }); + return mod.save(); + } + public async kick(user: Member|User, moderator: Member, reason?: string): Promise { if (reason && reason.length > 512) throw new Error('Kick reason cannot be longer than 512 characters'); await this.client.guilds.get(this.client.config.guildID).kickMember(user.id, reason); diff --git a/src/class/index.ts b/src/class/index.ts index b14fb21..3b55fea 100644 --- a/src/class/index.ts +++ b/src/class/index.ts @@ -2,6 +2,7 @@ export { default as Client } from './Client'; export { default as Collection } from './Collection'; export { default as Command } from './Command'; export { default as Event } from './Event'; +export { default as LocalStorage } from './LocalStorage'; export { default as Moderation } from './Moderation'; export { default as RichEmbed } from './RichEmbed'; export { default as Route } from './Route'; diff --git a/src/commands/addrank.ts b/src/commands/addrank.ts index dbdab64..241e2f7 100644 --- a/src/commands/addrank.ts +++ b/src/commands/addrank.ts @@ -17,7 +17,7 @@ export default class AddRank extends Command { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); if (!args[1]) return this.error(message.channel, 'Permissions are required.'); if (!args[2]) return this.error(message.channel, 'A description is required'); - const role = this.client.util.resolveRole(args[0], this.client.guilds.get(this.client.config.guildID)); + const role = this.client.util.resolveRole(args[0], this.mainGuild); if (!role) return this.error(message.channel, 'The role you specified doesn\'t appear to exist.'); const check = await this.client.db.Rank.findOne({ roleID: role.id }); diff --git a/src/commands/ban.ts b/src/commands/ban.ts index 160eeec..f97de93 100644 --- a/src/commands/ban.ts +++ b/src/commands/ban.ts @@ -16,7 +16,7 @@ export default class Ban extends Command { public async run(message: Message, args: string[]) { try { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); - const member = this.client.util.resolveMember(args[0], message.guild); + const member = this.client.util.resolveMember(args[0], this.mainGuild); let user: User; if (!member) { try { diff --git a/src/commands/delrank.ts b/src/commands/delrank.ts index 64c068b..9527fd3 100644 --- a/src/commands/delrank.ts +++ b/src/commands/delrank.ts @@ -15,7 +15,7 @@ export default class DelRank extends Command { public async run(message: Message, args: string[]) { try { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); - const role = this.client.util.resolveRole(args[0], this.client.guilds.get(this.client.config.guildID)); + const role = this.client.util.resolveRole(args[0], this.mainGuild); if (!role) return this.error(message.channel, 'The role you specified doesn\'t appear to exist.'); const check = await this.client.db.Rank.findOne({ roleID: role.id }); diff --git a/src/commands/game.ts b/src/commands/game.ts index 075a7aa..3c6d7a8 100644 --- a/src/commands/game.ts +++ b/src/commands/game.ts @@ -27,7 +27,7 @@ export default class Game extends Command { let member: Member; if (!args[0]) member = message.member; else { - member = this.client.util.resolveMember(args.join(' '), message.guild); + member = this.client.util.resolveMember(args.join(' '), this.mainGuild); if (!member) { return this.error(message.channel, 'Member not found.'); } diff --git a/src/commands/index.ts b/src/commands/index.ts index 7e21286..8e33dd4 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -12,10 +12,12 @@ export { default as help } from './help'; export { default as info } from './info'; export { default as kick } from './kick'; export { default as listredirects } from './listredirects'; +export { default as mute } from './mute'; export { default as npm } from './npm'; export { default as page } from './page'; export { default as ping } from './ping'; export { default as rank } from './rank'; export { default as roleinfo } from './roleinfo'; export { default as unban } from './unban'; +export { default as unmute } from './unmute'; export { default as whois } from './whois'; diff --git a/src/commands/kick.ts b/src/commands/kick.ts index 69dbff4..a606cab 100644 --- a/src/commands/kick.ts +++ b/src/commands/kick.ts @@ -18,7 +18,7 @@ export default class Kick extends Command { let user: Member = this.client.util.resolveMember(args[0], message.guild); if (!user) { try { - user = await this.client.getRESTGuildMember(this.client.config.guildID, args[0]); + user = await this.client.getRESTGuildMember(this.mainGuild.id, args[0]); } catch { return this.error(message.channel, 'Cannot find user.'); } diff --git a/src/commands/mute.ts b/src/commands/mute.ts new file mode 100644 index 0000000..73beb94 --- /dev/null +++ b/src/commands/mute.ts @@ -0,0 +1,45 @@ +import moment, { unitOfTime } from 'moment'; +import { Message } from 'eris'; +import { Client, Command } from '../class'; + +export default class Mute extends Command { + constructor(client: Client) { + super(client); + this.name = 'mute'; + this.description = 'Mutes a member.'; + this.usage = 'mute [time] [reason]'; + this.permissions = 2; + this.guildOnly = true; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); + const member = this.client.util.resolveMember(args[0], this.mainGuild); + if (!member) return this.error(message.channel, 'Cannot find user.'); + + try { + const res1 = await this.client.db.local.get(`muted-${member.id}`); + if (res1 || this.mainGuild.members.get(member.id).roles.includes('478373942638149643')) return this.error(message.channel, 'This user is already muted.'); + } catch {} // eslint-disable-line no-empty + if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.'); + message.delete(); + + let momentMilliseconds: number; + let reason: string; + if (args.length > 1) { + const lockLength = args[1].match(/[a-z]+|[^a-z]+/gi); + const length = Number(lockLength[0]); + const unit = lockLength[1] as unitOfTime.Base; + momentMilliseconds = moment.duration(length, unit).asMilliseconds(); + reason = momentMilliseconds ? args.slice(2).join(' ') : args.slice(1).join(' '); + if (reason.length > 512) return this.error(message.channel, 'Mute reasons cannot be longer than 512 characters.'); + } + await this.client.util.moderation.mute(member.user, message.member, momentMilliseconds, reason); + return this.success(message.channel, `${member.user.username}#${member.user.discriminator} has been muted.`); + } catch (err) { + return this.client.util.handleError(err, message, this, false); + } + } +} diff --git a/src/commands/page.ts b/src/commands/page.ts index 1297a9b..00a7e5d 100644 --- a/src/commands/page.ts +++ b/src/commands/page.ts @@ -65,7 +65,7 @@ export default class Page extends Command { } public logPage(sender: { number: string, user?: string }, recipient: { number: string, user?: string }, type: 'discord' | 'email', code: string): void { - const chan = this.client.guilds.get(this.client.config.guildID).channels.get('722636436716781619'); + const chan = this.mainGuild.channels.get('722636436716781619'); chan.createMessage(`***[${type.toUpperCase()}] \`${sender.number} (${sender.user ? sender.user : ''})\` sent a page to \`${recipient.number} (${recipient.user ? recipient.user : ''})\` with code \`${code}\`.***`); this.client.util.signale.log(`PAGE (${type.toUpperCase()})| TO: ${recipient.number}, FROM: ${sender.number}, CODE: ${code}`); } @@ -119,8 +119,8 @@ export default class Page extends Command { } for (const id of recipientEntry.discordIDs) { - const recipient = this.client.guilds.get(this.client.config.guildID).members.get(recipientEntry.individualAssignID); - const sender = this.client.guilds.get(this.client.config.guildID).members.get(senderEntry.individualAssignID); + const recipient = this.mainGuild.members.get(recipientEntry.individualAssignID); + const sender = this.mainGuild.members.get(senderEntry.individualAssignID); const chan = await this.client.getDMChannel(id); if (!chan) continue; if (!recipient || !sender) { @@ -131,8 +131,8 @@ export default class Page extends Command { chan.createMessage(`${options?.emergencyNumber ? `[SEN#${options.emergencyNumber}] ` : ''}__**Page**__\n**Recipient PN:** ${recipientNumber}\n**Sender PN:** ${senderNumber} (${sender ? `${sender.username}#${sender.discriminator}` : ''})\n**Initial Command:** https://discordapp.com/channels/${message.guild.id}/${message.channel.id}/${message.id} (<#${message.channel.id}>)\n\n**Pager Code:** ${code} (${this.local.codeDict.get(code)})${txt ? `\n**Message:** ${txt}` : ''}`); } for (const email of recipientEntry.emailAddresses) { - const recipient = this.client.guilds.get(this.client.config.guildID).members.get(recipientEntry.individualAssignID); - const sender = this.client.guilds.get(this.client.config.guildID).members.get(senderEntry.individualAssignID); + const recipient = this.mainGuild.members.get(recipientEntry.individualAssignID); + const sender = this.mainGuild.members.get(senderEntry.individualAssignID); if (!recipient || !sender) { this.logPage({ number: senderNumber, user: 'N/A' }, { number: recipientNumber, user: 'N/A' }, 'email', code); } else { diff --git a/src/commands/rank.ts b/src/commands/rank.ts index 3a2c418..2fe7c1e 100644 --- a/src/commands/rank.ts +++ b/src/commands/rank.ts @@ -1,4 +1,5 @@ import { Message, Role } from 'eris'; +import { createPaginationEmbed } from 'eris-pagination'; import { Client, Command, RichEmbed } from '../class'; export default class Rank extends Command { @@ -16,9 +17,7 @@ export default class Rank extends Command { try { if (!args[0]) { const roles = await this.client.db.Rank.find(); - const embed = new RichEmbed(); - embed.setTitle('Ranks'); - embed.setDescription(`Use \`${this.client.config.prefix}rank \` to join/leave the rank.`); + const rankArray: [{ name: string, value: string }?] = []; for (const rank of roles.sort((a, b) => a.name.localeCompare(b.name))) { let perms: string; if (rank.permissions.includes('0')) { @@ -26,17 +25,26 @@ export default class Rank extends Command { } else { const rolesArray: Role[] = []; rank.permissions.forEach((r) => { - rolesArray.push(this.client.guilds.get(this.client.config.guildID).roles.get(r)); + rolesArray.push(this.mainGuild.roles.get(r)); }); perms = rolesArray.map((r) => message.guild.roles.get(r.id)).sort((a, b) => b.position - a.position).map((r) => `<@&${r.id}>`).join(', '); } let hasRank = false; if (message.member.roles.includes(rank.roleID)) hasRank = true; - embed.addField(rank.name, `${hasRank ? '*You have this role.*\n' : ''}__Description:__ ${rank.description}\n__Permissions:__ ${perms}`); + rankArray.push({ name: rank.name, value: `${hasRank ? '*You have this role.*\n' : ''}__Description:__ ${rank.description}\n__Permissions:__ ${perms}` }); } - embed.setFooter(`Requested by: ${message.author.username}#${message.author.discriminator} | ${this.client.user.username}`, message.author.avatarURL); - embed.setTimestamp(); - return message.channel.createMessage({ embed }); + const ranksSplit = this.client.util.splitFields(rankArray); + const cmdPages: RichEmbed[] = []; + ranksSplit.forEach((split) => { + const embed = new RichEmbed(); + embed.setTitle('Ranks'); + embed.setDescription(`Use \`${this.client.config.prefix}rank \` to join/leave the rank.`); + embed.setFooter(`Requested by: ${message.author.username}#${message.author.discriminator} | ${this.client.user.username}`, message.author.avatarURL); + embed.setTimestamp(); + split.forEach((c) => embed.addField(c.name, c.value)); + }); + if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] }); + return createPaginationEmbed(message, cmdPages); } const role = this.client.util.resolveRole(args.join(' '), this.client.guilds.get(this.client.config.guildID)); if (!role) return this.error(message.channel, 'The role you specified doesn\'t exist.'); diff --git a/src/commands/roleinfo.ts b/src/commands/roleinfo.ts index aff53e8..6054447 100644 --- a/src/commands/roleinfo.ts +++ b/src/commands/roleinfo.ts @@ -17,10 +17,7 @@ export default class Roleinfo extends Command { try { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); - let role: Role = message.guild.roles.find((r: Role) => r.id === args[0]); - if (!role) { // if it's a role name - role = message.guild.roles.find((r: Role) => r.name.toLowerCase().includes(args.join(' ').toLowerCase())); - } + const role = this.client.util.resolveRole(args[0], this.mainGuild); if (!role) return this.error(message.channel, 'Could not find role.'); const perms = role.permissions; diff --git a/src/commands/unmute.ts b/src/commands/unmute.ts new file mode 100644 index 0000000..d642481 --- /dev/null +++ b/src/commands/unmute.ts @@ -0,0 +1,34 @@ +import { Message } from 'eris'; +import { Client, Command } from '../class'; + +export default class Unmute extends Command { + constructor(client: Client) { + super(client); + this.name = 'unmute'; + this.description = 'Unmutes a member.'; + this.usage = 'unmute [reason]'; + this.permissions = 2; + this.guildOnly = true; + this.enabled = true; + } + + public async run(message: Message, args: string[]) { + try { + if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); + const member = this.client.util.resolveMember(args[0], this.mainGuild); + if (!member) return this.error(message.channel, 'Cannot find user.'); + + try { + const res1 = await this.client.db.local.get(`muted-${member.id}`); + if (!res1 || !this.mainGuild.members.get(member.id).roles.includes('478373942638149643')) return this.error(message.channel, 'This user is already unmuted.'); + } catch {} // eslint-disable-line no-empty + if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.'); + message.delete(); + + await this.client.util.moderation.unmute(member.user.id, message.member, args.slice(1).join(' ')); + return this.success(message.channel, `${member.user.username}#${member.user.discriminator} has been unmuted.`); + } catch (err) { + return this.client.util.handleError(err, message, this, false); + } + } +} diff --git a/src/commands/whois.ts b/src/commands/whois.ts index abe7891..ab83fa5 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -64,7 +64,7 @@ export default class Whois extends Command { break; } } - embed.addField('Status', member.status === 'dnd' ? 'Do Not Disturb' : this.capsFirstLetter(member.status) || 'Unknown', true); + embed.addField('Status', member.status === 'dnd' ? 'Do Not Disturb' : this.capsFirstLetter(member.status) || 'Offline', true); // const platform = member.bot && member.status !== 'offline' ? 'API/WebSocket' : Object.entries(message.member.clientStatus).filter((a) => a[1] !== 'offline').map((a) => this.capsFirstLetter(a[0])).join(', '); // if (platform) embed.addField('Platform', platform, true); embed.addField('Joined At', `${moment(new Date(member.joinedAt)).format('dddd, MMMM Do YYYY, h:mm:ss A')} ET`, true); diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts new file mode 100644 index 0000000..f403204 --- /dev/null +++ b/src/events/guildMemberAdd.ts @@ -0,0 +1,22 @@ +import { Member } from 'eris'; +import { Client, Event } from '../class'; + +export default class GuildMemberAdd extends Event { + public client: Client; + + constructor(client: Client) { + super(client); + this.event = 'guildMemberAdd'; + } + + public async run(member: Member) { + try { + const search = await this.client.db.local.get(`muted-${member.user.id}`); + if (search === true) { + member.addRole('478373942638149643'); + } + } catch (err) { + this.client.util.handleError(err); + } + } +} diff --git a/src/intervals/autoRelease.ts b/src/intervals/autoRelease.ts index 3ca777c..74f144f 100644 --- a/src/intervals/autoRelease.ts +++ b/src/intervals/autoRelease.ts @@ -11,8 +11,21 @@ export default function checkLock(client: Client): NodeJS.Timeout { if (moderation.expiration.processed) return; if (new Date() > moderation.expiration.date) { await moderation.updateOne({ 'expiration.processed': true }); - const moderator = client.guilds.get(client.config.guildID).members.get(moderation.moderatorID); - await client.util.moderation.unban(moderation.userID, moderator); + // const moderator = client.guilds.get(client.config.guildID).members.get(moderation.moderatorID); + const system = client.guilds.get(client.config.guildID).members.get(client.user.id); + switch (moderation.type) { + case 5: + await client.util.moderation.unban(moderation.userID, system); + break; + case 2: + console.log(await client.db.local.get(`muted-${moderation.userID}`)); + if (await client.db.local.get(`muted-${moderation.userID}`) === true) { + await client.util.moderation.unmute(moderation.userID, system); + } + break; + default: + break; + } client.util.signale.complete(`Released member ${moderation.userID} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`); } }); diff --git a/src/models/Moderation.ts b/src/models/Moderation.ts index 1e12c8e..e2adc56 100644 --- a/src/models/Moderation.ts +++ b/src/models/Moderation.ts @@ -15,7 +15,7 @@ export interface ModerationInterface extends Document { */ type: 0 | 1 | 2 | 3 | 4 | 5 date: Date, - expiration: { + expiration?: { date: Date, processed: boolean }