mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-16 14:11:50 +00:00
Merge branch 'Dragory:master' into usoka-dev
This commit is contained in:
commit
613c98e378
150 changed files with 6918 additions and 495 deletions
6126
backend/package-lock.json
generated
6126
backend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -31,7 +31,7 @@
|
||||||
"deep-diff": "^1.0.2",
|
"deep-diff": "^1.0.2",
|
||||||
"dotenv": "^4.0.0",
|
"dotenv": "^4.0.0",
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
"eris": "github:abalabahaha/eris#dev",
|
"eris": "^0.15.1",
|
||||||
"erlpack": "github:abalabahaha/erlpack",
|
"erlpack": "github:abalabahaha/erlpack",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
"express": "^4.17.0",
|
"express": "^4.17.0",
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
"humanize-duration": "^3.15.0",
|
"humanize-duration": "^3.15.0",
|
||||||
"io-ts": "^2.0.0",
|
"io-ts": "^2.0.0",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"knub": "^30.0.0-beta.35",
|
"knub": "^30.0.0-beta.37",
|
||||||
"knub-command-manager": "^8.1.2",
|
"knub-command-manager": "^8.1.2",
|
||||||
"last-commit-log": "^2.1.0",
|
"last-commit-log": "^2.1.0",
|
||||||
"lodash.chunk": "^4.2.0",
|
"lodash.chunk": "^4.2.0",
|
||||||
|
|
|
@ -1,23 +1,38 @@
|
||||||
import { SECONDS } from "./utils";
|
import { SECONDS } from "./utils";
|
||||||
|
|
||||||
type QueueFn = (...args: any[]) => Promise<any>;
|
type InternalQueueFn = () => Promise<void>;
|
||||||
|
type AnyFn = (...args: any[]) => any;
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT = 10 * SECONDS;
|
const DEFAULT_TIMEOUT = 10 * SECONDS;
|
||||||
|
|
||||||
export class Queue {
|
export class Queue<TQueueFunction extends AnyFn = AnyFn> {
|
||||||
protected running: boolean = false;
|
protected running = false;
|
||||||
protected queue: QueueFn[] = [];
|
protected queue: InternalQueueFn[] = [];
|
||||||
protected timeout: number;
|
protected _timeout: number;
|
||||||
|
|
||||||
constructor(timeout = DEFAULT_TIMEOUT) {
|
constructor(timeout = DEFAULT_TIMEOUT) {
|
||||||
this.timeout = timeout;
|
this._timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(fn) {
|
get timeout(): number {
|
||||||
const promise = new Promise(resolve => {
|
return this._timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of operations that are currently queued up or running.
|
||||||
|
* I.e. backlog (queue) + current running process, if any.
|
||||||
|
*
|
||||||
|
* If this is 0, queueing a function will run it as soon as possible.
|
||||||
|
*/
|
||||||
|
get length(): number {
|
||||||
|
return this.queue.length + (this.running ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public add(fn: TQueueFunction): Promise<void> {
|
||||||
|
const promise = new Promise<void>(resolve => {
|
||||||
this.queue.push(async () => {
|
this.queue.push(async () => {
|
||||||
await fn();
|
await fn();
|
||||||
resolve(undefined);
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.running) this.next();
|
if (!this.running) this.next();
|
||||||
|
@ -26,7 +41,7 @@ export class Queue {
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public next() {
|
public next(): void {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
|
|
||||||
if (this.queue.length === 0) {
|
if (this.queue.length === 0) {
|
||||||
|
@ -37,8 +52,8 @@ export class Queue {
|
||||||
const fn = this.queue.shift()!;
|
const fn = this.queue.shift()!;
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
// Either fn() completes or the timeout is reached
|
// Either fn() completes or the timeout is reached
|
||||||
fn().then(resolve);
|
void fn().then(resolve);
|
||||||
setTimeout(resolve, this.timeout);
|
setTimeout(resolve, this._timeout);
|
||||||
}).then(() => this.next());
|
}).then(() => this.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ export function initArchives(app: express.Express) {
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setHeader("Content-Type", "text/plain; charset=UTF-8");
|
res.setHeader("Content-Type", "text/plain; charset=UTF-8");
|
||||||
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
||||||
res.end(body);
|
res.end(body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ export function initAuth(app: express.Express) {
|
||||||
|
|
||||||
const userId = await apiLogins.getUserIdByApiKey(apiKey);
|
const userId = await apiLogins.getUserIdByApiKey(apiKey);
|
||||||
if (userId) {
|
if (userId) {
|
||||||
|
void apiLogins.refreshApiKeyExpiryTime(apiKey); // Refresh expiry time in the background
|
||||||
return cb(null, { apiKey, userId });
|
return cb(null, { apiKey, userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,13 +155,19 @@ export function initAuth(app: express.Express) {
|
||||||
await apiLogins.expireApiKey(req.user!.apiKey);
|
await apiLogins.expireApiKey(req.user!.apiKey);
|
||||||
return ok(res);
|
return ok(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// API route to refresh the given API token's expiry time
|
||||||
|
// The actual refreshing happens in the api-token passport strategy above, so we just return 200 OK here
|
||||||
|
app.post("/auth/refresh", ...apiTokenAuthHandlers(), (req, res) => {
|
||||||
|
return ok(res);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function apiTokenAuthHandlers() {
|
export function apiTokenAuthHandlers() {
|
||||||
return [
|
return [
|
||||||
passport.authenticate("api-token", { failWithError: true }),
|
passport.authenticate("api-token", { failWithError: true }),
|
||||||
(err, req: Request, res: Response, next) => {
|
(err, req: Request, res: Response, next) => {
|
||||||
return res.json({ error: err.message });
|
return res.status(401).json({ error: err.message });
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
UnknownUser,
|
UnknownUser,
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import { GuildChannel, Member, TextChannel, User } from "eris";
|
import { GuildChannel, Member, TextChannel, User } from "eris";
|
||||||
import { baseTypeConverters, baseTypeHelpers, CommandContext, TypeConversionError } from "knub";
|
import { baseTypeConverters, baseCommandParameterTypeHelpers, CommandContext, TypeConversionError } from "knub";
|
||||||
import { createTypeHelper } from "knub-command-manager";
|
import { createTypeHelper } from "knub-command-manager";
|
||||||
import { getChannelIdFromMessageId } from "./data/getChannelIdFromMessageId";
|
import { getChannelIdFromMessageId } from "./data/getChannelIdFromMessageId";
|
||||||
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
||||||
|
@ -107,7 +107,7 @@ export const commandTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const commandTypeHelpers = {
|
export const commandTypeHelpers = {
|
||||||
...baseTypeHelpers,
|
...baseCommandParameterTypeHelpers,
|
||||||
|
|
||||||
delay: createTypeHelper<number>(commandTypes.delay),
|
delay: createTypeHelper<number>(commandTypes.delay),
|
||||||
resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser),
|
resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser),
|
||||||
|
|
|
@ -37,7 +37,7 @@ export async function validateGuildConfig(config: any): Promise<string | null> {
|
||||||
const plugin = pluginNameToPlugin.get(pluginName)!;
|
const plugin = pluginNameToPlugin.get(pluginName)!;
|
||||||
try {
|
try {
|
||||||
const mergedOptions = configUtils.mergeConfig(plugin.defaultOptions || {}, pluginOptions);
|
const mergedOptions = configUtils.mergeConfig(plugin.defaultOptions || {}, pluginOptions);
|
||||||
await plugin.configPreprocessor?.(mergedOptions as PluginOptions<any>);
|
await plugin.configPreprocessor?.((mergedOptions as unknown) as PluginOptions<any>, true);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof ConfigValidationError || err instanceof StrictValidationError) {
|
if (err instanceof ConfigValidationError || err instanceof StrictValidationError) {
|
||||||
return `${pluginName}: ${err.message}`;
|
return `${pluginName}: ${err.message}`;
|
||||||
|
|
|
@ -5,7 +5,9 @@ import crypto from "crypto";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
// tslint:disable-next-line:no-submodule-imports
|
// tslint:disable-next-line:no-submodule-imports
|
||||||
import uuidv4 from "uuid/v4";
|
import uuidv4 from "uuid/v4";
|
||||||
import { DBDateFormat } from "../utils";
|
import { DAYS, DBDateFormat } from "../utils";
|
||||||
|
|
||||||
|
const LOGIN_EXPIRY_TIME = 1 * DAYS;
|
||||||
|
|
||||||
export class ApiLogins extends BaseRepository {
|
export class ApiLogins extends BaseRepository {
|
||||||
private apiLogins: Repository<ApiLogin>;
|
private apiLogins: Repository<ApiLogin>;
|
||||||
|
@ -68,7 +70,7 @@ export class ApiLogins extends BaseRepository {
|
||||||
logged_in_at: moment.utc().format(DBDateFormat),
|
logged_in_at: moment.utc().format(DBDateFormat),
|
||||||
expires_at: moment
|
expires_at: moment
|
||||||
.utc()
|
.utc()
|
||||||
.add(1, "day")
|
.add(LOGIN_EXPIRY_TIME, "ms")
|
||||||
.format(DBDateFormat),
|
.format(DBDateFormat),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -86,4 +88,19 @@ export class ApiLogins extends BaseRepository {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async refreshApiKeyExpiryTime(apiKey) {
|
||||||
|
const [loginId, token] = apiKey.split(".");
|
||||||
|
if (!loginId || !token) return;
|
||||||
|
|
||||||
|
await this.apiLogins.update(
|
||||||
|
{ id: loginId },
|
||||||
|
{
|
||||||
|
expires_at: moment()
|
||||||
|
.utc()
|
||||||
|
.add(LOGIN_EXPIRY_TIME, "ms")
|
||||||
|
.format(DBDateFormat),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { getRepository, Repository } from "typeorm";
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
|
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
|
||||||
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
||||||
import { GuildChannel, Message } from "eris";
|
import { GuildChannel, Message, PossiblyUncachedTextableChannel } from "eris";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { MINUTES, SECONDS } from "../utils";
|
import { MINUTES, SECONDS } from "../utils";
|
||||||
import { isAPI } from "../globals";
|
import { isAPI } from "../globals";
|
||||||
|
@ -34,7 +34,7 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
this.toBePermanent = new Set();
|
this.toBePermanent = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public msgToSavedMessageData(msg: Message): ISavedMessageData {
|
public msgToSavedMessageData(msg: Message<PossiblyUncachedTextableChannel>): ISavedMessageData {
|
||||||
const data: ISavedMessageData = {
|
const data: ISavedMessageData = {
|
||||||
author: {
|
author: {
|
||||||
username: msg.author.username,
|
username: msg.author.username,
|
||||||
|
@ -139,7 +139,7 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
this.events.emit(`create:${data.id}`, [inserted]);
|
this.events.emit(`create:${data.id}`, [inserted]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createFromMsg(msg: Message, overrides = {}) {
|
async createFromMsg(msg: Message<PossiblyUncachedTextableChannel>, overrides = {}) {
|
||||||
const existingSavedMsg = await this.find(msg.id);
|
const existingSavedMsg = await this.find(msg.id);
|
||||||
if (existingSavedMsg) return;
|
if (existingSavedMsg) return;
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
this.events.emit(`update:${id}`, [newMessage, oldMessage]);
|
this.events.emit(`update:${id}`, [newMessage, oldMessage]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveEditFromMsg(msg: Message) {
|
async saveEditFromMsg(msg: Message<PossiblyUncachedTextableChannel>) {
|
||||||
const newData = this.msgToSavedMessageData(msg);
|
const newData = this.msgToSavedMessageData(msg);
|
||||||
return this.saveEdit(msg.id, newData);
|
return this.saveEdit(msg.id, newData);
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,9 @@ connect().then(async () => {
|
||||||
restMode: true,
|
restMode: true,
|
||||||
compress: false,
|
compress: false,
|
||||||
guildCreateTimeout: 0,
|
guildCreateTimeout: 0,
|
||||||
|
rest: {
|
||||||
|
ratelimiterOffset: 150,
|
||||||
|
},
|
||||||
// Disable mentions by default
|
// Disable mentions by default
|
||||||
allowedMentions: {
|
allowedMentions: {
|
||||||
everyone: false,
|
everyone: false,
|
||||||
|
|
|
@ -27,8 +27,12 @@ export function canActOn(pluginData: GuildPluginData<any>, member1: Member, memb
|
||||||
return allowSameLevel ? ourLevel >= memberLevel : ourLevel > memberLevel;
|
return allowSameLevel ? ourLevel >= memberLevel : ourLevel > memberLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasPermission(pluginData: AnyPluginData<any>, permission: string, matchParams: ExtendedMatchParams) {
|
export async function hasPermission(
|
||||||
const config = pluginData.config.getMatchingConfig(matchParams);
|
pluginData: AnyPluginData<any>,
|
||||||
|
permission: string,
|
||||||
|
matchParams: ExtendedMatchParams,
|
||||||
|
) {
|
||||||
|
const config = await pluginData.config.getMatchingConfig(matchParams);
|
||||||
return helpers.hasPermission(config, permission);
|
return helpers.hasPermission(config, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +54,19 @@ const PluginOverrideCriteriaType: t.Type<PluginOverrideCriteria<unknown>> = t.re
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const validTopLevelOverrideKeys = [
|
||||||
|
"channel",
|
||||||
|
"category",
|
||||||
|
"level",
|
||||||
|
"user",
|
||||||
|
"role",
|
||||||
|
"all",
|
||||||
|
"any",
|
||||||
|
"not",
|
||||||
|
"extra",
|
||||||
|
"config",
|
||||||
|
];
|
||||||
|
|
||||||
const BasicPluginStructureType = t.type({
|
const BasicPluginStructureType = t.type({
|
||||||
enabled: tNullable(t.boolean),
|
enabled: tNullable(t.boolean),
|
||||||
config: tNullable(t.unknown),
|
config: tNullable(t.unknown),
|
||||||
|
@ -70,7 +87,7 @@ export function getPluginConfigPreprocessor(
|
||||||
blueprint: ZeppelinPlugin,
|
blueprint: ZeppelinPlugin,
|
||||||
customPreprocessor?: ZeppelinPlugin["configPreprocessor"],
|
customPreprocessor?: ZeppelinPlugin["configPreprocessor"],
|
||||||
) {
|
) {
|
||||||
return async (options: PluginOptions<any>) => {
|
return async (options: PluginOptions<any>, strict?: boolean) => {
|
||||||
// 1. Validate the basic structure of plugin config
|
// 1. Validate the basic structure of plugin config
|
||||||
const basicOptionsValidation = validate(BasicPluginStructureType, options);
|
const basicOptionsValidation = validate(BasicPluginStructureType, options);
|
||||||
if (basicOptionsValidation instanceof StrictValidationError) {
|
if (basicOptionsValidation instanceof StrictValidationError) {
|
||||||
|
@ -89,8 +106,32 @@ export function getPluginConfigPreprocessor(
|
||||||
|
|
||||||
if (options.overrides) {
|
if (options.overrides) {
|
||||||
for (const override of options.overrides) {
|
for (const override of options.overrides) {
|
||||||
const partialOverrideConfigValidation = validate(partialConfigSchema, override.config || {});
|
// Validate criteria and extra criteria
|
||||||
if (partialOverrideConfigValidation) {
|
// FIXME: This is ugly
|
||||||
|
for (const key of Object.keys(override)) {
|
||||||
|
if (!validTopLevelOverrideKeys.includes(key)) {
|
||||||
|
if (strict) {
|
||||||
|
throw new ConfigValidationError(`Unknown override criterion '${key}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete override[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (override.extra != null) {
|
||||||
|
for (const extraCriterion of Object.keys(override.extra)) {
|
||||||
|
if (!blueprint.customOverrideCriteriaFunctions?.[extraCriterion]) {
|
||||||
|
if (strict) {
|
||||||
|
throw new ConfigValidationError(`Unknown override extra criterion '${extraCriterion}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete override.extra[extraCriterion];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate override config
|
||||||
|
const partialOverrideConfigValidation = decodeAndValidateStrict(partialConfigSchema, override.config || {});
|
||||||
|
if (partialOverrideConfigValidation instanceof StrictValidationError) {
|
||||||
throw strictValidationErrorToConfigValidationError(partialOverrideConfigValidation);
|
throw strictValidationErrorToConfigValidationError(partialOverrideConfigValidation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ const defaultOptions: PluginOptions<AutoDeletePluginType> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()("auto_delete", {
|
export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()({
|
||||||
|
name: "auto_delete",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Auto-delete",
|
prettyName: "Auto-delete",
|
||||||
|
@ -28,7 +29,7 @@ export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()("aut
|
||||||
configSchema: ConfigSchema,
|
configSchema: ConfigSchema,
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.guildSavedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
state.guildSavedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
||||||
|
@ -39,6 +40,10 @@ export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()("aut
|
||||||
state.nextDeletionTimeout = null;
|
state.nextDeletionTimeout = null;
|
||||||
|
|
||||||
state.maxDelayWarningSent = false;
|
state.maxDelayWarningSent = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.onMessageCreateFn = msg => onMessageCreate(pluginData, msg);
|
state.onMessageCreateFn = msg => onMessageCreate(pluginData, msg);
|
||||||
state.guildSavedMessages.events.on("create", state.onMessageCreateFn);
|
state.guildSavedMessages.events.on("create", state.onMessageCreateFn);
|
||||||
|
@ -50,7 +55,7 @@ export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()("aut
|
||||||
state.guildSavedMessages.events.on("deleteBulk", state.onMessageDeleteBulkFn);
|
state.guildSavedMessages.events.on("deleteBulk", state.onMessageDeleteBulkFn);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
pluginData.state.guildSavedMessages.events.off("create", pluginData.state.onMessageCreateFn);
|
pluginData.state.guildSavedMessages.events.off("create", pluginData.state.onMessageCreateFn);
|
||||||
pluginData.state.guildSavedMessages.events.off("delete", pluginData.state.onMessageDeleteFn);
|
pluginData.state.guildSavedMessages.events.off("delete", pluginData.state.onMessageDeleteFn);
|
||||||
pluginData.state.guildSavedMessages.events.off("deleteBulk", pluginData.state.onMessageDeleteBulkFn);
|
pluginData.state.guildSavedMessages.events.off("deleteBulk", pluginData.state.onMessageDeleteBulkFn);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { tDelayString, MINUTES } from "../../utils";
|
import { tDelayString, MINUTES } from "../../utils";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { addMessageToDeletionQueue } from "./addMessageToDeletionQueue";
|
||||||
|
|
||||||
export async function onMessageCreate(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
export async function onMessageCreate(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, msg.user_id);
|
const member = await resolveMember(pluginData.client, pluginData.guild, msg.user_id);
|
||||||
const config = pluginData.config.getMatchingConfig({ member, channelId: msg.channel_id });
|
const config = await pluginData.config.getMatchingConfig({ member, channelId: msg.channel_id });
|
||||||
if (config.enabled) {
|
if (config.enabled) {
|
||||||
let delay = convertDelayStringToMS(config.delay)!;
|
let delay = convertDelayStringToMS(config.delay)!;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>()("auto_reactions", {
|
export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>()({
|
||||||
|
name: "auto_reactions",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Auto-reactions",
|
prettyName: "Auto-reactions",
|
||||||
|
@ -47,10 +48,8 @@ export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>(
|
||||||
AddReactionsEvt,
|
AddReactionsEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
pluginData.state.savedMessages = GuildSavedMessages.getGuildInstance(pluginData.guild.id);
|
||||||
|
pluginData.state.autoReactions = GuildAutoReactions.getGuildInstance(pluginData.guild.id);
|
||||||
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
|
||||||
state.autoReactions = GuildAutoReactions.getGuildInstance(guild.id);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||||
|
@ -18,5 +18,5 @@ export interface AutoReactionsPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const autoReactionsCmd = guildCommand<AutoReactionsPluginType>();
|
export const autoReactionsCmd = typedGuildCommand<AutoReactionsPluginType>();
|
||||||
export const autoReactionsEvt = guildEventListener<AutoReactionsPluginType>();
|
export const autoReactionsEvt = typedGuildEventListener<AutoReactionsPluginType>();
|
||||||
|
|
|
@ -152,7 +152,8 @@ const configPreprocessor: ConfigPreprocessorFn<AutomodPluginType> = options => {
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod", {
|
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
||||||
|
name: "automod",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: pluginInfo,
|
info: pluginInfo,
|
||||||
|
|
||||||
|
@ -168,8 +169,10 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod",
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
configPreprocessor,
|
configPreprocessor,
|
||||||
|
|
||||||
customOverrideMatcher(pluginData, criteria, matchParams) {
|
customOverrideCriteriaFunctions: {
|
||||||
return criteria?.antiraid_level ? criteria.antiraid_level === pluginData.state.cachedAntiraidLevel : false;
|
antiraid_level: (pluginData, matchParams, value) => {
|
||||||
|
return value ? value === pluginData.state.cachedAntiraidLevel : false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
@ -181,22 +184,16 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod",
|
||||||
|
|
||||||
commands: [AntiraidClearCmd, SetAntiraidCmd, ViewAntiraidCmd],
|
commands: [AntiraidClearCmd, SetAntiraidCmd, ViewAntiraidCmd],
|
||||||
|
|
||||||
async onLoad(pluginData) {
|
async beforeLoad(pluginData) {
|
||||||
pluginData.state.queue = new Queue();
|
pluginData.state.queue = new Queue();
|
||||||
|
|
||||||
pluginData.state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
pluginData.state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
||||||
|
|
||||||
pluginData.state.recentActions = [];
|
pluginData.state.recentActions = [];
|
||||||
pluginData.state.clearRecentActionsInterval = setInterval(() => clearOldRecentActions(pluginData), 1 * MINUTES);
|
|
||||||
|
|
||||||
pluginData.state.recentSpam = [];
|
pluginData.state.recentSpam = [];
|
||||||
pluginData.state.clearRecentSpamInterval = setInterval(() => clearOldRecentSpam(pluginData), 1 * SECONDS);
|
|
||||||
|
|
||||||
pluginData.state.recentNicknameChanges = new Map();
|
pluginData.state.recentNicknameChanges = new Map();
|
||||||
pluginData.state.clearRecentNicknameChangesInterval = setInterval(
|
|
||||||
() => clearOldRecentNicknameChanges(pluginData),
|
|
||||||
30 * SECONDS,
|
|
||||||
);
|
|
||||||
|
|
||||||
pluginData.state.ignoredRoleChanges = new Set();
|
pluginData.state.ignoredRoleChanges = new Set();
|
||||||
|
|
||||||
|
@ -207,16 +204,23 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod",
|
||||||
pluginData.state.antiraidLevels = GuildAntiraidLevels.getGuildInstance(pluginData.guild.id);
|
pluginData.state.antiraidLevels = GuildAntiraidLevels.getGuildInstance(pluginData.guild.id);
|
||||||
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
||||||
|
|
||||||
|
pluginData.state.cachedAntiraidLevel = await pluginData.state.antiraidLevels.get();
|
||||||
|
},
|
||||||
|
|
||||||
|
async afterLoad(pluginData) {
|
||||||
|
pluginData.state.clearRecentActionsInterval = setInterval(() => clearOldRecentActions(pluginData), 1 * MINUTES);
|
||||||
|
pluginData.state.clearRecentSpamInterval = setInterval(() => clearOldRecentSpam(pluginData), 1 * SECONDS);
|
||||||
|
pluginData.state.clearRecentNicknameChangesInterval = setInterval(
|
||||||
|
() => clearOldRecentNicknameChanges(pluginData),
|
||||||
|
30 * SECONDS,
|
||||||
|
);
|
||||||
|
|
||||||
pluginData.state.onMessageCreateFn = message => runAutomodOnMessage(pluginData, message, false);
|
pluginData.state.onMessageCreateFn = message => runAutomodOnMessage(pluginData, message, false);
|
||||||
pluginData.state.savedMessages.events.on("create", pluginData.state.onMessageCreateFn);
|
pluginData.state.savedMessages.events.on("create", pluginData.state.onMessageCreateFn);
|
||||||
|
|
||||||
pluginData.state.onMessageUpdateFn = message => runAutomodOnMessage(pluginData, message, true);
|
pluginData.state.onMessageUpdateFn = message => runAutomodOnMessage(pluginData, message, true);
|
||||||
pluginData.state.savedMessages.events.on("update", pluginData.state.onMessageUpdateFn);
|
pluginData.state.savedMessages.events.on("update", pluginData.state.onMessageUpdateFn);
|
||||||
|
|
||||||
pluginData.state.cachedAntiraidLevel = await pluginData.state.antiraidLevels.get();
|
|
||||||
},
|
|
||||||
|
|
||||||
async onAfterLoad(pluginData) {
|
|
||||||
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
||||||
|
|
||||||
pluginData.state.onCounterTrigger = (name, triggerName, channelId, userId) => {
|
pluginData.state.onCounterTrigger = (name, triggerName, channelId, userId) => {
|
||||||
|
@ -268,7 +272,7 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod",
|
||||||
registerEventListenersFromMap(mutesEvents, pluginData.state.mutesListeners);
|
registerEventListenersFromMap(mutesEvents, pluginData.state.mutesListeners);
|
||||||
},
|
},
|
||||||
|
|
||||||
async onBeforeUnload(pluginData) {
|
async beforeUnload(pluginData) {
|
||||||
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
||||||
countersPlugin.offCounterEvent("trigger", pluginData.state.onCounterTrigger);
|
countersPlugin.offCounterEvent("trigger", pluginData.state.onCounterTrigger);
|
||||||
countersPlugin.offCounterEvent("reverseTrigger", pluginData.state.onCounterReverseTrigger);
|
countersPlugin.offCounterEvent("reverseTrigger", pluginData.state.onCounterReverseTrigger);
|
||||||
|
@ -278,9 +282,7 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod",
|
||||||
|
|
||||||
const mutesEvents = pluginData.getPlugin(MutesPlugin).getEventEmitter();
|
const mutesEvents = pluginData.getPlugin(MutesPlugin).getEventEmitter();
|
||||||
unregisterEventListenersFromMap(mutesEvents, pluginData.state.mutesListeners);
|
unregisterEventListenersFromMap(mutesEvents, pluginData.state.mutesListeners);
|
||||||
},
|
|
||||||
|
|
||||||
async onUnload(pluginData) {
|
|
||||||
pluginData.state.queue.clear();
|
pluginData.state.queue.clear();
|
||||||
|
|
||||||
discardRegExpRunner(`guild-${pluginData.guild.id}`);
|
discardRegExpRunner(`guild-${pluginData.guild.id}`);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { guildCommand, GuildPluginData } from "knub";
|
import { typedGuildCommand, GuildPluginData } from "knub";
|
||||||
import { AutomodPluginType } from "../types";
|
import { AutomodPluginType } from "../types";
|
||||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||||
import { sendSuccessMessage } from "../../../pluginUtils";
|
import { sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
|
||||||
export const AntiraidClearCmd = guildCommand<AutomodPluginType>()({
|
export const AntiraidClearCmd = typedGuildCommand<AutomodPluginType>()({
|
||||||
trigger: ["antiraid clear", "antiraid reset", "antiraid none", "antiraid off"],
|
trigger: ["antiraid clear", "antiraid reset", "antiraid none", "antiraid off"],
|
||||||
permission: "can_set_antiraid",
|
permission: "can_set_antiraid",
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { guildCommand, GuildPluginData } from "knub";
|
import { typedGuildCommand, GuildPluginData } from "knub";
|
||||||
import { AutomodPluginType } from "../types";
|
import { AutomodPluginType } from "../types";
|
||||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
|
||||||
export const SetAntiraidCmd = guildCommand<AutomodPluginType>()({
|
export const SetAntiraidCmd = typedGuildCommand<AutomodPluginType>()({
|
||||||
trigger: "antiraid",
|
trigger: "antiraid",
|
||||||
permission: "can_set_antiraid",
|
permission: "can_set_antiraid",
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { guildCommand, GuildPluginData } from "knub";
|
import { typedGuildCommand, GuildPluginData } from "knub";
|
||||||
import { AutomodPluginType } from "../types";
|
import { AutomodPluginType } from "../types";
|
||||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
|
||||||
export const ViewAntiraidCmd = guildCommand<AutomodPluginType>()({
|
export const ViewAntiraidCmd = typedGuildCommand<AutomodPluginType>()({
|
||||||
trigger: "antiraid",
|
trigger: "antiraid",
|
||||||
permission: "can_view_antiraid",
|
permission: "can_view_antiraid",
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { guildEventListener } from "knub";
|
import { typedGuildEventListener } from "knub";
|
||||||
import { AutomodContext, AutomodPluginType } from "../types";
|
import { AutomodContext, AutomodPluginType } from "../types";
|
||||||
import { runAutomod } from "../functions/runAutomod";
|
import { runAutomod } from "../functions/runAutomod";
|
||||||
import { RecentActionType } from "../constants";
|
import { RecentActionType } from "../constants";
|
||||||
|
|
||||||
export const RunAutomodOnJoinEvt = guildEventListener<AutomodPluginType>()(
|
export const RunAutomodOnJoinEvt = typedGuildEventListener<AutomodPluginType>()({
|
||||||
"guildMemberAdd",
|
event: "guildMemberAdd",
|
||||||
({ pluginData, args: { member } }) => {
|
listener({ pluginData, args: { member } }) {
|
||||||
const context: AutomodContext = {
|
const context: AutomodContext = {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
user: member.user,
|
user: member.user,
|
||||||
|
@ -24,4 +24,4 @@ export const RunAutomodOnJoinEvt = guildEventListener<AutomodPluginType>()(
|
||||||
runAutomod(pluginData, context);
|
runAutomod(pluginData, context);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { guildEventListener } from "knub";
|
import { typedGuildEventListener } from "knub";
|
||||||
import { AutomodContext, AutomodPluginType } from "../types";
|
import { AutomodContext, AutomodPluginType } from "../types";
|
||||||
import { RecentActionType } from "../constants";
|
import { RecentActionType } from "../constants";
|
||||||
import { runAutomod } from "../functions/runAutomod";
|
import { runAutomod } from "../functions/runAutomod";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import diff from "lodash.difference";
|
import diff from "lodash.difference";
|
||||||
|
|
||||||
export const RunAutomodOnMemberUpdate = guildEventListener<AutomodPluginType>()(
|
export const RunAutomodOnMemberUpdate = typedGuildEventListener<AutomodPluginType>()({
|
||||||
"guildMemberUpdate",
|
event: "guildMemberUpdate",
|
||||||
({ pluginData, args: { member, oldMember } }) => {
|
listener({ pluginData, args: { member, oldMember } }) {
|
||||||
if (!oldMember) return;
|
if (!oldMember) return;
|
||||||
|
|
||||||
if (isEqual(oldMember.roles, member.roles)) return;
|
if (isEqual(oldMember.roles, member.roles)) return;
|
||||||
|
@ -31,4 +31,4 @@ export const RunAutomodOnMemberUpdate = guildEventListener<AutomodPluginType>()(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -15,7 +15,7 @@ export async function runAutomod(pluginData: GuildPluginData<AutomodPluginType>,
|
||||||
const channel = channelId ? (pluginData.guild.channels.get(channelId) as TextChannel) : null;
|
const channel = channelId ? (pluginData.guild.channels.get(channelId) as TextChannel) : null;
|
||||||
const categoryId = channel?.parentID;
|
const categoryId = channel?.parentID;
|
||||||
|
|
||||||
const config = pluginData.config.getMatchingConfig({
|
const config = await pluginData.config.getMatchingConfig({
|
||||||
channelId,
|
channelId,
|
||||||
categoryId,
|
categoryId,
|
||||||
userId,
|
userId,
|
||||||
|
|
|
@ -27,7 +27,8 @@ const defaultOptions = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()("bot_control", {
|
export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()({
|
||||||
|
name: "bot_control",
|
||||||
configSchema: ConfigSchema,
|
configSchema: ConfigSchema,
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()("bo
|
||||||
EligibleCmd,
|
EligibleCmd,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
afterLoad(pluginData) {
|
||||||
pluginData.state.archives = new GuildArchives(0);
|
pluginData.state.archives = new GuildArchives(0);
|
||||||
pluginData.state.allowedGuilds = new AllowedGuilds();
|
pluginData.state.allowedGuilds = new AllowedGuilds();
|
||||||
pluginData.state.configs = new Configs();
|
pluginData.state.configs = new Configs();
|
||||||
|
|
|
@ -45,26 +45,36 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
|
|
||||||
// If we have user, always display which guilds they have permissions in (or only specified guild permissions)
|
// If we have user, always display which guilds they have permissions in (or only specified guild permissions)
|
||||||
if (args.user) {
|
if (args.user) {
|
||||||
|
const userInfo = `**${args.user.username}#${args.user.discriminator}** (\`${args.user.id}\`)`;
|
||||||
|
|
||||||
for (const assignment of existingUserAssignment!) {
|
for (const assignment of existingUserAssignment!) {
|
||||||
if (guild != null && assignment.guild_id !== args.guildId) continue;
|
if (guild != null && assignment.guild_id !== args.guildId) continue;
|
||||||
finalMessage += `The user has the following permissions on server \`${
|
const assignmentGuild = await pluginData.state.allowedGuilds.find(assignment.guild_id);
|
||||||
assignment.guild_id
|
const guildName = assignmentGuild?.name ?? "Unknown";
|
||||||
}\`:\n${assignment.permissions.join("\n")}\n\n`;
|
const guildInfo = `**${guildName}** (\`${assignment.guild_id}\`)`;
|
||||||
|
finalMessage += `The user ${userInfo} has the following permissions on server ${guildInfo}:`;
|
||||||
|
finalMessage += `\n${assignment.permissions.join("\n")}\n\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finalMessage === "") {
|
if (finalMessage === "") {
|
||||||
sendErrorMessage(pluginData, msg.channel, "The user has no assigned permissions on the specified server.");
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`The user ${userInfo} has no assigned permissions on the specified server.`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Else display all users that have permissions on the specified guild
|
// Else display all users that have permissions on the specified guild
|
||||||
} else if (guild) {
|
} else if (guild) {
|
||||||
|
const guildInfo = `**${guild.name}** (\`${guild.id}\`)`;
|
||||||
|
|
||||||
const existingGuildAssignment = await pluginData.state.apiPermissionAssignments.getByGuildId(guild.id);
|
const existingGuildAssignment = await pluginData.state.apiPermissionAssignments.getByGuildId(guild.id);
|
||||||
if (existingGuildAssignment.length === 0) {
|
if (existingGuildAssignment.length === 0) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "The server has no assigned permissions.");
|
sendErrorMessage(pluginData, msg.channel, `The server ${guildInfo} has no assigned permissions.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
finalMessage += `The server \`${guild.id}\` has the following assigned permissions:\n`; // Double \n for consistency with AddDashboardUserCmd
|
finalMessage += `The server ${guildInfo} has the following assigned permissions:\n`; // Double \n for consistency with AddDashboardUserCmd
|
||||||
for (const assignment of existingGuildAssignment) {
|
for (const assignment of existingGuildAssignment) {
|
||||||
const user = await resolveUser(pluginData.client, assignment.target_id);
|
const user = await resolveUser(pluginData.client, assignment.target_id);
|
||||||
finalMessage += `\n**${user.username}#${user.discriminator}**, \`${
|
finalMessage += `\n**${user.username}#${user.discriminator}**, \`${
|
||||||
|
|
|
@ -2,7 +2,8 @@ import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
import { resolveUser } from "../../../utils";
|
import { resolveUser, UnknownUser } from "../../../utils";
|
||||||
|
import { User } from "eris";
|
||||||
|
|
||||||
export const ListDashboardUsersCmd = botControlCmd({
|
export const ListDashboardUsersCmd = botControlCmd({
|
||||||
trigger: ["list_dashboard_users"],
|
trigger: ["list_dashboard_users"],
|
||||||
|
|
|
@ -16,6 +16,6 @@ export const ReloadGlobalPluginsCmd = botControlCmd({
|
||||||
setActiveReload((message.channel as TextChannel).guild?.id, message.channel.id);
|
setActiveReload((message.channel as TextChannel).guild?.id, message.channel.id);
|
||||||
await message.channel.createMessage("Reloading global plugins...");
|
await message.channel.createMessage("Reloading global plugins...");
|
||||||
|
|
||||||
pluginData.getKnubInstance().reloadAllGlobalPlugins();
|
pluginData.getKnubInstance().reloadGlobalContext();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { tNullable } from "../../utils";
|
import { tNullable } from "../../utils";
|
||||||
import { BasePluginType, globalCommand, globalEventListener } from "knub";
|
import { BasePluginType, typedGlobalCommand, typedGlobalEventListener } from "knub";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
||||||
|
@ -23,5 +23,5 @@ export interface BotControlPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const botControlCmd = globalCommand<BotControlPluginType>();
|
export const botControlCmd = typedGlobalCommand<BotControlPluginType>();
|
||||||
export const botControlEvt = globalEventListener<BotControlPluginType>();
|
export const botControlEvt = typedGlobalEventListener<BotControlPluginType>();
|
||||||
|
|
|
@ -28,7 +28,8 @@ const defaultOptions = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CasesPlugin = zeppelinGuildPlugin<CasesPluginType>()("cases", {
|
export const CasesPlugin = zeppelinGuildPlugin<CasesPluginType>()({
|
||||||
|
name: "cases",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Cases",
|
prettyName: "Cases",
|
||||||
|
@ -73,7 +74,7 @@ export const CasesPlugin = zeppelinGuildPlugin<CasesPluginType>()("cases", {
|
||||||
getCaseSummary: mapToPublicFn(getCaseSummary),
|
getCaseSummary: mapToPublicFn(getCaseSummary),
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(pluginData) {
|
afterLoad(pluginData) {
|
||||||
pluginData.state.logs = new GuildLogs(pluginData.guild.id);
|
pluginData.state.logs = new GuildLogs(pluginData.guild.id);
|
||||||
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
||||||
pluginData.state.cases = GuildCases.getGuildInstance(pluginData.guild.id);
|
pluginData.state.cases = GuildCases.getGuildInstance(pluginData.guild.id);
|
||||||
|
|
|
@ -46,7 +46,7 @@ export async function createCaseNote(pluginData: GuildPluginData<CasesPluginType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const modConfig = pluginData.config.getForUser(mod);
|
const modConfig = await pluginData.config.getForUser(mod);
|
||||||
if (
|
if (
|
||||||
args.postInCaseLogOverride === true ||
|
args.postInCaseLogOverride === true ||
|
||||||
((!args.automatic || modConfig.log_automatic_actions) && args.postInCaseLogOverride !== false)
|
((!args.automatic || modConfig.log_automatic_actions) && args.postInCaseLogOverride !== false)
|
||||||
|
|
|
@ -13,6 +13,7 @@ export async function getCaseEmbed(
|
||||||
pluginData: GuildPluginData<CasesPluginType>,
|
pluginData: GuildPluginData<CasesPluginType>,
|
||||||
caseOrCaseId: Case | number,
|
caseOrCaseId: Case | number,
|
||||||
requestMemberId?: string,
|
requestMemberId?: string,
|
||||||
|
noOriginalCaseLink?: boolean,
|
||||||
): Promise<AdvancedMessageContent> {
|
): Promise<AdvancedMessageContent> {
|
||||||
const theCase = await pluginData.state.cases.with("notes").find(resolveCaseId(caseOrCaseId));
|
const theCase = await pluginData.state.cases.with("notes").find(resolveCaseId(caseOrCaseId));
|
||||||
if (!theCase) {
|
if (!theCase) {
|
||||||
|
@ -98,7 +99,7 @@ export async function getCaseEmbed(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theCase.log_message_id) {
|
if (theCase.log_message_id && noOriginalCaseLink !== false) {
|
||||||
const [channelId, messageId] = theCase.log_message_id.split("-");
|
const [channelId, messageId] = theCase.log_message_id.split("-");
|
||||||
const link = messageLink(pluginData.guild.id, channelId, messageId);
|
const link = messageLink(pluginData.guild.id, channelId, messageId);
|
||||||
embed.fields.push({
|
embed.fields.push({
|
||||||
|
|
|
@ -43,7 +43,7 @@ export async function postCaseToCaseLogChannel(
|
||||||
const theCase = await pluginData.state.cases.find(resolveCaseId(caseOrCaseId));
|
const theCase = await pluginData.state.cases.find(resolveCaseId(caseOrCaseId));
|
||||||
if (!theCase) return null;
|
if (!theCase) return null;
|
||||||
|
|
||||||
const caseEmbed = await getCaseEmbed(pluginData, caseOrCaseId);
|
const caseEmbed = await getCaseEmbed(pluginData, caseOrCaseId, undefined, true);
|
||||||
if (!caseEmbed) return null;
|
if (!caseEmbed) return null;
|
||||||
|
|
||||||
if (theCase.log_message_id) {
|
if (theCase.log_message_id) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { tDelayString, tPartialDictionary, tNullable } from "../../utils";
|
import { tDelayString, tPartialDictionary, tNullable } from "../../utils";
|
||||||
import { CaseNameToType, CaseTypes } from "../../data/CaseTypes";
|
import { CaseNameToType, CaseTypes } from "../../data/CaseTypes";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
|
|
|
@ -43,7 +43,8 @@ const defaultOptions: PluginOptions<CensorPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CensorPlugin = zeppelinGuildPlugin<CensorPluginType>()("censor", {
|
export const CensorPlugin = zeppelinGuildPlugin<CensorPluginType>()({
|
||||||
|
name: "censor",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Censor",
|
prettyName: "Censor",
|
||||||
|
@ -57,13 +58,17 @@ export const CensorPlugin = zeppelinGuildPlugin<CensorPluginType>()("censor", {
|
||||||
configSchema: ConfigSchema,
|
configSchema: ConfigSchema,
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.serverLogs = new GuildLogs(guild.id);
|
state.serverLogs = new GuildLogs(guild.id);
|
||||||
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
||||||
|
|
||||||
state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.onMessageCreateFn = msg => onMessageCreate(pluginData, msg);
|
state.onMessageCreateFn = msg => onMessageCreate(pluginData, msg);
|
||||||
state.savedMessages.events.on("create", state.onMessageCreateFn);
|
state.savedMessages.events.on("create", state.onMessageCreateFn);
|
||||||
|
@ -72,7 +77,7 @@ export const CensorPlugin = zeppelinGuildPlugin<CensorPluginType>()("censor", {
|
||||||
state.savedMessages.events.on("update", state.onMessageUpdateFn);
|
state.savedMessages.events.on("update", state.onMessageUpdateFn);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
discardRegExpRunner(`guild-${pluginData.guild.id}`);
|
discardRegExpRunner(`guild-${pluginData.guild.id}`);
|
||||||
|
|
||||||
pluginData.state.savedMessages.events.off("create", pluginData.state.onMessageCreateFn);
|
pluginData.state.savedMessages.events.off("create", pluginData.state.onMessageCreateFn);
|
||||||
|
|
|
@ -15,7 +15,7 @@ export async function applyFiltersToMsg(
|
||||||
savedMessage: SavedMessage,
|
savedMessage: SavedMessage,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, savedMessage.user_id);
|
const member = await resolveMember(pluginData.client, pluginData.guild, savedMessage.user_id);
|
||||||
const config = pluginData.config.getMatchingConfig({ member, channelId: savedMessage.channel_id });
|
const config = await pluginData.config.getMatchingConfig({ member, channelId: savedMessage.channel_id });
|
||||||
|
|
||||||
let messageContent = savedMessage.data.content || "";
|
let messageContent = savedMessage.data.content || "";
|
||||||
if (savedMessage.data.attachments) messageContent += " " + JSON.stringify(savedMessage.data.attachments);
|
if (savedMessage.data.attachments) messageContent += " " + JSON.stringify(savedMessage.data.attachments);
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
|
|
||||||
export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginType>()("channel_archiver", {
|
export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginType>()({
|
||||||
|
name: "channel_archiver",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
dependencies: [TimeAndDatePlugin],
|
dependencies: [TimeAndDatePlugin],
|
||||||
|
@ -13,9 +14,5 @@ export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginTy
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
commands: [
|
commands: [
|
||||||
ArchiveChannelCmd,
|
ArchiveChannelCmd,
|
||||||
],
|
]
|
||||||
|
|
||||||
onLoad(pluginData) {
|
|
||||||
const { state, guild } = pluginData;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { BasePluginType, guildCommand } from "knub";
|
import { BasePluginType, typedGuildCommand } from "knub";
|
||||||
|
|
||||||
export interface ChannelArchiverPluginType extends BasePluginType {
|
export interface ChannelArchiverPluginType extends BasePluginType {
|
||||||
state: {};
|
state: {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const channelArchiverCmd = guildCommand<ChannelArchiverPluginType>();
|
export const channelArchiverCmd = typedGuildCommand<ChannelArchiverPluginType>();
|
||||||
|
|
|
@ -13,7 +13,8 @@ const defaultOptions = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CompanionChannelsPlugin = zeppelinGuildPlugin<CompanionChannelsPluginType>()("companion_channels", {
|
export const CompanionChannelsPlugin = zeppelinGuildPlugin<CompanionChannelsPluginType>()({
|
||||||
|
name: "companion_channels",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Companion channels",
|
prettyName: "Companion channels",
|
||||||
|
@ -30,7 +31,7 @@ export const CompanionChannelsPlugin = zeppelinGuildPlugin<CompanionChannelsPlug
|
||||||
|
|
||||||
events: [VoiceChannelJoinEvt, VoiceChannelSwitchEvt, VoiceChannelLeaveEvt],
|
events: [VoiceChannelJoinEvt, VoiceChannelSwitchEvt, VoiceChannelLeaveEvt],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
pluginData.state.errorCooldownManager = new CooldownManager();
|
pluginData.state.errorCooldownManager = new CooldownManager();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { companionChannelsEvt } from "../types";
|
||||||
import { handleCompanionPermissions } from "../functions/handleCompanionPermissions";
|
import { handleCompanionPermissions } from "../functions/handleCompanionPermissions";
|
||||||
import { stripObjectToScalars } from "../../../utils";
|
import { stripObjectToScalars } from "../../../utils";
|
||||||
|
|
||||||
export const VoiceChannelJoinEvt = companionChannelsEvt(
|
export const VoiceChannelJoinEvt = companionChannelsEvt({
|
||||||
"voiceChannelJoin",
|
event: "voiceChannelJoin",
|
||||||
({ pluginData, args: { member, newChannel } }) => {
|
listener({ pluginData, args: { member, newChannel } }) {
|
||||||
handleCompanionPermissions(pluginData, member.id, newChannel);
|
handleCompanionPermissions(pluginData, member.id, newChannel);
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { companionChannelsEvt } from "../types";
|
import { companionChannelsEvt } from "../types";
|
||||||
import { handleCompanionPermissions } from "../functions/handleCompanionPermissions";
|
import { handleCompanionPermissions } from "../functions/handleCompanionPermissions";
|
||||||
|
|
||||||
export const VoiceChannelLeaveEvt = companionChannelsEvt(
|
export const VoiceChannelLeaveEvt = companionChannelsEvt({
|
||||||
"voiceChannelLeave",
|
event: "voiceChannelLeave",
|
||||||
({ pluginData, args: { member, oldChannel } }) => {
|
listener({ pluginData, args: { member, oldChannel } }) {
|
||||||
handleCompanionPermissions(pluginData, member.id, null, oldChannel);
|
handleCompanionPermissions(pluginData, member.id, null, oldChannel);
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { companionChannelsEvt } from "../types";
|
import { companionChannelsEvt } from "../types";
|
||||||
import { handleCompanionPermissions } from "../functions/handleCompanionPermissions";
|
import { handleCompanionPermissions } from "../functions/handleCompanionPermissions";
|
||||||
|
|
||||||
export const VoiceChannelSwitchEvt = companionChannelsEvt(
|
export const VoiceChannelSwitchEvt = companionChannelsEvt({
|
||||||
"voiceChannelSwitch",
|
event: "voiceChannelSwitch",
|
||||||
({ pluginData, args: { member, oldChannel, newChannel } }) => {
|
listener({ pluginData, args: { member, oldChannel, newChannel } }) {
|
||||||
handleCompanionPermissions(pluginData, member.id, newChannel, oldChannel);
|
handleCompanionPermissions(pluginData, member.id, newChannel, oldChannel);
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -6,12 +6,12 @@ const defaultCompanionChannelOpts: Partial<TCompanionChannelOpts> = {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getCompanionChannelOptsForVoiceChannelId(
|
export async function getCompanionChannelOptsForVoiceChannelId(
|
||||||
pluginData: GuildPluginData<CompanionChannelsPluginType>,
|
pluginData: GuildPluginData<CompanionChannelsPluginType>,
|
||||||
userId: string,
|
userId: string,
|
||||||
voiceChannel: VoiceChannel,
|
voiceChannel: VoiceChannel,
|
||||||
): TCompanionChannelOpts[] {
|
): Promise<TCompanionChannelOpts[]> {
|
||||||
const config = pluginData.config.getMatchingConfig({ userId, channelId: voiceChannel.id });
|
const config = await pluginData.config.getMatchingConfig({ userId, channelId: voiceChannel.id });
|
||||||
return Object.values(config.entries)
|
return Object.values(config.entries)
|
||||||
.filter(
|
.filter(
|
||||||
opts =>
|
opts =>
|
||||||
|
|
|
@ -36,10 +36,10 @@ export async function handleCompanionPermissions(
|
||||||
const permsToSet: Map<string, number> = new Map(); // channelId => permissions
|
const permsToSet: Map<string, number> = new Map(); // channelId => permissions
|
||||||
|
|
||||||
const oldChannelOptsArr: TCompanionChannelOpts[] = oldChannel
|
const oldChannelOptsArr: TCompanionChannelOpts[] = oldChannel
|
||||||
? getCompanionChannelOptsForVoiceChannelId(pluginData, userId, oldChannel)
|
? await getCompanionChannelOptsForVoiceChannelId(pluginData, userId, oldChannel)
|
||||||
: [];
|
: [];
|
||||||
const newChannelOptsArr: TCompanionChannelOpts[] = voiceChannel
|
const newChannelOptsArr: TCompanionChannelOpts[] = voiceChannel
|
||||||
? getCompanionChannelOptsForVoiceChannelId(pluginData, userId, voiceChannel)
|
? await getCompanionChannelOptsForVoiceChannelId(pluginData, userId, voiceChannel)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
for (const oldChannelOpts of oldChannelOptsArr) {
|
for (const oldChannelOpts of oldChannelOptsArr) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { tNullable } from "../../utils";
|
import { tNullable } from "../../utils";
|
||||||
import { BasePluginType, CooldownManager, guildEventListener } from "knub";
|
import { BasePluginType, CooldownManager, typedGuildEventListener } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
|
||||||
|
@ -29,4 +29,4 @@ export interface CompanionChannelsPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const companionChannelsEvt = guildEventListener<CompanionChannelsPluginType>();
|
export const companionChannelsEvt = typedGuildEventListener<CompanionChannelsPluginType>();
|
||||||
|
|
|
@ -106,7 +106,8 @@ const configPreprocessor: ConfigPreprocessorFn<CountersPluginType> = options =>
|
||||||
* A single trigger can only trigger once per user/channel/in general, depending on how specific the counter is (e.g. a per-user trigger can only trigger once per user).
|
* A single trigger can only trigger once per user/channel/in general, depending on how specific the counter is (e.g. a per-user trigger can only trigger once per user).
|
||||||
* After being triggered, a trigger is "reset" if the counter value no longer matches the trigger (e.g. drops to 100 or below in the above example). After this, that trigger can be triggered again.
|
* After being triggered, a trigger is "reset" if the counter value no longer matches the trigger (e.g. drops to 100 or below in the above example). After this, that trigger can be triggered again.
|
||||||
*/
|
*/
|
||||||
export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()("counters", {
|
export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()({
|
||||||
|
name: "counters",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Counters",
|
prettyName: "Counters",
|
||||||
|
@ -145,7 +146,7 @@ export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()("counter
|
||||||
ResetAllCounterValuesCmd,
|
ResetAllCounterValuesCmd,
|
||||||
],
|
],
|
||||||
|
|
||||||
async onLoad(pluginData) {
|
async beforeLoad(pluginData) {
|
||||||
pluginData.state.counters = new GuildCounters(pluginData.guild.id);
|
pluginData.state.counters = new GuildCounters(pluginData.guild.id);
|
||||||
pluginData.state.events = new EventEmitter();
|
pluginData.state.events = new EventEmitter();
|
||||||
pluginData.state.counterTriggersByCounterId = new Map();
|
pluginData.state.counterTriggersByCounterId = new Map();
|
||||||
|
@ -189,6 +190,10 @@ export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()("counter
|
||||||
|
|
||||||
// Mark old/unused triggers to be deleted later
|
// Mark old/unused triggers to be deleted later
|
||||||
await pluginData.state.counters.markUnusedTriggersToBeDeleted(activeTriggerIds);
|
await pluginData.state.counters.markUnusedTriggersToBeDeleted(activeTriggerIds);
|
||||||
|
},
|
||||||
|
|
||||||
|
async afterLoad(pluginData) {
|
||||||
|
const config = pluginData.config.get();
|
||||||
|
|
||||||
// Start decay timers
|
// Start decay timers
|
||||||
pluginData.state.decayTimers = [];
|
pluginData.state.decayTimers = [];
|
||||||
|
@ -207,7 +212,7 @@ export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()("counter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
for (const interval of pluginData.state.decayTimers) {
|
for (const interval of pluginData.state.decayTimers) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { guildCommand } from "knub";
|
import { typedGuildCommand } from "knub";
|
||||||
import { CountersPluginType } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage } from "../../../pluginUtils";
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
@ -7,7 +7,7 @@ import { TextChannel, User } from "eris";
|
||||||
import { resolveUser, UnknownUser } from "../../../utils";
|
import { resolveUser, UnknownUser } from "../../../utils";
|
||||||
import { changeCounterValue } from "../functions/changeCounterValue";
|
import { changeCounterValue } from "../functions/changeCounterValue";
|
||||||
|
|
||||||
export const AddCounterCmd = guildCommand<CountersPluginType>()({
|
export const AddCounterCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
trigger: ["counters add", "counter add", "addcounter"],
|
trigger: ["counters add", "counter add", "addcounter"],
|
||||||
permission: "can_edit",
|
permission: "can_edit",
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ export const AddCounterCmd = guildCommand<CountersPluginType>()({
|
||||||
],
|
],
|
||||||
|
|
||||||
async run({ pluginData, message, args }) {
|
async run({ pluginData, message, args }) {
|
||||||
const config = pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
const counter = config.counters[args.counterName];
|
const counter = config.counters[args.counterName];
|
||||||
const counterId = pluginData.state.counterIds[args.counterName];
|
const counterId = pluginData.state.counterIds[args.counterName];
|
||||||
if (!counter || !counterId) {
|
if (!counter || !counterId) {
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { guildCommand } from "knub";
|
import { typedGuildCommand } from "knub";
|
||||||
import { CountersPluginType } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
import { sendErrorMessage } from "../../../pluginUtils";
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
import { trimMultilineString, ucfirst } from "../../../utils";
|
import { trimMultilineString, ucfirst } from "../../../utils";
|
||||||
import { getGuildPrefix } from "../../../utils/getGuildPrefix";
|
import { getGuildPrefix } from "../../../utils/getGuildPrefix";
|
||||||
|
|
||||||
export const CountersListCmd = guildCommand<CountersPluginType>()({
|
export const CountersListCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
trigger: ["counters list", "counter list", "counters"],
|
trigger: ["counters list", "counter list", "counters"],
|
||||||
permission: "can_view",
|
permission: "can_view",
|
||||||
|
|
||||||
signature: {},
|
signature: {},
|
||||||
|
|
||||||
async run({ pluginData, message, args }) {
|
async run({ pluginData, message, args }) {
|
||||||
const config = pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
|
|
||||||
const countersToShow = Array.from(Object.values(config.counters)).filter(c => c.can_view !== false);
|
const countersToShow = Array.from(Object.values(config.counters)).filter(c => c.can_view !== false);
|
||||||
if (!countersToShow.length) {
|
if (!countersToShow.length) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { guildCommand } from "knub";
|
import { typedGuildCommand } from "knub";
|
||||||
import { CountersPluginType } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
@ -10,7 +10,7 @@ import { setCounterValue } from "../functions/setCounterValue";
|
||||||
import { resetAllCounterValues } from "../functions/resetAllCounterValues";
|
import { resetAllCounterValues } from "../functions/resetAllCounterValues";
|
||||||
import { counterIdLock } from "../../../utils/lockNameHelpers";
|
import { counterIdLock } from "../../../utils/lockNameHelpers";
|
||||||
|
|
||||||
export const ResetAllCounterValuesCmd = guildCommand<CountersPluginType>()({
|
export const ResetAllCounterValuesCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
trigger: ["counters reset_all"],
|
trigger: ["counters reset_all"],
|
||||||
permission: "can_reset_all",
|
permission: "can_reset_all",
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export const ResetAllCounterValuesCmd = guildCommand<CountersPluginType>()({
|
||||||
},
|
},
|
||||||
|
|
||||||
async run({ pluginData, message, args }) {
|
async run({ pluginData, message, args }) {
|
||||||
const config = pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
const counter = config.counters[args.counterName];
|
const counter = config.counters[args.counterName];
|
||||||
const counterId = pluginData.state.counterIds[args.counterName];
|
const counterId = pluginData.state.counterIds[args.counterName];
|
||||||
if (!counter || !counterId) {
|
if (!counter || !counterId) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { guildCommand } from "knub";
|
import { typedGuildCommand } from "knub";
|
||||||
import { CountersPluginType } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage } from "../../../pluginUtils";
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
@ -7,7 +7,7 @@ import { TextChannel } from "eris";
|
||||||
import { resolveUser, UnknownUser } from "../../../utils";
|
import { resolveUser, UnknownUser } from "../../../utils";
|
||||||
import { setCounterValue } from "../functions/setCounterValue";
|
import { setCounterValue } from "../functions/setCounterValue";
|
||||||
|
|
||||||
export const ResetCounterCmd = guildCommand<CountersPluginType>()({
|
export const ResetCounterCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
trigger: ["counters reset", "counter reset", "resetcounter"],
|
trigger: ["counters reset", "counter reset", "resetcounter"],
|
||||||
permission: "can_edit",
|
permission: "can_edit",
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export const ResetCounterCmd = guildCommand<CountersPluginType>()({
|
||||||
],
|
],
|
||||||
|
|
||||||
async run({ pluginData, message, args }) {
|
async run({ pluginData, message, args }) {
|
||||||
const config = pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
const counter = config.counters[args.counterName];
|
const counter = config.counters[args.counterName];
|
||||||
const counterId = pluginData.state.counterIds[args.counterName];
|
const counterId = pluginData.state.counterIds[args.counterName];
|
||||||
if (!counter || !counterId) {
|
if (!counter || !counterId) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { guildCommand } from "knub";
|
import { typedGuildCommand } from "knub";
|
||||||
import { CountersPluginType } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage } from "../../../pluginUtils";
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
@ -8,7 +8,7 @@ import { resolveUser, UnknownUser } from "../../../utils";
|
||||||
import { changeCounterValue } from "../functions/changeCounterValue";
|
import { changeCounterValue } from "../functions/changeCounterValue";
|
||||||
import { setCounterValue } from "../functions/setCounterValue";
|
import { setCounterValue } from "../functions/setCounterValue";
|
||||||
|
|
||||||
export const SetCounterCmd = guildCommand<CountersPluginType>()({
|
export const SetCounterCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
trigger: ["counters set", "counter set", "setcounter"],
|
trigger: ["counters set", "counter set", "setcounter"],
|
||||||
permission: "can_edit",
|
permission: "can_edit",
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export const SetCounterCmd = guildCommand<CountersPluginType>()({
|
||||||
],
|
],
|
||||||
|
|
||||||
async run({ pluginData, message, args }) {
|
async run({ pluginData, message, args }) {
|
||||||
const config = pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
const counter = config.counters[args.counterName];
|
const counter = config.counters[args.counterName];
|
||||||
const counterId = pluginData.state.counterIds[args.counterName];
|
const counterId = pluginData.state.counterIds[args.counterName];
|
||||||
if (!counter || !counterId) {
|
if (!counter || !counterId) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { guildCommand } from "knub";
|
import { typedGuildCommand } from "knub";
|
||||||
import { CountersPluginType } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage } from "../../../pluginUtils";
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
|
@ -6,7 +6,7 @@ import { resolveChannel, waitForReply } from "knub/dist/helpers";
|
||||||
import { TextChannel, User } from "eris";
|
import { TextChannel, User } from "eris";
|
||||||
import { resolveUser, UnknownUser } from "../../../utils";
|
import { resolveUser, UnknownUser } from "../../../utils";
|
||||||
|
|
||||||
export const ViewCounterCmd = guildCommand<CountersPluginType>()({
|
export const ViewCounterCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
trigger: ["counters view", "counter view", "viewcounter", "counter"],
|
trigger: ["counters view", "counter view", "viewcounter", "counter"],
|
||||||
permission: "can_view",
|
permission: "can_view",
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ export const ViewCounterCmd = guildCommand<CountersPluginType>()({
|
||||||
],
|
],
|
||||||
|
|
||||||
async run({ pluginData, message, args }) {
|
async run({ pluginData, message, args }) {
|
||||||
const config = pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
const counter = config.counters[args.counterName];
|
const counter = config.counters[args.counterName];
|
||||||
const counterId = pluginData.state.counterIds[args.counterName];
|
const counterId = pluginData.state.counterIds[args.counterName];
|
||||||
if (!counter || !counterId) {
|
if (!counter || !counterId) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { ConfigSchema, CustomEventsPluginType } from "./types";
|
import { ConfigSchema, CustomEventsPluginType } from "./types";
|
||||||
import { guildCommand, parseSignature } from "knub";
|
import { typedGuildCommand, parseSignature } from "knub";
|
||||||
import { commandTypes } from "../../commandTypes";
|
import { commandTypes } from "../../commandTypes";
|
||||||
import { stripObjectToScalars } from "../../utils";
|
import { stripObjectToScalars } from "../../utils";
|
||||||
import { runEvent } from "./functions/runEvent";
|
import { runEvent } from "./functions/runEvent";
|
||||||
|
@ -11,18 +11,19 @@ const defaultOptions = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CustomEventsPlugin = zeppelinGuildPlugin<CustomEventsPluginType>()("custom_events", {
|
export const CustomEventsPlugin = zeppelinGuildPlugin<CustomEventsPluginType>()({
|
||||||
|
name: "custom_events",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configSchema: ConfigSchema,
|
configSchema: ConfigSchema,
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
onLoad(pluginData) {
|
afterLoad(pluginData) {
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
for (const [key, event] of Object.entries(config.events)) {
|
for (const [key, event] of Object.entries(config.events)) {
|
||||||
if (event.trigger.type === "command") {
|
if (event.trigger.type === "command") {
|
||||||
const signature = event.trigger.params ? parseSignature(event.trigger.params, commandTypes) : {};
|
const signature = event.trigger.params ? parseSignature(event.trigger.params, commandTypes) : {};
|
||||||
const eventCommand = guildCommand({
|
const eventCommand = typedGuildCommand({
|
||||||
trigger: event.trigger.name,
|
trigger: event.trigger.name,
|
||||||
permission: `events.${key}.trigger.can_use`,
|
permission: `events.${key}.trigger.can_use`,
|
||||||
signature,
|
signature,
|
||||||
|
@ -36,7 +37,7 @@ export const CustomEventsPlugin = zeppelinGuildPlugin<CustomEventsPluginType>()(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload() {
|
beforeUnload() {
|
||||||
// TODO: Run clearTriggers() once we actually have something there
|
// TODO: Run clearTriggers() once we actually have something there
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { BasePluginType, globalEventListener, GlobalPluginData } from "knub";
|
import { BasePluginType, typedGlobalEventListener, GlobalPluginData } from "knub";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
import { Guild } from "eris";
|
import { Guild } from "eris";
|
||||||
|
@ -14,25 +14,32 @@ interface GuildAccessMonitorPluginType extends BasePluginType {
|
||||||
async function checkGuild(pluginData: GlobalPluginData<GuildAccessMonitorPluginType>, guild: Guild) {
|
async function checkGuild(pluginData: GlobalPluginData<GuildAccessMonitorPluginType>, guild: Guild) {
|
||||||
if (!(await pluginData.state.allowedGuilds.isAllowed(guild.id))) {
|
if (!(await pluginData.state.allowedGuilds.isAllowed(guild.id))) {
|
||||||
console.log(`Non-allowed server ${guild.name} (${guild.id}), leaving`);
|
console.log(`Non-allowed server ${guild.name} (${guild.id}), leaving`);
|
||||||
guild.leave();
|
console.log("[Temporarily not leaving automatically]");
|
||||||
|
// guild.leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global plugin to monitor if Zeppelin is invited to a non-whitelisted server, and leave it
|
* Global plugin to monitor if Zeppelin is invited to a non-whitelisted server, and leave it
|
||||||
*/
|
*/
|
||||||
export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorPluginType>()("guild_access_monitor", {
|
export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorPluginType>()({
|
||||||
|
name: "guild_access_monitor",
|
||||||
configSchema: t.type({}),
|
configSchema: t.type({}),
|
||||||
|
|
||||||
events: [
|
events: [
|
||||||
globalEventListener<GuildAccessMonitorPluginType>()("guildAvailable", ({ pluginData, args: { guild } }) => {
|
typedGlobalEventListener<GuildAccessMonitorPluginType>()({
|
||||||
checkGuild(pluginData, guild);
|
event: "guildAvailable",
|
||||||
|
listener({ pluginData, args: { guild } }) {
|
||||||
|
checkGuild(pluginData, guild);
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
pluginData.state.allowedGuilds = new AllowedGuilds();
|
pluginData.state.allowedGuilds = new AllowedGuilds();
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
for (const guild of pluginData.client.guilds.values()) {
|
for (const guild of pluginData.client.guilds.values()) {
|
||||||
checkGuild(pluginData, guild);
|
checkGuild(pluginData, guild);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,23 @@ import { Configs } from "../../data/Configs";
|
||||||
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds";
|
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
|
|
||||||
export const GuildConfigReloaderPlugin = zeppelinGlobalPlugin<GuildConfigReloaderPluginType>()(
|
export const GuildConfigReloaderPlugin = zeppelinGlobalPlugin<GuildConfigReloaderPluginType>()({
|
||||||
"guild_config_reloader",
|
name: "guild_config_reloader",
|
||||||
{
|
showInDocs: false,
|
||||||
showInDocs: false,
|
|
||||||
|
|
||||||
configSchema: t.type({}),
|
configSchema: t.type({}),
|
||||||
|
|
||||||
async onLoad(pluginData) {
|
async beforeLoad(pluginData) {
|
||||||
pluginData.state.guildConfigs = new Configs();
|
pluginData.state.guildConfigs = new Configs();
|
||||||
pluginData.state.highestConfigId = await pluginData.state.guildConfigs.getHighestId();
|
pluginData.state.highestConfigId = await pluginData.state.guildConfigs.getHighestId();
|
||||||
|
|
||||||
reloadChangedGuilds(pluginData);
|
|
||||||
},
|
|
||||||
|
|
||||||
onUnload(pluginData) {
|
|
||||||
clearTimeout(pluginData.state.nextCheckTimeout);
|
|
||||||
pluginData.state.unloaded = true;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
);
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
|
reloadChangedGuilds(pluginData);
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeUnload(pluginData) {
|
||||||
|
clearTimeout(pluginData.state.nextCheckTimeout);
|
||||||
|
pluginData.state.unloaded = true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -5,18 +5,23 @@ import { GuildInfoSaverPluginType } from "./types";
|
||||||
import { MINUTES } from "../../utils";
|
import { MINUTES } from "../../utils";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
|
|
||||||
export const GuildInfoSaverPlugin = zeppelinGuildPlugin<GuildInfoSaverPluginType>()("guild_info_saver", {
|
export const GuildInfoSaverPlugin = zeppelinGuildPlugin<GuildInfoSaverPluginType>()({
|
||||||
|
name: "guild_info_saver",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configSchema: t.type({}),
|
configSchema: t.type({}),
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
pluginData.state.allowedGuilds = new AllowedGuilds();
|
||||||
|
},
|
||||||
state.allowedGuilds = new AllowedGuilds();
|
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
updateGuildInfo(pluginData);
|
updateGuildInfo(pluginData);
|
||||||
state.updateInterval = setInterval(() => updateGuildInfo(pluginData), 60 * MINUTES);
|
pluginData.state.updateInterval = setInterval(() => updateGuildInfo(pluginData), 60 * MINUTES);
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeUnload(pluginData) {
|
||||||
|
clearInterval(pluginData.state.updateInterval);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ const defaultOptions: PluginOptions<LocateUserPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LocateUserPlugin = zeppelinGuildPlugin<LocateUserPluginType>()("locate_user", {
|
export const LocateUserPlugin = zeppelinGuildPlugin<LocateUserPluginType>()({
|
||||||
|
name: "locate_user",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Locate user",
|
prettyName: "Locate user",
|
||||||
|
@ -58,19 +59,21 @@ export const LocateUserPlugin = zeppelinGuildPlugin<LocateUserPluginType>()("loc
|
||||||
GuildBanRemoveAlertsEvt
|
GuildBanRemoveAlertsEvt
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.alerts = GuildVCAlerts.getGuildInstance(guild.id);
|
state.alerts = GuildVCAlerts.getGuildInstance(guild.id);
|
||||||
state.outdatedAlertsTimeout = null;
|
state.outdatedAlertsTimeout = null;
|
||||||
state.usersWithAlerts = [];
|
state.usersWithAlerts = [];
|
||||||
state.unloaded = false;
|
state.unloaded = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
outdatedAlertsLoop(pluginData);
|
outdatedAlertsLoop(pluginData);
|
||||||
fillActiveAlertsList(pluginData);
|
fillActiveAlertsList(pluginData);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
clearTimeout(pluginData.state.outdatedAlertsTimeout as Timeout);
|
clearTimeout(pluginData.state.outdatedAlertsTimeout as Timeout);
|
||||||
pluginData.state.unloaded = true;
|
pluginData.state.unloaded = true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
|
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
|
@ -19,5 +19,5 @@ export interface LocateUserPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const locateUserCmd = guildCommand<LocateUserPluginType>();
|
export const locateUserCmd = typedGuildCommand<LocateUserPluginType>();
|
||||||
export const locateUserEvt = guildEventListener<LocateUserPluginType>();
|
export const locateUserEvt = typedGuildEventListener<LocateUserPluginType>();
|
||||||
|
|
|
@ -47,7 +47,8 @@ const defaultOptions: PluginOptions<LogsPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()("logs", {
|
export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()({
|
||||||
|
name: "logs",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Logs",
|
prettyName: "Logs",
|
||||||
|
@ -84,7 +85,7 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()("logs", {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.guildLogs = new GuildLogs(guild.id);
|
state.guildLogs = new GuildLogs(guild.id);
|
||||||
|
@ -92,11 +93,17 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()("logs", {
|
||||||
state.archives = GuildArchives.getGuildInstance(guild.id);
|
state.archives = GuildArchives.getGuildInstance(guild.id);
|
||||||
state.cases = GuildCases.getGuildInstance(guild.id);
|
state.cases = GuildCases.getGuildInstance(guild.id);
|
||||||
|
|
||||||
|
state.batches = new Map();
|
||||||
|
|
||||||
|
state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.logListener = ({ type, data }) => log(pluginData, type, data);
|
state.logListener = ({ type, data }) => log(pluginData, type, data);
|
||||||
state.guildLogs.on("log", state.logListener);
|
state.guildLogs.on("log", state.logListener);
|
||||||
|
|
||||||
state.batches = new Map();
|
|
||||||
|
|
||||||
state.onMessageDeleteFn = msg => onMessageDelete(pluginData, msg);
|
state.onMessageDeleteFn = msg => onMessageDelete(pluginData, msg);
|
||||||
state.savedMessages.events.on("delete", state.onMessageDeleteFn);
|
state.savedMessages.events.on("delete", state.onMessageDeleteFn);
|
||||||
|
|
||||||
|
@ -106,7 +113,6 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()("logs", {
|
||||||
state.onMessageUpdateFn = (newMsg, oldMsg) => onMessageUpdate(pluginData, newMsg, oldMsg);
|
state.onMessageUpdateFn = (newMsg, oldMsg) => onMessageUpdate(pluginData, newMsg, oldMsg);
|
||||||
state.savedMessages.events.on("update", state.onMessageUpdateFn);
|
state.savedMessages.events.on("update", state.onMessageUpdateFn);
|
||||||
|
|
||||||
state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
|
||||||
state.regexRunnerRepeatedTimeoutListener = (regexSource, timeoutMs, failedTimes) => {
|
state.regexRunnerRepeatedTimeoutListener = (regexSource, timeoutMs, failedTimes) => {
|
||||||
logger.warn(`Disabled heavy regex temporarily: ${regexSource}`);
|
logger.warn(`Disabled heavy regex temporarily: ${regexSource}`);
|
||||||
log(pluginData, LogType.BOT_ALERT, {
|
log(pluginData, LogType.BOT_ALERT, {
|
||||||
|
@ -122,7 +128,7 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()("logs", {
|
||||||
state.regexRunner.on("repeatedTimeout", state.regexRunnerRepeatedTimeoutListener);
|
state.regexRunner.on("repeatedTimeout", state.regexRunnerRepeatedTimeoutListener);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
pluginData.state.guildLogs.removeListener("log", pluginData.state.logListener);
|
pluginData.state.guildLogs.removeListener("log", pluginData.state.logListener);
|
||||||
|
|
||||||
pluginData.state.savedMessages.events.off("delete", pluginData.state.onMessageDeleteFn);
|
pluginData.state.savedMessages.events.off("delete", pluginData.state.onMessageDeleteFn);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildEventListener } from "knub";
|
||||||
import { TRegex } from "../../validatorUtils";
|
import { TRegex } from "../../validatorUtils";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
@ -21,6 +21,7 @@ const LogChannel = t.partial({
|
||||||
excluded_channels: t.array(t.string),
|
excluded_channels: t.array(t.string),
|
||||||
excluded_categories: t.array(t.string),
|
excluded_categories: t.array(t.string),
|
||||||
exclude_bots: t.boolean,
|
exclude_bots: t.boolean,
|
||||||
|
excluded_roles: t.array(t.string),
|
||||||
format: tNullable(tLogFormats),
|
format: tNullable(tLogFormats),
|
||||||
timestamp_format: t.string,
|
timestamp_format: t.string,
|
||||||
include_embed_timestamp: t.boolean,
|
include_embed_timestamp: t.boolean,
|
||||||
|
@ -71,4 +72,4 @@ export interface LogsPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const logsEvt = guildEventListener<LogsPluginType>();
|
export const logsEvt = typedGuildEventListener<LogsPluginType>();
|
||||||
|
|
|
@ -59,7 +59,7 @@ export async function getLogMessage(
|
||||||
member = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
member = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const memberConfig = pluginData.config.getMatchingConfig({ member, userId: user.id }) || ({} as any);
|
const memberConfig = (await pluginData.config.getMatchingConfig({ member, userId: user.id })) || ({} as any);
|
||||||
|
|
||||||
// Revert to old behavior (verbose name w/o ping if allow_user_mentions is enabled (for whatever reason))
|
// Revert to old behavior (verbose name w/o ping if allow_user_mentions is enabled (for whatever reason))
|
||||||
if (config.allow_user_mentions) {
|
if (config.allow_user_mentions) {
|
||||||
|
|
|
@ -2,11 +2,16 @@ import { GuildPluginData } from "knub";
|
||||||
import { LogsPluginType, TLogChannelMap } from "../types";
|
import { LogsPluginType, TLogChannelMap } from "../types";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { TextChannel } from "eris";
|
import { TextChannel } from "eris";
|
||||||
import { createChunkedMessage, noop } from "../../../utils";
|
import { createChunkedMessage, get, noop } from "../../../utils";
|
||||||
import { getLogMessage } from "./getLogMessage";
|
import { getLogMessage } from "./getLogMessage";
|
||||||
import { allowTimeout } from "../../../RegExpRunner";
|
import { allowTimeout } from "../../../RegExpRunner";
|
||||||
|
|
||||||
const excludedUserProps = ["user", "member", "mod"];
|
const excludedUserProps = ["user", "member", "mod"];
|
||||||
|
const excludedRoleProps = ["message.member.roles", "member.roles"];
|
||||||
|
|
||||||
|
function isRoleArray(value: any): value is string[] {
|
||||||
|
return Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
export async function log(pluginData: GuildPluginData<LogsPluginType>, type: LogType, data: any) {
|
export async function log(pluginData: GuildPluginData<LogsPluginType>, type: LogType, data: any) {
|
||||||
const logChannels: TLogChannelMap = pluginData.config.get().channels;
|
const logChannels: TLogChannelMap = pluginData.config.get().channels;
|
||||||
|
@ -36,6 +41,21 @@ export async function log(pluginData: GuildPluginData<LogsPluginType>, type: Log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts.excluded_roles) {
|
||||||
|
for (const prop of excludedRoleProps) {
|
||||||
|
const roles = get(data, prop);
|
||||||
|
if (!isRoleArray(roles)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const role of roles) {
|
||||||
|
if (opts.excluded_roles.includes(role)) {
|
||||||
|
continue logChannelLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If this entry is from an excluded channel, skip it
|
// If this entry is from an excluded channel, skip it
|
||||||
if (opts.excluded_channels) {
|
if (opts.excluded_channels) {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -20,7 +20,8 @@ const defaultOptions: PluginOptions<MessageSaverPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MessageSaverPlugin = zeppelinGuildPlugin<MessageSaverPluginType>()("message_saver", {
|
export const MessageSaverPlugin = zeppelinGuildPlugin<MessageSaverPluginType>()({
|
||||||
|
name: "message_saver",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configSchema: ConfigSchema,
|
configSchema: ConfigSchema,
|
||||||
|
@ -40,7 +41,7 @@ export const MessageSaverPlugin = zeppelinGuildPlugin<MessageSaverPluginType>()(
|
||||||
MessageDeleteBulkEvt,
|
MessageDeleteBulkEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
|
@ -14,5 +14,5 @@ export interface MessageSaverPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const messageSaverCmd = guildCommand<MessageSaverPluginType>();
|
export const messageSaverCmd = typedGuildCommand<MessageSaverPluginType>();
|
||||||
export const messageSaverEvt = guildEventListener<MessageSaverPluginType>();
|
export const messageSaverEvt = typedGuildEventListener<MessageSaverPluginType>();
|
||||||
|
|
|
@ -34,7 +34,7 @@ import { Member, Message } from "eris";
|
||||||
import { kickMember } from "./functions/kickMember";
|
import { kickMember } from "./functions/kickMember";
|
||||||
import { banUserId } from "./functions/banUserId";
|
import { banUserId } from "./functions/banUserId";
|
||||||
import { MassmuteCmd } from "./commands/MassmuteCmd";
|
import { MassmuteCmd } from "./commands/MassmuteCmd";
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { MINUTES, trimPluginDescription } from "../../utils";
|
||||||
import { DeleteCaseCmd } from "./commands/DeleteCaseCmd";
|
import { DeleteCaseCmd } from "./commands/DeleteCaseCmd";
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
import { GuildTempbans } from "../../data/GuildTempbans";
|
import { GuildTempbans } from "../../data/GuildTempbans";
|
||||||
|
@ -44,6 +44,7 @@ import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { onModActionsEvent } from "./functions/onModActionsEvent";
|
import { onModActionsEvent } from "./functions/onModActionsEvent";
|
||||||
import { offModActionsEvent } from "./functions/offModActionsEvent";
|
import { offModActionsEvent } from "./functions/offModActionsEvent";
|
||||||
import { updateCase } from "./functions/updateCase";
|
import { updateCase } from "./functions/updateCase";
|
||||||
|
import { Queue } from "../../Queue";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -109,7 +110,8 @@ const defaultOptions = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()("mod_actions", {
|
export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
|
||||||
|
name: "mod_actions",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Mod actions",
|
prettyName: "Mod actions",
|
||||||
|
@ -186,7 +188,7 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()("mod
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.mutes = GuildMutes.getGuildInstance(guild.id);
|
state.mutes = GuildMutes.getGuildInstance(guild.id);
|
||||||
|
@ -197,13 +199,18 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()("mod
|
||||||
state.unloaded = false;
|
state.unloaded = false;
|
||||||
state.outdatedTempbansTimeout = null;
|
state.outdatedTempbansTimeout = null;
|
||||||
state.ignoredEvents = [];
|
state.ignoredEvents = [];
|
||||||
|
// Massbans can take a while depending on rate limits,
|
||||||
|
// so we're giving each massban 15 minutes to complete before launching the next massban
|
||||||
|
state.massbanQueue = new Queue(15 * MINUTES);
|
||||||
|
|
||||||
state.events = new EventEmitter();
|
state.events = new EventEmitter();
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
outdatedTempbansLoop(pluginData);
|
outdatedTempbansLoop(pluginData);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
pluginData.state.unloaded = true;
|
pluginData.state.unloaded = true;
|
||||||
pluginData.state.events.removeAllListeners();
|
pluginData.state.events.removeAllListeners();
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,7 +44,7 @@ export const AddCaseCmd = modActionsCmd({
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ export const BanCmd = modActionsCmd({
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,8 @@ export const BanCmd = modActionsCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteMessageDays = args["delete-days"] ?? pluginData.config.getForMessage(msg).ban_delete_message_days;
|
const deleteMessageDays =
|
||||||
|
args["delete-days"] ?? (await pluginData.config.getForMessage(msg)).ban_delete_message_days;
|
||||||
const banResult = await banUserId(
|
const banResult = await banUserId(
|
||||||
pluginData,
|
pluginData,
|
||||||
user.id,
|
user.id,
|
||||||
|
|
|
@ -53,7 +53,7 @@ export const ForcebanCmd = modActionsCmd({
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { modActionsCmd, IgnoredEventType } from "../types";
|
import { modActionsCmd, IgnoredEventType } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { canActOn, sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
import { canActOn, sendErrorMessage, hasPermission, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { resolveUser, resolveMember, stripObjectToScalars } from "../../../utils";
|
import { resolveUser, resolveMember, stripObjectToScalars, noop, MINUTES } from "../../../utils";
|
||||||
import { isBanned } from "../functions/isBanned";
|
import { isBanned } from "../functions/isBanned";
|
||||||
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
||||||
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
|
@ -12,6 +12,9 @@ import { waitForReply } from "knub/dist/helpers";
|
||||||
import { ignoreEvent } from "../functions/ignoreEvent";
|
import { ignoreEvent } from "../functions/ignoreEvent";
|
||||||
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
|
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { performance } from "perf_hooks";
|
||||||
|
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
||||||
|
import { load } from "js-yaml";
|
||||||
|
|
||||||
export const MassbanCmd = modActionsCmd({
|
export const MassbanCmd = modActionsCmd({
|
||||||
trigger: "massban",
|
trigger: "massban",
|
||||||
|
@ -50,62 +53,103 @@ export const MassbanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore automatic ban cases and logs for these users
|
|
||||||
// We'll create our own cases below and post a single "mass banned" log instead
|
|
||||||
args.userIds.forEach(userId => {
|
|
||||||
// Use longer timeouts since this can take a while
|
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Ban, userId, 120 * 1000);
|
|
||||||
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show a loading indicator since this can take a while
|
// Show a loading indicator since this can take a while
|
||||||
const loadingMsg = await msg.channel.createMessage("Banning...");
|
const maxWaitTime = pluginData.state.massbanQueue.timeout * pluginData.state.massbanQueue.length;
|
||||||
|
const maxWaitTimeFormatted = humanizeDurationShort(maxWaitTime, { round: true });
|
||||||
|
const initialLoadingText =
|
||||||
|
pluginData.state.massbanQueue.length === 0
|
||||||
|
? "Banning..."
|
||||||
|
: `Massban queued. Waiting for previous massban to finish (max wait ${maxWaitTimeFormatted}).`;
|
||||||
|
const loadingMsg = await msg.channel.createMessage(initialLoadingText);
|
||||||
|
|
||||||
// Ban each user and count failed bans (if any)
|
const waitTimeStart = performance.now();
|
||||||
const failedBans: string[] = [];
|
const waitingInterval = setInterval(() => {
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const waitTime = humanizeDurationShort(performance.now() - waitTimeStart, { round: true });
|
||||||
for (const userId of args.userIds) {
|
loadingMsg
|
||||||
try {
|
.edit(`Massban queued. Still waiting for previous massban to finish (waited ${waitTime}).`)
|
||||||
await pluginData.guild.banMember(userId, 1, banReason != null ? encodeURIComponent(banReason) : undefined);
|
.catch(() => clearInterval(waitingInterval));
|
||||||
|
}, 1 * MINUTES);
|
||||||
|
|
||||||
await casesPlugin.createCase({
|
pluginData.state.massbanQueue.add(async () => {
|
||||||
userId,
|
clearInterval(waitingInterval);
|
||||||
modId: msg.author.id,
|
|
||||||
type: CaseTypes.Ban,
|
if (pluginData.state.unloaded) {
|
||||||
reason: `Mass ban: ${banReason}`,
|
void loadingMsg.delete().catch(noop);
|
||||||
postInCaseLogOverride: false,
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadingMsg.edit("Banning...").catch(noop);
|
||||||
|
|
||||||
|
// Ban each user and count failed bans (if any)
|
||||||
|
const startTime = performance.now();
|
||||||
|
const failedBans: string[] = [];
|
||||||
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
for (const [i, userId] of args.userIds.entries()) {
|
||||||
|
if (pluginData.state.unloaded) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ignore automatic ban cases and logs
|
||||||
|
// We create our own cases below and post a single "mass banned" log instead
|
||||||
|
ignoreEvent(pluginData, IgnoredEventType.Ban, userId, 120 * 1000);
|
||||||
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000);
|
||||||
|
|
||||||
|
await pluginData.guild.banMember(userId, 1, banReason != null ? encodeURIComponent(banReason) : undefined);
|
||||||
|
|
||||||
|
await casesPlugin.createCase({
|
||||||
|
userId,
|
||||||
|
modId: msg.author.id,
|
||||||
|
type: CaseTypes.Ban,
|
||||||
|
reason: `Mass ban: ${banReason}`,
|
||||||
|
postInCaseLogOverride: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
pluginData.state.events.emit("ban", userId, banReason);
|
||||||
|
} catch {
|
||||||
|
failedBans.push(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a status update every 10 bans
|
||||||
|
if ((i + 1) % 10 === 0) {
|
||||||
|
loadingMsg.edit(`Banning... ${i + 1}/${args.userIds.length}`).catch(noop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalTime = performance.now() - startTime;
|
||||||
|
const formattedTimeTaken = humanizeDurationShort(totalTime, { round: true });
|
||||||
|
|
||||||
|
// Clear loading indicator
|
||||||
|
loadingMsg.delete().catch(noop);
|
||||||
|
|
||||||
|
const successfulBanCount = args.userIds.length - failedBans.length;
|
||||||
|
if (successfulBanCount === 0) {
|
||||||
|
// All bans failed - don't create a log entry and notify the user
|
||||||
|
sendErrorMessage(pluginData, msg.channel, "All bans failed. Make sure the IDs are valid.");
|
||||||
|
} else {
|
||||||
|
// Some or all bans were successful. Create a log entry for the mass ban and notify the user.
|
||||||
|
pluginData.state.serverLogs.log(LogType.MASSBAN, {
|
||||||
|
mod: stripObjectToScalars(msg.author),
|
||||||
|
count: successfulBanCount,
|
||||||
|
reason: banReason,
|
||||||
});
|
});
|
||||||
|
|
||||||
pluginData.state.events.emit("ban", userId, banReason);
|
if (failedBans.length) {
|
||||||
} catch {
|
sendSuccessMessage(
|
||||||
failedBans.push(userId);
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`Banned ${successfulBanCount} users in ${formattedTimeTaken}, ${
|
||||||
|
failedBans.length
|
||||||
|
} failed: ${failedBans.join(" ")}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sendSuccessMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`Banned ${successfulBanCount} users successfully in ${formattedTimeTaken}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// Clear loading indicator
|
|
||||||
loadingMsg.delete();
|
|
||||||
|
|
||||||
const successfulBanCount = args.userIds.length - failedBans.length;
|
|
||||||
if (successfulBanCount === 0) {
|
|
||||||
// All bans failed - don't create a log entry and notify the user
|
|
||||||
sendErrorMessage(pluginData, msg.channel, "All bans failed. Make sure the IDs are valid.");
|
|
||||||
} else {
|
|
||||||
// Some or all bans were successful. Create a log entry for the mass ban and notify the user.
|
|
||||||
pluginData.state.serverLogs.log(LogType.MASSBAN, {
|
|
||||||
mod: stripObjectToScalars(msg.author),
|
|
||||||
count: successfulBanCount,
|
|
||||||
reason: banReason,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (failedBans.length) {
|
|
||||||
sendSuccessMessage(
|
|
||||||
pluginData,
|
|
||||||
msg.channel,
|
|
||||||
`Banned ${successfulBanCount} users, ${failedBans.length} failed: ${failedBans.join(" ")}`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
sendSuccessMessage(pluginData, msg.channel, `Banned ${successfulBanCount} users successfully`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,7 +36,7 @@ export const UnbanCmd = modActionsCmd({
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ export const WarnCmd = modActionsCmd({
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
||||||
msg.channel.createMessage(errorMessage("You don't have permission to use -mod"));
|
msg.channel.createMessage(errorMessage("You don't have permission to use -mod"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ import { Case } from "../../../data/entities/Case";
|
||||||
* Create a BAN case automatically when a user is banned manually.
|
* Create a BAN case automatically when a user is banned manually.
|
||||||
* Attempts to find the ban's details in the audit log.
|
* Attempts to find the ban's details in the audit log.
|
||||||
*/
|
*/
|
||||||
export const CreateBanCaseOnManualBanEvt = modActionsEvt(
|
export const CreateBanCaseOnManualBanEvt = modActionsEvt({
|
||||||
"guildBanAdd",
|
event: "guildBanAdd",
|
||||||
async ({ pluginData, args: { guild, user } }) => {
|
async listener({ pluginData, args: { guild, user } }) {
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) {
|
||||||
clearIgnoredEvents(pluginData, IgnoredEventType.Ban, user.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Ban, user.id);
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +39,7 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt(
|
||||||
|
|
||||||
mod = await resolveUser(pluginData.client, modId);
|
mod = await resolveUser(pluginData.client, modId);
|
||||||
|
|
||||||
const config = mod instanceof UnknownUser ? pluginData.config.get() : pluginData.config.getForUser(mod);
|
const config = mod instanceof UnknownUser ? pluginData.config.get() : await pluginData.config.getForUser(mod);
|
||||||
|
|
||||||
if (config.create_cases_for_manual_actions) {
|
if (config.create_cases_for_manual_actions) {
|
||||||
reason = relevantAuditLogEntry.reason || "";
|
reason = relevantAuditLogEntry.reason || "";
|
||||||
|
@ -72,4 +72,4 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt(
|
||||||
|
|
||||||
pluginData.state.events.emit("ban", user.id, reason);
|
pluginData.state.events.emit("ban", user.id, reason);
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -14,9 +14,9 @@ import { Case } from "../../../data/entities/Case";
|
||||||
* Create a KICK case automatically when a user is kicked manually.
|
* Create a KICK case automatically when a user is kicked manually.
|
||||||
* Attempts to find the kick's details in the audit log.
|
* Attempts to find the kick's details in the audit log.
|
||||||
*/
|
*/
|
||||||
export const CreateKickCaseOnManualKickEvt = modActionsEvt(
|
export const CreateKickCaseOnManualKickEvt = modActionsEvt({
|
||||||
"guildMemberRemove",
|
event: "guildMemberRemove",
|
||||||
async ({ pluginData, args: { member } }) => {
|
async listener({ pluginData, args: { member } }) {
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Kick, member.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Kick, member.id)) {
|
||||||
clearIgnoredEvents(pluginData, IgnoredEventType.Kick, member.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Kick, member.id);
|
||||||
return;
|
return;
|
||||||
|
@ -42,7 +42,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt(
|
||||||
} else {
|
} else {
|
||||||
mod = await resolveUser(pluginData.client, kickAuditLogEntry.user.id);
|
mod = await resolveUser(pluginData.client, kickAuditLogEntry.user.id);
|
||||||
|
|
||||||
const config = mod instanceof UnknownUser ? pluginData.config.get() : pluginData.config.getForUser(mod);
|
const config = mod instanceof UnknownUser ? pluginData.config.get() : await pluginData.config.getForUser(mod);
|
||||||
|
|
||||||
if (config.create_cases_for_manual_actions) {
|
if (config.create_cases_for_manual_actions) {
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
@ -67,4 +67,4 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt(
|
||||||
pluginData.state.events.emit("kick", member.id, kickAuditLogEntry.reason || undefined);
|
pluginData.state.events.emit("kick", member.id, kickAuditLogEntry.reason || undefined);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -13,9 +13,9 @@ import { Case } from "../../../data/entities/Case";
|
||||||
* Create an UNBAN case automatically when a user is unbanned manually.
|
* Create an UNBAN case automatically when a user is unbanned manually.
|
||||||
* Attempts to find the unban's details in the audit log.
|
* Attempts to find the unban's details in the audit log.
|
||||||
*/
|
*/
|
||||||
export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt(
|
export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({
|
||||||
"guildBanRemove",
|
event: "guildBanRemove",
|
||||||
async ({ pluginData, args: { guild, user } }) => {
|
async listener({ pluginData, args: { guild, user } }) {
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) {
|
||||||
clearIgnoredEvents(pluginData, IgnoredEventType.Unban, user.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Unban, user.id);
|
||||||
return;
|
return;
|
||||||
|
@ -38,7 +38,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt(
|
||||||
|
|
||||||
mod = await resolveUser(pluginData.client, modId);
|
mod = await resolveUser(pluginData.client, modId);
|
||||||
|
|
||||||
const config = mod instanceof UnknownUser ? pluginData.config.get() : pluginData.config.getForUser(mod);
|
const config = mod instanceof UnknownUser ? pluginData.config.get() : await pluginData.config.getForUser(mod);
|
||||||
|
|
||||||
if (config.create_cases_for_manual_actions) {
|
if (config.create_cases_for_manual_actions) {
|
||||||
createdCase = await casesPlugin.createCase({
|
createdCase = await casesPlugin.createCase({
|
||||||
|
@ -69,4 +69,4 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt(
|
||||||
|
|
||||||
pluginData.state.events.emit("unban", user.id);
|
pluginData.state.events.emit("unban", user.id);
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||||
/**
|
/**
|
||||||
* Show an alert if a member with prior notes joins the server
|
* Show an alert if a member with prior notes joins the server
|
||||||
*/
|
*/
|
||||||
export const PostAlertOnMemberJoinEvt = modActionsEvt(
|
export const PostAlertOnMemberJoinEvt = modActionsEvt({
|
||||||
"guildMemberAdd",
|
event: "guildMemberAdd",
|
||||||
async ({ pluginData, args: { guild, member } }) => {
|
async listener({ pluginData, args: { guild, member } }) {
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
|
|
||||||
if (!config.alert_on_rejoin) return;
|
if (!config.alert_on_rejoin) return;
|
||||||
|
@ -51,4 +51,4 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -51,7 +51,7 @@ export async function actualKickMemberCmd(
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData.config.getForMessage(msg), "can_act_as_other")) {
|
if (!(await hasPermission(await pluginData.config.getForMessage(msg), "can_act_as_other"))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Member, Message, TextChannel, User } from "eris";
|
import { GuildTextableChannel, Member, Message, TextChannel, User } from "eris";
|
||||||
import { asSingleLine, isDiscordRESTError, UnknownUser } from "../../../utils";
|
import { asSingleLine, isDiscordRESTError, UnknownUser } from "../../../utils";
|
||||||
import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
@ -10,7 +10,6 @@ import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
||||||
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";
|
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";
|
||||||
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
import { GuildMessage } from "knub/dist/helpers";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual function run by both !mute and !forcemute.
|
* The actual function run by both !mute and !forcemute.
|
||||||
|
@ -19,7 +18,7 @@ import { GuildMessage } from "knub/dist/helpers";
|
||||||
export async function actualMuteUserCmd(
|
export async function actualMuteUserCmd(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
user: User | UnknownUser,
|
user: User | UnknownUser,
|
||||||
msg: GuildMessage,
|
msg: Message<GuildTextableChannel>,
|
||||||
args: { time?: number; reason?: string; mod: Member; notify?: string; "notify-channel"?: TextChannel },
|
args: { time?: number; reason?: string; mod: Member; notify?: string; "notify-channel"?: TextChannel },
|
||||||
) {
|
) {
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
|
@ -27,7 +26,7 @@ export async function actualMuteUserCmd(
|
||||||
let pp: User | null = null;
|
let pp: User | null = null;
|
||||||
|
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export async function actualUnmuteCmd(
|
||||||
let pp: User | null = null;
|
let pp: User | null = null;
|
||||||
|
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id })) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { tNullable, UserNotificationMethod, UserNotificationResult } from "../../utils";
|
import { tNullable, UserNotificationMethod, UserNotificationResult } from "../../utils";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildMutes } from "../../data/GuildMutes";
|
import { GuildMutes } from "../../data/GuildMutes";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
|
@ -10,6 +10,7 @@ import { TextChannel } from "eris";
|
||||||
import { GuildTempbans } from "../../data/GuildTempbans";
|
import { GuildTempbans } from "../../data/GuildTempbans";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
|
import { Queue } from "../../Queue";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
dm_on_warn: t.boolean,
|
dm_on_warn: t.boolean,
|
||||||
|
@ -72,6 +73,7 @@ export interface ModActionsPluginType extends BasePluginType {
|
||||||
unloaded: boolean;
|
unloaded: boolean;
|
||||||
outdatedTempbansTimeout: Timeout | null;
|
outdatedTempbansTimeout: Timeout | null;
|
||||||
ignoredEvents: IIgnoredEvent[];
|
ignoredEvents: IIgnoredEvent[];
|
||||||
|
massbanQueue: Queue;
|
||||||
|
|
||||||
events: ModActionsEventEmitter;
|
events: ModActionsEventEmitter;
|
||||||
};
|
};
|
||||||
|
@ -146,5 +148,5 @@ export interface BanOptions {
|
||||||
|
|
||||||
export type ModActionType = "note" | "warn" | "mute" | "unmute" | "kick" | "ban" | "unban";
|
export type ModActionType = "note" | "warn" | "mute" | "unmute" | "kick" | "ban" | "unban";
|
||||||
|
|
||||||
export const modActionsCmd = guildCommand<ModActionsPluginType>();
|
export const modActionsCmd = typedGuildCommand<ModActionsPluginType>();
|
||||||
export const modActionsEvt = guildEventListener<ModActionsPluginType>();
|
export const modActionsEvt = typedGuildEventListener<ModActionsPluginType>();
|
||||||
|
|
|
@ -62,7 +62,8 @@ const EXPIRED_MUTE_CHECK_INTERVAL = 60 * 1000;
|
||||||
let FIRST_CHECK_TIME = Date.now();
|
let FIRST_CHECK_TIME = Date.now();
|
||||||
const FIRST_CHECK_INCREMENT = 5 * 1000;
|
const FIRST_CHECK_INCREMENT = 5 * 1000;
|
||||||
|
|
||||||
export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()("mutes", {
|
export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({
|
||||||
|
name: "mutes",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Mutes",
|
prettyName: "Mutes",
|
||||||
|
@ -105,14 +106,16 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()("mutes", {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
pluginData.state.mutes = GuildMutes.getGuildInstance(pluginData.guild.id);
|
pluginData.state.mutes = GuildMutes.getGuildInstance(pluginData.guild.id);
|
||||||
pluginData.state.cases = GuildCases.getGuildInstance(pluginData.guild.id);
|
pluginData.state.cases = GuildCases.getGuildInstance(pluginData.guild.id);
|
||||||
pluginData.state.serverLogs = new GuildLogs(pluginData.guild.id);
|
pluginData.state.serverLogs = new GuildLogs(pluginData.guild.id);
|
||||||
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
||||||
|
|
||||||
pluginData.state.events = new EventEmitter();
|
pluginData.state.events = new EventEmitter();
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
// Check for expired mutes every 5s
|
// Check for expired mutes every 5s
|
||||||
const firstCheckTime = Math.max(Date.now(), FIRST_CHECK_TIME) + FIRST_CHECK_INCREMENT;
|
const firstCheckTime = Math.max(Date.now(), FIRST_CHECK_TIME) + FIRST_CHECK_INCREMENT;
|
||||||
FIRST_CHECK_TIME = firstCheckTime;
|
FIRST_CHECK_TIME = firstCheckTime;
|
||||||
|
@ -126,7 +129,7 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()("mutes", {
|
||||||
}, firstCheckTime - Date.now());
|
}, firstCheckTime - Date.now());
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
clearInterval(pluginData.state.muteClearIntervalId);
|
clearInterval(pluginData.state.muteClearIntervalId);
|
||||||
pluginData.state.events.removeAllListeners();
|
pluginData.state.events.removeAllListeners();
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,9 +3,12 @@ import { mutesEvt } from "../types";
|
||||||
/**
|
/**
|
||||||
* Clear active mute from the member if the member is banned
|
* Clear active mute from the member if the member is banned
|
||||||
*/
|
*/
|
||||||
export const ClearActiveMuteOnMemberBanEvt = mutesEvt("guildBanAdd", async ({ pluginData, args: { user } }) => {
|
export const ClearActiveMuteOnMemberBanEvt = mutesEvt({
|
||||||
const mute = await pluginData.state.mutes.findExistingMuteForUserId(user.id);
|
event: "guildBanAdd",
|
||||||
if (mute) {
|
async listener({ pluginData, args: { user } }) {
|
||||||
pluginData.state.mutes.clear(user.id);
|
const mute = await pluginData.state.mutes.findExistingMuteForUserId(user.id);
|
||||||
}
|
if (mute) {
|
||||||
|
pluginData.state.mutes.clear(user.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { memberHasMutedRole } from "../functions/memberHasMutedRole";
|
||||||
/**
|
/**
|
||||||
* Clear active mute if the mute role is removed manually
|
* Clear active mute if the mute role is removed manually
|
||||||
*/
|
*/
|
||||||
export const ClearActiveMuteOnRoleRemovalEvt = mutesEvt(
|
export const ClearActiveMuteOnRoleRemovalEvt = mutesEvt({
|
||||||
"guildMemberUpdate",
|
event: "guildMemberUpdate",
|
||||||
async ({ pluginData, args: { member } }) => {
|
async listener({ pluginData, args: { member } }) {
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
if (!muteRole) return;
|
if (!muteRole) return;
|
||||||
|
|
||||||
|
@ -17,4 +17,4 @@ export const ClearActiveMuteOnRoleRemovalEvt = mutesEvt(
|
||||||
await pluginData.state.mutes.clear(muteRole);
|
await pluginData.state.mutes.clear(muteRole);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
|
@ -6,19 +6,22 @@ import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
||||||
/**
|
/**
|
||||||
* Reapply active mutes on join
|
* Reapply active mutes on join
|
||||||
*/
|
*/
|
||||||
export const ReapplyActiveMuteOnJoinEvt = mutesEvt("guildMemberAdd", async ({ pluginData, args: { member } }) => {
|
export const ReapplyActiveMuteOnJoinEvt = mutesEvt({
|
||||||
const mute = await pluginData.state.mutes.findExistingMuteForUserId(member.id);
|
event: "guildMemberAdd",
|
||||||
if (mute) {
|
async listener({ pluginData, args: { member } }) {
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const mute = await pluginData.state.mutes.findExistingMuteForUserId(member.id);
|
||||||
|
if (mute) {
|
||||||
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
|
|
||||||
if (muteRole) {
|
if (muteRole) {
|
||||||
const memberRoleLock = await pluginData.locks.acquire(memberRolesLock(member));
|
const memberRoleLock = await pluginData.locks.acquire(memberRolesLock(member));
|
||||||
await member.addRole(muteRole);
|
await member.addRole(muteRole);
|
||||||
memberRoleLock.unlock();
|
memberRoleLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginData.state.serverLogs.log(LogType.MEMBER_MUTE_REJOIN, {
|
||||||
|
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
pluginData.state.serverLogs.log(LogType.MEMBER_MUTE_REJOIN, {
|
|
||||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,7 +51,7 @@ export async function muteUser(
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, user.id, true); // Grab the fresh member so we don't have stale role info
|
const member = await resolveMember(pluginData.client, pluginData.guild, user.id, true); // Grab the fresh member so we don't have stale role info
|
||||||
const config = pluginData.config.getMatchingConfig({ member, userId });
|
const config = await pluginData.config.getMatchingConfig({ member, userId });
|
||||||
|
|
||||||
muteTime = muteTime !== undefined
|
muteTime = muteTime !== undefined
|
||||||
? muteTime
|
? muteTime
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { tDelayString, tNullable, UserNotificationMethod, UserNotificationResult
|
||||||
import { Mute } from "../../data/entities/Mute";
|
import { Mute } from "../../data/entities/Mute";
|
||||||
import { Member } from "eris";
|
import { Member } from "eris";
|
||||||
import { Case } from "../../data/entities/Case";
|
import { Case } from "../../data/entities/Case";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
|
@ -80,5 +80,5 @@ export interface MuteOptions {
|
||||||
isAutomodAction?: boolean;
|
isAutomodAction?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mutesCmd = guildCommand<MutesPluginType>();
|
export const mutesCmd = typedGuildCommand<MutesPluginType>();
|
||||||
export const mutesEvt = guildEventListener<MutesPluginType>();
|
export const mutesEvt = typedGuildEventListener<MutesPluginType>();
|
||||||
|
|
|
@ -21,7 +21,8 @@ const defaultOptions: PluginOptions<NameHistoryPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NameHistoryPlugin = zeppelinGuildPlugin<NameHistoryPluginType>()("name_history", {
|
export const NameHistoryPlugin = zeppelinGuildPlugin<NameHistoryPluginType>()({
|
||||||
|
name: "name_history",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configSchema: ConfigSchema,
|
configSchema: ConfigSchema,
|
||||||
|
@ -38,7 +39,7 @@ export const NameHistoryPlugin = zeppelinGuildPlugin<NameHistoryPluginType>()("n
|
||||||
MessageCreateEvt,
|
MessageCreateEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.nicknameHistory = GuildNicknameHistory.getGuildInstance(guild.id);
|
state.nicknameHistory = GuildNicknameHistory.getGuildInstance(guild.id);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildNicknameHistory } from "../../data/GuildNicknameHistory";
|
import { GuildNicknameHistory } from "../../data/GuildNicknameHistory";
|
||||||
import { UsernameHistory } from "../../data/UsernameHistory";
|
import { UsernameHistory } from "../../data/UsernameHistory";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
|
@ -18,5 +18,5 @@ export interface NameHistoryPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const nameHistoryCmd = guildCommand<NameHistoryPluginType>();
|
export const nameHistoryCmd = typedGuildCommand<NameHistoryPluginType>();
|
||||||
export const nameHistoryEvt = guildEventListener<NameHistoryPluginType>();
|
export const nameHistoryEvt = typedGuildEventListener<NameHistoryPluginType>();
|
||||||
|
|
|
@ -16,7 +16,8 @@ const defaultOptions: PluginOptions<PersistPluginType> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PersistPlugin = zeppelinGuildPlugin<PersistPluginType>()("persist", {
|
export const PersistPlugin = zeppelinGuildPlugin<PersistPluginType>()({
|
||||||
|
name: "persist",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Persist",
|
prettyName: "Persist",
|
||||||
|
@ -36,7 +37,7 @@ export const PersistPlugin = zeppelinGuildPlugin<PersistPluginType>()("persist",
|
||||||
LoadDataEvt,
|
LoadDataEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.persistedData = GuildPersistedData.getGuildInstance(guild.id);
|
state.persistedData = GuildPersistedData.getGuildInstance(guild.id);
|
||||||
|
|
|
@ -27,12 +27,12 @@ export const LoadDataEvt = persistEvt({
|
||||||
}
|
}
|
||||||
|
|
||||||
const toRestore: MemberOptions = {};
|
const toRestore: MemberOptions = {};
|
||||||
const config = pluginData.config.getForMember(member);
|
const config = await pluginData.config.getForMember(member);
|
||||||
const restoredData: string[] = [];
|
const restoredData: string[] = [];
|
||||||
|
|
||||||
// Check permissions
|
// Check permissions
|
||||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
||||||
let requiredPermissions = 0;
|
let requiredPermissions = 0n;
|
||||||
if (config.persist_nicknames) requiredPermissions |= p.manageNicknames;
|
if (config.persist_nicknames) requiredPermissions |= p.manageNicknames;
|
||||||
if (config.persisted_roles) requiredPermissions |= p.manageRoles;
|
if (config.persisted_roles) requiredPermissions |= p.manageRoles;
|
||||||
const missingPermissions = getMissingPermissions(me.permission, requiredPermissions);
|
const missingPermissions = getMissingPermissions(me.permission, requiredPermissions);
|
||||||
|
|
|
@ -12,7 +12,7 @@ export const StoreDataEvt = persistEvt({
|
||||||
|
|
||||||
let persist = false;
|
let persist = false;
|
||||||
const persistData: IPartialPersistData = {};
|
const persistData: IPartialPersistData = {};
|
||||||
const config = pluginData.config.getForUser(member.user);
|
const config = await pluginData.config.getForUser(member.user);
|
||||||
|
|
||||||
const persistedRoles = config.persisted_roles;
|
const persistedRoles = config.persisted_roles;
|
||||||
if (persistedRoles.length && member.roles) {
|
if (persistedRoles.length && member.roles) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildEventListener } from "knub";
|
||||||
import { GuildPersistedData } from "../../data/GuildPersistedData";
|
import { GuildPersistedData } from "../../data/GuildPersistedData";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
|
|
||||||
|
@ -19,4 +19,4 @@ export interface PersistPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const persistEvt = guildEventListener<PersistPluginType>();
|
export const persistEvt = typedGuildEventListener<PersistPluginType>();
|
||||||
|
|
|
@ -20,7 +20,8 @@ const defaultOptions: PluginOptions<PingableRolesPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PingableRolesPlugin = zeppelinGuildPlugin<PingableRolesPluginType>()("pingable_roles", {
|
export const PingableRolesPlugin = zeppelinGuildPlugin<PingableRolesPluginType>()({
|
||||||
|
name: "pingable_roles",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Pingable roles",
|
prettyName: "Pingable roles",
|
||||||
|
@ -41,7 +42,7 @@ export const PingableRolesPlugin = zeppelinGuildPlugin<PingableRolesPluginType>(
|
||||||
MessageCreateDisablePingableEvt,
|
MessageCreateDisablePingableEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.pingableRoles = GuildPingableRoles.getGuildInstance(guild.id);
|
state.pingableRoles = GuildPingableRoles.getGuildInstance(guild.id);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand, guildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
import { GuildPingableRoles } from "../../data/GuildPingableRoles";
|
import { GuildPingableRoles } from "../../data/GuildPingableRoles";
|
||||||
import { PingableRole } from "../../data/entities/PingableRole";
|
import { PingableRole } from "../../data/entities/PingableRole";
|
||||||
|
|
||||||
|
@ -18,5 +18,5 @@ export interface PingableRolesPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pingableRolesCmd = guildCommand<PingableRolesPluginType>();
|
export const pingableRolesCmd = typedGuildCommand<PingableRolesPluginType>();
|
||||||
export const pingableRolesEvt = guildEventListener<PingableRolesPluginType>();
|
export const pingableRolesEvt = typedGuildEventListener<PingableRolesPluginType>();
|
||||||
|
|
|
@ -28,7 +28,8 @@ const defaultOptions: PluginOptions<PostPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PostPlugin = zeppelinGuildPlugin<PostPluginType>()("post", {
|
export const PostPlugin = zeppelinGuildPlugin<PostPluginType>()({
|
||||||
|
name: "post",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Post",
|
prettyName: "Post",
|
||||||
|
@ -49,17 +50,19 @@ export const PostPlugin = zeppelinGuildPlugin<PostPluginType>()("post", {
|
||||||
ScheduledPostsDeleteCmd,
|
ScheduledPostsDeleteCmd,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
|
||||||
state.scheduledPosts = GuildScheduledPosts.getGuildInstance(guild.id);
|
state.scheduledPosts = GuildScheduledPosts.getGuildInstance(guild.id);
|
||||||
state.logs = new GuildLogs(guild.id);
|
state.logs = new GuildLogs(guild.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
scheduledPostLoop(pluginData);
|
scheduledPostLoop(pluginData);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
clearTimeout(pluginData.state.scheduledPostLoopTimeout);
|
clearTimeout(pluginData.state.scheduledPostLoopTimeout);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand } from "knub";
|
import { BasePluginType, typedGuildCommand } from "knub";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { GuildScheduledPosts } from "../../data/GuildScheduledPosts";
|
import { GuildScheduledPosts } from "../../data/GuildScheduledPosts";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
|
@ -20,4 +20,4 @@ export interface PostPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const postCmd = guildCommand<PostPluginType>();
|
export const postCmd = typedGuildCommand<PostPluginType>();
|
||||||
|
|
|
@ -31,7 +31,8 @@ const defaultOptions: PluginOptions<ReactionRolesPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>()("reaction_roles", {
|
export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>()({
|
||||||
|
name: "reaction_roles",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Reaction roles",
|
prettyName: "Reaction roles",
|
||||||
|
@ -53,7 +54,7 @@ export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>(
|
||||||
AddReactionRoleEvt,
|
AddReactionRoleEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.reactionRoles = GuildReactionRoles.getGuildInstance(guild.id);
|
state.reactionRoles = GuildReactionRoles.getGuildInstance(guild.id);
|
||||||
|
@ -62,7 +63,9 @@ export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>(
|
||||||
state.roleChangeQueue = new Queue();
|
state.roleChangeQueue = new Queue();
|
||||||
state.pendingRoleChanges = new Map();
|
state.pendingRoleChanges = new Map();
|
||||||
state.pendingRefreshes = new Set();
|
state.pendingRefreshes = new Set();
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
let autoRefreshInterval = pluginData.config.get().auto_refresh_interval;
|
let autoRefreshInterval = pluginData.config.get().auto_refresh_interval;
|
||||||
if (autoRefreshInterval != null) {
|
if (autoRefreshInterval != null) {
|
||||||
autoRefreshInterval = Math.max(MIN_AUTO_REFRESH, autoRefreshInterval);
|
autoRefreshInterval = Math.max(MIN_AUTO_REFRESH, autoRefreshInterval);
|
||||||
|
@ -70,7 +73,7 @@ export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
if (pluginData.state.autoRefreshTimeout) {
|
if (pluginData.state.autoRefreshTimeout) {
|
||||||
clearTimeout(pluginData.state.autoRefreshTimeout);
|
clearTimeout(pluginData.state.autoRefreshTimeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ export const AddReactionRoleEvt = reactionRolesEvt({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the reaction after a small delay
|
// Remove the reaction after a small delay
|
||||||
const config = pluginData.config.getForMember(member);
|
const config = await pluginData.config.getForMember(member);
|
||||||
if (config.remove_user_reactions) {
|
if (config.remove_user_reactions) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
pluginData.state.reactionRemoveQueue.add(async () => {
|
pluginData.state.reactionRemoveQueue.add(async () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildEventListener, guildCommand } from "knub";
|
import { BasePluginType, typedGuildEventListener, typedGuildCommand } from "knub";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { GuildReactionRoles } from "../../data/GuildReactionRoles";
|
import { GuildReactionRoles } from "../../data/GuildReactionRoles";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
|
@ -41,5 +41,5 @@ export interface ReactionRolesPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reactionRolesCmd = guildCommand<ReactionRolesPluginType>();
|
export const reactionRolesCmd = typedGuildCommand<ReactionRolesPluginType>();
|
||||||
export const reactionRolesEvt = guildEventListener<ReactionRolesPluginType>();
|
export const reactionRolesEvt = typedGuildEventListener<ReactionRolesPluginType>();
|
||||||
|
|
|
@ -22,7 +22,8 @@ const defaultOptions: PluginOptions<RemindersPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RemindersPlugin = zeppelinGuildPlugin<RemindersPluginType>()("reminders", {
|
export const RemindersPlugin = zeppelinGuildPlugin<RemindersPluginType>()({
|
||||||
|
name: "reminders",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Reminders",
|
prettyName: "Reminders",
|
||||||
|
@ -39,7 +40,7 @@ export const RemindersPlugin = zeppelinGuildPlugin<RemindersPluginType>()("remin
|
||||||
RemindersDeleteCmd,
|
RemindersDeleteCmd,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.reminders = GuildReminders.getGuildInstance(guild.id);
|
state.reminders = GuildReminders.getGuildInstance(guild.id);
|
||||||
|
@ -47,10 +48,13 @@ export const RemindersPlugin = zeppelinGuildPlugin<RemindersPluginType>()("remin
|
||||||
state.unloaded = false;
|
state.unloaded = false;
|
||||||
|
|
||||||
state.postRemindersTimeout = null;
|
state.postRemindersTimeout = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
afterLoad(pluginData) {
|
||||||
postDueRemindersLoop(pluginData);
|
postDueRemindersLoop(pluginData);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload(pluginData) {
|
beforeUnload(pluginData) {
|
||||||
clearTimeout(pluginData.state.postRemindersTimeout);
|
clearTimeout(pluginData.state.postRemindersTimeout);
|
||||||
pluginData.state.unloaded = true;
|
pluginData.state.unloaded = true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, guildCommand } from "knub";
|
import { BasePluginType, typedGuildCommand } from "knub";
|
||||||
import { GuildReminders } from "../../data/GuildReminders";
|
import { GuildReminders } from "../../data/GuildReminders";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
|
@ -19,4 +19,4 @@ export interface RemindersPluginType extends BasePluginType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const remindersCmd = guildCommand<RemindersPluginType>();
|
export const remindersCmd = typedGuildCommand<RemindersPluginType>();
|
||||||
|
|
|
@ -30,7 +30,8 @@ const defaultOptions: PluginOptions<RolesPluginType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RolesPlugin = zeppelinGuildPlugin<RolesPluginType>()("roles", {
|
export const RolesPlugin = zeppelinGuildPlugin<RolesPluginType>()({
|
||||||
|
name: "roles",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Roles",
|
prettyName: "Roles",
|
||||||
|
@ -50,7 +51,7 @@ export const RolesPlugin = zeppelinGuildPlugin<RolesPluginType>()("roles", {
|
||||||
MassRemoveRoleCmd,
|
MassRemoveRoleCmd,
|
||||||
],
|
],
|
||||||
|
|
||||||
onLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
const { state, guild } = pluginData;
|
const { state, guild } = pluginData;
|
||||||
|
|
||||||
state.logs = new GuildLogs(guild.id);
|
state.logs = new GuildLogs(guild.id);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue