diff --git a/src/plugins/AutoReactionsPlugin.ts b/src/plugins/AutoReactionsPlugin.ts index fcf6e1ac..92eeac8c 100644 --- a/src/plugins/AutoReactionsPlugin.ts +++ b/src/plugins/AutoReactionsPlugin.ts @@ -1,4 +1,4 @@ -import { decorators as d } from "knub"; +import { decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildAutoReactions } from "../data/GuildAutoReactions"; @@ -6,7 +6,11 @@ import { Message } from "eris"; import { customEmojiRegex, errorMessage, isEmoji, successMessage } from "../utils"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; -export class AutoReactionsPlugin extends ZeppelinPlugin { +interface IAutoReactionsPluginPermissions { + use: boolean; +} + +export class AutoReactionsPlugin extends ZeppelinPlugin { public static pluginName = "auto_reactions"; protected savedMessages: GuildSavedMessages; @@ -14,8 +18,10 @@ export class AutoReactionsPlugin extends ZeppelinPlugin { private onMessageCreateFn; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { use: false, }, diff --git a/src/plugins/BotControl.ts b/src/plugins/BotControl.ts index 64693d14..6064d2fa 100644 --- a/src/plugins/BotControl.ts +++ b/src/plugins/BotControl.ts @@ -1,4 +1,4 @@ -import { decorators as d, GlobalPlugin } from "knub"; +import { decorators as d, GlobalPlugin, IPluginOptions } from "knub"; import child_process from "child_process"; import { GuildChannel, Message, TextChannel } from "eris"; import { createChunkedMessage, errorMessage, noop, sleep, sorter, successMessage } from "../utils"; @@ -6,17 +6,25 @@ import { ReactionRolesPlugin } from "./ReactionRoles"; let activeReload: [string, string] = null; +interface IBotControlPluginConfig { + owners: string[]; + update_cmd: string; +} + /** * A global plugin that allows bot owners to control the bot */ -export class BotControlPlugin extends GlobalPlugin { +export class BotControlPlugin extends GlobalPlugin { public static pluginName = "bot_control"; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { owners: [], + update_cmd: null, }, + + permissions: {}, }; } @@ -36,14 +44,14 @@ export class BotControlPlugin extends GlobalPlugin { } isOwner(userId) { - return this.configValue("owners").includes(userId); + return this.getConfig().owners.includes(userId); } @d.command("bot_full_update") async fullUpdateCmd(msg: Message) { if (!this.isOwner(msg.author.id)) return; - const updateCmd = this.configValue("update_cmd"); + const updateCmd = this.getConfig().update_cmd; if (!updateCmd) { msg.channel.createMessage(errorMessage("Update command not specified!")); return; diff --git a/src/plugins/Cases.ts b/src/plugins/Cases.ts index 8bdf0cbc..390bfb32 100644 --- a/src/plugins/Cases.ts +++ b/src/plugins/Cases.ts @@ -7,20 +7,28 @@ import { CaseTypeColors } from "../data/CaseTypeColors"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; import { GuildActions } from "../data/GuildActions"; import { GuildArchives } from "../data/GuildArchives"; +import { IPluginOptions } from "knub"; -export class CasesPlugin extends ZeppelinPlugin { +interface ICasesPluginConfig { + log_automatic_actions: boolean; + case_log_channel: string; +} + +export class CasesPlugin extends ZeppelinPlugin { public static pluginName = "cases"; protected actions: GuildActions; protected cases: GuildCases; protected archives: GuildArchives; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { log_automatic_actions: true, case_log_channel: null, }, + + permissions: {}, }; } @@ -103,11 +111,9 @@ export class CasesPlugin extends ZeppelinPlugin { await this.createCaseNote(createdCase, modId, reason, automatic, false); } - if ( - this.configValue("case_log_channel") && - (!automatic || this.configValue("log_automatic_actions")) && - postInCaseLogOverride !== false - ) { + const config = this.getConfig(); + + if (config.case_log_channel && (!automatic || config.log_automatic_actions) && postInCaseLogOverride !== false) { try { await this.postCaseToCaseLogChannel(createdCase); } catch (e) {} // tslint:disable-line @@ -154,7 +160,7 @@ export class CasesPlugin extends ZeppelinPlugin { this.archives.makePermanent(archiveId); } - if ((!automatic || this.configValue("log_automatic_actions")) && postInCaseLogOverride !== false) { + if ((!automatic || this.getConfig().log_automatic_actions) && postInCaseLogOverride !== false) { try { await this.postCaseToCaseLogChannel(theCase.id); } catch (e) {} // tslint:disable-line @@ -225,7 +231,7 @@ export class CasesPlugin extends ZeppelinPlugin { * Returns silently if the case log channel isn't specified or is invalid. */ public postToCaseLogChannel(content: MessageContent, file: MessageFile = null): Promise { - const caseLogChannelId = this.configValue("case_log_channel"); + const caseLogChannelId = this.getConfig().case_log_channel; if (!caseLogChannelId) return; const caseLogChannel = this.guild.channels.get(caseLogChannelId); diff --git a/src/plugins/Censor.ts b/src/plugins/Censor.ts index 028fc9a4..3762bed0 100644 --- a/src/plugins/Censor.ts +++ b/src/plugins/Censor.ts @@ -1,4 +1,4 @@ -import { decorators as d, Plugin } from "knub"; +import { decorators as d, IPluginOptions, Plugin } from "knub"; import { Invite, Message } from "eris"; import escapeStringRegexp from "escape-string-regexp"; import { GuildLogs } from "../data/GuildLogs"; @@ -13,8 +13,27 @@ import { import { ZalgoRegex } from "../data/Zalgo"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; -export class CensorPlugin extends Plugin { +interface ICensorPluginConfig { + filter_zalgo: boolean; + filter_invites: boolean; + invite_guild_whitelist: string[]; + invite_guild_blacklist: string[]; + invite_code_whitelist: string[]; + invite_code_blacklist: string[]; + allow_group_dm_invites: boolean; + + filter_domains: boolean; + domain_whitelist: string[]; + domain_blacklist: string[]; + + blocked_tokens: string[]; + blocked_words: string[]; + blocked_regex: string[]; +} + +export class CensorPlugin extends ZeppelinPlugin { public static pluginName = "censor"; protected serverLogs: GuildLogs; @@ -23,7 +42,7 @@ export class CensorPlugin extends Plugin { private onMessageCreateFn; private onMessageUpdateFn; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { filter_zalgo: false, @@ -43,6 +62,8 @@ export class CensorPlugin extends Plugin { blocked_regex: null, }, + permissions: {}, + overrides: [ { level: ">=50", @@ -97,12 +118,10 @@ export class CensorPlugin extends Plugin { async applyFiltersToMsg(savedMessage: SavedMessage) { if (!savedMessage.data.content) return; + const config = this.getConfigForMemberIdAndChannelId(savedMessage.user_id, savedMessage.channel_id); + // Filter zalgo - const filterZalgo = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "filter_zalgo", - ); + const filterZalgo = config.filter_zalgo; if (filterZalgo) { const result = ZalgoRegex.exec(savedMessage.data.content); if (result) { @@ -112,37 +131,13 @@ export class CensorPlugin extends Plugin { } // Filter invites - const filterInvites = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "filter_invites", - ); + const filterInvites = config.filter_invites; if (filterInvites) { - const inviteGuildWhitelist: string[] = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "invite_guild_whitelist", - ); - const inviteGuildBlacklist: string[] = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "invite_guild_blacklist", - ); - const inviteCodeWhitelist: string[] = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "invite_code_whitelist", - ); - const inviteCodeBlacklist: string[] = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "invite_code_blacklist", - ); - const allowGroupDMInvites: boolean = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "allow_group_dm_invites", - ); + const inviteGuildWhitelist = config.invite_guild_whitelist; + const inviteGuildBlacklist = config.invite_guild_blacklist; + const inviteCodeWhitelist = config.invite_code_whitelist; + const inviteCodeBlacklist = config.invite_code_blacklist; + const allowGroupDMInvites = config.allow_group_dm_invites; const inviteCodes = getInviteCodesInString(savedMessage.data.content); @@ -185,22 +180,10 @@ export class CensorPlugin extends Plugin { } // Filter domains - const filterDomains = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "filter_domains", - ); + const filterDomains = config.filter_domains; if (filterDomains) { - const domainWhitelist: string[] = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "domain_whitelist", - ); - const domainBlacklist: string[] = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "domain_blacklist", - ); + const domainWhitelist = config.domain_whitelist; + const domainBlacklist = config.domain_blacklist; const urls = getUrlsInString(savedMessage.data.content); for (const thisUrl of urls) { @@ -217,8 +200,7 @@ export class CensorPlugin extends Plugin { } // Filter tokens - const blockedTokens = - this.configValueForMemberIdAndChannelId(savedMessage.user_id, savedMessage.channel_id, "blocked_tokens") || []; + const blockedTokens = config.blocked_tokens || []; for (const token of blockedTokens) { if (savedMessage.data.content.toLowerCase().includes(token.toLowerCase())) { this.censorMessage(savedMessage, `blocked token (\`${token}\`) found`); @@ -227,8 +209,7 @@ export class CensorPlugin extends Plugin { } // Filter words - const blockedWords = - this.configValueForMemberIdAndChannelId(savedMessage.user_id, savedMessage.channel_id, "blocked_words") || []; + const blockedWords = config.blocked_words || []; for (const word of blockedWords) { const regex = new RegExp(`\\b${escapeStringRegexp(word)}\\b`, "i"); if (regex.test(savedMessage.data.content)) { @@ -238,8 +219,7 @@ export class CensorPlugin extends Plugin { } // Filter regex - const blockedRegex = - this.configValueForMemberIdAndChannelId(savedMessage.user_id, savedMessage.channel_id, "blocked_regex") || []; + const blockedRegex = config.blocked_regex || []; for (const regexStr of blockedRegex) { const regex = new RegExp(regexStr, "i"); if (regex.test(savedMessage.data.content)) { diff --git a/src/plugins/LogServer.ts b/src/plugins/LogServer.ts index 3fc352c5..987062d9 100644 --- a/src/plugins/LogServer.ts +++ b/src/plugins/LogServer.ts @@ -1,5 +1,5 @@ import http, { ServerResponse } from "http"; -import { GlobalPlugin } from "knub"; +import { GlobalPlugin, IPluginOptions } from "knub"; import { GuildArchives } from "../data/GuildArchives"; import { sleep } from "../utils"; import moment from "moment-timezone"; @@ -12,12 +12,26 @@ function notFound(res: ServerResponse) { res.end("Not Found"); } -export class LogServerPlugin extends GlobalPlugin { +interface ILogServerPluginConfig { + port: number; +} + +export class LogServerPlugin extends GlobalPlugin { public static pluginName = "log_server"; protected archives: GuildArchives; protected server: http.Server; + protected getDefaultOptions(): IPluginOptions { + return { + config: { + port: DEFAULT_PORT, + }, + + permissions: {}, + }; + } + async onLoad() { this.archives = new GuildArchives(null); @@ -55,6 +69,7 @@ export class LogServerPlugin extends GlobalPlugin { } }); + const port = this.getConfig().port; let retried = false; this.server.on("error", async (err: any) => { @@ -62,13 +77,13 @@ export class LogServerPlugin extends GlobalPlugin { console.log("Got EADDRINUSE, retrying in 2 sec..."); retried = true; await sleep(2000); - this.server.listen(this.configValue("port", DEFAULT_PORT)); + this.server.listen(port); } else { throw err; } }); - this.server.listen(this.configValue("port", DEFAULT_PORT)); + this.server.listen(port); } async onUnload() { diff --git a/src/plugins/Logs.ts b/src/plugins/Logs.ts index cd88b26f..5d6d261b 100644 --- a/src/plugins/Logs.ts +++ b/src/plugins/Logs.ts @@ -1,4 +1,4 @@ -import { decorators as d, Plugin } from "knub"; +import { decorators as d, IPluginOptions, Plugin } from "knub"; import { GuildLogs } from "../data/GuildLogs"; import { LogType } from "../data/LogType"; import { Channel, Constants as ErisConstants, Member, Message, TextChannel, User } from "eris"; @@ -22,6 +22,7 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildArchives } from "../data/GuildArchives"; import { GuildCases } from "../data/GuildCases"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; interface ILogChannel { include?: string[]; @@ -40,7 +41,24 @@ const unknownUser = { discriminator: "0000", }; -export class LogsPlugin extends Plugin { +interface IChannelConfig { + include?: string[]; + exclude?: string[]; + batched?: boolean; + batch_time?: number; +} + +interface ILogsPluginConfig { + channels: { + [key: string]: IChannelConfig; + }; + format: { + [key: string]: string; + timestamp: string; + }; +} + +export class LogsPlugin extends ZeppelinPlugin { public static pluginName = "logs"; protected guildLogs: GuildLogs; @@ -56,7 +74,7 @@ export class LogsPlugin extends Plugin { private onMessageDeleteBulkFn; private onMessageUpdateFn; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { channels: {}, @@ -65,6 +83,8 @@ export class LogsPlugin extends Plugin { ...DefaultLogMessages, }, }, + + permissions: {}, }; } @@ -98,7 +118,7 @@ export class LogsPlugin extends Plugin { } async log(type, data) { - const logChannels: ILogChannelMap = this.configValue("channels"); + const logChannels: ILogChannelMap = this.getConfig().channels; const typeStr = LogType[type]; for (const [channelId, opts] of Object.entries(logChannels)) { @@ -130,12 +150,13 @@ export class LogsPlugin extends Plugin { } getLogMessage(type, data): string { - const format = this.configValue(`format.${LogType[type]}`, ""); + const config = this.getConfig(); + const format = config.format[LogType[type]] || ""; if (format === "") return; const formatted = formatTemplateString(format, data); - const timestampFormat = this.configValue("format.timestamp"); + const timestampFormat = config.format.timestamp; if (timestampFormat) { const timestamp = moment().format(timestampFormat); return `\`[${timestamp}]\` ${formatted}`; @@ -387,7 +408,7 @@ export class LogsPlugin extends Plugin { member: stripObjectToScalars(member, ["user"]), channel: stripObjectToScalars(channel), messageText: disableCodeBlocks(deactivateMentions(savedMessage.data.content || "")), - messageDate: moment(savedMessage.data.timestamp, "x").format(this.configValue("format.timestamp")), + messageDate: moment(savedMessage.data.timestamp, "x").format(this.getConfig().format.timestamp), attachments: disableLinkPreviews(useMediaUrls(attachments)), }, savedMessage.id, diff --git a/src/plugins/MessageSaver.ts b/src/plugins/MessageSaver.ts index a489a52c..ca8a26c2 100644 --- a/src/plugins/MessageSaver.ts +++ b/src/plugins/MessageSaver.ts @@ -1,15 +1,21 @@ -import { Plugin, decorators as d } from "knub"; +import { Plugin, decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { GuildChannel, Message, TextChannel } from "eris"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { successMessage } from "../utils"; -export class MessageSaverPlugin extends Plugin { +interface IMessageSaverPluginPermissions { + manage: boolean; +} + +export class MessageSaverPlugin extends Plugin { public static pluginName = "message_saver"; protected savedMessages: GuildSavedMessages; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { manage: false, }, diff --git a/src/plugins/ModActions.ts b/src/plugins/ModActions.ts index f82c23e8..625c2412 100644 --- a/src/plugins/ModActions.ts +++ b/src/plugins/ModActions.ts @@ -1,4 +1,4 @@ -import { decorators as d, waitForReaction, waitForReply } from "knub"; +import { decorators as d, IPluginOptions, waitForReaction, waitForReply } from "knub"; import { Attachment, Constants as ErisConstants, Guild, Member, Message, TextChannel, User } from "eris"; import humanizeDuration from "humanize-duration"; import { GuildCases } from "../data/GuildCases"; @@ -48,7 +48,39 @@ const MessageResultText = { [MessageResult.ChannelMessaged]: "user messaged with a ping", }; -export class ModActionsPlugin extends ZeppelinPlugin { +interface IModActionsPluginConfig { + dm_on_warn: boolean; + dm_on_mute: boolean; + dm_on_kick: boolean; + dm_on_ban: boolean; + message_on_warn: boolean; + message_on_mute: boolean; + message_on_kick: boolean; + message_on_ban: boolean; + message_channel: string; + warn_message: string; + mute_message: string; + timed_mute_message: string; + kick_message: string; + ban_message: string; + alert_on_rejoin: boolean; + alert_channel: string; +} + +interface IModActionsPluginPermissions { + note: boolean; + warn: boolean; + mute: boolean; + kick: boolean; + ban: boolean; + view: boolean; + addcase: boolean; + massban: boolean; + hidecase: boolean; + act_as_other: boolean; +} + +export class ModActionsPlugin extends ZeppelinPlugin { public static pluginName = "mod_actions"; protected actions: GuildActions; @@ -67,7 +99,7 @@ export class ModActionsPlugin extends ZeppelinPlugin { this.ignoredEvents = []; } - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { dm_on_warn: true, @@ -225,9 +257,11 @@ export class ModActionsPlugin extends ZeppelinPlugin { */ @d.event("guildMemberAdd") async onGuildMemberAdd(_, member: Member) { - if (!this.configValue("alert_on_rejoin")) return; + const config = this.getConfig(); - const alertChannelId = this.configValue("alert_channel"); + if (!config.alert_on_rejoin) return; + + const alertChannelId = config.alert_channel; if (!alertChannelId) return; const actions = await this.cases.getByUserId(member.id); @@ -353,17 +387,16 @@ export class ModActionsPlugin extends ZeppelinPlugin { mod = args.mod; } + const config = this.getConfig(); const reason = this.formatReasonWithAttachments(args.reason, msg.attachments); - const warnMessage = this.configValue("warn_message") - .replace("{guildName}", this.guild.name) - .replace("{reason}", reason); + const warnMessage = config.warn_message.replace("{guildName}", this.guild.name).replace("{reason}", reason); const userMessageResult = await this.tryToMessageUser( args.member.user, warnMessage, - this.configValue("dm_on_warn"), - this.configValue("message_on_warn"), + config.dm_on_warn, + config.message_on_warn, ); if (userMessageResult === MessageResult.Failed) { @@ -474,10 +507,12 @@ export class ModActionsPlugin extends ZeppelinPlugin { await this.mutes.setCaseId(args.member.id, theCase.id); } + const config = this.getConfig(); + // Message the user informing them of the mute // Don't message them if we're updating an old mute if (reason && !hasOldCase) { - const template = muteTime ? this.configValue("timed_mute_message") : this.configValue("mute_message"); + const template = muteTime ? config.timed_mute_message : config.mute_message; const muteMessage = formatTemplateString(template, { guildName: this.guild.name, @@ -488,8 +523,8 @@ export class ModActionsPlugin extends ZeppelinPlugin { userMessageResult = await this.tryToMessageUser( args.member.user, muteMessage, - this.configValue("dm_on_mute"), - this.configValue("message_on_mute"), + config.dm_on_mute, + config.message_on_mute, ); } @@ -636,12 +671,13 @@ export class ModActionsPlugin extends ZeppelinPlugin { mod = args.mod; } + const config = this.getConfig(); const reason = this.formatReasonWithAttachments(args.reason, msg.attachments); // Attempt to message the user *before* kicking them, as doing it after may not be possible let userMessageResult: MessageResult = MessageResult.Ignored; if (args.reason) { - const kickMessage = formatTemplateString(this.configValue("kick_message"), { + const kickMessage = formatTemplateString(config.kick_message, { guildName: this.guild.name, reason, }); @@ -649,8 +685,8 @@ export class ModActionsPlugin extends ZeppelinPlugin { userMessageResult = await this.tryToMessageUser( args.member.user, kickMessage, - this.configValue("dm_on_kick"), - this.configValue("message_on_kick"), + config.dm_on_kick, + config.message_on_kick, ); } @@ -705,12 +741,13 @@ export class ModActionsPlugin extends ZeppelinPlugin { mod = args.mod; } + const config = this.getConfig(); const reason = this.formatReasonWithAttachments(args.reason, msg.attachments); // Attempt to message the user *before* banning them, as doing it after may not be possible let userMessageResult: MessageResult = MessageResult.Ignored; if (reason) { - const banMessage = formatTemplateString(this.configValue("ban_message"), { + const banMessage = formatTemplateString(config.ban_message, { guildName: this.guild.name, reason, }); @@ -718,8 +755,8 @@ export class ModActionsPlugin extends ZeppelinPlugin { userMessageResult = await this.tryToMessageUser( args.member.user, banMessage, - this.configValue("dm_on_ban"), - this.configValue("message_on_ban"), + config.dm_on_ban, + config.message_on_ban, ); } @@ -1215,9 +1252,11 @@ export class ModActionsPlugin extends ZeppelinPlugin { } catch (e) {} // tslint:disable-line } - if (useChannel && this.configValue("message_channel")) { + const messageChannel = this.getConfig().message_channel; + + if (useChannel && messageChannel) { try { - const channel = this.guild.channels.get(this.configValue("message_channel")) as TextChannel; + const channel = this.guild.channels.get(messageChannel) as TextChannel; await channel.createMessage(`<@!${user.id}> ${str}`); return MessageResult.ChannelMessaged; } catch (e) {} // tslint:disable-line diff --git a/src/plugins/Mutes.ts b/src/plugins/Mutes.ts index 3f64de7a..06ac5e5d 100644 --- a/src/plugins/Mutes.ts +++ b/src/plugins/Mutes.ts @@ -1,4 +1,4 @@ -import { Member, Message, TextableChannel, User } from "eris"; +import { Member, Message, User } from "eris"; import { GuildCases } from "../data/GuildCases"; import moment from "moment-timezone"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; @@ -8,9 +8,18 @@ import { DBDateFormat, chunkMessageLines, stripObjectToScalars, successMessage, import humanizeDuration from "humanize-duration"; import { LogType } from "../data/LogType"; import { GuildLogs } from "../data/GuildLogs"; -import { decorators as d } from "knub"; +import { decorators as d, IPluginOptions } from "knub"; -export class MutesPlugin extends ZeppelinPlugin { +interface IMutesPluginConfig { + mute_role: string; +} + +interface IMutesPluginPermissions { + view_list: boolean; + cleanup: boolean; +} + +export class MutesPlugin extends ZeppelinPlugin { public static pluginName = "mutes"; protected actions: GuildActions; @@ -19,7 +28,7 @@ export class MutesPlugin extends ZeppelinPlugin { protected serverLogs: GuildLogs; private muteClearIntervalId: NodeJS.Timer; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { mute_role: null, @@ -71,7 +80,7 @@ export class MutesPlugin extends ZeppelinPlugin { } public async muteMember(member: Member, muteTime: number = null) { - const muteRole = this.configValue("mute_role"); + const muteRole = this.getConfig().mute_role; if (!muteRole) return; await member.addRole(muteRole); @@ -82,9 +91,9 @@ export class MutesPlugin extends ZeppelinPlugin { if (unmuteTime) { await this.mutes.addOrUpdateMute(member.id, unmuteTime); } else { - const muteRole = this.configValue("mute_role"); + const muteRole = this.getConfig().mute_role; if (member.roles.includes(muteRole)) { - await member.removeRole(this.configValue("mute_role")); + await member.removeRole(muteRole); } await this.mutes.clear(member.id); @@ -139,7 +148,7 @@ export class MutesPlugin extends ZeppelinPlugin { // Manually added mute roles const muteUserIds = activeMutes.reduce((set, m) => set.add(m.user_id), new Set()); const manuallyMutedMembers = []; - const muteRole = this.configValue("mute_role"); + const muteRole = this.getConfig().mute_role; if (muteRole) { this.guild.members.forEach(member => { @@ -206,7 +215,7 @@ export class MutesPlugin extends ZeppelinPlugin { */ @d.event("guildMemberUpdate") async onGuildMemberUpdate(_, member: Member) { - const muteRole = this.configValue("mute_role"); + const muteRole = this.getConfig().mute_role; if (!muteRole) return; const mute = await this.mutes.findExistingMuteForUserId(member.id); @@ -224,7 +233,7 @@ export class MutesPlugin extends ZeppelinPlugin { @d.permission("cleanup") async clearMutesWithoutRoleCmd(msg: Message) { const activeMutes = await this.mutes.getActiveMutes(); - const muteRole = this.configValue("mute_role"); + const muteRole = this.getConfig().mute_role; if (!muteRole) return; await msg.channel.createMessage("Clearing mutes from members that don't have the mute role..."); @@ -264,7 +273,7 @@ export class MutesPlugin extends ZeppelinPlugin { try { this.serverLogs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, member.id); - await member.removeRole(this.configValue("mute_role")); + await member.removeRole(this.getConfig().mute_role); } catch (e) {} // tslint:disable-line await this.mutes.clear(member.id); diff --git a/src/plugins/NameHistory.ts b/src/plugins/NameHistory.ts index 4da744db..1ec45a84 100644 --- a/src/plugins/NameHistory.ts +++ b/src/plugins/NameHistory.ts @@ -1,16 +1,23 @@ -import { Plugin, decorators as d } from "knub"; +import { decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { GuildNameHistory } from "../data/GuildNameHistory"; -import { Member, Message, Relationship, User } from "eris"; +import { Member, Message, User } from "eris"; import { NameHistoryEntryTypes } from "../data/NameHistoryEntryTypes"; import { createChunkedMessage, errorMessage, trimLines } from "../utils"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; -export class NameHistoryPlugin extends Plugin { +interface INameHistoryPluginPermissions { + view: boolean; +} + +export class NameHistoryPlugin extends ZeppelinPlugin { public static pluginName = "name_history"; protected nameHistory: GuildNameHistory; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { view: false, }, diff --git a/src/plugins/Persist.ts b/src/plugins/Persist.ts index 40c97a58..797e9239 100644 --- a/src/plugins/Persist.ts +++ b/src/plugins/Persist.ts @@ -1,24 +1,33 @@ -import { Plugin, decorators as d } from "knub"; +import { decorators as d, IPluginOptions } from "knub"; import { GuildPersistedData, IPartialPersistData } from "../data/GuildPersistedData"; import intersection from "lodash.intersection"; import { Member, MemberOptions } from "eris"; import { GuildLogs } from "../data/GuildLogs"; import { LogType } from "../data/LogType"; import { stripObjectToScalars } from "../utils"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; -export class PersistPlugin extends Plugin { +interface IPersistPluginConfig { + persisted_roles: string[]; + persist_nicknames: boolean; + persist_voice_mutes: boolean; +} + +export class PersistPlugin extends ZeppelinPlugin { public static pluginName = "persist"; protected persistedData: GuildPersistedData; protected logs: GuildLogs; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { persisted_roles: [], persist_nicknames: false, persist_voice_mutes: false, }, + + permissions: {}, }; } @@ -31,8 +40,9 @@ export class PersistPlugin extends Plugin { onGuildMemberRemove(_, member: Member) { let persist = false; const persistData: IPartialPersistData = {}; + const config = this.getConfig(); - const persistedRoles = this.configValue("persisted_roles"); + const persistedRoles = config.persisted_roles; if (persistedRoles.length && member.roles) { const rolesToPersist = intersection(persistedRoles, member.roles); if (rolesToPersist.length) { @@ -41,12 +51,12 @@ export class PersistPlugin extends Plugin { } } - if (this.configValue("persist_nicknames") && member.nick) { + if (config.persist_nicknames && member.nick) { persist = true; persistData.nickname = member.nick; } - if (this.configValue("persist_voice_mutes") && member.voiceState && member.voiceState.mute) { + if (config.persist_voice_mutes && member.voiceState && member.voiceState.mute) { persist = true; persistData.is_voice_muted = true; } @@ -63,8 +73,9 @@ export class PersistPlugin extends Plugin { let restore = false; const toRestore: MemberOptions = {}; + const config = this.getConfig(); - const persistedRoles = this.configValue("persisted_roles"); + const persistedRoles = config.persisted_roles; if (persistedRoles.length) { const rolesToRestore = intersection(persistedRoles, persistedData.roles); if (rolesToRestore.length) { @@ -73,12 +84,12 @@ export class PersistPlugin extends Plugin { } } - if (this.configValue("persist_nicknames") && persistedData.nickname) { + if (config.persist_nicknames && persistedData.nickname) { restore = true; toRestore.nick = persistedData.nickname; } - if (this.configValue("persist_voice_mutes") && persistedData.is_voice_muted) { + if (config.persist_voice_mutes && persistedData.is_voice_muted) { restore = true; toRestore.mute = true; } diff --git a/src/plugins/PingableRolesPlugin.ts b/src/plugins/PingableRolesPlugin.ts index ba823469..a60f02b3 100644 --- a/src/plugins/PingableRolesPlugin.ts +++ b/src/plugins/PingableRolesPlugin.ts @@ -1,20 +1,27 @@ -import { Plugin, decorators as d } from "knub"; +import { decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { Message, Role, TextableChannel, User } from "eris"; import { GuildPingableRoles } from "../data/GuildPingableRoles"; import { PingableRole } from "../data/entities/PingableRole"; import { errorMessage, successMessage } from "../utils"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; const TIMEOUT = 10 * 1000; -export class PingableRolesPlugin extends Plugin { +interface IPingableRolesPluginPermissions { + use: boolean; +} + +export class PingableRolesPlugin extends ZeppelinPlugin { public static pluginName = "pingable_roles"; protected pingableRoles: GuildPingableRoles; protected cache: Map; protected timeouts: Map; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { use: false, }, diff --git a/src/plugins/Post.ts b/src/plugins/Post.ts index 4dfe1c42..06c90a61 100644 --- a/src/plugins/Post.ts +++ b/src/plugins/Post.ts @@ -1,14 +1,20 @@ -import { Plugin, decorators as d } from "knub"; +import { Plugin, decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { Channel, EmbedBase, Message, Role, TextChannel } from "eris"; -import { errorMessage, downloadFile, roleMentionRegex, getRoleMentions } from "../utils"; +import { errorMessage, downloadFile, getRoleMentions } from "../utils"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; import fs from "fs"; const fsp = fs.promises; const COLOR_MATCH_REGEX = /^#?([0-9a-f]{6})$/; -export class PostPlugin extends Plugin { +interface IPostPluginPermissions { + post: boolean; + edit: boolean; +} + +export class PostPlugin extends ZeppelinPlugin { public static pluginName = "post"; protected savedMessages: GuildSavedMessages; @@ -17,8 +23,10 @@ export class PostPlugin extends Plugin { this.savedMessages = GuildSavedMessages.getInstance(this.guildId); } - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { post: false, edit: false, diff --git a/src/plugins/ReactionRoles.ts b/src/plugins/ReactionRoles.ts index 64ab4209..554b5d22 100644 --- a/src/plugins/ReactionRoles.ts +++ b/src/plugins/ReactionRoles.ts @@ -1,4 +1,4 @@ -import { decorators as d, logger } from "knub"; +import { decorators as d, IPluginOptions, logger } from "knub"; import { CustomEmoji, errorMessage, isSnowflake, noop, sleep, successMessage } from "../utils"; import { GuildReactionRoles } from "../data/GuildReactionRoles"; import { Message, TextChannel } from "eris"; @@ -25,7 +25,16 @@ type PendingMemberRoleChanges = { }>; }; -export class ReactionRolesPlugin extends ZeppelinPlugin { +interface IReactionRolesPluginConfig { + auto_refresh_interval: number; +} + +interface IReactionRolesPluginPermissions { + manage: boolean; + fallback_command: boolean; +} + +export class ReactionRolesPlugin extends ZeppelinPlugin { public static pluginName = "reaction_roles"; protected reactionRoles: GuildReactionRoles; @@ -37,7 +46,7 @@ export class ReactionRolesPlugin extends ZeppelinPlugin { private autoRefreshTimeout; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { auto_refresh_interval: null, @@ -66,7 +75,7 @@ export class ReactionRolesPlugin extends ZeppelinPlugin { this.pendingRoleChanges = new Map(); this.pendingRefreshes = new Set(); - let autoRefreshInterval = this.configValue("auto_refresh_interval"); + let autoRefreshInterval = this.getConfig().auto_refresh_interval; if (autoRefreshInterval != null) { autoRefreshInterval = Math.max(MIN_AUTO_REFRESH, autoRefreshInterval); this.autoRefreshLoop(autoRefreshInterval); diff --git a/src/plugins/Reminders.ts b/src/plugins/Reminders.ts index 005cbc83..acd3f160 100644 --- a/src/plugins/Reminders.ts +++ b/src/plugins/Reminders.ts @@ -1,4 +1,4 @@ -import { decorators as d } from "knub"; +import { decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; import { GuildReminders } from "../data/GuildReminders"; import { Message, TextChannel } from "eris"; @@ -9,7 +9,11 @@ import { convertDelayStringToMS, createChunkedMessage, errorMessage, sorter, suc const REMINDER_LOOP_TIME = 10 * 1000; const MAX_TRIES = 3; -export class RemindersPlugin extends ZeppelinPlugin { +interface IRemindersPluginPermissions { + use: boolean; +} + +export class RemindersPlugin extends ZeppelinPlugin { public static pluginName = "reminders"; protected reminders: GuildReminders; @@ -17,8 +21,10 @@ export class RemindersPlugin extends ZeppelinPlugin { private postRemindersTimeout; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { use: false, }, diff --git a/src/plugins/SelfGrantableRolesPlugin.ts b/src/plugins/SelfGrantableRolesPlugin.ts index 5dfc3436..84ee12a3 100644 --- a/src/plugins/SelfGrantableRolesPlugin.ts +++ b/src/plugins/SelfGrantableRolesPlugin.ts @@ -1,15 +1,24 @@ -import { Plugin, decorators as d } from "knub"; +import { Plugin, decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { GuildSelfGrantableRoles } from "../data/GuildSelfGrantableRoles"; import { GuildChannel, Message, Role, TextChannel } from "eris"; import { chunkArray, errorMessage, sorter, successMessage } from "../utils"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; -export class SelfGrantableRolesPlugin extends Plugin { +interface ISelfGrantableRolesPluginPermissions { + manage: boolean; + use: boolean; + ignore_cooldown: boolean; +} + +export class SelfGrantableRolesPlugin extends ZeppelinPlugin { public static pluginName = "self_grantable_roles"; protected selfGrantableRoles: GuildSelfGrantableRoles; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { manage: false, use: false, diff --git a/src/plugins/Slowmode.ts b/src/plugins/Slowmode.ts index 2a6eb05f..749b3674 100644 --- a/src/plugins/Slowmode.ts +++ b/src/plugins/Slowmode.ts @@ -1,17 +1,25 @@ -import { Plugin, decorators as d } from "knub"; +import { Plugin, decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { GuildChannel, Message, TextChannel, Constants as ErisConstants, User } from "eris"; import { convertDelayStringToMS, errorMessage, noop, successMessage } from "../utils"; import { GuildSlowmodes } from "../data/GuildSlowmodes"; import humanizeDuration from "humanize-duration"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; -export class SlowmodePlugin extends Plugin { +interface ISlowmodePluginPermissions { + manage: boolean; + affected: boolean; +} + +export class SlowmodePlugin extends ZeppelinPlugin { public static pluginName = "slowmode"; protected slowmodes: GuildSlowmodes; protected clearInterval; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { manage: false, affected: true, diff --git a/src/plugins/Spam.ts b/src/plugins/Spam.ts index af2feffc..9751a78b 100644 --- a/src/plugins/Spam.ts +++ b/src/plugins/Spam.ts @@ -1,4 +1,4 @@ -import { decorators as d, Plugin } from "knub"; +import { decorators as d, IPluginOptions, Plugin } from "knub"; import { Channel, Member, User } from "eris"; import { getEmojiInString, @@ -18,6 +18,7 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { GuildActions } from "../data/GuildActions"; import { Case } from "../data/entities/Case"; import { GuildMutes } from "../data/GuildMutes"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; enum RecentActionType { Message = 1, @@ -44,7 +45,28 @@ const MAX_INTERVAL = 300; const SPAM_ARCHIVE_EXPIRY_DAYS = 90; -export class SpamPlugin extends Plugin { +interface IBaseSingleSpamConfig { + interval: number; + count: number; + mute?: boolean; + mute_time?: number; + clean?: boolean; +} + +interface ISpamPluginConfig { + max_censor: IBaseSingleSpamConfig; + max_messages: IBaseSingleSpamConfig; + max_mentions: IBaseSingleSpamConfig; + max_links: IBaseSingleSpamConfig; + max_attachments: IBaseSingleSpamConfig; + max_emojis: IBaseSingleSpamConfig; + max_newlines: IBaseSingleSpamConfig; + max_duplicates: IBaseSingleSpamConfig; + max_characters: IBaseSingleSpamConfig; + max_voice_moves: IBaseSingleSpamConfig; +} + +export class SpamPlugin extends ZeppelinPlugin { public static pluginName = "spam"; protected actions: GuildActions; @@ -68,9 +90,10 @@ export class SpamPlugin extends Plugin { private expiryInterval; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { + max_censor: null, max_messages: null, max_mentions: null, max_links: null, @@ -82,6 +105,8 @@ export class SpamPlugin extends Plugin { max_voice_moves: null, }, + permissions: {}, + // Default override to make mods immune to the spam filter overrides: [ { @@ -178,7 +203,7 @@ export class SpamPlugin extends Plugin { async logAndDetectMessageSpam( savedMessage: SavedMessage, type: RecentActionType, - spamConfig: any, + spamConfig: IBaseSingleSpamConfig, actionCount: number, description: string, ) { @@ -360,11 +385,9 @@ export class SpamPlugin extends Plugin { // For interoperability with the Censor plugin async logCensor(savedMessage: SavedMessage) { - const spamConfig = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_censor", - ); + const config = this.getConfigForMemberIdAndChannelId(savedMessage.user_id, savedMessage.channel_id); + const spamConfig = config.max_censor; + if (spamConfig) { this.logAndDetectMessageSpam(savedMessage, RecentActionType.Censor, spamConfig, 1, "too many censored messages"); } @@ -373,20 +396,14 @@ export class SpamPlugin extends Plugin { async onMessageCreate(savedMessage: SavedMessage) { if (savedMessage.is_bot) return; - const maxMessages = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_messages", - ); + const config = this.getConfigForMemberIdAndChannelId(savedMessage.user_id, savedMessage.channel_id); + + const maxMessages = config.max_messages; if (maxMessages) { this.logAndDetectMessageSpam(savedMessage, RecentActionType.Message, maxMessages, 1, "too many messages"); } - const maxMentions = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_mentions", - ); + const maxMentions = config.max_mentions; const mentions = savedMessage.data.content ? [...getUserMentions(savedMessage.data.content), ...getRoleMentions(savedMessage.data.content)] : []; @@ -400,21 +417,13 @@ export class SpamPlugin extends Plugin { ); } - const maxLinks = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_links", - ); - if (maxLinks && savedMessage.data.content) { + const maxLinks = config.max_links; + if (maxLinks && savedMessage.data.content && typeof savedMessage.data.content === "string") { const links = getUrlsInString(savedMessage.data.content); this.logAndDetectMessageSpam(savedMessage, RecentActionType.Link, maxLinks, links.length, "too many links"); } - const maxAttachments = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_attachments", - ); + const maxAttachments = config.max_attachments; if (maxAttachments && savedMessage.data.attachments) { this.logAndDetectMessageSpam( savedMessage, @@ -425,21 +434,13 @@ export class SpamPlugin extends Plugin { ); } - const maxEmoji = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_emojis", - ); + const maxEmoji = config.max_emojis; if (maxEmoji && savedMessage.data.content) { const emojiCount = getEmojiInString(savedMessage.data.content).length; this.logAndDetectMessageSpam(savedMessage, RecentActionType.Emoji, maxEmoji, emojiCount, "too many emoji"); } - const maxNewlines = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_newlines", - ); + const maxNewlines = config.max_newlines; if (maxNewlines && savedMessage.data.content) { const newlineCount = (savedMessage.data.content.match(/\n/g) || []).length; this.logAndDetectMessageSpam( @@ -451,11 +452,7 @@ export class SpamPlugin extends Plugin { ); } - const maxCharacters = this.configValueForMemberIdAndChannelId( - savedMessage.user_id, - savedMessage.channel_id, - "max_characters", - ); + const maxCharacters = config.max_characters; if (maxCharacters && savedMessage.data.content) { const characterCount = [...savedMessage.data.content.trim()].length; this.logAndDetectMessageSpam( @@ -473,11 +470,12 @@ export class SpamPlugin extends Plugin { @d.event("voiceChannelJoin") @d.event("voiceChannelSwitch") onVoiceChannelSwitch(member: Member, channel: Channel) { - const spamConfig = this.configValueForMemberIdAndChannelId(member.id, channel.id, "max_voice_moves"); - if (spamConfig) { + const config = this.getConfigForMemberIdAndChannelId(member.id, channel.id); + const maxVoiceMoves = config.max_voice_moves; + if (maxVoiceMoves) { this.logAndDetectOtherSpam( RecentActionType.VoiceChannelMove, - spamConfig, + maxVoiceMoves, member.id, 1, "0", diff --git a/src/plugins/Starboard.ts b/src/plugins/Starboard.ts index 973a2f38..561c2780 100644 --- a/src/plugins/Starboard.ts +++ b/src/plugins/Starboard.ts @@ -1,4 +1,4 @@ -import { decorators as d, waitForReply, utils as knubUtils } from "knub"; +import { decorators as d, waitForReply, utils as knubUtils, IBasePluginConfig, IPluginOptions } from "knub"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; import { GuildStarboards } from "../data/GuildStarboards"; import { GuildChannel, Message, TextChannel } from "eris"; @@ -17,7 +17,11 @@ import moment from "moment-timezone"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; -export class StarboardPlugin extends ZeppelinPlugin { +interface IStarboardPluginPermissions { + manage: boolean; +} + +export class StarboardPlugin extends ZeppelinPlugin { public static pluginName = "starboard"; protected starboards: GuildStarboards; @@ -25,8 +29,10 @@ export class StarboardPlugin extends ZeppelinPlugin { private onMessageDeleteFn; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { manage: false, }, diff --git a/src/plugins/Tags.ts b/src/plugins/Tags.ts index cbffb1e0..951a09e3 100644 --- a/src/plugins/Tags.ts +++ b/src/plugins/Tags.ts @@ -1,4 +1,4 @@ -import { Plugin, decorators as d } from "knub"; +import { Plugin, decorators as d, IPluginOptions } from "knub"; import { Message, TextChannel } from "eris"; import { errorMessage, successMessage } from "../utils"; import { GuildTags } from "../data/GuildTags"; @@ -6,6 +6,7 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { SavedMessage } from "../data/entities/SavedMessage"; import moment from "moment-timezone"; import humanizeDuration from "humanize-duration"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; const TAG_FUNCTIONS = { countdown(toDate) { @@ -14,10 +15,21 @@ const TAG_FUNCTIONS = { const diff = target.diff(now); const result = humanizeDuration(diff, { largest: 2, round: true }); return diff >= 0 ? result : `${result} ago`; - } + }, }; -export class TagsPlugin extends Plugin { +interface ITagsPluginConfig { + prefix: string; + delete_with_command: boolean; +} + +interface ITagsPluginPermissions { + create: boolean; + use: boolean; + list: boolean; +} + +export class TagsPlugin extends ZeppelinPlugin { public static pluginName = "tags"; protected tags: GuildTags; @@ -26,17 +38,17 @@ export class TagsPlugin extends Plugin { private onMessageCreateFn; private onMessageDeleteFn; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { config: { prefix: "!!", - delete_with_command: true + delete_with_command: true, }, permissions: { create: false, use: true, - list: false + list: false, }, overrides: [ @@ -44,10 +56,10 @@ export class TagsPlugin extends Plugin { level: ">=50", permissions: { create: true, - list: true - } - } - ] + list: true, + }, + }, + ], }; } @@ -78,7 +90,7 @@ export class TagsPlugin extends Plugin { return; } - const prefix = this.configValueForMsg(msg, "prefix"); + const prefix = this.getConfigForMsg(msg).prefix; const tagNames = tags.map(t => t.tag).sort(); msg.channel.createMessage(` Available tags (use with ${prefix}tag): \`\`\`${tagNames.join(", ")}\`\`\` @@ -103,7 +115,7 @@ export class TagsPlugin extends Plugin { async tagCmd(msg: Message, args: { tag: string; body: string }) { await this.tags.createOrUpdate(args.tag, args.body, msg.author.id); - const prefix = this.configValue("prefix"); + const prefix = this.getConfig().prefix; msg.channel.createMessage(successMessage(`Tag set! Use it with: \`${prefix}${args.tag}\``)); } @@ -114,7 +126,7 @@ export class TagsPlugin extends Plugin { if (!msg.data.content) return; if (msg.is_bot) return; - const prefix = this.configValueForMemberIdAndChannelId(msg.user_id, msg.channel_id, "prefix"); + const prefix = this.getConfigForMemberIdAndChannelId(msg.user_id, msg.channel_id).prefix; if (!msg.data.content.startsWith(prefix)) return; const tagNameMatch = msg.data.content.slice(prefix.length).match(/^\S+/); @@ -148,7 +160,7 @@ export class TagsPlugin extends Plugin { const responseMsg = await channel.createMessage(body); // Save the command-response message pair once the message is in our database - if (this.configValueForMemberIdAndChannelId(msg.user_id, msg.channel_id, "delete_with_command")) { + if (this.getConfigForMemberIdAndChannelId(msg.user_id, msg.channel_id).delete_with_command) { this.savedMessages.onceMessageAvailable(responseMsg.id, async () => { await this.tags.addResponse(msg.id, responseMsg.id); }); diff --git a/src/plugins/Utility.ts b/src/plugins/Utility.ts index 057bc975..89c94677 100644 --- a/src/plugins/Utility.ts +++ b/src/plugins/Utility.ts @@ -1,4 +1,4 @@ -import { decorators as d } from "knub"; +import { decorators as d, IBasePluginConfig, IPluginOptions } from "knub"; import { CategoryChannel, Channel, EmbedOptions, Member, Message, Role, TextChannel, User, VoiceChannel } from "eris"; import { channelMentionRegex, @@ -33,7 +33,21 @@ const CLEAN_COMMAND_DELETE_DELAY = 5000; const activeReloads: Map = new Map(); -export class UtilityPlugin extends ZeppelinPlugin { +interface IUtilityPluginPermissions { + roles: boolean; + level: boolean; + search: boolean; + clean: boolean; + info: boolean; + server: boolean; + reload_guild: boolean; + nickname: boolean; + ping: boolean; + source: boolean; + vcmove: boolean; +} + +export class UtilityPlugin extends ZeppelinPlugin { public static pluginName = "utility"; protected logs: GuildLogs; @@ -41,8 +55,10 @@ export class UtilityPlugin extends ZeppelinPlugin { protected savedMessages: GuildSavedMessages; protected archives: GuildArchives; - getDefaultOptions() { + getDefaultOptions(): IPluginOptions { return { + config: {}, + permissions: { roles: false, level: false, diff --git a/src/plugins/ZeppelinPlugin.ts b/src/plugins/ZeppelinPlugin.ts index cd6a5649..f5ba8ce5 100644 --- a/src/plugins/ZeppelinPlugin.ts +++ b/src/plugins/ZeppelinPlugin.ts @@ -1,9 +1,12 @@ -import { IPluginOptions, Plugin } from "knub"; +import { IBasePluginConfig, IBasePluginPermissions, IPluginOptions, Plugin } from "knub"; import { PluginRuntimeError } from "../PluginRuntimeError"; import Ajv, { ErrorObject } from "ajv"; import { isSnowflake, isUnicodeEmoji } from "../utils"; -export class ZeppelinPlugin extends Plugin { +export class ZeppelinPlugin< + TConfig extends {} = IBasePluginConfig, + TPermissions extends {} = IBasePluginPermissions +> extends Plugin { protected configSchema: any; protected permissionsSchema: any;