/* eslint-disable no-bitwise */ import { Member, User } from 'eris'; import { randomBytes } from 'crypto'; import moment, { unitOfTime } from 'moment'; import { Client, RichEmbed } from '.'; import { Moderation as ModerationModel, ModerationInterface } from '../models'; import { moderation as channels } from '../configs/channels.json'; export default class Moderation { public client: Client; public logChannels: { modlogs: string }; constructor(client: Client) { this.client = client; this.logChannels = { modlogs: channels.modlogs, }; } public checkPermissions(member: Member, moderator: Member): boolean { if (member.id === moderator.id) return false; if (member.roles.some((r) => ['662163685439045632', '455972169449734144', '453689940140883988'].includes(r))) return false; const bit = member.permission.allow; if ((bit | 8) === bit) return false; if ((bit | 20) === bit) return false; return true; } /** * Converts some sort of time based duration to milliseconds based on length. * @param time The time, examples: 2h, 1m, 1w */ public convertTimeDurationToMilliseconds(time: string): number { const lockLength = time.match(/[a-z]+|[^a-z]+/gi); const length = Number(lockLength[0]); const unit = lockLength[1] as unitOfTime.Base; return moment.duration(length, unit).asMilliseconds(); } public async ban(user: User, moderator: Member, duration: number, reason?: string): Promise { if (reason && reason.length > 512) throw new Error('Ban reason cannot be longer than 512 characters'); await this.client.guilds.get(this.client.config.guildID).banMember(user.id, 7, reason); const logID = randomBytes(2).toString('hex'); const mod = new ModerationModel({ userID: user.id, logID, moderatorID: moderator.id, reason: reason || null, type: 5, 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; const embed = new RichEmbed(); embed.setTitle(`Case ${logID} | Ban`); embed.setColor('#e74c3c'); 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 unban(userID: string, moderator: Member, reason?: string): Promise { this.client.unbanGuildMember(this.client.config.guildID, userID, reason); const user = await this.client.getRESTUser(userID); if (!user) throw new Error('Cannot get user.'); const logID = randomBytes(2).toString('hex'); const mod = new ModerationModel({ userID, logID, moderatorID: moderator.id, reason: reason || null, type: 4, date: new Date(), }); const embed = new RichEmbed(); embed.setTitle(`Case ${logID} | Unban`); embed.setColor('#1abc9c'); 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); } embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); this.client.createMessage(this.logChannels.modlogs, { embed }); 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); const user = await this.client.getRESTUser(this.client.config.guildID); if (member) { 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(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); } 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); const logID = randomBytes(2).toString('hex'); const mod = new ModerationModel({ userID: user.id, logID, moderatorID: moderator.id, reason: reason || null, type: 5, date: new Date(), }); const embed = new RichEmbed(); embed.setTitle(`Case ${logID} | Kick`); embed.setColor('#e74c3c'); 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); } embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); this.client.createMessage(this.logChannels.modlogs, { embed }); return mod.save(); } }