Merge pull request #238 from DarkView/djs
This commit is contained in:
commit
09f7cbbd25
517 changed files with 8840 additions and 4185 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -77,3 +77,5 @@ npm-audit.txt
|
||||||
# Debug files
|
# Debug files
|
||||||
*.debug.ts
|
*.debug.ts
|
||||||
*.debug.js
|
*.debug.js
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
||||||
14
|
16.6
|
||||||
|
|
1413
backend/package-lock.json
generated
1413
backend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -23,24 +23,23 @@
|
||||||
"test-watch": "tsc-watch --onSuccess \"npx ava\""
|
"test-watch": "tsc-watch --onSuccess \"npx ava\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/sharp": "^0.23.1",
|
"bufferutil": "^4.0.3",
|
||||||
"@types/twemoji": "^12.1.0",
|
|
||||||
"bufferutil": "^4.0.1",
|
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"deep-diff": "^1.0.2",
|
"deep-diff": "^1.0.2",
|
||||||
|
"discord-api-types": "^0.22.0",
|
||||||
|
"discord.js": "^13.1.0",
|
||||||
"dotenv": "^4.0.0",
|
"dotenv": "^4.0.0",
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
"eris": "^0.15.1",
|
"erlpack": "github:almeidx/erlpack#f0c535f73817fd914806d6ca26a7730c14e0fb7c",
|
||||||
"erlpack": "github:abalabahaha/erlpack",
|
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
"express": "^4.17.0",
|
"express": "^4.17.0",
|
||||||
"fp-ts": "^2.0.1",
|
"fp-ts": "^2.0.1",
|
||||||
"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.37",
|
"knub": "file:../../Knub",
|
||||||
"knub-command-manager": "^8.1.2",
|
"knub-command-manager": "^9.1.0",
|
||||||
"last-commit-log": "^2.1.0",
|
"last-commit-log": "^2.1.0",
|
||||||
"lodash.chunk": "^4.2.0",
|
"lodash.chunk": "^4.2.0",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
@ -59,13 +58,14 @@
|
||||||
"regexp-worker": "^1.1.0",
|
"regexp-worker": "^1.1.0",
|
||||||
"safe-regex": "^2.0.2",
|
"safe-regex": "^2.0.2",
|
||||||
"seedrandom": "^3.0.1",
|
"seedrandom": "^3.0.1",
|
||||||
"sharp": "^0.23.4",
|
"sharp": "github:almeidx/sharp#68b4f387ae2ee1ee2dd8f289f5ec5fcf722fd3d3",
|
||||||
"strip-combining-marks": "^1.0.0",
|
"strip-combining-marks": "^1.0.0",
|
||||||
"tlds": "^1.203.1",
|
"tlds": "^1.203.1",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"twemoji": "^12.1.4",
|
"twemoji": "^12.1.4",
|
||||||
"typeorm": "^0.2.31",
|
"typeorm": "^0.2.31",
|
||||||
|
"utf-8-validate": "^5.0.5",
|
||||||
"uuid": "^3.3.2",
|
"uuid": "^3.3.2",
|
||||||
"yawn-yaml": "github:dragory/yawn-yaml#string-number-fix-build",
|
"yawn-yaml": "github:dragory/yawn-yaml#string-number-fix-build",
|
||||||
"zlib-sync": "^0.1.7"
|
"zlib-sync": "^0.1.7"
|
||||||
|
@ -82,12 +82,14 @@
|
||||||
"@types/passport-oauth2": "^1.4.8",
|
"@types/passport-oauth2": "^1.4.8",
|
||||||
"@types/passport-strategy": "^0.2.35",
|
"@types/passport-strategy": "^0.2.35",
|
||||||
"@types/safe-regex": "^1.1.2",
|
"@types/safe-regex": "^1.1.2",
|
||||||
|
"@types/sharp": "^0.23.1",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
|
"@types/twemoji": "^12.1.0",
|
||||||
"ava": "^3.10.0",
|
"ava": "^3.10.0",
|
||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
"source-map-support": "^0.5.16",
|
"source-map-support": "^0.5.16",
|
||||||
"tsc-watch": "^4.0.0",
|
"tsc-watch": "^4.0.0",
|
||||||
"typescript": "^4.1.3"
|
"typescript": "^4.3.4"
|
||||||
},
|
},
|
||||||
"ava": {
|
"ava": {
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import util from "util";
|
import util from "util";
|
||||||
|
|
||||||
export class ErisError extends Error {
|
export class DiscordJSError extends Error {
|
||||||
code: number | string | undefined;
|
code: number | string | undefined;
|
||||||
shardId: number;
|
shardId: number;
|
||||||
|
|
||||||
|
@ -11,6 +11,6 @@ export class ErisError extends Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
[util.inspect.custom]() {
|
[util.inspect.custom]() {
|
||||||
return `[ERIS] [ERROR CODE ${this.code || "?"}] [SHARD ${this.shardId}] ${this.message}`;
|
return `[DISCORDJS] [ERROR CODE ${this.code ?? "?"}] [SHARD ${this.shardId}] ${this.message}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { Guild } from "eris";
|
import { Guild } from "discord.js";
|
||||||
|
|
||||||
export enum ERRORS {
|
export enum ERRORS {
|
||||||
NO_MUTE_ROLE_IN_CONFIG = 1,
|
NO_MUTE_ROLE_IN_CONFIG = 1,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { RegExpWorker, TimeoutError } from "regexp-worker";
|
|
||||||
import { CooldownManager } from "knub";
|
|
||||||
import { MINUTES, SECONDS } from "./utils";
|
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
|
import { CooldownManager } from "knub";
|
||||||
|
import { RegExpWorker, TimeoutError } from "regexp-worker";
|
||||||
|
import { MINUTES, SECONDS } from "./utils";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
const isTimeoutError = (a): a is TimeoutError => {
|
const isTimeoutError = (a): a is TimeoutError => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import express, { Request, Response } from "express";
|
import express, { Request, Response } from "express";
|
||||||
|
import moment from "moment-timezone";
|
||||||
import { GuildArchives } from "../data/GuildArchives";
|
import { GuildArchives } from "../data/GuildArchives";
|
||||||
import { notFound } from "./responses";
|
import { notFound } from "./responses";
|
||||||
import moment from "moment-timezone";
|
|
||||||
|
|
||||||
export function initArchives(app: express.Express) {
|
export function initArchives(app: express.Express) {
|
||||||
const archives = new GuildArchives(null);
|
const archives = new GuildArchives(null);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import express, { Request, Response } from "express";
|
import express, { Request, Response } from "express";
|
||||||
import passport from "passport";
|
|
||||||
import OAuth2Strategy from "passport-oauth2";
|
|
||||||
import { Strategy as CustomStrategy } from "passport-custom";
|
|
||||||
import { ApiLogins } from "../data/ApiLogins";
|
|
||||||
import pick from "lodash.pick";
|
|
||||||
import https from "https";
|
import https from "https";
|
||||||
|
import pick from "lodash.pick";
|
||||||
|
import passport from "passport";
|
||||||
|
import { Strategy as CustomStrategy } from "passport-custom";
|
||||||
|
import OAuth2Strategy from "passport-oauth2";
|
||||||
|
import { ApiLogins } from "../data/ApiLogins";
|
||||||
|
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
||||||
import { ApiUserInfo } from "../data/ApiUserInfo";
|
import { ApiUserInfo } from "../data/ApiUserInfo";
|
||||||
import { ApiUserInfoData } from "../data/entities/ApiUserInfo";
|
import { ApiUserInfoData } from "../data/entities/ApiUserInfo";
|
||||||
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
|
||||||
import { ok } from "./responses";
|
import { ok } from "./responses";
|
||||||
|
|
||||||
interface IPassportApiUser {
|
interface IPassportApiUser {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { guildPlugins } from "../plugins/availablePlugins";
|
import { guildPlugins } from "../plugins/availablePlugins";
|
||||||
import { notFound } from "./responses";
|
|
||||||
import { indentLines } from "../utils";
|
import { indentLines } from "../utils";
|
||||||
|
import { notFound } from "./responses";
|
||||||
|
|
||||||
function formatConfigSchema(schema) {
|
function formatConfigSchema(schema) {
|
||||||
if (schema._tag === "InterfaceType" || schema._tag === "PartialType") {
|
if (schema._tag === "InterfaceType" || schema._tag === "PartialType") {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import express, { Request, Response } from "express";
|
|
||||||
import { AllowedGuilds } from "../data/AllowedGuilds";
|
|
||||||
import { clientError, ok, serverError, unauthorized } from "./responses";
|
|
||||||
import { Configs } from "../data/Configs";
|
|
||||||
import { validateGuildConfig } from "../configValidator";
|
|
||||||
import yaml, { YAMLException } from "js-yaml";
|
|
||||||
import { apiTokenAuthHandlers } from "./auth";
|
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
import { hasGuildPermission, requireGuildPermission } from "./permissions";
|
import express, { Request, Response } from "express";
|
||||||
|
import yaml, { YAMLException } from "js-yaml";
|
||||||
|
import { validateGuildConfig } from "../configValidator";
|
||||||
|
import { AllowedGuilds } from "../data/AllowedGuilds";
|
||||||
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
||||||
|
import { Configs } from "../data/Configs";
|
||||||
|
import { apiTokenAuthHandlers } from "./auth";
|
||||||
|
import { hasGuildPermission, requireGuildPermission } from "./permissions";
|
||||||
|
import { clientError, ok, serverError, unauthorized } from "./responses";
|
||||||
|
|
||||||
const apiPermissionAssignments = new ApiPermissionAssignments();
|
const apiPermissionAssignments = new ApiPermissionAssignments();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import "./loadEnv";
|
|
||||||
|
|
||||||
import { connect } from "../data/db";
|
import { connect } from "../data/db";
|
||||||
import path from "path";
|
|
||||||
import { setIsAPI } from "../globals";
|
import { setIsAPI } from "../globals";
|
||||||
|
import "./loadEnv";
|
||||||
|
|
||||||
if (!process.env.KEY) {
|
if (!process.env.KEY) {
|
||||||
// tslint:disable-next-line:no-console
|
// tslint:disable-next-line:no-console
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { ApiPermissions, hasPermission, permissionArrToSet } from "@shared/apiPermissions";
|
import { ApiPermissions, hasPermission, permissionArrToSet } from "@shared/apiPermissions";
|
||||||
import { isStaff } from "../staff";
|
|
||||||
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
||||||
|
import { isStaff } from "../staff";
|
||||||
import { unauthorized } from "./responses";
|
import { unauthorized } from "./responses";
|
||||||
|
|
||||||
const apiPermissionAssignments = new ApiPermissionAssignments();
|
const apiPermissionAssignments = new ApiPermissionAssignments();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import express, { Request, Response } from "express";
|
import express, { Request, Response } from "express";
|
||||||
import { apiTokenAuthHandlers } from "./auth";
|
|
||||||
import { isStaff } from "../staff";
|
import { isStaff } from "../staff";
|
||||||
|
import { apiTokenAuthHandlers } from "./auth";
|
||||||
|
|
||||||
export function initStaff(app: express.Express) {
|
export function initStaff(app: express.Express) {
|
||||||
const staffRouter = express.Router();
|
const staffRouter = express.Router();
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { clientError, error, notFound } from "./responses";
|
|
||||||
import express from "express";
|
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import { initAuth } from "./auth";
|
import express from "express";
|
||||||
import { initGuildsAPI } from "./guilds";
|
|
||||||
import { initArchives } from "./archives";
|
|
||||||
import { initDocs } from "./docs";
|
|
||||||
import { TokenError } from "passport-oauth2";
|
import { TokenError } from "passport-oauth2";
|
||||||
|
import { initArchives } from "./archives";
|
||||||
|
import { initAuth } from "./auth";
|
||||||
|
import { initDocs } from "./docs";
|
||||||
|
import { initGuildsAPI } from "./guilds";
|
||||||
|
import { clientError, error, notFound } from "./responses";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import { GuildChannel, GuildMember, Snowflake, Util, User } from "discord.js";
|
||||||
|
import { baseCommandParameterTypeHelpers, baseTypeConverters, CommandContext, TypeConversionError } from "knub";
|
||||||
|
import { createTypeHelper } from "knub-command-manager";
|
||||||
import {
|
import {
|
||||||
channelMentionRegex,
|
channelMentionRegex,
|
||||||
convertDelayStringToMS,
|
convertDelayStringToMS,
|
||||||
disableCodeBlocks,
|
|
||||||
disableInlineCode,
|
|
||||||
isSnowflake,
|
|
||||||
isValidSnowflake,
|
isValidSnowflake,
|
||||||
resolveMember,
|
resolveMember,
|
||||||
resolveUser,
|
resolveUser,
|
||||||
|
@ -11,13 +11,9 @@ import {
|
||||||
roleMentionRegex,
|
roleMentionRegex,
|
||||||
UnknownUser,
|
UnknownUser,
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import { GuildChannel, Member, TextChannel, User } from "eris";
|
import { isValidTimezone } from "./utils/isValidTimezone";
|
||||||
import { baseTypeConverters, baseCommandParameterTypeHelpers, CommandContext, TypeConversionError } from "knub";
|
|
||||||
import { createTypeHelper } from "knub-command-manager";
|
|
||||||
import { getChannelIdFromMessageId } from "./data/getChannelIdFromMessageId";
|
|
||||||
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
||||||
import { inputPatternToRegExp } from "./validatorUtils";
|
import { inputPatternToRegExp } from "./validatorUtils";
|
||||||
import { isValidTimezone } from "./utils/isValidTimezone";
|
|
||||||
|
|
||||||
export const commandTypes = {
|
export const commandTypes = {
|
||||||
...baseTypeConverters,
|
...baseTypeConverters,
|
||||||
|
@ -34,7 +30,7 @@ export const commandTypes = {
|
||||||
async resolvedUser(value, context: CommandContext<any>) {
|
async resolvedUser(value, context: CommandContext<any>) {
|
||||||
const result = await resolveUser(context.pluginData.client, value);
|
const result = await resolveUser(context.pluginData.client, value);
|
||||||
if (result == null || result instanceof UnknownUser) {
|
if (result == null || result instanceof UnknownUser) {
|
||||||
throw new TypeConversionError(`User \`${disableCodeBlocks(value)}\` was not found`);
|
throw new TypeConversionError(`User \`${Util.escapeCodeBlock(value)}\` was not found`);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
@ -42,7 +38,7 @@ export const commandTypes = {
|
||||||
async resolvedUserLoose(value, context: CommandContext<any>) {
|
async resolvedUserLoose(value, context: CommandContext<any>) {
|
||||||
const result = await resolveUser(context.pluginData.client, value);
|
const result = await resolveUser(context.pluginData.client, value);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new TypeConversionError(`Invalid user: \`${disableCodeBlocks(value)}\``);
|
throw new TypeConversionError(`Invalid user: \`${Util.escapeCodeBlock(value)}\``);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
@ -55,7 +51,7 @@ export const commandTypes = {
|
||||||
const result = await resolveMember(context.pluginData.client, context.message.channel.guild, value);
|
const result = await resolveMember(context.pluginData.client, context.message.channel.guild, value);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new TypeConversionError(
|
throw new TypeConversionError(
|
||||||
`Member \`${disableCodeBlocks(value)}\` was not found or they have left the server`,
|
`Member \`${Util.escapeCodeBlock(value)}\` was not found or they have left the server`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -66,7 +62,7 @@ export const commandTypes = {
|
||||||
|
|
||||||
const result = await resolveMessageTarget(context.pluginData, value);
|
const result = await resolveMessageTarget(context.pluginData, value);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new TypeConversionError(`Unknown message \`${disableInlineCode(value)}\``);
|
throw new TypeConversionError(`Unknown message \`${Util.escapeInlineCode(value)}\``);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -74,32 +70,32 @@ export const commandTypes = {
|
||||||
|
|
||||||
async anyId(value: string, context: CommandContext<any>) {
|
async anyId(value: string, context: CommandContext<any>) {
|
||||||
const userId = resolveUserId(context.pluginData.client, value);
|
const userId = resolveUserId(context.pluginData.client, value);
|
||||||
if (userId) return userId;
|
if (userId) return userId as Snowflake;
|
||||||
|
|
||||||
const channelIdMatch = value.match(channelMentionRegex);
|
const channelIdMatch = value.match(channelMentionRegex);
|
||||||
if (channelIdMatch) return channelIdMatch[1];
|
if (channelIdMatch) return channelIdMatch[1] as Snowflake;
|
||||||
|
|
||||||
const roleIdMatch = value.match(roleMentionRegex);
|
const roleIdMatch = value.match(roleMentionRegex);
|
||||||
if (roleIdMatch) return roleIdMatch[1];
|
if (roleIdMatch) return roleIdMatch[1] as Snowflake;
|
||||||
|
|
||||||
if (isValidSnowflake(value)) {
|
if (isValidSnowflake(value)) {
|
||||||
return value;
|
return value as Snowflake;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TypeConversionError(`Could not parse ID: \`${disableInlineCode(value)}\``);
|
throw new TypeConversionError(`Could not parse ID: \`${Util.escapeInlineCode(value)}\``);
|
||||||
},
|
},
|
||||||
|
|
||||||
regex(value: string, context: CommandContext<any>): RegExp {
|
regex(value: string, context: CommandContext<any>): RegExp {
|
||||||
try {
|
try {
|
||||||
return inputPatternToRegExp(value);
|
return inputPatternToRegExp(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new TypeConversionError(`Could not parse RegExp: \`${disableInlineCode(e.message)}\``);
|
throw new TypeConversionError(`Could not parse RegExp: \`${Util.escapeInlineCode(e.message)}\``);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
timezone(value: string) {
|
timezone(value: string) {
|
||||||
if (!isValidTimezone(value)) {
|
if (!isValidTimezone(value)) {
|
||||||
throw new TypeConversionError(`Invalid timezone: ${disableInlineCode(value)}`);
|
throw new TypeConversionError(`Invalid timezone: ${Util.escapeInlineCode(value)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
@ -112,9 +108,9 @@ export const commandTypeHelpers = {
|
||||||
delay: createTypeHelper<number>(commandTypes.delay),
|
delay: createTypeHelper<number>(commandTypes.delay),
|
||||||
resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser),
|
resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser),
|
||||||
resolvedUserLoose: createTypeHelper<Promise<User | UnknownUser>>(commandTypes.resolvedUserLoose),
|
resolvedUserLoose: createTypeHelper<Promise<User | UnknownUser>>(commandTypes.resolvedUserLoose),
|
||||||
resolvedMember: createTypeHelper<Promise<Member>>(commandTypes.resolvedMember),
|
resolvedMember: createTypeHelper<Promise<GuildMember>>(commandTypes.resolvedMember),
|
||||||
messageTarget: createTypeHelper<Promise<MessageTarget>>(commandTypes.messageTarget),
|
messageTarget: createTypeHelper<Promise<MessageTarget>>(commandTypes.messageTarget),
|
||||||
anyId: createTypeHelper<Promise<string>>(commandTypes.anyId),
|
anyId: createTypeHelper<Promise<Snowflake>>(commandTypes.anyId),
|
||||||
regex: createTypeHelper<RegExp>(commandTypes.regex),
|
regex: createTypeHelper<RegExp>(commandTypes.regex),
|
||||||
timezone: createTypeHelper<string>(commandTypes.timezone),
|
timezone: createTypeHelper<string>(commandTypes.timezone),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { guildPlugins } from "./plugins/availablePlugins";
|
|
||||||
import { decodeAndValidateStrict, StrictValidationError } from "./validatorUtils";
|
|
||||||
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
|
||||||
import { PartialZeppelinGuildConfigSchema, ZeppelinGuildConfig } from "./types";
|
|
||||||
import { configUtils, ConfigValidationError, PluginOptions } from "knub";
|
import { configUtils, ConfigValidationError, PluginOptions } from "knub";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { guildPlugins } from "./plugins/availablePlugins";
|
||||||
|
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
||||||
|
import { PartialZeppelinGuildConfigSchema, ZeppelinGuildConfig } from "./types";
|
||||||
|
import { decodeAndValidateStrict, StrictValidationError } from "./validatorUtils";
|
||||||
|
|
||||||
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
|
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
|
||||||
for (const plugin of guildPlugins) {
|
for (const plugin of guildPlugins) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { AllowedGuild } from "./entities/AllowedGuild";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { BaseRepository } from "./BaseRepository";
|
|
||||||
import { ApiPermissionTypes } from "./ApiPermissionAssignments";
|
import { ApiPermissionTypes } from "./ApiPermissionAssignments";
|
||||||
|
import { BaseRepository } from "./BaseRepository";
|
||||||
|
import { AllowedGuild } from "./entities/AllowedGuild";
|
||||||
|
|
||||||
export class AllowedGuilds extends BaseRepository {
|
export class AllowedGuilds extends BaseRepository {
|
||||||
private allowedGuilds: Repository<AllowedGuild>;
|
private allowedGuilds: Repository<AllowedGuild>;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { getRepository, Repository } from "typeorm";
|
|
||||||
import { ApiLogin } from "./entities/ApiLogin";
|
|
||||||
import { BaseRepository } from "./BaseRepository";
|
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { getRepository, Repository } from "typeorm";
|
||||||
// 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 { DAYS, DBDateFormat } from "../utils";
|
import { DAYS, DBDateFormat } from "../utils";
|
||||||
|
import { BaseRepository } from "./BaseRepository";
|
||||||
|
import { ApiLogin } from "./entities/ApiLogin";
|
||||||
|
|
||||||
const LOGIN_EXPIRY_TIME = 1 * DAYS;
|
const LOGIN_EXPIRY_TIME = 1 * DAYS;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { getRepository, Repository } from "typeorm";
|
|
||||||
import { ApiPermissionAssignment } from "./entities/ApiPermissionAssignment";
|
|
||||||
import { BaseRepository } from "./BaseRepository";
|
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseRepository } from "./BaseRepository";
|
||||||
|
import { ApiPermissionAssignment } from "./entities/ApiPermissionAssignment";
|
||||||
|
|
||||||
export enum ApiPermissionTypes {
|
export enum ApiPermissionTypes {
|
||||||
User = "USER",
|
User = "USER",
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import moment from "moment-timezone";
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { ApiUserInfo as ApiUserInfoEntity, ApiUserInfoData } from "./entities/ApiUserInfo";
|
import { DBDateFormat } from "../utils";
|
||||||
import { BaseRepository } from "./BaseRepository";
|
import { BaseRepository } from "./BaseRepository";
|
||||||
import { connection } from "./db";
|
import { connection } from "./db";
|
||||||
import moment from "moment-timezone";
|
import { ApiUserInfo as ApiUserInfoEntity, ApiUserInfoData } from "./entities/ApiUserInfo";
|
||||||
import { DBDateFormat } from "../utils";
|
|
||||||
|
|
||||||
export class ApiUserInfo extends BaseRepository {
|
export class ApiUserInfo extends BaseRepository {
|
||||||
private apiUserInfo: Repository<ApiUserInfoEntity>;
|
private apiUserInfo: Repository<ApiUserInfoEntity>;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Config } from "./entities/Config";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { connection } from "./db";
|
|
||||||
import { BaseRepository } from "./BaseRepository";
|
|
||||||
import { isAPI } from "../globals";
|
import { isAPI } from "../globals";
|
||||||
import { HOURS, SECONDS } from "../utils";
|
import { HOURS, SECONDS } from "../utils";
|
||||||
|
import { BaseRepository } from "./BaseRepository";
|
||||||
import { cleanupConfigs } from "./cleanup/configs";
|
import { cleanupConfigs } from "./cleanup/configs";
|
||||||
|
import { connection } from "./db";
|
||||||
|
import { Config } from "./entities/Config";
|
||||||
|
|
||||||
if (isAPI()) {
|
if (isAPI()) {
|
||||||
const CLEANUP_INTERVAL = 1 * HOURS;
|
const CLEANUP_INTERVAL = 1 * HOURS;
|
||||||
|
|
|
@ -24,11 +24,15 @@
|
||||||
|
|
||||||
"CHANNEL_CREATE": "🖊 Channel {channelMention(channel)} was created",
|
"CHANNEL_CREATE": "🖊 Channel {channelMention(channel)} was created",
|
||||||
"CHANNEL_DELETE": "🗑 Channel {channelMention(channel)} was deleted",
|
"CHANNEL_DELETE": "🗑 Channel {channelMention(channel)} was deleted",
|
||||||
"CHANNEL_EDIT": "✏ Channel {channelMention(channel)} was edited",
|
"CHANNEL_UPDATE": "✏ Channel {channelMention(newChannel)} was edited. Changes:\n{differenceString}",
|
||||||
|
|
||||||
|
"THREAD_CREATE": "🖊 Thread {channelMention(thread)} was created in channel <#{thread.parentId}>",
|
||||||
|
"THREAD_DELETE": "🗑 Thread {channelMention(thread)} was deleted/archived from channel <#{thread.parentId}>",
|
||||||
|
"THREAD_UPDATE": "✏ Thread {channelMention(newThread)} was edited. Changes:\n{differenceString}",
|
||||||
|
|
||||||
"ROLE_CREATE": "🖊 Role **{role.name}** (`{role.id}`) was created",
|
"ROLE_CREATE": "🖊 Role **{role.name}** (`{role.id}`) was created",
|
||||||
"ROLE_DELETE": "🖊 Role **{role.name}** (`{role.id}`) was deleted",
|
"ROLE_DELETE": "🖊 Role **{role.name}** (`{role.id}`) was deleted",
|
||||||
"ROLE_EDIT": "🖊 Role **{role.name}** (`{role.id}`) was edited",
|
"ROLE_UPDATE": "🖊 Role **{newRole.name}** (`{newRole.id}`) was edited. Changes:\n{differenceString}",
|
||||||
|
|
||||||
"MESSAGE_EDIT": "✏ {userMention(user)} edited their message (`{after.id}`) in {channelMention(channel)}:\n**Before:**{messageSummary(before)}**After:**{messageSummary(after)}",
|
"MESSAGE_EDIT": "✏ {userMention(user)} edited their message (`{after.id}`) in {channelMention(channel)}:\n**Before:**{messageSummary(before)}**After:**{messageSummary(after)}",
|
||||||
"MESSAGE_DELETE": "🗑 Message (`{message.id}`) from {userMention(user)} deleted in {channelMention(channel)} (originally posted at **{messageDate}**):{messageSummary(message)}",
|
"MESSAGE_DELETE": "🗑 Message (`{message.id}`) from {userMention(user)} deleted in {channelMention(channel)} (originally posted at **{messageDate}**):{messageSummary(message)}",
|
||||||
|
@ -42,6 +46,18 @@
|
||||||
"VOICE_CHANNEL_FORCE_MOVE": "\uD83C\uDF99 ✍ {userMention(member)} was moved from **{oldChannel.name}** to **{newChannel.name}** by {userMention(mod)}",
|
"VOICE_CHANNEL_FORCE_MOVE": "\uD83C\uDF99 ✍ {userMention(member)} was moved from **{oldChannel.name}** to **{newChannel.name}** by {userMention(mod)}",
|
||||||
"VOICE_CHANNEL_FORCE_DISCONNECT": "\uD83C\uDF99 🚫 {userMention(member)} was forcefully disconnected from **{oldChannel.name}** by {userMention(mod)}",
|
"VOICE_CHANNEL_FORCE_DISCONNECT": "\uD83C\uDF99 🚫 {userMention(member)} was forcefully disconnected from **{oldChannel.name}** by {userMention(mod)}",
|
||||||
|
|
||||||
|
"STAGE_INSTANCE_CREATE": "📣 Stage Instance `{stageInstance.topic}` was created in Stage Channel <#{stageChannel.id}>",
|
||||||
|
"STAGE_INSTANCE_DELETE": "📣 Stage Instance `{stageInstance.topic}` was deleted in Stage Channel <#{stageChannel.id}>",
|
||||||
|
"STAGE_INSTANCE_UPDATE": "📣 Stage Instance `{newStageInstance.topic}` was edited in Stage Channel <#{stageChannel.id}>. Changes:\n{differenceString}",
|
||||||
|
|
||||||
|
"EMOJI_CREATE": "<{emoji.identifier}> Emoji `{emoji.name} ({emoji.id})` was created",
|
||||||
|
"EMOJI_DELETE": "👋 Emoji `{emoji.name} ({emoji.id})` was deleted",
|
||||||
|
"EMOJI_UPDATE": "<{newEmoji.identifier}> Emoji `{newEmoji.name} ({newEmoji.id})` was updated. Changes:\n{differenceString}",
|
||||||
|
|
||||||
|
"STICKER_CREATE": "🖼️ Sticker `{sticker.name} ({sticker.id})` was created. Description: `{sticker.description}` Format: {emoji.format}",
|
||||||
|
"STICKER_DELETE": "🖼️ Sticker `{sticker.name} ({sticker.id})` was deleted.",
|
||||||
|
"STICKER_UPDATE": "🖼️ Sticker `{newSticker.name} ({sticker.id})` was updated. Changes:\n{differenceString}",
|
||||||
|
|
||||||
"COMMAND": "🤖 {userMention(member)} used command in {channelMention(channel)}:\n`{command}`",
|
"COMMAND": "🤖 {userMention(member)} used command in {channelMention(channel)}:\n`{command}`",
|
||||||
|
|
||||||
"MESSAGE_SPAM_DETECTED": "🛑 {userMention(member)} spam detected in {channelMention(channel)}: {description} (more than {limit} in {interval}s)\n{archiveUrl}",
|
"MESSAGE_SPAM_DETECTED": "🛑 {userMention(member)} spam detected in {channelMention(channel)}: {description} (more than {limit} in {interval}s)\n{archiveUrl}",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { AntiraidLevel } from "./entities/AntiraidLevel";
|
import { AntiraidLevel } from "./entities/AntiraidLevel";
|
||||||
|
|
||||||
export class GuildAntiraidLevels extends BaseGuildRepository {
|
export class GuildAntiraidLevels extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
import { Guild, Snowflake } from "discord.js";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { ArchiveEntry } from "./entities/ArchiveEntry";
|
import { isDefaultSticker } from "src/utils/isDefaultSticker";
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { trimLines } from "../utils";
|
|
||||||
import { SavedMessage } from "./entities/SavedMessage";
|
|
||||||
import { Guild } from "eris";
|
|
||||||
import { renderTemplate } from "../templateFormatter";
|
import { renderTemplate } from "../templateFormatter";
|
||||||
|
import { trimLines } from "../utils";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { ArchiveEntry } from "./entities/ArchiveEntry";
|
||||||
|
import { SavedMessage } from "./entities/SavedMessage";
|
||||||
|
|
||||||
const DEFAULT_EXPIRY_DAYS = 30;
|
const DEFAULT_EXPIRY_DAYS = 30;
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ const MESSAGE_ARCHIVE_HEADER_FORMAT = trimLines(`
|
||||||
Server: {guild.name} ({guild.id})
|
Server: {guild.name} ({guild.id})
|
||||||
`);
|
`);
|
||||||
const MESSAGE_ARCHIVE_MESSAGE_FORMAT =
|
const MESSAGE_ARCHIVE_MESSAGE_FORMAT =
|
||||||
"[#{channel.name}] [{user.id}] [{timestamp}] {user.username}#{user.discriminator}: {content}{attachments}";
|
"[#{channel.name}] [{user.id}] [{timestamp}] {user.username}#{user.discriminator}: {content}{attachments}{stickers}";
|
||||||
|
|
||||||
export class GuildArchives extends BaseGuildRepository {
|
export class GuildArchives extends BaseGuildRepository {
|
||||||
protected archives: Repository<ArchiveEntry>;
|
protected archives: Repository<ArchiveEntry>;
|
||||||
|
@ -73,13 +74,19 @@ export class GuildArchives extends BaseGuildRepository {
|
||||||
protected async renderLinesFromSavedMessages(savedMessages: SavedMessage[], guild: Guild) {
|
protected async renderLinesFromSavedMessages(savedMessages: SavedMessage[], guild: Guild) {
|
||||||
const msgLines: string[] = [];
|
const msgLines: string[] = [];
|
||||||
for (const msg of savedMessages) {
|
for (const msg of savedMessages) {
|
||||||
const channel = guild.channels.get(msg.channel_id);
|
const channel = guild.channels.cache.get(msg.channel_id as Snowflake);
|
||||||
const user = { ...msg.data.author, id: msg.user_id };
|
const user = { ...msg.data.author, id: msg.user_id };
|
||||||
|
|
||||||
const line = await renderTemplate(MESSAGE_ARCHIVE_MESSAGE_FORMAT, {
|
const line = await renderTemplate(MESSAGE_ARCHIVE_MESSAGE_FORMAT, {
|
||||||
id: msg.id,
|
id: msg.id,
|
||||||
timestamp: moment.utc(msg.posted_at).format("YYYY-MM-DD HH:mm:ss"),
|
timestamp: moment.utc(msg.posted_at).format("YYYY-MM-DD HH:mm:ss"),
|
||||||
content: msg.data.content,
|
content: msg.data.content,
|
||||||
|
attachments: msg.data.attachments?.map(att => {
|
||||||
|
return JSON.stringify({ name: att.name, url: att.url, type: att.contentType });
|
||||||
|
}),
|
||||||
|
stickers: msg.data.stickers?.map(sti => {
|
||||||
|
return JSON.stringify({ name: sti.name, id: sti.id, isDefault: isDefaultSticker(sti.id) });
|
||||||
|
}),
|
||||||
user,
|
user,
|
||||||
channel,
|
channel,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { AutoReaction } from "./entities/AutoReaction";
|
import { AutoReaction } from "./entities/AutoReaction";
|
||||||
|
|
||||||
export class GuildAutoReactions extends BaseGuildRepository {
|
export class GuildAutoReactions extends BaseGuildRepository {
|
||||||
|
|
58
backend/src/data/GuildButtonRoles.ts
Normal file
58
backend/src/data/GuildButtonRoles.ts
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { ButtonRole } from "./entities/ButtonRole";
|
||||||
|
|
||||||
|
export class GuildButtonRoles extends BaseGuildRepository {
|
||||||
|
private buttonRoles: Repository<ButtonRole>;
|
||||||
|
|
||||||
|
constructor(guildId) {
|
||||||
|
super(guildId);
|
||||||
|
this.buttonRoles = getRepository(ButtonRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getForButtonId(buttonId: string) {
|
||||||
|
return this.buttonRoles.findOne({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
button_id: buttonId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllForMessageId(messageId: string) {
|
||||||
|
return this.buttonRoles.find({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
message_id: messageId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeForButtonId(buttonId: string) {
|
||||||
|
return this.buttonRoles.delete({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
button_id: buttonId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeAllForMessageId(messageId: string) {
|
||||||
|
return this.buttonRoles.delete({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
message_id: messageId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getForButtonGroup(buttonGroup: string) {
|
||||||
|
return this.buttonRoles.find({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
button_group: buttonGroup,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(channelId: string, messageId: string, buttonId: string, buttonGroup: string, buttonName: string) {
|
||||||
|
await this.buttonRoles.insert({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
channel_id: channelId,
|
||||||
|
message_id: messageId,
|
||||||
|
button_id: buttonId,
|
||||||
|
button_group: buttonGroup,
|
||||||
|
button_name: buttonName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
|
import { getRepository, In, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { CaseTypes } from "./CaseTypes";
|
||||||
|
import { connection } from "./db";
|
||||||
import { Case } from "./entities/Case";
|
import { Case } from "./entities/Case";
|
||||||
import { CaseNote } from "./entities/CaseNote";
|
import { CaseNote } from "./entities/CaseNote";
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, In, Repository } from "typeorm";
|
|
||||||
import { DBDateFormat, disableLinkPreviews } from "../utils";
|
|
||||||
import { CaseTypes } from "./CaseTypes";
|
|
||||||
import moment = require("moment-timezone");
|
import moment = require("moment-timezone");
|
||||||
import { connection } from "./db";
|
|
||||||
|
|
||||||
const CASE_SUMMARY_REASON_MAX_LENGTH = 300;
|
const CASE_SUMMARY_REASON_MAX_LENGTH = 300;
|
||||||
|
|
||||||
|
|
35
backend/src/data/GuildContextMenuLinks.ts
Normal file
35
backend/src/data/GuildContextMenuLinks.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { DeleteResult, getRepository, InsertResult, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { ContextMenuLink } from "./entities/ContextMenuLink";
|
||||||
|
|
||||||
|
export class GuildContextMenuLinks extends BaseGuildRepository {
|
||||||
|
private contextLinks: Repository<ContextMenuLink>;
|
||||||
|
|
||||||
|
constructor(guildId) {
|
||||||
|
super(guildId);
|
||||||
|
this.contextLinks = getRepository(ContextMenuLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(id: string): Promise<ContextMenuLink | undefined> {
|
||||||
|
return this.contextLinks.findOne({
|
||||||
|
where: {
|
||||||
|
guild_id: this.guildId,
|
||||||
|
context_id: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(contextId: string, contextAction: string): Promise<InsertResult> {
|
||||||
|
return this.contextLinks.insert({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
context_id: contextId,
|
||||||
|
action_name: contextAction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAll(): Promise<DeleteResult> {
|
||||||
|
return this.contextLinks.delete({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,13 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { FindConditions, getRepository, In, IsNull, LessThan, Not, Repository } from "typeorm";
|
|
||||||
import { Counter } from "./entities/Counter";
|
|
||||||
import { CounterValue } from "./entities/CounterValue";
|
|
||||||
import {
|
|
||||||
CounterTrigger,
|
|
||||||
isValidCounterComparisonOp,
|
|
||||||
TRIGGER_COMPARISON_OPS,
|
|
||||||
TriggerComparisonOp,
|
|
||||||
} from "./entities/CounterTrigger";
|
|
||||||
import { CounterTriggerState } from "./entities/CounterTriggerState";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { DAYS, DBDateFormat, HOURS, MINUTES } from "../utils";
|
import { FindConditions, getRepository, In, IsNull, Not, Repository } from "typeorm";
|
||||||
import { connection } from "./db";
|
|
||||||
import { Queue } from "../Queue";
|
import { Queue } from "../Queue";
|
||||||
|
import { DAYS, DBDateFormat, HOURS, MINUTES } from "../utils";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { connection } from "./db";
|
||||||
|
import { Counter } from "./entities/Counter";
|
||||||
|
import { CounterTrigger, isValidCounterComparisonOp, TriggerComparisonOp } from "./entities/CounterTrigger";
|
||||||
|
import { CounterTriggerState } from "./entities/CounterTriggerState";
|
||||||
|
import { CounterValue } from "./entities/CounterValue";
|
||||||
|
|
||||||
const DELETE_UNUSED_COUNTERS_AFTER = 1 * DAYS;
|
const DELETE_UNUSED_COUNTERS_AFTER = 1 * DAYS;
|
||||||
const DELETE_UNUSED_COUNTER_TRIGGERS_AFTER = 1 * DAYS;
|
const DELETE_UNUSED_COUNTER_TRIGGERS_AFTER = 1 * DAYS;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
|
||||||
export class GuildEvents extends BaseGuildRepository {
|
export class GuildEvents extends BaseGuildRepository {
|
||||||
private queuedEventEmitter: QueuedEventEmitter;
|
private queuedEventEmitter: QueuedEventEmitter;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { MemberTimezone } from "./entities/MemberTimezone";
|
|
||||||
import { getRepository, Repository } from "typeorm/index";
|
import { getRepository, Repository } from "typeorm/index";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { connection } from "./db";
|
import { connection } from "./db";
|
||||||
|
import { MemberTimezone } from "./entities/MemberTimezone";
|
||||||
|
|
||||||
export class GuildMemberTimezones extends BaseGuildRepository {
|
export class GuildMemberTimezones extends BaseGuildRepository {
|
||||||
protected memberTimezones: Repository<MemberTimezone>;
|
protected memberTimezones: Repository<MemberTimezone>;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { Mute } from "./entities/Mute";
|
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { Brackets, getRepository, Repository } from "typeorm";
|
import { Brackets, getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { Mute } from "./entities/Mute";
|
||||||
|
|
||||||
export class GuildMutes extends BaseGuildRepository {
|
export class GuildMutes extends BaseGuildRepository {
|
||||||
private mutes: Repository<Mute>;
|
private mutes: Repository<Mute>;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, In, Repository } from "typeorm";
|
import { getRepository, In, Repository } from "typeorm";
|
||||||
import { NicknameHistoryEntry } from "./entities/NicknameHistoryEntry";
|
|
||||||
import { MINUTES, SECONDS } from "../utils";
|
|
||||||
import { isAPI } from "../globals";
|
import { isAPI } from "../globals";
|
||||||
|
import { MINUTES, SECONDS } from "../utils";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { cleanupNicknames } from "./cleanup/nicknames";
|
import { cleanupNicknames } from "./cleanup/nicknames";
|
||||||
|
import { NicknameHistoryEntry } from "./entities/NicknameHistoryEntry";
|
||||||
|
|
||||||
if (!isAPI()) {
|
if (!isAPI()) {
|
||||||
const CLEANUP_INTERVAL = 5 * MINUTES;
|
const CLEANUP_INTERVAL = 5 * MINUTES;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { PersistedData } from "./entities/PersistedData";
|
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { PersistedData } from "./entities/PersistedData";
|
||||||
|
|
||||||
export interface IPartialPersistData {
|
export interface IPartialPersistData {
|
||||||
roles?: string[];
|
roles?: string[];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { PingableRole } from "./entities/PingableRole";
|
import { PingableRole } from "./entities/PingableRole";
|
||||||
|
|
||||||
export class GuildPingableRoles extends BaseGuildRepository {
|
export class GuildPingableRoles extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ReactionRole } from "./entities/ReactionRole";
|
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { ReactionRole } from "./entities/ReactionRole";
|
||||||
|
|
||||||
export class GuildReactionRoles extends BaseGuildRepository {
|
export class GuildReactionRoles extends BaseGuildRepository {
|
||||||
private reactionRoles: Repository<ReactionRole>;
|
private reactionRoles: Repository<ReactionRole>;
|
||||||
|
@ -24,6 +24,9 @@ export class GuildReactionRoles extends BaseGuildRepository {
|
||||||
guild_id: this.guildId,
|
guild_id: this.guildId,
|
||||||
message_id: messageId,
|
message_id: messageId,
|
||||||
},
|
},
|
||||||
|
order: {
|
||||||
|
order: "ASC",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +53,14 @@ export class GuildReactionRoles extends BaseGuildRepository {
|
||||||
await this.reactionRoles.delete(criteria);
|
await this.reactionRoles.delete(criteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
async add(channelId: string, messageId: string, emoji: string, roleId: string, exclusive?: boolean) {
|
async add(
|
||||||
|
channelId: string,
|
||||||
|
messageId: string,
|
||||||
|
emoji: string,
|
||||||
|
roleId: string,
|
||||||
|
exclusive?: boolean,
|
||||||
|
position?: number,
|
||||||
|
) {
|
||||||
await this.reactionRoles.insert({
|
await this.reactionRoles.insert({
|
||||||
guild_id: this.guildId,
|
guild_id: this.guildId,
|
||||||
channel_id: channelId,
|
channel_id: channelId,
|
||||||
|
@ -58,6 +68,7 @@ export class GuildReactionRoles extends BaseGuildRepository {
|
||||||
emoji,
|
emoji,
|
||||||
role_id: roleId,
|
role_id: roleId,
|
||||||
is_exclusive: Boolean(exclusive),
|
is_exclusive: Boolean(exclusive),
|
||||||
|
order: position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { Reminder } from "./entities/Reminder";
|
import { Reminder } from "./entities/Reminder";
|
||||||
|
|
||||||
export class GuildReminders extends BaseGuildRepository {
|
export class GuildReminders extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { GuildChannel, Message } from "discord.js";
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
|
|
||||||
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
|
||||||
import { GuildChannel, Message, PossiblyUncachedTextableChannel } from "eris";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { MINUTES, SECONDS } from "../utils";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||||
import { isAPI } from "../globals";
|
import { isAPI } from "../globals";
|
||||||
|
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
||||||
|
import { MINUTES, SECONDS } from "../utils";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { cleanupMessages } from "./cleanup/messages";
|
import { cleanupMessages } from "./cleanup/messages";
|
||||||
|
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
|
||||||
|
|
||||||
if (!isAPI()) {
|
if (!isAPI()) {
|
||||||
const CLEANUP_INTERVAL = 5 * MINUTES;
|
const CLEANUP_INTERVAL = 5 * MINUTES;
|
||||||
|
@ -34,19 +35,19 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
this.toBePermanent = new Set();
|
this.toBePermanent = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public msgToSavedMessageData(msg: Message<PossiblyUncachedTextableChannel>): ISavedMessageData {
|
public msgToSavedMessageData(msg: Message): ISavedMessageData {
|
||||||
const data: ISavedMessageData = {
|
const data: ISavedMessageData = {
|
||||||
author: {
|
author: {
|
||||||
username: msg.author.username,
|
username: msg.author.username,
|
||||||
discriminator: msg.author.discriminator,
|
discriminator: msg.author.discriminator,
|
||||||
},
|
},
|
||||||
content: msg.content,
|
content: msg.content,
|
||||||
timestamp: msg.timestamp,
|
timestamp: msg.createdTimestamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (msg.attachments.length) data.attachments = msg.attachments;
|
if (msg.attachments.size) data.attachments = [...msg.attachments.values()];
|
||||||
if (msg.embeds.length) data.embeds = msg.embeds;
|
if (msg.embeds.length) data.embeds = msg.embeds;
|
||||||
if (msg.stickers?.length) data.stickers = msg.stickers;
|
if (msg.stickers?.size) data.stickers = [...msg.stickers.values()];
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -139,12 +140,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
this.events.emit(`create:${data.id}`, [inserted]);
|
this.events.emit(`create:${data.id}`, [inserted]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createFromMsg(msg: Message<PossiblyUncachedTextableChannel>, overrides = {}) {
|
async createFromMsg(msg: Message, overrides = {}) {
|
||||||
const existingSavedMsg = await this.find(msg.id);
|
const existingSavedMsg = await this.find(msg.id);
|
||||||
if (existingSavedMsg) return;
|
if (existingSavedMsg) return;
|
||||||
|
|
||||||
const savedMessageData = this.msgToSavedMessageData(msg);
|
const savedMessageData = this.msgToSavedMessageData(msg);
|
||||||
const postedAt = moment.utc(msg.timestamp, "x").format("YYYY-MM-DD HH:mm:ss");
|
const postedAt = moment.utc(msg.createdTimestamp, "x").format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
id: msg.id,
|
id: msg.id,
|
||||||
|
@ -159,6 +160,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
return this.create({ ...data, ...overrides });
|
return this.create({ ...data, ...overrides });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createFromMessages(messages: Message[], overrides = {}) {
|
||||||
|
for (const msg of messages) {
|
||||||
|
await this.createFromMsg(msg, overrides);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async markAsDeleted(id) {
|
async markAsDeleted(id) {
|
||||||
await this.messages
|
await this.messages
|
||||||
.createQueryBuilder("messages")
|
.createQueryBuilder("messages")
|
||||||
|
@ -211,10 +218,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
|
|
||||||
const newMessage = { ...oldMessage, data: newData };
|
const newMessage = { ...oldMessage, data: newData };
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
await this.messages.update(
|
await this.messages.update(
|
||||||
|
// FIXME?
|
||||||
{ id },
|
{ id },
|
||||||
{
|
{
|
||||||
data: newData,
|
data: newData as QueryDeepPartialEntity<ISavedMessageData>,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -222,7 +231,7 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
this.events.emit(`update:${id}`, [newMessage, oldMessage]);
|
this.events.emit(`update:${id}`, [newMessage, oldMessage]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveEditFromMsg(msg: Message<PossiblyUncachedTextableChannel>) {
|
async saveEditFromMsg(msg: Message) {
|
||||||
const newData = this.msgToSavedMessageData(msg);
|
const newData = this.msgToSavedMessageData(msg);
|
||||||
return this.saveEdit(msg.id, newData);
|
return this.saveEdit(msg.id, newData);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { ScheduledPost } from "./entities/ScheduledPost";
|
import { ScheduledPost } from "./entities/ScheduledPost";
|
||||||
|
|
||||||
export class GuildScheduledPosts extends BaseGuildRepository {
|
export class GuildScheduledPosts extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
import moment from "moment-timezone";
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { SlowmodeChannel } from "./entities/SlowmodeChannel";
|
import { SlowmodeChannel } from "./entities/SlowmodeChannel";
|
||||||
import { SlowmodeUser } from "./entities/SlowmodeUser";
|
import { SlowmodeUser } from "./entities/SlowmodeUser";
|
||||||
import moment from "moment-timezone";
|
|
||||||
|
|
||||||
export class GuildSlowmodes extends BaseGuildRepository {
|
export class GuildSlowmodes extends BaseGuildRepository {
|
||||||
private slowmodeChannels: Repository<SlowmodeChannel>;
|
private slowmodeChannels: Repository<SlowmodeChannel>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { StarboardMessage } from "./entities/StarboardMessage";
|
import { StarboardMessage } from "./entities/StarboardMessage";
|
||||||
|
|
||||||
export class GuildStarboardMessages extends BaseGuildRepository {
|
export class GuildStarboardMessages extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { StarboardReaction } from "./entities/StarboardReaction";
|
import { StarboardReaction } from "./entities/StarboardReaction";
|
||||||
|
|
||||||
export class GuildStarboardReactions extends BaseGuildRepository {
|
export class GuildStarboardReactions extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { StatValue } from "./entities/StatValue";
|
import { StatValue } from "./entities/StatValue";
|
||||||
|
|
||||||
export class GuildStats extends BaseGuildRepository {
|
export class GuildStats extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Tag } from "./entities/Tag";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
|
import { Tag } from "./entities/Tag";
|
||||||
import { TagResponse } from "./entities/TagResponse";
|
import { TagResponse } from "./entities/TagResponse";
|
||||||
|
|
||||||
export class GuildTags extends BaseGuildRepository {
|
export class GuildTags extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { Mute } from "./entities/Mute";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { Brackets, getRepository, Repository } from "typeorm";
|
|
||||||
import { Tempban } from "./entities/Tempban";
|
import { Tempban } from "./entities/Tempban";
|
||||||
|
|
||||||
export class GuildTempbans extends BaseGuildRepository {
|
export class GuildTempbans extends BaseGuildRepository {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||||
import { VCAlert } from "./entities/VCAlert";
|
import { VCAlert } from "./entities/VCAlert";
|
||||||
|
|
||||||
export class GuildVCAlerts extends BaseGuildRepository {
|
export class GuildVCAlerts extends BaseGuildRepository {
|
||||||
|
|
|
@ -18,9 +18,15 @@ export enum LogType {
|
||||||
|
|
||||||
CHANNEL_CREATE,
|
CHANNEL_CREATE,
|
||||||
CHANNEL_DELETE,
|
CHANNEL_DELETE,
|
||||||
|
CHANNEL_UPDATE,
|
||||||
|
|
||||||
|
THREAD_CREATE,
|
||||||
|
THREAD_DELETE,
|
||||||
|
THREAD_UPDATE,
|
||||||
|
|
||||||
ROLE_CREATE,
|
ROLE_CREATE,
|
||||||
ROLE_DELETE,
|
ROLE_DELETE,
|
||||||
|
ROLE_UPDATE,
|
||||||
|
|
||||||
MESSAGE_EDIT,
|
MESSAGE_EDIT,
|
||||||
MESSAGE_DELETE,
|
MESSAGE_DELETE,
|
||||||
|
@ -31,6 +37,18 @@ export enum LogType {
|
||||||
VOICE_CHANNEL_LEAVE,
|
VOICE_CHANNEL_LEAVE,
|
||||||
VOICE_CHANNEL_MOVE,
|
VOICE_CHANNEL_MOVE,
|
||||||
|
|
||||||
|
STAGE_INSTANCE_CREATE,
|
||||||
|
STAGE_INSTANCE_DELETE,
|
||||||
|
STAGE_INSTANCE_UPDATE,
|
||||||
|
|
||||||
|
EMOJI_CREATE,
|
||||||
|
EMOJI_DELETE,
|
||||||
|
EMOJI_UPDATE,
|
||||||
|
|
||||||
|
STICKER_CREATE,
|
||||||
|
STICKER_DELETE,
|
||||||
|
STICKER_UPDATE,
|
||||||
|
|
||||||
COMMAND,
|
COMMAND,
|
||||||
|
|
||||||
MESSAGE_SPAM_DETECTED,
|
MESSAGE_SPAM_DETECTED,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseRepository } from "./BaseRepository";
|
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
|
import { BaseRepository } from "./BaseRepository";
|
||||||
import { Supporter } from "./entities/Supporter";
|
import { Supporter } from "./entities/Supporter";
|
||||||
|
|
||||||
export class Supporters extends BaseRepository {
|
export class Supporters extends BaseRepository {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { getRepository, In, Repository } from "typeorm";
|
import { getRepository, In, Repository } from "typeorm";
|
||||||
import { UsernameHistoryEntry } from "./entities/UsernameHistoryEntry";
|
import { isAPI } from "../globals";
|
||||||
import { MINUTES, SECONDS } from "../utils";
|
import { MINUTES, SECONDS } from "../utils";
|
||||||
import { BaseRepository } from "./BaseRepository";
|
import { BaseRepository } from "./BaseRepository";
|
||||||
import { isAPI } from "../globals";
|
|
||||||
import { cleanupUsernames } from "./cleanup/usernames";
|
import { cleanupUsernames } from "./cleanup/usernames";
|
||||||
|
import { UsernameHistoryEntry } from "./entities/UsernameHistoryEntry";
|
||||||
|
|
||||||
if (!isAPI()) {
|
if (!isAPI()) {
|
||||||
const CLEANUP_INTERVAL = 5 * MINUTES;
|
const CLEANUP_INTERVAL = 5 * MINUTES;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { connection } from "../db";
|
|
||||||
import { getRepository, In } from "typeorm";
|
|
||||||
import { Config } from "../entities/Config";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { getRepository, In } from "typeorm";
|
||||||
import { DBDateFormat } from "../../utils";
|
import { DBDateFormat } from "../../utils";
|
||||||
|
import { connection } from "../db";
|
||||||
|
import { Config } from "../entities/Config";
|
||||||
|
|
||||||
const CLEAN_PER_LOOP = 50;
|
const CLEAN_PER_LOOP = 50;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { DAYS, DBDateFormat, MINUTES } from "../../utils";
|
|
||||||
import { getRepository, In } from "typeorm";
|
|
||||||
import { SavedMessage } from "../entities/SavedMessage";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { getRepository, In } from "typeorm";
|
||||||
|
import { DAYS, DBDateFormat, MINUTES } from "../../utils";
|
||||||
import { connection } from "../db";
|
import { connection } from "../db";
|
||||||
|
import { SavedMessage } from "../entities/SavedMessage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How long message edits, deletions, etc. will include the original message content.
|
* How long message edits, deletions, etc. will include the original message content.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { getRepository, In } from "typeorm";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { NicknameHistoryEntry } from "../entities/NicknameHistoryEntry";
|
import { getRepository, In } from "typeorm";
|
||||||
import { DAYS, DBDateFormat } from "../../utils";
|
import { DAYS, DBDateFormat } from "../../utils";
|
||||||
import { connection } from "../db";
|
import { connection } from "../db";
|
||||||
|
import { NicknameHistoryEntry } from "../entities/NicknameHistoryEntry";
|
||||||
|
|
||||||
export const NICKNAME_RETENTION_PERIOD = 30 * DAYS;
|
export const NICKNAME_RETENTION_PERIOD = 30 * DAYS;
|
||||||
const CLEAN_PER_LOOP = 500;
|
const CLEAN_PER_LOOP = 500;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { getRepository, In } from "typeorm";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { UsernameHistoryEntry } from "../entities/UsernameHistoryEntry";
|
import { getRepository, In } from "typeorm";
|
||||||
import { DAYS, DBDateFormat } from "../../utils";
|
import { DAYS, DBDateFormat } from "../../utils";
|
||||||
import { connection } from "../db";
|
import { connection } from "../db";
|
||||||
|
import { UsernameHistoryEntry } from "../entities/UsernameHistoryEntry";
|
||||||
|
|
||||||
export const USERNAME_RETENTION_PERIOD = 30 * DAYS;
|
export const USERNAME_RETENTION_PERIOD = 30 * DAYS;
|
||||||
const CLEAN_PER_LOOP = 500;
|
const CLEAN_PER_LOOP = 500;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { SimpleError } from "../SimpleError";
|
|
||||||
import { Connection, createConnection } from "typeorm";
|
import { Connection, createConnection } from "typeorm";
|
||||||
|
import { SimpleError } from "../SimpleError";
|
||||||
|
|
||||||
let connectionPromise: Promise<Connection>;
|
let connectionPromise: Promise<Connection>;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { decrypt, encrypt } from "../utils/crypt";
|
|
||||||
import { ValueTransformer } from "typeorm";
|
import { ValueTransformer } from "typeorm";
|
||||||
|
import { decrypt, encrypt } from "../utils/crypt";
|
||||||
|
|
||||||
interface EncryptedJsonTransformer<T> extends ValueTransformer {
|
interface EncryptedJsonTransformer<T> extends ValueTransformer {
|
||||||
from(dbValue: any): T;
|
from(dbValue: any): T;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { decrypt, encrypt } from "../utils/crypt";
|
|
||||||
import { ValueTransformer } from "typeorm";
|
import { ValueTransformer } from "typeorm";
|
||||||
|
import { decrypt, encrypt } from "../utils/crypt";
|
||||||
|
|
||||||
interface EncryptedTextTransformer extends ValueTransformer {
|
interface EncryptedTextTransformer extends ValueTransformer {
|
||||||
from(dbValue: any): string;
|
from(dbValue: any): string;
|
||||||
|
|
24
backend/src/data/entities/ButtonRole.ts
Normal file
24
backend/src/data/entities/ButtonRole.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||||
|
|
||||||
|
@Entity("button_roles")
|
||||||
|
export class ButtonRole {
|
||||||
|
@Column()
|
||||||
|
@PrimaryColumn()
|
||||||
|
guild_id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
@PrimaryColumn()
|
||||||
|
channel_id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
@PrimaryColumn()
|
||||||
|
message_id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
@PrimaryColumn()
|
||||||
|
button_id: string;
|
||||||
|
|
||||||
|
@Column() button_group: string;
|
||||||
|
|
||||||
|
@Column() button_name: string;
|
||||||
|
}
|
10
backend/src/data/entities/ContextMenuLink.ts
Normal file
10
backend/src/data/entities/ContextMenuLink.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||||
|
|
||||||
|
@Entity("context_menus")
|
||||||
|
export class ContextMenuLink {
|
||||||
|
@Column() guild_id: string;
|
||||||
|
|
||||||
|
@Column() @PrimaryColumn() context_id: string;
|
||||||
|
|
||||||
|
@Column() action_name: string;
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ export function getReverseCounterComparisonOp(op: TriggerComparisonOp): TriggerC
|
||||||
return REVERSE_OPS[op];
|
return REVERSE_OPS[op];
|
||||||
}
|
}
|
||||||
|
|
||||||
const comparisonStringRegex = new RegExp(`^(${TRIGGER_COMPARISON_OPS.join("|")})([1-9]\\d*)$`);
|
const comparisonStringRegex = new RegExp(`^(${TRIGGER_COMPARISON_OPS.join("|")})(\\d*)$`);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Parsed comparison op and value, or null if the comparison string was invalid
|
* @return Parsed comparison op and value, or null if the comparison string was invalid
|
||||||
|
|
|
@ -21,4 +21,6 @@ export class ReactionRole {
|
||||||
@Column() role_id: string;
|
@Column() role_id: string;
|
||||||
|
|
||||||
@Column() is_exclusive: boolean;
|
@Column() is_exclusive: boolean;
|
||||||
|
|
||||||
|
@Column() order: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import { MessageAttachment, Sticker } from "discord.js";
|
||||||
import { Column, Entity, PrimaryColumn } from "typeorm";
|
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||||
import { createEncryptedJsonTransformer } from "../encryptedJsonTransformer";
|
import { createEncryptedJsonTransformer } from "../encryptedJsonTransformer";
|
||||||
import { Attachment, Sticker } from "eris";
|
|
||||||
|
|
||||||
export interface ISavedMessageData {
|
export interface ISavedMessageData {
|
||||||
attachments?: Attachment[];
|
attachments?: MessageAttachment[];
|
||||||
author: {
|
author: {
|
||||||
username: string;
|
username: string;
|
||||||
discriminator: string;
|
discriminator: string;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { MessageAttachment } from "discord.js";
|
||||||
import { Column, Entity, PrimaryColumn } from "typeorm";
|
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||||
import { Attachment } from "eris";
|
|
||||||
import { StrictMessageContent } from "../../utils";
|
import { StrictMessageContent } from "../../utils";
|
||||||
|
|
||||||
@Entity("scheduled_posts")
|
@Entity("scheduled_posts")
|
||||||
|
@ -18,7 +18,7 @@ export class ScheduledPost {
|
||||||
|
|
||||||
@Column("simple-json") content: StrictMessageContent;
|
@Column("simple-json") content: StrictMessageContent;
|
||||||
|
|
||||||
@Column("simple-json") attachments: Attachment[];
|
@Column("simple-json") attachments: MessageAttachment[];
|
||||||
|
|
||||||
@Column({ type: String, nullable: true }) post_at: string | null;
|
@Column({ type: String, nullable: true }) post_at: string | null;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { SavedMessage } from "./entities/SavedMessage";
|
import { SavedMessage } from "./entities/SavedMessage";
|
||||||
import { Repository, getRepository } from "typeorm";
|
|
||||||
|
|
||||||
let repository: Repository<SavedMessage>;
|
let repository: Repository<SavedMessage>;
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,24 @@
|
||||||
import "./loadEnv";
|
import { Client, Intents, TextChannel } from "discord.js";
|
||||||
|
|
||||||
import path from "path";
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
import fs from "fs";
|
|
||||||
import { Knub, PluginError } from "knub";
|
import { Knub, PluginError } from "knub";
|
||||||
import { SimpleError } from "./SimpleError";
|
import { PluginLoadError } from "knub/dist/plugins/PluginLoadError";
|
||||||
|
|
||||||
import { Configs } from "./data/Configs";
|
|
||||||
// Always use UTC internally
|
// Always use UTC internally
|
||||||
// This is also enforced for the database in data/db.ts
|
// This is also enforced for the database in data/db.ts
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { Client, DiscordHTTPError, TextChannel } from "eris";
|
|
||||||
import { connect } from "./data/db";
|
|
||||||
import { baseGuildPlugins, globalPlugins, guildPlugins } from "./plugins/availablePlugins";
|
|
||||||
import { errorMessage, isDiscordHTTPError, isDiscordRESTError, MINUTES, successMessage } from "./utils";
|
|
||||||
import { startUptimeCounter } from "./uptime";
|
|
||||||
import { AllowedGuilds } from "./data/AllowedGuilds";
|
import { AllowedGuilds } from "./data/AllowedGuilds";
|
||||||
import { ZeppelinGlobalConfig, ZeppelinGuildConfig } from "./types";
|
import { Configs } from "./data/Configs";
|
||||||
import { RecoverablePluginError } from "./RecoverablePluginError";
|
import { connect } from "./data/db";
|
||||||
import { GuildLogs } from "./data/GuildLogs";
|
import { GuildLogs } from "./data/GuildLogs";
|
||||||
import { LogType } from "./data/LogType";
|
import { LogType } from "./data/LogType";
|
||||||
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
import { DiscordJSError } from "./DiscordJSError";
|
||||||
|
import "./loadEnv";
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
import { PluginLoadError } from "knub/dist/plugins/PluginLoadError";
|
import { baseGuildPlugins, globalPlugins, guildPlugins } from "./plugins/availablePlugins";
|
||||||
import { ErisError } from "./ErisError";
|
import { RecoverablePluginError } from "./RecoverablePluginError";
|
||||||
|
import { SimpleError } from "./SimpleError";
|
||||||
const fsp = fs.promises;
|
import { ZeppelinGlobalConfig, ZeppelinGuildConfig } from "./types";
|
||||||
|
import { startUptimeCounter } from "./uptime";
|
||||||
|
import { errorMessage, isDiscordAPIError, isDiscordHTTPError, successMessage } from "./utils";
|
||||||
|
|
||||||
if (!process.env.KEY) {
|
if (!process.env.KEY) {
|
||||||
// tslint:disable-next-line:no-console
|
// tslint:disable-next-line:no-console
|
||||||
|
@ -86,7 +78,7 @@ function errorHandler(err) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err instanceof ErisError) {
|
if (err instanceof DiscordJSError) {
|
||||||
if (err.code && SAFE_TO_IGNORE_ERIS_ERROR_CODES.includes(err.code)) {
|
if (err.code && SAFE_TO_IGNORE_ERIS_ERROR_CODES.includes(err.code)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +88,7 @@ function errorHandler(err) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err instanceof DiscordHTTPError && err.code >= 500) {
|
if (isDiscordHTTPError(err) && err.code >= 500) {
|
||||||
// Don't need stack traces on HTTP 500 errors
|
// Don't need stack traces on HTTP 500 errors
|
||||||
// These also shouldn't count towards RECENT_DISCORD_ERROR_EXIT_THRESHOLD because they don't indicate an error in our code
|
// These also shouldn't count towards RECENT_DISCORD_ERROR_EXIT_THRESHOLD because they don't indicate an error in our code
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
|
@ -118,7 +110,7 @@ function errorHandler(err) {
|
||||||
console.error(`Exiting after ${RECENT_PLUGIN_ERROR_EXIT_THRESHOLD} plugin errors`);
|
console.error(`Exiting after ${RECENT_PLUGIN_ERROR_EXIT_THRESHOLD} plugin errors`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
} else if (isDiscordRESTError(err) || isDiscordHTTPError(err)) {
|
} else if (isDiscordAPIError(err) || isDiscordHTTPError(err)) {
|
||||||
// Discord API errors, usually safe to just log instead of crash
|
// Discord API errors, usually safe to just log instead of crash
|
||||||
// We still bail if we get a ton of them in a short amount of time
|
// We still bail if we get a ton of them in a short amount of time
|
||||||
if (++recentDiscordErrors >= RECENT_DISCORD_ERROR_EXIT_THRESHOLD) {
|
if (++recentDiscordErrors >= RECENT_DISCORD_ERROR_EXIT_THRESHOLD) {
|
||||||
|
@ -151,48 +143,42 @@ moment.tz.setDefault("UTC");
|
||||||
|
|
||||||
logger.info("Connecting to database");
|
logger.info("Connecting to database");
|
||||||
connect().then(async () => {
|
connect().then(async () => {
|
||||||
const client = new Client(`Bot ${process.env.TOKEN}`, {
|
const client = new Client({
|
||||||
getAllUsers: false,
|
partials: ["USER", "CHANNEL", "GUILD_MEMBER", "MESSAGE", "REACTION"],
|
||||||
restMode: true,
|
restTimeOffset: 150,
|
||||||
compress: false,
|
restGlobalRateLimit: 50,
|
||||||
guildCreateTimeout: 0,
|
|
||||||
rest: {
|
|
||||||
ratelimiterOffset: 150,
|
|
||||||
},
|
|
||||||
// Disable mentions by default
|
// Disable mentions by default
|
||||||
allowedMentions: {
|
allowedMentions: {
|
||||||
everyone: false,
|
parse: [],
|
||||||
users: false,
|
users: [],
|
||||||
roles: false,
|
roles: [],
|
||||||
repliedUser: false,
|
repliedUser: false,
|
||||||
},
|
},
|
||||||
intents: [
|
intents: [
|
||||||
// Privileged
|
// Privileged
|
||||||
"guildMembers",
|
Intents.FLAGS.GUILD_MEMBERS,
|
||||||
// "guildPresences",
|
// Intents.FLAGS.GUILD_PRESENCES,
|
||||||
"guildMessageTyping",
|
Intents.FLAGS.GUILD_MESSAGE_TYPING,
|
||||||
|
|
||||||
// Regular
|
// Regular
|
||||||
"directMessages",
|
Intents.FLAGS.DIRECT_MESSAGES,
|
||||||
"guildBans",
|
Intents.FLAGS.GUILD_BANS,
|
||||||
"guildEmojis",
|
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS,
|
||||||
"guildInvites",
|
Intents.FLAGS.GUILD_INVITES,
|
||||||
"guildMessageReactions",
|
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
|
||||||
"guildMessages",
|
Intents.FLAGS.GUILD_MESSAGES,
|
||||||
"guilds",
|
Intents.FLAGS.GUILDS,
|
||||||
"guildVoiceStates",
|
Intents.FLAGS.GUILD_VOICE_STATES,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
client.setMaxListeners(200);
|
client.setMaxListeners(200);
|
||||||
|
|
||||||
client.on("debug", message => {
|
client.on("rateLimit", rateLimitData => {
|
||||||
if (message.includes(" 429 ")) {
|
logger.info(`[429] ${JSON.stringify(rateLimitData)}`);
|
||||||
logger.info(`[429] ${message}`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on("error", (err, shardId) => {
|
client.on("error", err => {
|
||||||
errorHandler(new ErisError(err.message, (err as any).code, shardId));
|
errorHandler(new DiscordJSError(err.message, (err as any).code, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
const allowedGuilds = new AllowedGuilds();
|
const allowedGuilds = new AllowedGuilds();
|
||||||
|
@ -257,13 +243,13 @@ connect().then(async () => {
|
||||||
sendSuccessMessageFn(channel, body) {
|
sendSuccessMessageFn(channel, body) {
|
||||||
const guildId = channel instanceof TextChannel ? channel.guild.id : undefined;
|
const guildId = channel instanceof TextChannel ? channel.guild.id : undefined;
|
||||||
const emoji = guildId ? bot.getLoadedGuild(guildId)!.config.success_emoji : undefined;
|
const emoji = guildId ? bot.getLoadedGuild(guildId)!.config.success_emoji : undefined;
|
||||||
channel.createMessage(successMessage(body, emoji));
|
channel.send(successMessage(body, emoji));
|
||||||
},
|
},
|
||||||
|
|
||||||
sendErrorMessageFn(channel, body) {
|
sendErrorMessageFn(channel, body) {
|
||||||
const guildId = channel instanceof TextChannel ? channel.guild.id : undefined;
|
const guildId = channel instanceof TextChannel ? channel.guild.id : undefined;
|
||||||
const emoji = guildId ? bot.getLoadedGuild(guildId)!.config.error_emoji : undefined;
|
const emoji = guildId ? bot.getLoadedGuild(guildId)!.config.error_emoji : undefined;
|
||||||
channel.createMessage(errorMessage(body, emoji));
|
channel.send(errorMessage(body, emoji));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -272,6 +258,8 @@ connect().then(async () => {
|
||||||
startUptimeCounter();
|
startUptimeCounter();
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info("Starting the bot");
|
bot.initialize();
|
||||||
bot.run();
|
logger.info("Bot Initialized");
|
||||||
|
logger.info("Logging in...");
|
||||||
|
await client.login(process.env.TOKEN);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// tslint:disable:no-console
|
// tslint:disable:no-console
|
||||||
import { connect } from "./data/db";
|
|
||||||
import { Configs } from "./data/Configs";
|
|
||||||
import path from "path";
|
|
||||||
import * as _fs from "fs";
|
import * as _fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import { Configs } from "./data/Configs";
|
||||||
|
import { connect } from "./data/db";
|
||||||
|
|
||||||
const fs = _fs.promises;
|
const fs = _fs.promises;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { MigrationInterface, QueryRunner, TableIndex, TableUnique } from "typeorm";
|
import { MigrationInterface, QueryRunner, TableIndex } from "typeorm";
|
||||||
|
|
||||||
export class FixStarboardReactionsIndices1608692857722 implements MigrationInterface {
|
export class FixStarboardReactionsIndices1608692857722 implements MigrationInterface {
|
||||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
|
18
backend/src/migrations/1622939525343-OrderReactionRoles.ts
Normal file
18
backend/src/migrations/1622939525343-OrderReactionRoles.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
|
||||||
|
|
||||||
|
export class OrderReactionRoles1622939525343 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.addColumn(
|
||||||
|
"reaction_roles",
|
||||||
|
new TableColumn({
|
||||||
|
name: "order",
|
||||||
|
type: "int",
|
||||||
|
isNullable: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.dropColumn("reaction_roles", "order");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { MigrationInterface, QueryRunner, Table } from "typeorm";
|
||||||
|
|
||||||
|
export class CreateButtonRolesTable1623018101018 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "button_roles",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "guild_id",
|
||||||
|
type: "bigint",
|
||||||
|
isPrimary: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "channel_id",
|
||||||
|
type: "bigint",
|
||||||
|
isPrimary: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "message_id",
|
||||||
|
type: "bigint",
|
||||||
|
isPrimary: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "button_id",
|
||||||
|
type: "varchar",
|
||||||
|
length: "100",
|
||||||
|
isPrimary: true,
|
||||||
|
isUnique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "button_group",
|
||||||
|
type: "varchar",
|
||||||
|
length: "100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "button_name",
|
||||||
|
type: "varchar",
|
||||||
|
length: "100",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.dropTable("button_roles");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { MigrationInterface, QueryRunner, Table } from "typeorm";
|
||||||
|
|
||||||
|
export class CreateContextMenuTable1628809879962 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "context_menus",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "guild_id",
|
||||||
|
type: "bigint",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "context_id",
|
||||||
|
type: "bigint",
|
||||||
|
isPrimary: true,
|
||||||
|
isUnique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "action_name",
|
||||||
|
type: "varchar",
|
||||||
|
length: "100",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.dropTable("context_menus");
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,23 +2,28 @@
|
||||||
* @file Utility functions that are plugin-instance-specific (i.e. use PluginData)
|
* @file Utility functions that are plugin-instance-specific (i.e. use PluginData)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AdvancedMessageContent, AllowedMentions, GuildTextableChannel, Member, Message, TextableChannel } from "eris";
|
import { GuildMember, Message, MessageMentionOptions, MessageOptions, TextChannel } from "discord.js";
|
||||||
import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub";
|
|
||||||
import { decodeAndValidateStrict, StrictValidationError, validate } from "./validatorUtils";
|
|
||||||
import { deepKeyIntersect, errorMessage, successMessage, tDeepPartial, tNullable } from "./utils";
|
|
||||||
import { TZeppelinKnub } from "./types";
|
|
||||||
import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager"; // TODO: Export from Knub index
|
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
|
import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub";
|
||||||
import { PluginOverrideCriteria } from "knub/dist/config/configTypes";
|
import { PluginOverrideCriteria } from "knub/dist/config/configTypes";
|
||||||
import { Tail } from "./utils/typeUtils";
|
import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager"; // TODO: Export from Knub index
|
||||||
import { AnyPluginData } from "knub/dist/plugins/PluginData";
|
import { AnyPluginData } from "knub/dist/plugins/PluginData";
|
||||||
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
|
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
||||||
|
import { TZeppelinKnub } from "./types";
|
||||||
|
import { deepKeyIntersect, errorMessage, successMessage, tDeepPartial, tNullable } from "./utils";
|
||||||
|
import { Tail } from "./utils/typeUtils";
|
||||||
|
import { decodeAndValidateStrict, StrictValidationError, validate } from "./validatorUtils";
|
||||||
|
|
||||||
const { getMemberLevel } = helpers;
|
const { getMemberLevel } = helpers;
|
||||||
|
|
||||||
export function canActOn(pluginData: GuildPluginData<any>, member1: Member, member2: Member, allowSameLevel = false) {
|
export function canActOn(
|
||||||
if (member2.id === pluginData.client.user.id) {
|
pluginData: GuildPluginData<any>,
|
||||||
|
member1: GuildMember,
|
||||||
|
member2: GuildMember,
|
||||||
|
allowSameLevel = false,
|
||||||
|
) {
|
||||||
|
if (member2.id === pluginData.client.user!.id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,45 +183,43 @@ export function getPluginConfigPreprocessor(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendSuccessMessage(
|
export async function sendSuccessMessage(
|
||||||
pluginData: AnyPluginData<any>,
|
pluginData: AnyPluginData<any>,
|
||||||
channel: TextableChannel,
|
channel: TextChannel,
|
||||||
body: string,
|
body: string,
|
||||||
allowedMentions?: AllowedMentions,
|
allowedMentions?: MessageMentionOptions,
|
||||||
): Promise<Message | undefined> {
|
): Promise<Message | undefined> {
|
||||||
const emoji = pluginData.fullConfig.success_emoji || undefined;
|
const emoji = pluginData.fullConfig.success_emoji || undefined;
|
||||||
const formattedBody = successMessage(body, emoji);
|
const formattedBody = successMessage(body, emoji);
|
||||||
const content: AdvancedMessageContent = allowedMentions
|
const content: MessageOptions = allowedMentions
|
||||||
? { content: formattedBody, allowedMentions }
|
? { content: formattedBody, allowedMentions }
|
||||||
: { content: formattedBody };
|
: { content: formattedBody };
|
||||||
|
|
||||||
return channel
|
return channel
|
||||||
.createMessage(content) // Force line break
|
.send({ ...content }) // Force line break
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
const channelInfo = (channel as GuildTextableChannel).guild
|
const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||||
? `${channel.id} (${(channel as GuildTextableChannel).guild.id})`
|
|
||||||
: `${channel.id}`;
|
|
||||||
logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`);
|
logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendErrorMessage(
|
export async function sendErrorMessage(
|
||||||
pluginData: AnyPluginData<any>,
|
pluginData: AnyPluginData<any>,
|
||||||
channel: TextableChannel,
|
channel: TextChannel,
|
||||||
body: string,
|
body: string,
|
||||||
allowedMentions?: AllowedMentions,
|
allowedMentions?: MessageMentionOptions,
|
||||||
): Promise<Message | undefined> {
|
): Promise<Message | undefined> {
|
||||||
const emoji = pluginData.fullConfig.error_emoji || undefined;
|
const emoji = pluginData.fullConfig.error_emoji || undefined;
|
||||||
const formattedBody = errorMessage(body, emoji);
|
const formattedBody = errorMessage(body, emoji);
|
||||||
const content: AdvancedMessageContent = allowedMentions
|
const content: MessageOptions = allowedMentions
|
||||||
? { content: formattedBody, allowedMentions }
|
? { content: formattedBody, allowedMentions }
|
||||||
: { content: formattedBody };
|
: { content: formattedBody };
|
||||||
|
|
||||||
return channel
|
return channel
|
||||||
.createMessage(content) // Force line break
|
.send({ ...content }) // Force line break
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
const channelInfo = (channel as GuildTextableChannel).guild
|
const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||||
? `${channel.id} (${(channel as GuildTextableChannel).guild.id})`
|
|
||||||
: `${channel.id}`;
|
|
||||||
logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`);
|
logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { AutoDeletePluginType, ConfigSchema } from "./types";
|
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
|
import { AutoDeletePluginType, ConfigSchema } from "./types";
|
||||||
import { onMessageCreate } from "./util/onMessageCreate";
|
import { onMessageCreate } from "./util/onMessageCreate";
|
||||||
import { onMessageDelete } from "./util/onMessageDelete";
|
import { onMessageDelete } from "./util/onMessageDelete";
|
||||||
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk";
|
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk";
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<AutoDeletePluginType> = {
|
const defaultOptions: PluginOptions<AutoDeletePluginType> = {
|
||||||
config: {
|
config: {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
import { tDelayString, MINUTES } from "../../utils";
|
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
import { MINUTES, tDelayString } from "../../utils";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
export const MAX_DELAY = 5 * MINUTES;
|
export const MAX_DELAY = 5 * MINUTES;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { AutoDeletePluginType } from "../types";
|
|
||||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
|
||||||
import { sorter } from "../../../utils";
|
import { sorter } from "../../../utils";
|
||||||
|
import { AutoDeletePluginType } from "../types";
|
||||||
|
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||||
|
|
||||||
export function addMessageToDeletionQueue(
|
export function addMessageToDeletionQueue(
|
||||||
pluginData: GuildPluginData<AutoDeletePluginType>,
|
pluginData: GuildPluginData<AutoDeletePluginType>,
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
|
import { Permissions, Snowflake, TextChannel } from "discord.js";
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { AutoDeletePluginType } from "../types";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "../../../utils/configAccessibleObjects";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { resolveUser, stripObjectToScalars, verboseChannelMention } from "../../../utils";
|
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
import { resolveUser, verboseChannelMention } from "../../../utils";
|
||||||
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
|
||||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||||
import { Constants } from "eris";
|
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
||||||
|
import { AutoDeletePluginType } from "../types";
|
||||||
|
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||||
|
|
||||||
export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePluginType>) {
|
export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePluginType>) {
|
||||||
const [itemToDelete] = pluginData.state.deletionQueue.splice(0, 1);
|
const [itemToDelete] = pluginData.state.deletionQueue.splice(0, 1);
|
||||||
|
@ -16,16 +17,16 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
||||||
|
|
||||||
scheduleNextDeletion(pluginData);
|
scheduleNextDeletion(pluginData);
|
||||||
|
|
||||||
const channel = pluginData.guild.channels.get(itemToDelete.message.channel_id);
|
const channel = pluginData.guild.channels.cache.get(itemToDelete.message.channel_id as Snowflake) as TextChannel;
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
// Channel was deleted, ignore
|
// Channel was deleted, ignore
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
const perms = channel.permissionsOf(pluginData.client.user.id);
|
const perms = channel.permissionsFor(pluginData.client.user!.id);
|
||||||
|
|
||||||
if (!hasDiscordPermissions(perms, Constants.Permissions.readMessages | Constants.Permissions.readMessageHistory)) {
|
if (!hasDiscordPermissions(perms, Permissions.FLAGS.VIEW_CHANNEL | Permissions.FLAGS.READ_MESSAGE_HISTORY)) {
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
body: `Missing permissions to read messages or message history in auto-delete channel ${verboseChannelMention(
|
body: `Missing permissions to read messages or message history in auto-delete channel ${verboseChannelMention(
|
||||||
channel,
|
channel,
|
||||||
|
@ -34,7 +35,7 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasDiscordPermissions(perms, Constants.Permissions.manageMessages)) {
|
if (!hasDiscordPermissions(perms, Permissions.FLAGS.MANAGE_MESSAGES)) {
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
body: `Missing permissions to delete messages in auto-delete channel ${verboseChannelMention(channel)}`,
|
body: `Missing permissions to delete messages in auto-delete channel ${verboseChannelMention(channel)}`,
|
||||||
});
|
});
|
||||||
|
@ -44,7 +45,7 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
||||||
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
|
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
|
||||||
|
|
||||||
pluginData.state.guildLogs.ignoreLog(LogType.MESSAGE_DELETE, itemToDelete.message.id);
|
pluginData.state.guildLogs.ignoreLog(LogType.MESSAGE_DELETE, itemToDelete.message.id);
|
||||||
pluginData.client.deleteMessage(itemToDelete.message.channel_id, itemToDelete.message.id).catch(err => {
|
(channel as TextChannel).messages.delete(itemToDelete.message.id as Snowflake).catch(err => {
|
||||||
if (err.code === 10008) {
|
if (err.code === 10008) {
|
||||||
// "Unknown Message", probably already deleted by automod or another bot, ignore
|
// "Unknown Message", probably already deleted by automod or another bot, ignore
|
||||||
return;
|
return;
|
||||||
|
@ -60,8 +61,8 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
||||||
|
|
||||||
pluginData.state.guildLogs.log(LogType.MESSAGE_DELETE_AUTO, {
|
pluginData.state.guildLogs.log(LogType.MESSAGE_DELETE_AUTO, {
|
||||||
message: itemToDelete.message,
|
message: itemToDelete.message,
|
||||||
user: stripObjectToScalars(user),
|
user: userToConfigAccessibleUser(user),
|
||||||
channel: stripObjectToScalars(channel),
|
channel: channelToConfigAccessibleChannel(channel),
|
||||||
messageDate,
|
messageDate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { AutoDeletePluginType, MAX_DELAY } from "../types";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||||
import { convertDelayStringToMS, resolveMember } from "../../../utils";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { convertDelayStringToMS, resolveMember } from "../../../utils";
|
||||||
|
import { AutoDeletePluginType, MAX_DELAY } from "../types";
|
||||||
import { addMessageToDeletionQueue } from "./addMessageToDeletionQueue";
|
import { addMessageToDeletionQueue } from "./addMessageToDeletionQueue";
|
||||||
|
|
||||||
export async function onMessageCreate(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
export async function onMessageCreate(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { AutoDeletePluginType } from "../types";
|
|
||||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||||
|
import { AutoDeletePluginType } from "../types";
|
||||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||||
|
|
||||||
export function onMessageDelete(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
export function onMessageDelete(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { AutoDeletePluginType } from "../types";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||||
|
import { AutoDeletePluginType } from "../types";
|
||||||
import { onMessageDelete } from "./onMessageDelete";
|
import { onMessageDelete } from "./onMessageDelete";
|
||||||
|
|
||||||
export function onMessageDeleteBulk(pluginData: GuildPluginData<AutoDeletePluginType>, messages: SavedMessage[]) {
|
export function onMessageDeleteBulk(pluginData: GuildPluginData<AutoDeletePluginType>, messages: SavedMessage[]) {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
|
||||||
import { AutoReactionsPluginType, ConfigSchema } from "./types";
|
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
|
|
||||||
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
|
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
|
||||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||||
import { AddReactionsEvt } from "./events/AddReactionsEvt";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
|
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
|
||||||
|
import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
|
||||||
|
import { AddReactionsEvt } from "./events/AddReactionsEvt";
|
||||||
|
import { AutoReactionsPluginType, ConfigSchema } from "./types";
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
|
const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
|
||||||
config: {
|
config: {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { autoReactionsCmd } from "../types";
|
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { autoReactionsCmd } from "../types";
|
||||||
|
|
||||||
export const DisableAutoReactionsCmd = autoReactionsCmd({
|
export const DisableAutoReactionsCmd = autoReactionsCmd({
|
||||||
trigger: "auto_reactions disable",
|
trigger: "auto_reactions disable",
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { autoReactionsCmd } from "../types";
|
import { GuildChannel, Permissions } from "discord.js";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { canUseEmoji, customEmojiRegex, isEmoji } from "../../../utils";
|
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { canUseEmoji, customEmojiRegex, isEmoji } from "../../../utils";
|
||||||
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
|
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
|
||||||
import { Constants, GuildChannel } from "eris";
|
|
||||||
import { readChannelPermissions } from "../../../utils/readChannelPermissions";
|
|
||||||
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||||
|
import { readChannelPermissions } from "../../../utils/readChannelPermissions";
|
||||||
|
import { autoReactionsCmd } from "../types";
|
||||||
|
|
||||||
const requiredPermissions = readChannelPermissions | Constants.Permissions.addReactions;
|
const requiredPermissions = readChannelPermissions | Permissions.FLAGS.ADD_REACTIONS;
|
||||||
|
|
||||||
export const NewAutoReactionsCmd = autoReactionsCmd({
|
export const NewAutoReactionsCmd = autoReactionsCmd({
|
||||||
trigger: "auto_reactions",
|
trigger: "auto_reactions",
|
||||||
|
@ -22,7 +22,7 @@ export const NewAutoReactionsCmd = autoReactionsCmd({
|
||||||
async run({ message: msg, args, pluginData }) {
|
async run({ message: msg, args, pluginData }) {
|
||||||
const finalReactions: string[] = [];
|
const finalReactions: string[] = [];
|
||||||
|
|
||||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!;
|
||||||
const missingPermissions = getMissingChannelPermissions(me, args.channel as GuildChannel, requiredPermissions);
|
const missingPermissions = getMissingChannelPermissions(me, args.channel as GuildChannel, requiredPermissions);
|
||||||
if (missingPermissions) {
|
if (missingPermissions) {
|
||||||
sendErrorMessage(
|
sendErrorMessage(
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import { autoReactionsEvt } from "../types";
|
import { GuildChannel, Permissions } from "discord.js";
|
||||||
import { isDiscordRESTError } from "../../../utils";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { logger } from "../../../logger";
|
import { isDiscordAPIError } from "../../../utils";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
|
||||||
import { Constants, GuildChannel } from "eris";
|
|
||||||
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
|
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
|
||||||
import { readChannelPermissions } from "../../../utils/readChannelPermissions";
|
|
||||||
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||||
|
import { readChannelPermissions } from "../../../utils/readChannelPermissions";
|
||||||
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { autoReactionsEvt } from "../types";
|
||||||
|
|
||||||
const p = Constants.Permissions;
|
const p = Permissions.FLAGS;
|
||||||
|
|
||||||
export const AddReactionsEvt = autoReactionsEvt({
|
export const AddReactionsEvt = autoReactionsEvt({
|
||||||
event: "messageCreate",
|
event: "messageCreate",
|
||||||
|
@ -19,11 +18,11 @@ export const AddReactionsEvt = autoReactionsEvt({
|
||||||
const autoReaction = await pluginData.state.autoReactions.getForChannel(message.channel.id);
|
const autoReaction = await pluginData.state.autoReactions.getForChannel(message.channel.id);
|
||||||
if (!autoReaction) return;
|
if (!autoReaction) return;
|
||||||
|
|
||||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!;
|
||||||
const missingPermissions = getMissingChannelPermissions(
|
const missingPermissions = getMissingChannelPermissions(
|
||||||
me,
|
me,
|
||||||
message.channel as GuildChannel,
|
message.channel as GuildChannel,
|
||||||
readChannelPermissions | p.addReactions,
|
readChannelPermissions | p.ADD_REACTIONS,
|
||||||
);
|
);
|
||||||
if (missingPermissions) {
|
if (missingPermissions) {
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
|
@ -35,9 +34,9 @@ export const AddReactionsEvt = autoReactionsEvt({
|
||||||
|
|
||||||
for (const reaction of autoReaction.reactions) {
|
for (const reaction of autoReaction.reactions) {
|
||||||
try {
|
try {
|
||||||
await message.addReaction(reaction);
|
await message.react(reaction);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (isDiscordRESTError(e)) {
|
if (isDiscordAPIError(e)) {
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
if (e.code === 10008) {
|
if (e.code === 10008) {
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||||
|
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||||
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";
|
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
can_manage: t.boolean,
|
can_manage: t.boolean,
|
||||||
|
|
|
@ -1,38 +1,35 @@
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
|
||||||
import { AutomodPluginType, ConfigSchema } from "./types";
|
|
||||||
import { RunAutomodOnJoinEvt } from "./events/RunAutomodOnJoinEvt";
|
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
|
||||||
import { runAutomodOnMessage } from "./events/runAutomodOnMessage";
|
|
||||||
import { Queue } from "../../Queue";
|
|
||||||
import { configUtils, CooldownManager } from "knub";
|
import { configUtils, CooldownManager } from "knub";
|
||||||
import { availableTriggers } from "./triggers/availableTriggers";
|
|
||||||
import { StrictValidationError } from "../../validatorUtils";
|
|
||||||
import { ConfigPreprocessorFn } from "knub/dist/config/configTypes";
|
import { ConfigPreprocessorFn } from "knub/dist/config/configTypes";
|
||||||
import { availableActions } from "./actions/availableActions";
|
|
||||||
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
|
||||||
import { disableCodeBlocks, MINUTES, SECONDS } from "../../utils";
|
|
||||||
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
|
||||||
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
import { Queue } from "../../Queue";
|
||||||
|
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
||||||
|
import { MINUTES, SECONDS } from "../../utils";
|
||||||
|
import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap";
|
||||||
|
import { unregisterEventListenersFromMap } from "../../utils/unregisterEventListenersFromMap";
|
||||||
|
import { StrictValidationError } from "../../validatorUtils";
|
||||||
|
import { CountersPlugin } from "../Counters/CountersPlugin";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
|
import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
|
||||||
import { MutesPlugin } from "../Mutes/MutesPlugin";
|
import { MutesPlugin } from "../Mutes/MutesPlugin";
|
||||||
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
|
import { availableActions } from "./actions/availableActions";
|
||||||
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
|
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
|
||||||
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
|
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
|
||||||
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
|
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
|
||||||
import { pluginInfo } from "./info";
|
|
||||||
import { RegExpRunner } from "../../RegExpRunner";
|
|
||||||
import { LogType } from "../../data/LogType";
|
|
||||||
import { logger } from "../../logger";
|
|
||||||
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
|
||||||
import { RunAutomodOnMemberUpdate } from "./events/RunAutomodOnMemberUpdate";
|
|
||||||
import { CountersPlugin } from "../Counters/CountersPlugin";
|
|
||||||
import { runAutomodOnCounterTrigger } from "./events/runAutomodOnCounterTrigger";
|
import { runAutomodOnCounterTrigger } from "./events/runAutomodOnCounterTrigger";
|
||||||
|
import { RunAutomodOnJoinEvt, RunAutomodOnLeaveEvt } from "./events/RunAutomodOnJoinLeaveEvt";
|
||||||
|
import { RunAutomodOnMemberUpdate } from "./events/RunAutomodOnMemberUpdate";
|
||||||
|
import { runAutomodOnMessage } from "./events/runAutomodOnMessage";
|
||||||
import { runAutomodOnModAction } from "./events/runAutomodOnModAction";
|
import { runAutomodOnModAction } from "./events/runAutomodOnModAction";
|
||||||
import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap";
|
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
|
||||||
import { unregisterEventListenersFromMap } from "../../utils/unregisterEventListenersFromMap";
|
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
||||||
|
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
||||||
|
import { pluginInfo } from "./info";
|
||||||
|
import { availableTriggers } from "./triggers/availableTriggers";
|
||||||
|
import { AutomodPluginType, ConfigSchema } from "./types";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -179,6 +176,7 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
||||||
events: [
|
events: [
|
||||||
RunAutomodOnJoinEvt,
|
RunAutomodOnJoinEvt,
|
||||||
RunAutomodOnMemberUpdate,
|
RunAutomodOnMemberUpdate,
|
||||||
|
RunAutomodOnLeaveEvt,
|
||||||
// Messages use message events from SavedMessages, see onLoad below
|
// Messages use message events from SavedMessages, see onLoad below
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
|
import { Permissions, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { nonNullish, unique } from "../../../utils";
|
import { nonNullish, unique } from "../../../utils";
|
||||||
import { Constants } from "eris";
|
|
||||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
|
||||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
|
||||||
import { canAssignRole } from "../../../utils/canAssignRole";
|
import { canAssignRole } from "../../../utils/canAssignRole";
|
||||||
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||||
import { ignoreRoleChange } from "../functions/ignoredRoleChanges";
|
|
||||||
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
||||||
|
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||||
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { ignoreRoleChange } from "../functions/ignoredRoleChanges";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
const p = Constants.Permissions;
|
const p = Permissions.FLAGS;
|
||||||
|
|
||||||
export const AddRolesAction = automodAction({
|
export const AddRolesAction = automodAction({
|
||||||
configType: t.array(t.string),
|
configType: t.array(t.string),
|
||||||
|
@ -19,9 +18,9 @@ export const AddRolesAction = automodAction({
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
||||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!;
|
||||||
|
|
||||||
const missingPermissions = getMissingPermissions(me.permission, p.manageRoles);
|
const missingPermissions = getMissingPermissions(me.permissions, p.MANAGE_ROLES);
|
||||||
if (missingPermissions) {
|
if (missingPermissions) {
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
|
@ -42,7 +41,7 @@ export const AddRolesAction = automodAction({
|
||||||
|
|
||||||
if (rolesWeCannotAssign.length) {
|
if (rolesWeCannotAssign.length) {
|
||||||
const roleNamesWeCannotAssign = rolesWeCannotAssign.map(
|
const roleNamesWeCannotAssign = rolesWeCannotAssign.map(
|
||||||
roleId => pluginData.guild.roles.get(roleId)?.name || roleId,
|
roleId => pluginData.guild.roles.cache.get(roleId as Snowflake)?.name || roleId,
|
||||||
);
|
);
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
|
@ -54,13 +53,13 @@ export const AddRolesAction = automodAction({
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
members.map(async member => {
|
members.map(async member => {
|
||||||
const memberRoles = new Set(member.roles);
|
const memberRoles = new Set(member.roles.cache.keys());
|
||||||
for (const roleId of rolesToAssign) {
|
for (const roleId of rolesToAssign) {
|
||||||
memberRoles.add(roleId);
|
memberRoles.add(roleId as Snowflake);
|
||||||
ignoreRoleChange(pluginData, member.id, roleId);
|
ignoreRoleChange(pluginData, member.id, roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memberRoles.size === member.roles.length) {
|
if (memberRoles.size === member.roles.cache.size) {
|
||||||
// No role changes
|
// No role changes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +70,6 @@ export const AddRolesAction = automodAction({
|
||||||
await member.edit({
|
await member.edit({
|
||||||
roles: rolesArr,
|
roles: rolesArr,
|
||||||
});
|
});
|
||||||
member.roles = rolesArr; // Make sure we know of the new roles internally as well
|
|
||||||
|
|
||||||
memberRoleLock.unlock();
|
memberRoleLock.unlock();
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const AddToCounterAction = automodAction({
|
export const AddToCounterAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
|
import { Snowflake, TextChannel } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { renderTemplate, TemplateParseError } from "../../../templateFormatter";
|
||||||
import {
|
import {
|
||||||
asyncMap,
|
|
||||||
createChunkedMessage,
|
createChunkedMessage,
|
||||||
isDiscordRESTError,
|
|
||||||
messageLink,
|
messageLink,
|
||||||
resolveMember,
|
|
||||||
stripObjectToScalars,
|
stripObjectToScalars,
|
||||||
tAllowedMentions,
|
tAllowedMentions,
|
||||||
tNormalizedNullOptional,
|
tNormalizedNullOptional,
|
||||||
tNullable,
|
|
||||||
verboseChannelMention,
|
verboseChannelMention,
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
|
||||||
import { TextChannel } from "eris";
|
|
||||||
import { renderTemplate, TemplateParseError } from "../../../templateFormatter";
|
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const AlertAction = automodAction({
|
export const AlertAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
@ -29,7 +24,7 @@ export const AlertAction = automodAction({
|
||||||
defaultConfig: {},
|
defaultConfig: {},
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
||||||
const channel = pluginData.guild.channels.get(actionConfig.channel);
|
const channel = pluginData.guild.channels.cache.get(actionConfig.channel as Snowflake);
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
|
|
||||||
if (channel && channel instanceof TextChannel) {
|
if (channel && channel instanceof TextChannel) {
|
||||||
|
@ -73,7 +68,11 @@ export const AlertAction = automodAction({
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await createChunkedMessage(channel, rendered, actionConfig.allowed_mentions);
|
await createChunkedMessage(
|
||||||
|
channel,
|
||||||
|
rendered,
|
||||||
|
erisAllowedMentionsToDjsMentionOptions(actionConfig.allowed_mentions),
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === 50001) {
|
if (err.code === 50001) {
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { CleanAction } from "./clean";
|
|
||||||
import { AutomodActionBlueprint } from "../helpers";
|
import { AutomodActionBlueprint } from "../helpers";
|
||||||
import { WarnAction } from "./warn";
|
|
||||||
import { MuteAction } from "./mute";
|
|
||||||
import { KickAction } from "./kick";
|
|
||||||
import { BanAction } from "./ban";
|
|
||||||
import { AlertAction } from "./alert";
|
|
||||||
import { ChangeNicknameAction } from "./changeNickname";
|
|
||||||
import { LogAction } from "./log";
|
|
||||||
import { AddRolesAction } from "./addRoles";
|
import { AddRolesAction } from "./addRoles";
|
||||||
import { RemoveRolesAction } from "./removeRoles";
|
|
||||||
import { SetAntiraidLevelAction } from "./setAntiraidLevel";
|
|
||||||
import { ReplyAction } from "./reply";
|
|
||||||
import { AddToCounterAction } from "./addToCounter";
|
import { AddToCounterAction } from "./addToCounter";
|
||||||
|
import { AlertAction } from "./alert";
|
||||||
|
import { BanAction } from "./ban";
|
||||||
|
import { ChangeNicknameAction } from "./changeNickname";
|
||||||
|
import { CleanAction } from "./clean";
|
||||||
|
import { KickAction } from "./kick";
|
||||||
|
import { LogAction } from "./log";
|
||||||
|
import { MuteAction } from "./mute";
|
||||||
|
import { RemoveRolesAction } from "./removeRoles";
|
||||||
|
import { ReplyAction } from "./reply";
|
||||||
|
import { SetAntiraidLevelAction } from "./setAntiraidLevel";
|
||||||
import { SetCounterAction } from "./setCounter";
|
import { SetCounterAction } from "./setCounter";
|
||||||
import { SetSlowmodeAction } from "./setSlowmode";
|
import { SetSlowmodeAction } from "./setSlowmode";
|
||||||
|
import { WarnAction } from "./warn";
|
||||||
|
|
||||||
export const availableActions: Record<string, AutomodActionBlueprint<any>> = {
|
export const availableActions: Record<string, AutomodActionBlueprint<any>> = {
|
||||||
clean: CleanAction,
|
clean: CleanAction,
|
||||||
|
|
|
@ -1,18 +1,9 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
import { convertDelayStringToMS, nonNullish, tDelayString, tNullable, unique } from "../../../utils";
|
||||||
import { LogType } from "../../../data/LogType";
|
|
||||||
import {
|
|
||||||
asyncMap,
|
|
||||||
convertDelayStringToMS,
|
|
||||||
nonNullish,
|
|
||||||
resolveMember,
|
|
||||||
tDelayString,
|
|
||||||
tNullable,
|
|
||||||
unique,
|
|
||||||
} from "../../../utils";
|
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
|
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||||
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const BanAction = automodAction({
|
export const BanAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
@ -37,7 +28,7 @@ export const BanAction = automodAction({
|
||||||
const deleteMessageDays = actionConfig.deleteMessageDays || undefined;
|
const deleteMessageDays = actionConfig.deleteMessageDays || undefined;
|
||||||
|
|
||||||
const caseArgs: Partial<CaseArgs> = {
|
const caseArgs: Partial<CaseArgs> = {
|
||||||
modId: pluginData.client.user.id,
|
modId: pluginData.client.user!.id,
|
||||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||||
automatic: true,
|
automatic: true,
|
||||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
|
||||||
import { nonNullish, unique } from "../../../utils";
|
import { nonNullish, unique } from "../../../utils";
|
||||||
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const ChangeNicknameAction = automodAction({
|
export const ChangeNicknameAction = automodAction({
|
||||||
configType: t.union([
|
configType: t.union([
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import { Snowflake, TextChannel } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { noop } from "../../../utils";
|
import { noop } from "../../../utils";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const CleanAction = automodAction({
|
export const CleanAction = automodAction({
|
||||||
configType: t.boolean,
|
configType: t.boolean,
|
||||||
|
@ -29,7 +30,8 @@ export const CleanAction = automodAction({
|
||||||
pluginData.state.logs.ignoreLog(LogType.MESSAGE_DELETE, id);
|
pluginData.state.logs.ignoreLog(LogType.MESSAGE_DELETE, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
await pluginData.client.deleteMessages(channelId, messageIds).catch(noop);
|
const channel = pluginData.guild.channels.cache.get(channelId as Snowflake) as TextChannel;
|
||||||
|
await channel.bulkDelete(messageIds as Snowflake[]).catch(noop);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
|
||||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
|
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||||
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const KickAction = automodAction({
|
export const KickAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
@ -25,7 +24,7 @@ export const KickAction = automodAction({
|
||||||
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
||||||
|
|
||||||
const caseArgs: Partial<CaseArgs> = {
|
const caseArgs: Partial<CaseArgs> = {
|
||||||
modId: pluginData.client.user.id,
|
modId: pluginData.client.user!.id,
|
||||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||||
automatic: true,
|
automatic: true,
|
||||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { stripObjectToScalars, unique } from "../../../utils";
|
import { stripObjectToScalars, unique } from "../../../utils";
|
||||||
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const LogAction = automodAction({
|
export const LogAction = automodAction({
|
||||||
configType: t.boolean,
|
configType: t.boolean,
|
||||||
|
|
|
@ -1,21 +1,12 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import {
|
|
||||||
asyncMap,
|
|
||||||
convertDelayStringToMS,
|
|
||||||
nonNullish,
|
|
||||||
resolveMember,
|
|
||||||
tDelayString,
|
|
||||||
tNullable,
|
|
||||||
unique,
|
|
||||||
} from "../../../utils";
|
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
|
||||||
import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
|
||||||
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { convertDelayStringToMS, nonNullish, tDelayString, tNullable, unique } from "../../../utils";
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
||||||
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const MuteAction = automodAction({
|
export const MuteAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
@ -42,7 +33,7 @@ export const MuteAction = automodAction({
|
||||||
const rolesToRestore = actionConfig.restore_roles_on_mute;
|
const rolesToRestore = actionConfig.restore_roles_on_mute;
|
||||||
|
|
||||||
const caseArgs: Partial<CaseArgs> = {
|
const caseArgs: Partial<CaseArgs> = {
|
||||||
modId: pluginData.client.user.id,
|
modId: pluginData.client.user!.id,
|
||||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||||
automatic: true,
|
automatic: true,
|
||||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
|
import { Permissions, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
import { nonNullish, unique } from "../../../utils";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
|
||||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
|
||||||
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
|
||||||
import { canAssignRole } from "../../../utils/canAssignRole";
|
import { canAssignRole } from "../../../utils/canAssignRole";
|
||||||
import { Constants } from "eris";
|
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||||
import { ignoreRoleChange } from "../functions/ignoredRoleChanges";
|
|
||||||
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
||||||
|
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||||
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
|
import { ignoreRoleChange } from "../functions/ignoredRoleChanges";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
const p = Constants.Permissions;
|
const p = Permissions.FLAGS;
|
||||||
|
|
||||||
export const RemoveRolesAction = automodAction({
|
export const RemoveRolesAction = automodAction({
|
||||||
configType: t.array(t.string),
|
configType: t.array(t.string),
|
||||||
|
@ -21,9 +19,9 @@ export const RemoveRolesAction = automodAction({
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
const members = unique(contexts.map(c => c.member).filter(nonNullish));
|
||||||
const me = pluginData.guild.members.get(pluginData.client.user.id)!;
|
const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!;
|
||||||
|
|
||||||
const missingPermissions = getMissingPermissions(me.permission, p.manageRoles);
|
const missingPermissions = getMissingPermissions(me.permissions, p.MANAGE_ROLES);
|
||||||
if (missingPermissions) {
|
if (missingPermissions) {
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
|
@ -44,7 +42,7 @@ export const RemoveRolesAction = automodAction({
|
||||||
|
|
||||||
if (rolesWeCannotRemove.length) {
|
if (rolesWeCannotRemove.length) {
|
||||||
const roleNamesWeCannotRemove = rolesWeCannotRemove.map(
|
const roleNamesWeCannotRemove = rolesWeCannotRemove.map(
|
||||||
roleId => pluginData.guild.roles.get(roleId)?.name || roleId,
|
roleId => pluginData.guild.roles.cache.get(roleId as Snowflake)?.name || roleId,
|
||||||
);
|
);
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
|
@ -56,13 +54,13 @@ export const RemoveRolesAction = automodAction({
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
members.map(async member => {
|
members.map(async member => {
|
||||||
const memberRoles = new Set(member.roles);
|
const memberRoles = new Set(member.roles.cache.keys());
|
||||||
for (const roleId of rolesToRemove) {
|
for (const roleId of rolesToRemove) {
|
||||||
memberRoles.delete(roleId);
|
memberRoles.delete(roleId as Snowflake);
|
||||||
ignoreRoleChange(pluginData, member.id, roleId);
|
ignoreRoleChange(pluginData, member.id, roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memberRoles.size === member.roles.length) {
|
if (memberRoles.size === member.roles.cache.size) {
|
||||||
// No role changes
|
// No role changes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +71,6 @@ export const RemoveRolesAction = automodAction({
|
||||||
await member.edit({
|
await member.edit({
|
||||||
roles: rolesArr,
|
roles: rolesArr,
|
||||||
});
|
});
|
||||||
member.roles = rolesArr; // Make sure we know of the new roles internally as well
|
|
||||||
|
|
||||||
memberRoleLock.unlock();
|
memberRoleLock.unlock();
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
|
import { MessageOptions, Permissions, Snowflake, TextChannel, User } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
import { userToConfigAccessibleUser } from "../../../utils/configAccessibleObjects";
|
||||||
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { renderTemplate } from "../../../templateFormatter";
|
||||||
import {
|
import {
|
||||||
convertDelayStringToMS,
|
convertDelayStringToMS,
|
||||||
noop,
|
noop,
|
||||||
renderRecursively,
|
renderRecursively,
|
||||||
StrictMessageContent,
|
|
||||||
stripObjectToScalars,
|
|
||||||
tDelayString,
|
tDelayString,
|
||||||
tMessageContent,
|
tMessageContent,
|
||||||
tNullable,
|
tNullable,
|
||||||
unique,
|
unique,
|
||||||
verboseChannelMention,
|
verboseChannelMention,
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import { AdvancedMessageContent, Constants, MessageContent, TextChannel, User } from "eris";
|
|
||||||
import { AutomodContext } from "../types";
|
|
||||||
import { renderTemplate } from "../../../templateFormatter";
|
|
||||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { automodAction } from "../helpers";
|
||||||
|
import { AutomodContext } from "../types";
|
||||||
|
|
||||||
export const ReplyAction = automodAction({
|
export const ReplyAction = automodAction({
|
||||||
configType: t.union([
|
configType: t.union([
|
||||||
|
@ -32,7 +31,7 @@ export const ReplyAction = automodAction({
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const contextsWithTextChannels = contexts
|
const contextsWithTextChannels = contexts
|
||||||
.filter(c => c.message?.channel_id)
|
.filter(c => c.message?.channel_id)
|
||||||
.filter(c => pluginData.guild.channels.get(c.message!.channel_id) instanceof TextChannel);
|
.filter(c => pluginData.guild.channels.cache.get(c.message!.channel_id as Snowflake) instanceof TextChannel);
|
||||||
|
|
||||||
const contextsByChannelId = contextsWithTextChannels.reduce((map: Map<string, AutomodContext[]>, context) => {
|
const contextsByChannelId = contextsWithTextChannels.reduce((map: Map<string, AutomodContext[]>, context) => {
|
||||||
if (!map.has(context.message!.channel_id)) {
|
if (!map.has(context.message!.channel_id)) {
|
||||||
|
@ -49,21 +48,21 @@ export const ReplyAction = automodAction({
|
||||||
|
|
||||||
const renderReplyText = async str =>
|
const renderReplyText = async str =>
|
||||||
renderTemplate(str, {
|
renderTemplate(str, {
|
||||||
user: stripObjectToScalars(user),
|
user: userToConfigAccessibleUser(user),
|
||||||
});
|
});
|
||||||
const formatted =
|
const formatted =
|
||||||
typeof actionConfig === "string"
|
typeof actionConfig === "string"
|
||||||
? await renderReplyText(actionConfig)
|
? await renderReplyText(actionConfig)
|
||||||
: ((await renderRecursively(actionConfig.text, renderReplyText)) as AdvancedMessageContent);
|
: ((await renderRecursively(actionConfig.text, renderReplyText)) as MessageOptions);
|
||||||
|
|
||||||
if (formatted) {
|
if (formatted) {
|
||||||
const channel = pluginData.guild.channels.get(channelId) as TextChannel;
|
const channel = pluginData.guild.channels.cache.get(channelId as Snowflake) as TextChannel;
|
||||||
|
|
||||||
// Check for basic Send Messages and View Channel permissions
|
// Check for basic Send Messages and View Channel permissions
|
||||||
if (
|
if (
|
||||||
!hasDiscordPermissions(
|
!hasDiscordPermissions(
|
||||||
channel.permissionsOf(pluginData.client.user.id),
|
channel.permissionsFor(pluginData.client.user!.id),
|
||||||
Constants.Permissions.sendMessages | Constants.Permissions.readMessages,
|
Permissions.FLAGS.SEND_MESSAGES | Permissions.FLAGS.VIEW_CHANNEL,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||||
|
@ -75,7 +74,7 @@ export const ReplyAction = automodAction({
|
||||||
// If the message is an embed, check for embed permissions
|
// If the message is an embed, check for embed permissions
|
||||||
if (
|
if (
|
||||||
typeof formatted !== "string" &&
|
typeof formatted !== "string" &&
|
||||||
!hasDiscordPermissions(channel.permissionsOf(pluginData.client.user.id), Constants.Permissions.embedLinks)
|
!hasDiscordPermissions(channel.permissionsFor(pluginData.client.user!.id), Permissions.FLAGS.EMBED_LINKS)
|
||||||
) {
|
) {
|
||||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||||
body: `Missing permissions to reply **with an embed** in ${verboseChannelMention(
|
body: `Missing permissions to reply **with an embed** in ${verboseChannelMention(
|
||||||
|
@ -85,8 +84,8 @@ export const ReplyAction = automodAction({
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageContent: StrictMessageContent = typeof formatted === "string" ? { content: formatted } : formatted;
|
const messageContent: MessageOptions = typeof formatted === "string" ? { content: formatted } : formatted;
|
||||||
const replyMsg = await channel.createMessage({
|
const replyMsg = await channel.send({
|
||||||
...messageContent,
|
...messageContent,
|
||||||
allowedMentions: {
|
allowedMentions: {
|
||||||
users: [user.id],
|
users: [user.id],
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
|
||||||
import { tNullable } from "../../../utils";
|
import { tNullable } from "../../../utils";
|
||||||
|
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const SetAntiraidLevelAction = automodAction({
|
export const SetAntiraidLevelAction = automodAction({
|
||||||
configType: tNullable(t.string),
|
configType: tNullable(t.string),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const SetCounterAction = automodAction({
|
export const SetCounterAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import { Snowflake, TextChannel } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
import { ChannelTypeStrings } from "src/types";
|
||||||
import { convertDelayStringToMS, isDiscordRESTError, tDelayString, tNullable } from "../../../utils";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { Constants, TextChannel } from "eris";
|
import { convertDelayStringToMS, isDiscordAPIError, tDelayString, tNullable } from "../../../utils";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const SetSlowmodeAction = automodAction({
|
export const SetSlowmodeAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
@ -18,24 +19,23 @@ export const SetSlowmodeAction = automodAction({
|
||||||
const slowmodeMs = Math.max(actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : 0, 0);
|
const slowmodeMs = Math.max(actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : 0, 0);
|
||||||
|
|
||||||
for (const channelId of actionConfig.channels) {
|
for (const channelId of actionConfig.channels) {
|
||||||
const channel = pluginData.guild.channels.get(channelId);
|
const channel = pluginData.guild.channels.cache.get(channelId as Snowflake);
|
||||||
|
|
||||||
// Only text channels and text channels within categories support slowmodes
|
// Only text channels and text channels within categories support slowmodes
|
||||||
if (
|
if (!channel || !(channel.type === ChannelTypeStrings.TEXT || ChannelTypeStrings.CATEGORY)) {
|
||||||
!channel ||
|
|
||||||
!(channel.type === Constants.ChannelTypes.GUILD_TEXT || channel.type === Constants.ChannelTypes.GUILD_CATEGORY)
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let channelsToSlowmode: TextChannel[] = [];
|
const channelsToSlowmode: TextChannel[] = [];
|
||||||
if (channel.type === Constants.ChannelTypes.GUILD_CATEGORY) {
|
if (channel.type === ChannelTypeStrings.CATEGORY) {
|
||||||
// Find all text channels within the category
|
// Find all text channels within the category
|
||||||
channelsToSlowmode = pluginData.guild.channels.filter(
|
for (const ch of pluginData.guild.channels.cache.values()) {
|
||||||
ch => ch.parentID === channel.id && ch.type === Constants.ChannelTypes.GUILD_TEXT,
|
if (ch.parentId === channel.id && ch.type === ChannelTypeStrings.TEXT) {
|
||||||
) as TextChannel[];
|
channelsToSlowmode.push(ch as TextChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
channelsToSlowmode.push(channel);
|
channelsToSlowmode.push(channel as TextChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
const slowmodeSeconds = Math.ceil(slowmodeMs / 1000);
|
const slowmodeSeconds = Math.ceil(slowmodeMs / 1000);
|
||||||
|
@ -49,7 +49,7 @@ export const SetSlowmodeAction = automodAction({
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Check for invalid form body -> indicates duration was too large
|
// Check for invalid form body -> indicates duration was too large
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
isDiscordRESTError(e) && e.code === 50035
|
isDiscordAPIError(e) && e.code === 50035
|
||||||
? `Duration is greater than maximum native slowmode duration`
|
? `Duration is greater than maximum native slowmode duration`
|
||||||
: e.message;
|
: e.message;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { automodAction } from "../helpers";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
|
||||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
|
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||||
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const WarnAction = automodAction({
|
export const WarnAction = automodAction({
|
||||||
configType: t.type({
|
configType: t.type({
|
||||||
|
@ -25,7 +24,7 @@ export const WarnAction = automodAction({
|
||||||
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
||||||
|
|
||||||
const caseArgs: Partial<CaseArgs> = {
|
const caseArgs: Partial<CaseArgs> = {
|
||||||
modId: pluginData.client.user.id,
|
modId: pluginData.client.user!.id,
|
||||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||||
automatic: true,
|
automatic: true,
|
||||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue