Add io-ts config schemas to all guild plugins

This commit is contained in:
Dragory 2019-07-21 21:15:52 +03:00
parent 2f3dfa96db
commit 74c78f51ce
23 changed files with 373 additions and 294 deletions

View file

@ -7,14 +7,14 @@ import { customEmojiRegex, errorMessage, isEmoji, successMessage } from "../util
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import * as t from "io-ts";
const configSchema = t.type({
const ConfigSchema = t.type({
can_manage: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof configSchema>;
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class AutoReactionsPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "auto_reactions";
protected static configSchema = configSchema;
protected static configSchema = ConfigSchema;
protected savedMessages: GuildSavedMessages;
protected autoReactions: GuildAutoReactions;

View file

@ -9,11 +9,13 @@ import { GuildArchives } from "../data/GuildArchives";
import { IPluginOptions } from "knub";
import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType";
import * as t from "io-ts";
interface ICasesPluginConfig {
log_automatic_actions: boolean;
case_log_channel: string;
}
const ConfigSchema = t.type({
log_automatic_actions: t.boolean,
case_log_channel: t.string,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
/**
* Can also be used as a config object for functions that create cases
@ -40,14 +42,15 @@ export type CaseNoteArgs = {
noteDetails?: string[];
};
export class CasesPlugin extends ZeppelinPlugin<ICasesPluginConfig> {
export class CasesPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "cases";
protected static configSchema = ConfigSchema;
protected cases: GuildCases;
protected archives: GuildArchives;
protected logs: GuildLogs;
getDefaultOptions(): IPluginOptions<ICasesPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
log_automatic_actions: true,

View file

@ -15,26 +15,26 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages";
import { SavedMessage } from "../data/entities/SavedMessage";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import cloneDeep from "lodash.clonedeep";
import * as t from "io-ts";
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;
const ConfigSchema = t.type({
filter_zalgo: t.boolean,
filter_invites: t.boolean,
invite_guild_whitelist: t.array(t.string),
invite_guild_blacklist: t.array(t.string),
invite_code_whitelist: t.array(t.string),
invite_code_blacklist: t.array(t.string),
allow_group_dm_invites: t.boolean,
filter_domains: t.boolean,
domain_whitelist: t.array(t.string),
domain_blacklist: t.array(t.string),
blocked_tokens: t.array(t.string),
blocked_words: t.array(t.string),
blocked_regex: t.array(t.string),
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
filter_domains: boolean;
domain_whitelist: string[];
domain_blacklist: string[];
blocked_tokens: string[];
blocked_words: string[];
blocked_regex: string[];
}
export class CensorPlugin extends ZeppelinPlugin<ICensorPluginConfig> {
export class CensorPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "censor";
protected serverLogs: GuildLogs;
@ -43,7 +43,7 @@ export class CensorPlugin extends ZeppelinPlugin<ICensorPluginConfig> {
private onMessageCreateFn;
private onMessageUpdateFn;
getDefaultOptions(): IPluginOptions<ICensorPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
filter_zalgo: false,

View file

@ -1,29 +1,31 @@
import { decorators as d, IPluginOptions, logger } from "knub";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { Member, Channel, GuildChannel, PermissionOverwrite, Permission, Message } from "eris";
import * as t from "io-ts";
// Permissions using these numbers: https://abal.moe/Eris/docs/reference (add all allowed/denied ones up)
interface ICompanionChannel {
channelIds: string[];
permissions: number;
}
const CompanionChannel = t.type({
channelIds: t.array(t.string),
permissions: t.number,
});
type TCompanionChannel = t.TypeOf<typeof CompanionChannel>;
const ConfigSchema = t.type({
channels: t.record(t.string, CompanionChannel),
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
interface ICompanionChannelMap {
[channelId: string]: ICompanionChannel;
[channelId: string]: TCompanionChannel;
}
interface ICompanionChannelPluginConfig {
channels: {
[key: string]: ICompanionChannel;
};
}
export class CompanionChannelPlugin extends ZeppelinPlugin<ICompanionChannelPluginConfig> {
export class CompanionChannelPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "companion_channels";
protected static configSchema = ConfigSchema;
companionChannels: Map<string, ICompanionChannel> = new Map();
companionChannels: Map<string, TCompanionChannel> = new Map();
getDefaultOptions(): IPluginOptions<ICompanionChannelPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
channels: {},

View file

@ -5,68 +5,77 @@ import { renderTemplate } from "../templateFormatter";
import { stripObjectToScalars } from "../utils";
import { CasesPlugin } from "./Cases";
import { CaseTypes } from "../data/CaseTypes";
import * as t from "io-ts";
// Triggers
type CommandTrigger = {
type: "command";
name: string;
params: string;
can_use: boolean;
};
const CommandTrigger = t.type({
type: t.literal("command"),
name: t.string,
params: t.string,
can_use: t.boolean,
});
type TCommandTrigger = t.TypeOf<typeof CommandTrigger>;
type AnyTrigger = CommandTrigger;
const AnyTrigger = CommandTrigger; // TODO: Make into a union once we have more triggers
type TAnyTrigger = t.TypeOf<typeof AnyTrigger>;
// Actions
type AddRoleAction = {
type: "add_role";
target: string;
role: string | string[];
};
const AddRoleAction = t.type({
type: t.literal("add_role"),
target: t.string,
role: t.union([t.string, t.array(t.string)]),
});
type TAddRoleAction = t.TypeOf<typeof AddRoleAction>;
type CreateCaseAction = {
type: "create_case";
case_type: string;
mod: string;
target: string;
reason: string;
};
const CreateCaseAction = t.type({
type: t.literal("create_case"),
case_type: t.string,
mod: t.string,
target: t.string,
reason: t.string,
});
type TCreateCaseAction = t.TypeOf<typeof CreateCaseAction>;
type MoveToVoiceChannelAction = {
type: "move_to_vc";
target: string;
channel: string;
};
const MoveToVoiceChannelAction = t.type({
type: t.literal("move_to_vc"),
target: t.string,
channel: t.string,
});
type TMoveToVoiceChannelAction = t.TypeOf<typeof MoveToVoiceChannelAction>;
type MessageAction = {
type: "message";
channel: string;
content: string;
};
const MessageAction = t.type({
type: t.literal("message"),
channel: t.string,
content: t.string,
});
type TMessageAction = t.TypeOf<typeof MessageAction>;
type AnyAction = AddRoleAction | CreateCaseAction | MoveToVoiceChannelAction | MessageAction;
const AnyAction = t.union([AddRoleAction, CreateCaseAction, MoveToVoiceChannelAction, MessageAction]);
type TAnyAction = t.TypeOf<typeof AnyAction>;
// Event
type CustomEvent = {
name: string;
trigger: AnyTrigger;
actions: AnyAction[];
};
// Full config schema
const CustomEvent = t.type({
name: t.string,
trigger: AnyTrigger,
actions: t.array(AnyAction),
});
type TCustomEvent = t.TypeOf<typeof CustomEvent>;
interface ICustomEventsPluginConfig {
events: {
[key: string]: CustomEvent;
};
}
const ConfigSchema = t.type({
events: t.record(t.string, CustomEvent),
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
class ActionError extends Error {}
export class CustomEventsPlugin extends ZeppelinPlugin<ICustomEventsPluginConfig> {
export class CustomEventsPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "custom_events";
public static dependencies = ["cases"];
protected static configSchema = ConfigSchema;
private clearTriggers: () => void;
public static dependencies = ["cases"];
getDefaultOptions(): IPluginOptions<ICustomEventsPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
events: {},
@ -97,7 +106,7 @@ export class CustomEventsPlugin extends ZeppelinPlugin<ICustomEventsPluginConfig
// TODO: Run this.clearTriggers() once we actually have something there
}
async runEvent(event: CustomEvent, eventData: any, values: any) {
async runEvent(event: TCustomEvent, eventData: any, values: any) {
try {
for (const action of event.actions) {
if (action.type === "add_role") {
@ -125,7 +134,7 @@ export class CustomEventsPlugin extends ZeppelinPlugin<ICustomEventsPluginConfig
}
}
async addRoleAction(action: AddRoleAction, values: any, event: CustomEvent, eventData: any) {
async addRoleAction(action: TAddRoleAction, values: any, event: TCustomEvent, eventData: any) {
const targetId = await renderTemplate(action.target, values, false);
const target = await this.getMember(targetId);
if (!target) throw new ActionError(`Unknown target member: ${targetId}`);
@ -140,7 +149,7 @@ export class CustomEventsPlugin extends ZeppelinPlugin<ICustomEventsPluginConfig
});
}
async createCaseAction(action: CreateCaseAction, values: any, event: CustomEvent, eventData: any) {
async createCaseAction(action: TCreateCaseAction, values: any, event: TCustomEvent, eventData: any) {
const modId = await renderTemplate(action.mod, values, false);
const targetId = await renderTemplate(action.target, values, false);
@ -159,7 +168,7 @@ export class CustomEventsPlugin extends ZeppelinPlugin<ICustomEventsPluginConfig
});
}
async moveToVoiceChannelAction(action: MoveToVoiceChannelAction, values: any, event: CustomEvent, eventData: any) {
async moveToVoiceChannelAction(action: TMoveToVoiceChannelAction, values: any, event: TCustomEvent, eventData: any) {
const targetId = await renderTemplate(action.target, values, false);
const target = await this.getMember(targetId);
if (!target) throw new ActionError("Unknown target member");
@ -179,7 +188,7 @@ export class CustomEventsPlugin extends ZeppelinPlugin<ICustomEventsPluginConfig
});
}
async messageAction(action: MessageAction, values: any) {
async messageAction(action: TMessageAction, values: any) {
const targetChannelId = await renderTemplate(action.channel, values, false);
const targetChannel = this.guild.channels.get(targetChannelId);
if (!targetChannel) throw new ActionError("Unknown target channel");

View file

@ -5,22 +5,25 @@ import { Message, Member, Guild, TextableChannel, VoiceChannel, Channel, User }
import { GuildVCAlerts } from "../data/GuildVCAlerts";
import moment = require("moment");
import { resolveMember, sorter, createChunkedMessage, errorMessage, successMessage } from "../utils";
import * as t from "io-ts";
const ConfigSchema = t.type({
can_where: t.boolean,
can_alert: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
const ALERT_LOOP_TIME = 30 * 1000;
interface ILocatePluginConfig {
can_where: boolean;
can_alert: boolean;
}
export class LocatePlugin extends ZeppelinPlugin<ILocatePluginConfig> {
export class LocatePlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "locate_user";
protected static configSchema = ConfigSchema;
private alerts: GuildVCAlerts;
private outdatedAlertsTimeout;
private usersWithAlerts: string[] = [];
getDefaultOptions(): IPluginOptions<ILocatePluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_where: false,

View file

@ -26,33 +26,35 @@ import { GuildCases } from "../data/GuildCases";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { renderTemplate, TemplateParseError } from "../templateFormatter";
import cloneDeep from "lodash.clonedeep";
import * as t from "io-ts";
interface ILogChannel {
include?: string[];
exclude?: string[];
batched?: boolean;
batch_time?: number;
excluded_users?: string[];
}
const LogChannel = t.partial({
include: t.array(t.string),
exclude: t.array(t.string),
batched: t.boolean,
batch_time: t.number,
excluded_users: t.array(t.string),
});
type TLogChannel = t.TypeOf<typeof LogChannel>;
interface ILogChannelMap {
[channelId: string]: ILogChannel;
}
const LogChannelMap = t.record(t.string, LogChannel);
type TLogChannelMap = t.TypeOf<typeof LogChannelMap>;
interface ILogsPluginConfig {
channels: {
[key: string]: ILogChannel;
};
format: {
[key: string]: string;
timestamp: string;
};
const ConfigSchema = t.type({
channels: LogChannelMap,
format: t.intersection([
t.record(t.string, t.string),
t.type({
timestamp: t.string,
}),
]),
ping_user: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
ping_user: boolean;
}
export class LogsPlugin extends ZeppelinPlugin<ILogsPluginConfig> {
export class LogsPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "logs";
protected static configSchema = ConfigSchema;
protected guildLogs: GuildLogs;
protected savedMessages: GuildSavedMessages;
@ -69,7 +71,7 @@ export class LogsPlugin extends ZeppelinPlugin<ILogsPluginConfig> {
private excludedUserProps = ["user", "member", "mod"];
getDefaultOptions(): IPluginOptions<ILogsPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
channels: {},
@ -121,7 +123,7 @@ export class LogsPlugin extends ZeppelinPlugin<ILogsPluginConfig> {
}
async log(type, data) {
const logChannels: ILogChannelMap = this.getConfig().channels;
const logChannels: TLogChannelMap = this.getConfig().channels;
const typeStr = LogType[type];
logChannelLoop: for (const [channelId, opts] of Object.entries(logChannels)) {

View file

@ -3,17 +3,20 @@ import { GuildChannel, Message, TextChannel } from "eris";
import { GuildSavedMessages } from "../data/GuildSavedMessages";
import { successMessage } from "../utils";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import * as t from "io-ts";
interface IMessageSaverPluginConfig {
can_manage: boolean;
}
const ConfigSchema = t.type({
can_manage: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class MessageSaverPlugin extends ZeppelinPlugin<IMessageSaverPluginConfig> {
export class MessageSaverPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "message_saver";
protected static configSchema = ConfigSchema;
protected savedMessages: GuildSavedMessages;
getDefaultOptions(): IPluginOptions<IMessageSaverPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_manage: false,

View file

@ -26,6 +26,33 @@ import { Case } from "../data/entities/Case";
import { renderTemplate } from "../templateFormatter";
import { CasesPlugin } from "./Cases";
import { MuteResult, MutesPlugin } from "./Mutes";
import * as t from "io-ts";
const ConfigSchema = t.type({
dm_on_warn: t.boolean,
dm_on_kick: t.boolean,
dm_on_ban: t.boolean,
message_on_warn: t.boolean,
message_on_kick: t.boolean,
message_on_ban: t.boolean,
message_channel: t.string,
warn_message: t.string,
kick_message: t.string,
ban_message: t.string,
alert_on_rejoin: t.boolean,
alert_channel: t.string,
can_note: t.boolean,
can_warn: t.boolean,
can_mute: t.boolean,
can_kick: t.boolean,
can_ban: t.boolean,
can_view: t.boolean,
can_addcase: t.boolean,
can_massban: t.boolean,
can_hidecase: t.boolean,
can_act_as_other: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
enum IgnoredEventType {
Ban = 1,
@ -38,35 +65,10 @@ interface IIgnoredEvent {
userId: string;
}
interface IModActionsPluginConfig {
dm_on_warn: boolean;
dm_on_kick: boolean;
dm_on_ban: boolean;
message_on_warn: boolean;
message_on_kick: boolean;
message_on_ban: boolean;
message_channel: string;
warn_message: string;
kick_message: string;
ban_message: string;
alert_on_rejoin: boolean;
alert_channel: string;
can_note: boolean;
can_warn: boolean;
can_mute: boolean;
can_kick: boolean;
can_ban: boolean;
can_view: boolean;
can_addcase: boolean;
can_massban: boolean;
can_hidecase: boolean;
can_act_as_other: boolean;
}
export class ModActionsPlugin extends ZeppelinPlugin<IModActionsPluginConfig> {
export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "mod_actions";
public static dependencies = ["cases", "mutes"];
protected static configSchema = ConfigSchema;
protected mutes: GuildMutes;
protected cases: GuildCases;
@ -82,7 +84,7 @@ export class ModActionsPlugin extends ZeppelinPlugin<IModActionsPluginConfig> {
this.ignoredEvents = [];
}
getDefaultOptions(): IPluginOptions<IModActionsPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
dm_on_warn: true,

View file

@ -25,26 +25,28 @@ import { renderTemplate } from "../templateFormatter";
import { CaseTypes } from "../data/CaseTypes";
import { CaseArgs, CasesPlugin } from "./Cases";
import { Case } from "../data/entities/Case";
import * as t from "io-ts";
const ConfigSchema = t.type({
mute_role: t.string,
move_to_voice_channel: t.string,
dm_on_mute: t.boolean,
message_on_mute: t.boolean,
message_channel: t.string,
mute_message: t.string,
timed_mute_message: t.string,
can_view_list: t.boolean,
can_cleanup: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
interface IMuteWithDetails extends Mute {
member?: Member;
banned?: boolean;
}
interface IMutesPluginConfig {
mute_role: string;
move_to_voice_channel: string;
dm_on_mute: boolean;
message_on_mute: boolean;
message_channel: string;
mute_message: string;
timed_mute_message: string;
can_view_list: boolean;
can_cleanup: boolean;
}
export type MuteResult = {
case: Case;
notifyResult: INotifyUserResult;
@ -59,15 +61,16 @@ const EXPIRED_MUTE_CHECK_INTERVAL = 60 * 1000;
let FIRST_CHECK_TIME = Date.now();
const FIRST_CHECK_INCREMENT = 5 * 1000;
export class MutesPlugin extends ZeppelinPlugin<IMutesPluginConfig> {
export class MutesPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "mutes";
protected static configSchema = ConfigSchema;
protected mutes: GuildMutes;
protected cases: GuildCases;
protected serverLogs: GuildLogs;
private muteClearIntervalId: NodeJS.Timer;
getDefaultOptions(): IPluginOptions<IMutesPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
mute_role: null,

View file

@ -4,18 +4,21 @@ import { Member, Message } from "eris";
import { createChunkedMessage, disableCodeBlocks } from "../utils";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { MAX_USERNAME_ENTRIES_PER_USER, UsernameHistory } from "../data/UsernameHistory";
import * as t from "io-ts";
interface INameHistoryPluginConfig {
can_view: boolean;
}
const ConfigSchema = t.type({
can_view: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class NameHistoryPlugin extends ZeppelinPlugin<INameHistoryPluginConfig> {
export class NameHistoryPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "name_history";
protected static configSchema = ConfigSchema;
protected nicknameHistory: GuildNicknameHistory;
protected usernameHistory: UsernameHistory;
getDefaultOptions(): IPluginOptions<INameHistoryPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_view: false,

View file

@ -6,20 +6,23 @@ import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType";
import { stripObjectToScalars } from "../utils";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import * as t from "io-ts";
interface IPersistPluginConfig {
persisted_roles: string[];
persist_nicknames: boolean;
persist_voice_mutes: boolean;
}
const ConfigSchema = t.type({
persisted_roles: t.array(t.string),
persist_nicknames: t.boolean,
persist_voice_mutes: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class PersistPlugin extends ZeppelinPlugin<IPersistPluginConfig> {
export class PersistPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "persist";
protected static configSchema = ConfigSchema;
protected persistedData: GuildPersistedData;
protected logs: GuildLogs;
getDefaultOptions(): IPluginOptions<IPersistPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
persisted_roles: [],

View file

@ -4,21 +4,24 @@ import { GuildPingableRoles } from "../data/GuildPingableRoles";
import { PingableRole } from "../data/entities/PingableRole";
import { errorMessage, successMessage } from "../utils";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import * as t from "io-ts";
const ConfigSchema = t.type({
can_manage: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
const TIMEOUT = 10 * 1000;
interface IPingableRolesPluginConfig {
can_manage: boolean;
}
export class PingableRolesPlugin extends ZeppelinPlugin<IPingableRolesPluginConfig> {
export class PingableRolesPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "pingable_roles";
protected static configSchema = ConfigSchema;
protected pingableRoles: GuildPingableRoles;
protected cache: Map<string, PingableRole[]>;
protected timeouts: Map<string, any>;
getDefaultOptions(): IPluginOptions<IPingableRolesPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_manage: false,

View file

@ -22,6 +22,13 @@ import { GuildScheduledPosts } from "../data/GuildScheduledPosts";
import moment, { Moment } from "moment-timezone";
import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType";
import * as t from "io-ts";
const ConfigSchema = t.type({
can_post: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
const fsp = fs.promises;
const COLOR_MATCH_REGEX = /^#?([0-9a-f]{6})$/;
@ -29,12 +36,9 @@ const COLOR_MATCH_REGEX = /^#?([0-9a-f]{6})$/;
const SCHEDULED_POST_CHECK_INTERVAL = 15 * SECONDS;
const SCHEDULED_POST_PREVIEW_TEXT_LENGTH = 50;
interface IPostPluginConfig {
can_post: boolean;
}
export class PostPlugin extends ZeppelinPlugin<IPostPluginConfig> {
export class PostPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "post";
protected static configSchema = ConfigSchema;
protected savedMessages: GuildSavedMessages;
protected scheduledPosts: GuildScheduledPosts;
@ -54,7 +58,7 @@ export class PostPlugin extends ZeppelinPlugin<IPostPluginConfig> {
clearTimeout(this.scheduledPostLoopTimeout);
}
getDefaultOptions(): IPluginOptions<IPostPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_post: false,

View file

@ -8,6 +8,22 @@ import { Queue } from "../Queue";
import { ReactionRole } from "../data/entities/ReactionRole";
import Timeout = NodeJS.Timeout;
import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line
import * as t from "io-ts";
/**
* Either of:
* [emojiId, roleId]
* [emojiId, roleId, emojiName]
* Where emojiId is either the snowflake of a custom emoji, or the actual unicode emoji
*/
const ReactionRolePair = t.union([t.tuple([t.string, t.string, t.string]), t.tuple([t.string, t.string])]);
type TReactionRolePair = t.TypeOf<typeof ReactionRolePair>;
const ConfigSchema = t.type({
auto_refresh_interval: t.number,
can_manage: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
type ReactionRolePair = [string, string, string?];
@ -26,14 +42,9 @@ type PendingMemberRoleChanges = {
}>;
};
interface IReactionRolesPluginConfig {
auto_refresh_interval: number;
can_manage: boolean;
}
export class ReactionRolesPlugin extends ZeppelinPlugin<IReactionRolesPluginConfig> {
export class ReactionRolesPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "reaction_roles";
protected static configSchema = ConfigSchema;
protected reactionRoles: GuildReactionRoles;
protected savedMessages: GuildSavedMessages;
@ -44,7 +55,7 @@ export class ReactionRolesPlugin extends ZeppelinPlugin<IReactionRolesPluginConf
private autoRefreshTimeout;
getDefaultOptions(): IPluginOptions<IReactionRolesPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
auto_refresh_interval: null,
@ -279,17 +290,17 @@ export class ReactionRolesPlugin extends ZeppelinPlugin<IReactionRolesPluginConf
// Turn "emoji = role" pairs into an array of tuples of the form [emoji, roleId]
// Emoji is either a unicode emoji or the snowflake of a custom emoji
const emojiRolePairs: ReactionRolePair[] = args.reactionRolePairs
const emojiRolePairs: TReactionRolePair[] = args.reactionRolePairs
.trim()
.split("\n")
.map(v => v.split("=").map(v => v.trim())) // tslint:disable-line
.map(
(pair): ReactionRolePair => {
(pair): TReactionRolePair => {
const customEmojiMatch = pair[0].match(/^<a?:(.*?):(\d+)>$/);
if (customEmojiMatch) {
return [customEmojiMatch[2], pair[1], customEmojiMatch[1]];
} else {
return pair as ReactionRolePair;
return pair as TReactionRolePair;
}
},
);

View file

@ -12,16 +12,19 @@ import {
sorter,
successMessage,
} from "../utils";
import * as t from "io-ts";
const ConfigSchema = t.type({
can_use: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
const REMINDER_LOOP_TIME = 10 * 1000;
const MAX_TRIES = 3;
interface IRemindersPluginConfig {
can_use: boolean;
}
export class RemindersPlugin extends ZeppelinPlugin<IRemindersPluginConfig> {
export class RemindersPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "reminders";
protected static configSchema = ConfigSchema;
protected reminders: GuildReminders;
protected tries: Map<number, number>;
@ -29,7 +32,7 @@ export class RemindersPlugin extends ZeppelinPlugin<IRemindersPluginConfig> {
private postRemindersTimeout;
private unloaded = false;
getDefaultOptions(): IPluginOptions<IRemindersPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_use: false,

View file

@ -3,19 +3,22 @@ import { GuildSelfGrantableRoles } from "../data/GuildSelfGrantableRoles";
import { GuildChannel, Message, Role, TextChannel } from "eris";
import { asSingleLine, chunkArray, errorMessage, sorter, successMessage, trimLines } from "../utils";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import * as t from "io-ts";
interface ISelfGrantableRolesPluginConfig {
can_manage: boolean;
can_use: boolean;
can_ignore_cooldown: boolean;
}
const ConfigSchema = t.type({
can_manage: t.boolean,
can_use: t.boolean,
can_ignore_cooldown: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class SelfGrantableRolesPlugin extends ZeppelinPlugin<ISelfGrantableRolesPluginConfig> {
export class SelfGrantableRolesPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "self_grantable_roles";
protected static configSchema = ConfigSchema;
protected selfGrantableRoles: GuildSelfGrantableRoles;
getDefaultOptions(): IPluginOptions<ISelfGrantableRolesPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_manage: false,

View file

@ -17,20 +17,23 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages";
import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line
import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType";
import * as t from "io-ts";
const ConfigSchema = t.type({
use_native_slowmode: t.boolean,
can_manage: t.boolean,
is_affected: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
const NATIVE_SLOWMODE_LIMIT = 6 * 60 * 60; // 6 hours
const MAX_SLOWMODE = 60 * 60 * 24 * 365 * 100; // 100 years
const BOT_SLOWMODE_CLEAR_INTERVAL = 60 * 1000;
interface ISlowmodePluginConfig {
use_native_slowmode: boolean;
can_manage: boolean;
is_affected: boolean;
}
export class SlowmodePlugin extends ZeppelinPlugin<ISlowmodePluginConfig> {
export class SlowmodePlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "slowmode";
protected static configSchema = ConfigSchema;
protected slowmodes: GuildSlowmodes;
protected savedMessages: GuildSavedMessages;
@ -39,7 +42,7 @@ export class SlowmodePlugin extends ZeppelinPlugin<ISlowmodePluginConfig> {
private onMessageCreateFn;
getDefaultOptions(): IPluginOptions<ISlowmodePluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
use_native_slowmode: true,

View file

@ -21,6 +21,34 @@ import { GuildMutes } from "../data/GuildMutes";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { MuteResult, MutesPlugin } from "./Mutes";
import { CasesPlugin } from "./Cases";
import * as t from "io-ts";
const BaseSingleSpamConfig = t.intersection([
t.type({
interval: t.number,
count: t.number,
}),
t.partial({
mute: t.boolean,
mute_time: t.number,
clean: t.boolean,
}),
]);
type TBaseSingleSpamConfig = t.TypeOf<typeof BaseSingleSpamConfig>;
const ConfigSchema = t.type({
max_censor: BaseSingleSpamConfig,
max_messages: BaseSingleSpamConfig,
max_mentions: BaseSingleSpamConfig,
max_links: BaseSingleSpamConfig,
max_attachments: BaseSingleSpamConfig,
max_emojis: BaseSingleSpamConfig,
max_newlines: BaseSingleSpamConfig,
max_duplicates: BaseSingleSpamConfig,
max_characters: BaseSingleSpamConfig,
max_voice_moves: BaseSingleSpamConfig,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
enum RecentActionType {
Message = 1,
@ -47,29 +75,9 @@ const MAX_INTERVAL = 300;
const SPAM_ARCHIVE_EXPIRY_DAYS = 90;
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> {
export class SpamPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "spam";
protected static configSchema = ConfigSchema;
protected logs: GuildLogs;
protected archives: GuildArchives;
@ -91,7 +99,7 @@ export class SpamPlugin extends ZeppelinPlugin<ISpamPluginConfig> {
private expiryInterval;
getDefaultOptions(): IPluginOptions<ISpamPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
max_censor: null,
@ -201,7 +209,7 @@ export class SpamPlugin extends ZeppelinPlugin<ISpamPluginConfig> {
async logAndDetectMessageSpam(
savedMessage: SavedMessage,
type: RecentActionType,
spamConfig: IBaseSingleSpamConfig,
spamConfig: TBaseSingleSpamConfig,
actionCount: number,
description: string,
) {

View file

@ -16,20 +16,23 @@ import path from "path";
import moment from "moment-timezone";
import { GuildSavedMessages } from "../data/GuildSavedMessages";
import { SavedMessage } from "../data/entities/SavedMessage";
import * as t from "io-ts";
interface IStarboardPluginConfig {
can_manage: boolean;
}
const ConfigSchema = t.type({
can_manage: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class StarboardPlugin extends ZeppelinPlugin<IStarboardPluginConfig> {
export class StarboardPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "starboard";
protected static configSchema = ConfigSchema;
protected starboards: GuildStarboards;
protected savedMessages: GuildSavedMessages;
private onMessageDeleteFn;
getDefaultOptions(): IPluginOptions<IStarboardPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_manage: false,

View file

@ -9,18 +9,21 @@ import humanizeDuration from "humanize-duration";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { parseTemplate, renderTemplate, TemplateParseError } from "../templateFormatter";
import { GuildArchives } from "../data/GuildArchives";
import * as t from "io-ts";
interface ITagsPluginConfig {
prefix: string;
delete_with_command: boolean;
const ConfigSchema = t.type({
prefix: t.string,
delete_with_command: t.boolean,
can_create: boolean;
can_use: boolean;
can_list: boolean;
}
can_create: t.boolean,
can_use: t.boolean,
can_list: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class TagsPlugin extends ZeppelinPlugin<ITagsPluginConfig> {
export class TagsPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "tags";
protected static configSchema = ConfigSchema;
protected archives: GuildArchives;
protected tags: GuildTags;
@ -31,7 +34,7 @@ export class TagsPlugin extends ZeppelinPlugin<ITagsPluginConfig> {
protected tagFunctions;
getDefaultOptions(): IPluginOptions<ITagsPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
prefix: "!!",

View file

@ -43,8 +43,25 @@ import { GuildSavedMessages } from "../data/GuildSavedMessages";
import { GuildArchives } from "../data/GuildArchives";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { getCurrentUptime } from "../uptime";
import LCL from "last-commit-log";
import * as t from "io-ts";
const ConfigSchema = t.type({
can_roles: t.boolean,
can_level: t.boolean,
can_search: t.boolean,
can_clean: t.boolean,
can_info: t.boolean,
can_server: t.boolean,
can_reload_guild: t.boolean,
can_nickname: t.boolean,
can_ping: t.boolean,
can_source: t.boolean,
can_vcmove: t.boolean,
can_help: t.boolean,
can_about: t.boolean,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
const { performance } = require("perf_hooks");
@ -63,24 +80,9 @@ type MemberSearchParams = {
"case-sensitive"?: boolean;
};
interface IUtilityPluginConfig {
can_roles: boolean;
can_level: boolean;
can_search: boolean;
can_clean: boolean;
can_info: boolean;
can_server: boolean;
can_reload_guild: boolean;
can_nickname: boolean;
can_ping: boolean;
can_source: boolean;
can_vcmove: boolean;
can_help: boolean;
can_about: boolean;
}
export class UtilityPlugin extends ZeppelinPlugin<IUtilityPluginConfig> {
export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "utility";
protected static configSchema = ConfigSchema;
protected logs: GuildLogs;
protected cases: GuildCases;
@ -89,7 +91,7 @@ export class UtilityPlugin extends ZeppelinPlugin<IUtilityPluginConfig> {
protected lastFullMemberRefresh = 0;
getDefaultOptions(): IPluginOptions<IUtilityPluginConfig> {
getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
can_roles: false,
@ -834,7 +836,7 @@ export class UtilityPlugin extends ZeppelinPlugin<IUtilityPluginConfig> {
const highest = Math.round(Math.max(...times));
const lowest = Math.round(Math.min(...times));
const mean = Math.round(times.reduce((t, v) => t + v, 0) / times.length);
const mean = Math.round(times.reduce((total, ms) => total + ms, 0) / times.length);
const shard = this.bot.shards.get(this.bot.guildShardMap[this.guildId]);

View file

@ -5,19 +5,22 @@ import { renderTemplate } from "../templateFormatter";
import { createChunkedMessage, stripObjectToScalars } from "../utils";
import { LogType } from "../data/LogType";
import { GuildLogs } from "../data/GuildLogs";
import * as t from "io-ts";
interface IWelcomeMessageConfig {
send_dm: boolean;
send_to_channel: string;
message: string;
}
const ConfigSchema = t.type({
send_dm: t.boolean,
send_to_channel: t.string,
message: t.string,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export class WelcomeMessagePlugin extends ZeppelinPlugin<IWelcomeMessageConfig> {
export class WelcomeMessagePlugin extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "welcome_message";
protected static configSchema = ConfigSchema;
protected logs: GuildLogs;
protected getDefaultOptions(): IPluginOptions<IWelcomeMessageConfig> {
protected getDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
send_dm: false,