3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

Add types for all plugin configs and permissions. Update code to work with Knub 18.

This commit is contained in:
Dragory 2019-03-04 21:44:04 +02:00
parent c96e98fcef
commit b7b42705f9
22 changed files with 415 additions and 225 deletions

View file

@ -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<IBasePluginConfig, IAutoReactionsPluginPermissions> {
public static pluginName = "auto_reactions";
protected savedMessages: GuildSavedMessages;
@ -14,8 +18,10 @@ export class AutoReactionsPlugin extends ZeppelinPlugin {
private onMessageCreateFn;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, IAutoReactionsPluginPermissions> {
return {
config: {},
permissions: {
use: false,
},

View file

@ -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<IBotControlPluginConfig> {
public static pluginName = "bot_control";
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBotControlPluginConfig> {
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;

View file

@ -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<ICasesPluginConfig> {
public static pluginName = "cases";
protected actions: GuildActions;
protected cases: GuildCases;
protected archives: GuildArchives;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<ICasesPluginConfig> {
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<Message> {
const caseLogChannelId = this.configValue("case_log_channel");
const caseLogChannelId = this.getConfig().case_log_channel;
if (!caseLogChannelId) return;
const caseLogChannel = this.guild.channels.get(caseLogChannelId);

View file

@ -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<ICensorPluginConfig> {
public static pluginName = "censor";
protected serverLogs: GuildLogs;
@ -23,7 +42,7 @@ export class CensorPlugin extends Plugin {
private onMessageCreateFn;
private onMessageUpdateFn;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<ICensorPluginConfig> {
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)) {

View file

@ -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<ILogServerPluginConfig> {
public static pluginName = "log_server";
protected archives: GuildArchives;
protected server: http.Server;
protected getDefaultOptions(): IPluginOptions<ILogServerPluginConfig> {
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() {

View file

@ -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<ILogsPluginConfig> {
public static pluginName = "logs";
protected guildLogs: GuildLogs;
@ -56,7 +74,7 @@ export class LogsPlugin extends Plugin {
private onMessageDeleteBulkFn;
private onMessageUpdateFn;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<ILogsPluginConfig> {
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 || "<no text 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,

View file

@ -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<IBasePluginConfig, IMessageSaverPluginPermissions> {
public static pluginName = "message_saver";
protected savedMessages: GuildSavedMessages;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, IMessageSaverPluginPermissions> {
return {
config: {},
permissions: {
manage: false,
},

View file

@ -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<IModActionsPluginConfig, IModActionsPluginPermissions> {
public static pluginName = "mod_actions";
protected actions: GuildActions;
@ -67,7 +99,7 @@ export class ModActionsPlugin extends ZeppelinPlugin {
this.ignoredEvents = [];
}
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IModActionsPluginConfig, IModActionsPluginPermissions> {
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

View file

@ -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<IMutesPluginConfig, IMutesPluginPermissions> {
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<IMutesPluginConfig, IMutesPluginPermissions> {
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);

View file

@ -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<IBasePluginConfig, INameHistoryPluginPermissions> {
public static pluginName = "name_history";
protected nameHistory: GuildNameHistory;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, INameHistoryPluginPermissions> {
return {
config: {},
permissions: {
view: false,
},

View file

@ -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<IPersistPluginConfig> {
public static pluginName = "persist";
protected persistedData: GuildPersistedData;
protected logs: GuildLogs;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IPersistPluginConfig> {
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;
}

View file

@ -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<IBasePluginConfig, IPingableRolesPluginPermissions> {
public static pluginName = "pingable_roles";
protected pingableRoles: GuildPingableRoles;
protected cache: Map<string, PingableRole[]>;
protected timeouts: Map<string, any>;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, IPingableRolesPluginPermissions> {
return {
config: {},
permissions: {
use: false,
},

View file

@ -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<IBasePluginConfig, IPostPluginPermissions> {
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<IBasePluginConfig, IPostPluginPermissions> {
return {
config: {},
permissions: {
post: false,
edit: false,

View file

@ -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<IReactionRolesPluginConfig, IReactionRolesPluginPermissions> {
public static pluginName = "reaction_roles";
protected reactionRoles: GuildReactionRoles;
@ -37,7 +46,7 @@ export class ReactionRolesPlugin extends ZeppelinPlugin {
private autoRefreshTimeout;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IReactionRolesPluginConfig, IReactionRolesPluginPermissions> {
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);

View file

@ -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<IBasePluginConfig, IRemindersPluginPermissions> {
public static pluginName = "reminders";
protected reminders: GuildReminders;
@ -17,8 +21,10 @@ export class RemindersPlugin extends ZeppelinPlugin {
private postRemindersTimeout;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, IRemindersPluginPermissions> {
return {
config: {},
permissions: {
use: false,
},

View file

@ -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<IBasePluginConfig, ISelfGrantableRolesPluginPermissions> {
public static pluginName = "self_grantable_roles";
protected selfGrantableRoles: GuildSelfGrantableRoles;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, ISelfGrantableRolesPluginPermissions> {
return {
config: {},
permissions: {
manage: false,
use: false,

View file

@ -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<IBasePluginConfig, ISlowmodePluginPermissions> {
public static pluginName = "slowmode";
protected slowmodes: GuildSlowmodes;
protected clearInterval;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, ISlowmodePluginPermissions> {
return {
config: {},
permissions: {
manage: false,
affected: true,

View file

@ -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<ISpamPluginConfig> {
public static pluginName = "spam";
protected actions: GuildActions;
@ -68,9 +90,10 @@ export class SpamPlugin extends Plugin {
private expiryInterval;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<ISpamPluginConfig> {
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",

View file

@ -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<IBasePluginConfig, IStarboardPluginPermissions> {
public static pluginName = "starboard";
protected starboards: GuildStarboards;
@ -25,8 +29,10 @@ export class StarboardPlugin extends ZeppelinPlugin {
private onMessageDeleteFn;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<IBasePluginConfig, IStarboardPluginPermissions> {
return {
config: {},
permissions: {
manage: false,
},

View file

@ -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<ITagsPluginConfig, ITagsPluginPermissions> {
public static pluginName = "tags";
protected tags: GuildTags;
@ -26,17 +38,17 @@ export class TagsPlugin extends Plugin {
private onMessageCreateFn;
private onMessageDeleteFn;
getDefaultOptions() {
getDefaultOptions(): IPluginOptions<ITagsPluginConfig, ITagsPluginPermissions> {
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);
});

View file

@ -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<string, TextChannel> = 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<IBasePluginConfig, IUtilityPluginPermissions> {
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<IBasePluginConfig, IUtilityPluginPermissions> {
return {
config: {},
permissions: {
roles: false,
level: false,

View file

@ -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<TConfig, TPermissions> {
protected configSchema: any;
protected permissionsSchema: any;