Add censor plugin. Various other fixes/features. Update Knub to 9.4.13.
This commit is contained in:
parent
0c806f32fd
commit
e7734c558c
9 changed files with 283 additions and 43 deletions
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -2176,9 +2176,9 @@
|
|||
}
|
||||
},
|
||||
"knub": {
|
||||
"version": "9.4.11",
|
||||
"resolved": "https://registry.npmjs.org/knub/-/knub-9.4.11.tgz",
|
||||
"integrity": "sha512-C/Ps3jegzgVfaKfcyumUhPdFd269t4yuAUWnXf71S3d/6MCLhVMfGehG0Ma2AMb5M85DqN8ge9n3OME3k1zwJw==",
|
||||
"version": "9.4.13",
|
||||
"resolved": "https://registry.npmjs.org/knub/-/knub-9.4.13.tgz",
|
||||
"integrity": "sha512-4m5IMbctg1xAe6DoYSkk1jdQNWpUb6ZkjKxJPxHEmbXtIZm11qt/AmIcASgG5pvZOM7Q/PnsbLfRyzlUTbvOLA==",
|
||||
"requires": {
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"js-yaml": "^3.9.1",
|
||||
|
@ -3670,6 +3670,11 @@
|
|||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
|
||||
"dev": true
|
||||
},
|
||||
"tlds": {
|
||||
"version": "1.203.1",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.203.1.tgz",
|
||||
"integrity": "sha512-7MUlYyGJ6rSitEZ3r1Q1QNV8uSIzapS8SmmhSusBuIc7uIxPPwsKllEP0GRp1NS6Ik6F+fRZvnjDWm3ecv2hDw=="
|
||||
},
|
||||
"to-object-path": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
|
||||
|
|
|
@ -29,14 +29,16 @@
|
|||
"@types/node": "^8.0.50",
|
||||
"dotenv": "^4.0.0",
|
||||
"eris": "^0.8.6",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"humanize-duration": "^3.15.0",
|
||||
"knex": "^0.14.6",
|
||||
"knub": "^9.4.11",
|
||||
"knub": "^9.4.13",
|
||||
"lodash.at": "^4.6.0",
|
||||
"lodash.difference": "^4.5.0",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"mariasql": "^0.2.6",
|
||||
"moment-timezone": "^0.5.21",
|
||||
"tlds": "^1.203.1",
|
||||
"ts-node": "^3.3.0",
|
||||
"typescript": "^2.9.2"
|
||||
},
|
||||
|
|
|
@ -24,17 +24,18 @@
|
|||
"ROLE_EDIT": "🖊 Role **{role.name}** was edited",
|
||||
|
||||
"MESSAGE_EDIT": "✏ **{member.user.username}#{member.user.discriminator}** (`{member.id}`) message edited in **{channel.name}**:\n`B:` {before}\n`A:` {after}",
|
||||
"MESSAGE_DELETE": "🗑 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) message deleted in **{channel.name}**:\n{messageText}{attachments}",
|
||||
"MESSAGE_DELETE": "🗑 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) message deleted in **{channel.name}**:\n```{messageText}```",
|
||||
"MESSAGE_DELETE_BULK": "🗑 **{count}** messages deleted in **{channel.name}**",
|
||||
"MESSAGE_DELETE_BARE": "🗑 message (id `{messageId}`) deleted in **{channel.name}** (no more info available due to restart)",
|
||||
|
||||
"VOICE_CHANNEL_JOIN": "🔸 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) joined **{channel.name}**",
|
||||
"VOICE_CHANNEL_MOVE": "🔹 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) moved **{oldChannel.name}** ➞ **{newChannel.name}**",
|
||||
"VOICE_CHANNEL_LEAVE": "♦ **{member.user.username}#{member.user.discriminator}** (`{member.id}`) left **{channel.name}**",
|
||||
|
||||
"COMMAND": "🤖 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) used command in **{channel.name}**:\n`{command}`",
|
||||
"COMMAND": "🤖 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) used command in **#{channel.name}**:\n`{command}`",
|
||||
|
||||
"SPAM_DELETE": "🛑 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) triggered spam filter: **{filterName}**",
|
||||
"CENSOR": "🛑 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) censored message in **{channel.name}**:\n`{messageText}`",
|
||||
"CENSOR": "🛑 **{member.user.username}#{member.user.discriminator}** (`{member.id}`) censored message in **#{channel.name}** (`{channel.id}`) {reason}:\n```{messageText}```",
|
||||
|
||||
"CASE_CREATE": "✏ **{member.user.username}#{member.user.discriminator}** (`{member.id}`) manually created new **{caseType}** case (#{caseNum})"
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ export class GuildLogs extends EventEmitter {
|
|||
|
||||
super();
|
||||
this.guildId = guildId;
|
||||
this.ignoredLogs = [];
|
||||
|
||||
// Store the instance for this guild so it can be returned later if a new instance for this guild is requested
|
||||
guildInstances.set(guildId, this);
|
||||
|
|
|
@ -24,6 +24,7 @@ export enum LogType {
|
|||
MESSAGE_EDIT,
|
||||
MESSAGE_DELETE,
|
||||
MESSAGE_DELETE_BULK,
|
||||
MESSAGE_DELETE_BARE,
|
||||
|
||||
VOICE_CHANNEL_JOIN,
|
||||
VOICE_CHANNEL_LEAVE,
|
||||
|
|
|
@ -19,6 +19,7 @@ import { UtilityPlugin } from "./plugins/Utility";
|
|||
import { LogsPlugin } from "./plugins/Logs";
|
||||
import { PostPlugin } from "./plugins/Post";
|
||||
import { ReactionRolesPlugin } from "./plugins/ReactionRoles";
|
||||
import { CensorPlugin } from "./plugins/Censor";
|
||||
import knex from "./knex";
|
||||
|
||||
// Run latest database migrations
|
||||
|
@ -32,7 +33,8 @@ knex.migrate.latest().then(() => {
|
|||
mod_actions: ModActionsPlugin,
|
||||
logs: LogsPlugin,
|
||||
post: PostPlugin,
|
||||
reaction_roles: ReactionRolesPlugin
|
||||
reaction_roles: ReactionRolesPlugin,
|
||||
censor: CensorPlugin
|
||||
},
|
||||
globalPlugins: {
|
||||
bot_control: BotControlPlugin
|
||||
|
|
212
src/plugins/Censor.ts
Normal file
212
src/plugins/Censor.ts
Normal file
|
@ -0,0 +1,212 @@
|
|||
import { Plugin, decorators as d } from "knub";
|
||||
import { Invite, Message } from "eris";
|
||||
import url from "url";
|
||||
import tlds from "tlds";
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
import { GuildLogs } from "../data/GuildLogs";
|
||||
import { LogType } from "../data/LogType";
|
||||
import { stripObjectToScalars } from "../utils";
|
||||
|
||||
const urlRegex = /(\S+\.\S+)/g;
|
||||
const protocolRegex = /^[a-z]+:\/\//;
|
||||
|
||||
const getInviteCodesInString = (str: string): string[] => {
|
||||
const inviteCodeRegex = /(?:discord.gg|discordapp.com\/invite)\/([a-z0-9]+)/gi;
|
||||
const inviteCodes = [];
|
||||
let match;
|
||||
|
||||
// tslint:disable-next-line
|
||||
while ((match = inviteCodeRegex.exec(str)) !== null) {
|
||||
inviteCodes.push(match[1]);
|
||||
}
|
||||
|
||||
return inviteCodes;
|
||||
};
|
||||
|
||||
const getUrlsInString = (str: string): url.URL[] => {
|
||||
const matches = str.match(urlRegex) || [];
|
||||
return matches.reduce((urls, match) => {
|
||||
if (!protocolRegex.test(match)) {
|
||||
match = `https://${match}`;
|
||||
}
|
||||
|
||||
let matchUrl: url.URL;
|
||||
try {
|
||||
matchUrl = new url.URL(match);
|
||||
} catch (e) {
|
||||
return urls;
|
||||
}
|
||||
|
||||
const hostnameParts = matchUrl.hostname.split(".");
|
||||
const tld = hostnameParts[hostnameParts.length - 1];
|
||||
if (tlds.includes(tld)) {
|
||||
urls.push(matchUrl);
|
||||
}
|
||||
|
||||
return urls;
|
||||
}, []);
|
||||
};
|
||||
|
||||
export class CensorPlugin extends Plugin {
|
||||
protected serverLogs: GuildLogs;
|
||||
|
||||
getDefaultOptions() {
|
||||
return {
|
||||
config: {
|
||||
filter_invites: false,
|
||||
invite_guild_whitelist: null,
|
||||
invite_guild_blacklist: null,
|
||||
invite_code_whitelist: null,
|
||||
invite_code_blacklist: null,
|
||||
|
||||
filter_domains: false,
|
||||
domain_whitelist: null,
|
||||
domain_blacklist: null,
|
||||
|
||||
blocked_tokens: null,
|
||||
blocked_words: null,
|
||||
blocked_regex: null
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
level: ">=50",
|
||||
config: {
|
||||
filter_invites: false,
|
||||
filter_domains: false,
|
||||
blocked_tokens: null,
|
||||
blocked_words: null,
|
||||
blocked_regex: null
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
onLoad() {
|
||||
this.serverLogs = new GuildLogs(this.guildId);
|
||||
}
|
||||
|
||||
async censorMessage(msg: Message, reason: string) {
|
||||
this.serverLogs.ignoreLog(LogType.MESSAGE_DELETE, msg.id);
|
||||
|
||||
try {
|
||||
await msg.delete("Censored");
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.serverLogs.log(LogType.CENSOR, {
|
||||
member: stripObjectToScalars(msg.member, ["user"]),
|
||||
channel: stripObjectToScalars(msg.channel),
|
||||
reason,
|
||||
messageText: msg.cleanContent
|
||||
});
|
||||
}
|
||||
|
||||
async applyFiltersToMsg(msg: Message) {
|
||||
if (msg.author.bot) return;
|
||||
if (msg.type !== 0) return;
|
||||
if (!msg.content) return;
|
||||
|
||||
// Filter invites
|
||||
if (this.configValueForMsg(msg, "filter_invites")) {
|
||||
const inviteGuildWhitelist: string[] = this.configValueForMsg(msg, "invite_guild_whitelist");
|
||||
const inviteGuildBlacklist: string[] = this.configValueForMsg(msg, "invite_guild_blacklist");
|
||||
const inviteCodeWhitelist: string[] = this.configValueForMsg(msg, "invite_code_whitelist");
|
||||
const inviteCodeBlacklist: string[] = this.configValueForMsg(msg, "invite_code_blacklist");
|
||||
|
||||
const inviteCodes = getInviteCodesInString(msg.content);
|
||||
|
||||
const invites: Invite[] = await Promise.all(
|
||||
inviteCodes.map(code => this.bot.getInvite(code))
|
||||
);
|
||||
|
||||
for (const invite of invites) {
|
||||
if (inviteGuildWhitelist && !inviteGuildWhitelist.includes(invite.guild.id)) {
|
||||
this.censorMessage(
|
||||
msg,
|
||||
`invite guild (**${invite.guild.name}** \`${invite.guild.id}\`) not found in whitelist`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inviteGuildBlacklist && inviteGuildBlacklist.includes(invite.guild.id)) {
|
||||
this.censorMessage(
|
||||
msg,
|
||||
`invite guild (**${invite.guild.name}** \`${invite.guild.id}\`) found in blacklist`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inviteCodeWhitelist && !inviteCodeWhitelist.includes(invite.code)) {
|
||||
this.censorMessage(msg, `invite code (\`${invite.code}\`) not found in whitelist`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inviteCodeBlacklist && inviteCodeBlacklist.includes(invite.code)) {
|
||||
this.censorMessage(msg, `invite code (\`${invite.code}\`) found in blacklist`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter domains
|
||||
if (this.configValueForMsg(msg, "filter_domains")) {
|
||||
const domainWhitelist: string[] = this.configValueForMsg(msg, "domain_whitelist");
|
||||
const domainBlacklist: string[] = this.configValueForMsg(msg, "domain_blacklist");
|
||||
|
||||
const urls = getUrlsInString(msg.content);
|
||||
for (const thisUrl of urls) {
|
||||
if (domainWhitelist && !domainWhitelist.includes(thisUrl.hostname)) {
|
||||
this.censorMessage(msg, `domain (\`${thisUrl.hostname}\`) not found in whitelist`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (domainBlacklist && domainBlacklist.includes(thisUrl.hostname)) {
|
||||
this.censorMessage(msg, `domain (\`${thisUrl.hostname}\`) found in blacklist`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter tokens
|
||||
const blockedTokens = this.configValueForMsg(msg, "blocked_tokens") || [];
|
||||
for (const token of blockedTokens) {
|
||||
if (msg.content.includes(token)) {
|
||||
this.censorMessage(msg, `blocked token (\`${token}\`) found`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter words
|
||||
const blockedWords = this.configValueForMsg(msg, "blocked_words") || [];
|
||||
for (const word of blockedWords) {
|
||||
const regex = new RegExp(`\\b${escapeStringRegexp(word)}\\b`, "i");
|
||||
if (regex.test(msg.content)) {
|
||||
this.censorMessage(msg, `blocked word (\`${word}\`) found`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter regex
|
||||
const blockedRegex = this.configValueForMsg(msg, "blocked_regex") || [];
|
||||
for (const regexStr of blockedRegex) {
|
||||
const regex = new RegExp(regexStr);
|
||||
if (regex.test(msg.content)) {
|
||||
this.censorMessage(msg, `blocked regex (\`${regexStr}\`) found`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@d.event("messageCreate")
|
||||
async onMessageCreate(msg: Message) {
|
||||
this.applyFiltersToMsg(msg);
|
||||
}
|
||||
|
||||
@d.event("messageUpdate")
|
||||
async onMessageUpdate(msg: Message) {
|
||||
this.applyFiltersToMsg(msg);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,7 @@
|
|||
import { decorators as d, Plugin } from "knub";
|
||||
import { GuildLogs } from "../data/GuildLogs";
|
||||
import { LogType } from "../data/LogType";
|
||||
import {
|
||||
Channel,
|
||||
Constants as ErisConstants,
|
||||
Member,
|
||||
Message,
|
||||
PrivateChannel,
|
||||
TextChannel,
|
||||
User
|
||||
} from "eris";
|
||||
import { Channel, Constants as ErisConstants, Member, Message, TextChannel, User } from "eris";
|
||||
import { findRelevantAuditLogEntry, formatTemplateString, stripObjectToScalars } from "../utils";
|
||||
import DefaultLogMessages from "../data/DefaultLogMessages.json";
|
||||
import moment from "moment-timezone";
|
||||
|
@ -98,7 +90,7 @@ export class LogsPlugin extends Plugin {
|
|||
round: true
|
||||
});
|
||||
|
||||
this.log(LogType.MEMBER_JOIN, {
|
||||
this.serverLogs.log(LogType.MEMBER_JOIN, {
|
||||
member: stripObjectToScalars(member, ["user"]),
|
||||
new: member.createdAt >= newThreshold ? " :new:" : "",
|
||||
account_age: accountAge
|
||||
|
@ -107,7 +99,7 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
@d.event("guildMemberRemove")
|
||||
onMemberLeave(_, member) {
|
||||
this.log(LogType.MEMBER_LEAVE, {
|
||||
this.serverLogs.log(LogType.MEMBER_LEAVE, {
|
||||
member: stripObjectToScalars(member, ["user"])
|
||||
});
|
||||
}
|
||||
|
@ -121,7 +113,7 @@ export class LogsPlugin extends Plugin {
|
|||
);
|
||||
const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser;
|
||||
|
||||
this.log(LogType.MEMBER_BAN, {
|
||||
this.serverLogs.log(LogType.MEMBER_BAN, {
|
||||
user: stripObjectToScalars(user),
|
||||
mod: stripObjectToScalars(mod)
|
||||
});
|
||||
|
@ -136,7 +128,7 @@ export class LogsPlugin extends Plugin {
|
|||
);
|
||||
const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser;
|
||||
|
||||
this.log(LogType.MEMBER_UNBAN, {
|
||||
this.serverLogs.log(LogType.MEMBER_UNBAN, {
|
||||
user: stripObjectToScalars(user),
|
||||
mod: stripObjectToScalars(mod)
|
||||
});
|
||||
|
@ -147,7 +139,7 @@ export class LogsPlugin extends Plugin {
|
|||
if (!oldMember) return;
|
||||
|
||||
if (member.nick !== oldMember.nick) {
|
||||
this.log(LogType.MEMBER_NICK_CHANGE, {
|
||||
this.serverLogs.log(LogType.MEMBER_NICK_CHANGE, {
|
||||
member,
|
||||
oldNick: oldMember.nick,
|
||||
newNick: member.nick
|
||||
|
@ -166,13 +158,13 @@ export class LogsPlugin extends Plugin {
|
|||
const mod = relevantAuditLogEntry ? relevantAuditLogEntry.user : unknownUser;
|
||||
|
||||
if (addedRoles.length) {
|
||||
this.log(LogType.MEMBER_ROLE_ADD, {
|
||||
this.serverLogs.log(LogType.MEMBER_ROLE_ADD, {
|
||||
member,
|
||||
role: this.guild.roles.get(addedRoles[0]),
|
||||
mod: stripObjectToScalars(mod)
|
||||
});
|
||||
} else if (removedRoles.length) {
|
||||
this.log(LogType.MEMBER_ROLE_REMOVE, {
|
||||
this.serverLogs.log(LogType.MEMBER_ROLE_REMOVE, {
|
||||
member,
|
||||
role: this.guild.roles.get(removedRoles[0]),
|
||||
mod: stripObjectToScalars(mod)
|
||||
|
@ -187,7 +179,7 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
if (user.username !== oldUser.username || user.discriminator !== oldUser.discriminator) {
|
||||
const member = this.guild.members.get(user.id) || { id: user.id, user };
|
||||
this.log(LogType.MEMBER_USERNAME_CHANGE, {
|
||||
this.serverLogs.log(LogType.MEMBER_USERNAME_CHANGE, {
|
||||
member: stripObjectToScalars(member, ["user"]),
|
||||
oldName: `${oldUser.username}#${oldUser.discriminator}`,
|
||||
newName: `${user.username}#${user.discriminator}`
|
||||
|
@ -197,28 +189,28 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
@d.event("channelCreate")
|
||||
onChannelCreate(channel) {
|
||||
this.log(LogType.CHANNEL_CREATE, {
|
||||
this.serverLogs.log(LogType.CHANNEL_CREATE, {
|
||||
channel: stripObjectToScalars(channel)
|
||||
});
|
||||
}
|
||||
|
||||
@d.event("channelDelete")
|
||||
onChannelDelete(channel) {
|
||||
this.log(LogType.CHANNEL_DELETE, {
|
||||
this.serverLogs.log(LogType.CHANNEL_DELETE, {
|
||||
channel: stripObjectToScalars(channel)
|
||||
});
|
||||
}
|
||||
|
||||
@d.event("guildRoleCreate")
|
||||
onRoleCreate(_, role) {
|
||||
this.log(LogType.ROLE_CREATE, {
|
||||
this.serverLogs.log(LogType.ROLE_CREATE, {
|
||||
role: stripObjectToScalars(role)
|
||||
});
|
||||
}
|
||||
|
||||
@d.event("guildRoleDelete")
|
||||
onRoleDelete(_, role) {
|
||||
this.log(LogType.ROLE_DELETE, {
|
||||
this.serverLogs.log(LogType.ROLE_DELETE, {
|
||||
role: stripObjectToScalars(role)
|
||||
});
|
||||
}
|
||||
|
@ -226,8 +218,9 @@ export class LogsPlugin extends Plugin {
|
|||
@d.event("messageUpdate")
|
||||
onMessageUpdate(msg: Message, oldMsg: Message) {
|
||||
if (oldMsg && msg.content === oldMsg.content) return;
|
||||
if (msg.type !== 0) return;
|
||||
|
||||
this.log(LogType.MESSAGE_EDIT, {
|
||||
this.serverLogs.log(LogType.MESSAGE_EDIT, {
|
||||
member: stripObjectToScalars(msg.member, ["user"]),
|
||||
channel: stripObjectToScalars(msg.channel),
|
||||
before: oldMsg ? oldMsg.content || "" : "Unavailable due to restart",
|
||||
|
@ -237,16 +230,33 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
@d.event("messageDelete")
|
||||
onMessageDelete(msg: Message) {
|
||||
this.log(LogType.MESSAGE_DELETE, {
|
||||
member: stripObjectToScalars(msg.member, ["user"]),
|
||||
channel: stripObjectToScalars(msg.channel),
|
||||
messageText: msg.cleanContent || ""
|
||||
});
|
||||
if (msg.type !== 0) return;
|
||||
|
||||
if (msg.member) {
|
||||
this.serverLogs.log(
|
||||
LogType.MESSAGE_DELETE,
|
||||
{
|
||||
member: stripObjectToScalars(msg.member, ["user"]),
|
||||
channel: stripObjectToScalars(msg.channel),
|
||||
messageText: msg.cleanContent || ""
|
||||
},
|
||||
msg.id
|
||||
);
|
||||
} else {
|
||||
this.serverLogs.log(
|
||||
LogType.MESSAGE_DELETE_BARE,
|
||||
{
|
||||
messageId: msg.id,
|
||||
channel: stripObjectToScalars(msg.channel)
|
||||
},
|
||||
msg.id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@d.event("messageDeleteBulk")
|
||||
onMessageDeleteBulk(messages: Message[]) {
|
||||
this.log(LogType.MESSAGE_DELETE_BULK, {
|
||||
this.serverLogs.log(LogType.MESSAGE_DELETE_BULK, {
|
||||
count: messages.length,
|
||||
channel: messages[0] ? messages[0].channel : null
|
||||
});
|
||||
|
@ -254,7 +264,7 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
@d.event("voiceChannelJoin")
|
||||
onVoiceChannelJoin(member: Member, channel: Channel) {
|
||||
this.log(LogType.VOICE_CHANNEL_JOIN, {
|
||||
this.serverLogs.log(LogType.VOICE_CHANNEL_JOIN, {
|
||||
member: stripObjectToScalars(member, ["user"]),
|
||||
channel: stripObjectToScalars(channel)
|
||||
});
|
||||
|
@ -262,7 +272,7 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
@d.event("voiceChannelLeave")
|
||||
onVoiceChannelLeave(member: Member, channel: Channel) {
|
||||
this.log(LogType.VOICE_CHANNEL_LEAVE, {
|
||||
this.serverLogs.log(LogType.VOICE_CHANNEL_LEAVE, {
|
||||
member: stripObjectToScalars(member, ["user"]),
|
||||
channel: stripObjectToScalars(channel)
|
||||
});
|
||||
|
@ -270,7 +280,7 @@ export class LogsPlugin extends Plugin {
|
|||
|
||||
@d.event("voiceChannelSwitch")
|
||||
onVoiceChannelSwitch(member: Member, newChannel: Channel, oldChannel: Channel) {
|
||||
this.log(LogType.VOICE_CHANNEL_MOVE, {
|
||||
this.serverLogs.log(LogType.VOICE_CHANNEL_MOVE, {
|
||||
member: stripObjectToScalars(member, ["user"]),
|
||||
oldChannel: stripObjectToScalars(oldChannel),
|
||||
newChannel: stripObjectToScalars(newChannel)
|
||||
|
|
|
@ -220,6 +220,12 @@ export class ModActionsPlugin extends Plugin {
|
|||
@d.command("warn", "<member:Member> <reason:string$>")
|
||||
@d.permission("warn")
|
||||
async warnCmd(msg: Message, args: any) {
|
||||
// Make sure we're allowed to warn this member
|
||||
if (!this.canActOn(msg.member, args.member)) {
|
||||
msg.channel.createMessage(errorMessage("Cannot warn: insufficient permissions"));
|
||||
return;
|
||||
}
|
||||
|
||||
const warnMessage = this.configValue("warn_message")
|
||||
.replace("{guildName}", this.guild.name)
|
||||
.replace("{reason}", args.reason);
|
||||
|
@ -235,7 +241,7 @@ export class ModActionsPlugin extends Plugin {
|
|||
const failedMsg = await msg.channel.createMessage(
|
||||
"Failed to message the user. Log the warning anyway?"
|
||||
);
|
||||
const reply = await waitForReaction(this.bot, failedMsg, ["✅", "❌"]);
|
||||
const reply = await waitForReaction(this.bot, failedMsg, ["✅", "❌"], msg.author.id);
|
||||
failedMsg.delete();
|
||||
if (!reply || reply.name === "❌") {
|
||||
return;
|
||||
|
@ -508,11 +514,11 @@ export class ModActionsPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
@d.command("addcase", "<type:string> <target:userId> [reason:string$]")
|
||||
@d.command("addcase", "<type:string> <target:string> [reason:string$]")
|
||||
@d.permission("addcase")
|
||||
async addcaseCmd(msg: Message, args: any) {
|
||||
// Verify the user id is a valid snowflake-ish
|
||||
if (!args.type.match(/^[0-9]{17,20}$/)) {
|
||||
if (!args.target.match(/^[0-9]{17,20}$/)) {
|
||||
msg.channel.createMessage(errorMessage("Cannot add case: invalid user id"));
|
||||
return;
|
||||
}
|
||||
|
@ -535,7 +541,7 @@ export class ModActionsPlugin extends Plugin {
|
|||
|
||||
// Create the case
|
||||
const caseId = await this.createCase(
|
||||
args.userId,
|
||||
args.target,
|
||||
msg.author.id,
|
||||
CaseType[type],
|
||||
null,
|
||||
|
|
Loading…
Add table
Reference in a new issue