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.ts
|
||||
*.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\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/sharp": "^0.23.1",
|
||||
"@types/twemoji": "^12.1.0",
|
||||
"bufferutil": "^4.0.1",
|
||||
"bufferutil": "^4.0.3",
|
||||
"cors": "^2.8.5",
|
||||
"cross-env": "^5.2.0",
|
||||
"deep-diff": "^1.0.2",
|
||||
"discord-api-types": "^0.22.0",
|
||||
"discord.js": "^13.1.0",
|
||||
"dotenv": "^4.0.0",
|
||||
"emoji-regex": "^8.0.0",
|
||||
"eris": "^0.15.1",
|
||||
"erlpack": "github:abalabahaha/erlpack",
|
||||
"erlpack": "github:almeidx/erlpack#f0c535f73817fd914806d6ca26a7730c14e0fb7c",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"express": "^4.17.0",
|
||||
"fp-ts": "^2.0.1",
|
||||
"humanize-duration": "^3.15.0",
|
||||
"io-ts": "^2.0.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"knub": "^30.0.0-beta.37",
|
||||
"knub-command-manager": "^8.1.2",
|
||||
"knub": "file:../../Knub",
|
||||
"knub-command-manager": "^9.1.0",
|
||||
"last-commit-log": "^2.1.0",
|
||||
"lodash.chunk": "^4.2.0",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
|
@ -59,13 +58,14 @@
|
|||
"regexp-worker": "^1.1.0",
|
||||
"safe-regex": "^2.0.2",
|
||||
"seedrandom": "^3.0.1",
|
||||
"sharp": "^0.23.4",
|
||||
"sharp": "github:almeidx/sharp#68b4f387ae2ee1ee2dd8f289f5ec5fcf722fd3d3",
|
||||
"strip-combining-marks": "^1.0.0",
|
||||
"tlds": "^1.203.1",
|
||||
"tmp": "0.0.33",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"twemoji": "^12.1.4",
|
||||
"typeorm": "^0.2.31",
|
||||
"utf-8-validate": "^5.0.5",
|
||||
"uuid": "^3.3.2",
|
||||
"yawn-yaml": "github:dragory/yawn-yaml#string-number-fix-build",
|
||||
"zlib-sync": "^0.1.7"
|
||||
|
@ -82,12 +82,14 @@
|
|||
"@types/passport-oauth2": "^1.4.8",
|
||||
"@types/passport-strategy": "^0.2.35",
|
||||
"@types/safe-regex": "^1.1.2",
|
||||
"@types/sharp": "^0.23.1",
|
||||
"@types/tmp": "0.0.33",
|
||||
"@types/twemoji": "^12.1.0",
|
||||
"ava": "^3.10.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"source-map-support": "^0.5.16",
|
||||
"tsc-watch": "^4.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
"typescript": "^4.3.4"
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import util from "util";
|
||||
|
||||
export class ErisError extends Error {
|
||||
export class DiscordJSError extends Error {
|
||||
code: number | string | undefined;
|
||||
shardId: number;
|
||||
|
||||
|
@ -11,6 +11,6 @@ export class ErisError extends Error {
|
|||
}
|
||||
|
||||
[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 {
|
||||
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 { CooldownManager } from "knub";
|
||||
import { RegExpWorker, TimeoutError } from "regexp-worker";
|
||||
import { MINUTES, SECONDS } from "./utils";
|
||||
import Timeout = NodeJS.Timeout;
|
||||
|
||||
const isTimeoutError = (a): a is TimeoutError => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import express, { Request, Response } from "express";
|
||||
import moment from "moment-timezone";
|
||||
import { GuildArchives } from "../data/GuildArchives";
|
||||
import { notFound } from "./responses";
|
||||
import moment from "moment-timezone";
|
||||
|
||||
export function initArchives(app: express.Express) {
|
||||
const archives = new GuildArchives(null);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
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 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 { ApiUserInfoData } from "../data/entities/ApiUserInfo";
|
||||
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
||||
import { ok } from "./responses";
|
||||
|
||||
interface IPassportApiUser {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import express from "express";
|
||||
import { guildPlugins } from "../plugins/availablePlugins";
|
||||
import { notFound } from "./responses";
|
||||
import { indentLines } from "../utils";
|
||||
import { notFound } from "./responses";
|
||||
|
||||
function formatConfigSchema(schema) {
|
||||
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 { 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 { Configs } from "../data/Configs";
|
||||
import { apiTokenAuthHandlers } from "./auth";
|
||||
import { hasGuildPermission, requireGuildPermission } from "./permissions";
|
||||
import { clientError, ok, serverError, unauthorized } from "./responses";
|
||||
|
||||
const apiPermissionAssignments = new ApiPermissionAssignments();
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import "./loadEnv";
|
||||
|
||||
import { connect } from "../data/db";
|
||||
import path from "path";
|
||||
import { setIsAPI } from "../globals";
|
||||
import "./loadEnv";
|
||||
|
||||
if (!process.env.KEY) {
|
||||
// tslint:disable-next-line:no-console
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ApiPermissions, hasPermission, permissionArrToSet } from "@shared/apiPermissions";
|
||||
import { isStaff } from "../staff";
|
||||
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
||||
import { Request, Response } from "express";
|
||||
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
|
||||
import { isStaff } from "../staff";
|
||||
import { unauthorized } from "./responses";
|
||||
|
||||
const apiPermissionAssignments = new ApiPermissionAssignments();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import express, { Request, Response } from "express";
|
||||
import { apiTokenAuthHandlers } from "./auth";
|
||||
import { isStaff } from "../staff";
|
||||
import { apiTokenAuthHandlers } from "./auth";
|
||||
|
||||
export function initStaff(app: express.Express) {
|
||||
const staffRouter = express.Router();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { clientError, error, notFound } from "./responses";
|
||||
import express from "express";
|
||||
import cors from "cors";
|
||||
import { initAuth } from "./auth";
|
||||
import { initGuildsAPI } from "./guilds";
|
||||
import { initArchives } from "./archives";
|
||||
import { initDocs } from "./docs";
|
||||
import express from "express";
|
||||
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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
channelMentionRegex,
|
||||
convertDelayStringToMS,
|
||||
disableCodeBlocks,
|
||||
disableInlineCode,
|
||||
isSnowflake,
|
||||
isValidSnowflake,
|
||||
resolveMember,
|
||||
resolveUser,
|
||||
|
@ -11,13 +11,9 @@ import {
|
|||
roleMentionRegex,
|
||||
UnknownUser,
|
||||
} from "./utils";
|
||||
import { GuildChannel, Member, TextChannel, User } from "eris";
|
||||
import { baseTypeConverters, baseCommandParameterTypeHelpers, CommandContext, TypeConversionError } from "knub";
|
||||
import { createTypeHelper } from "knub-command-manager";
|
||||
import { getChannelIdFromMessageId } from "./data/getChannelIdFromMessageId";
|
||||
import { isValidTimezone } from "./utils/isValidTimezone";
|
||||
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
||||
import { inputPatternToRegExp } from "./validatorUtils";
|
||||
import { isValidTimezone } from "./utils/isValidTimezone";
|
||||
|
||||
export const commandTypes = {
|
||||
...baseTypeConverters,
|
||||
|
@ -34,7 +30,7 @@ export const commandTypes = {
|
|||
async resolvedUser(value, context: CommandContext<any>) {
|
||||
const result = await resolveUser(context.pluginData.client, value);
|
||||
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;
|
||||
},
|
||||
|
@ -42,7 +38,7 @@ export const commandTypes = {
|
|||
async resolvedUserLoose(value, context: CommandContext<any>) {
|
||||
const result = await resolveUser(context.pluginData.client, value);
|
||||
if (result == null) {
|
||||
throw new TypeConversionError(`Invalid user: \`${disableCodeBlocks(value)}\``);
|
||||
throw new TypeConversionError(`Invalid user: \`${Util.escapeCodeBlock(value)}\``);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
@ -55,7 +51,7 @@ export const commandTypes = {
|
|||
const result = await resolveMember(context.pluginData.client, context.message.channel.guild, value);
|
||||
if (result == null) {
|
||||
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;
|
||||
|
@ -66,7 +62,7 @@ export const commandTypes = {
|
|||
|
||||
const result = await resolveMessageTarget(context.pluginData, value);
|
||||
if (!result) {
|
||||
throw new TypeConversionError(`Unknown message \`${disableInlineCode(value)}\``);
|
||||
throw new TypeConversionError(`Unknown message \`${Util.escapeInlineCode(value)}\``);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -74,32 +70,32 @@ export const commandTypes = {
|
|||
|
||||
async anyId(value: string, context: CommandContext<any>) {
|
||||
const userId = resolveUserId(context.pluginData.client, value);
|
||||
if (userId) return userId;
|
||||
if (userId) return userId as Snowflake;
|
||||
|
||||
const channelIdMatch = value.match(channelMentionRegex);
|
||||
if (channelIdMatch) return channelIdMatch[1];
|
||||
if (channelIdMatch) return channelIdMatch[1] as Snowflake;
|
||||
|
||||
const roleIdMatch = value.match(roleMentionRegex);
|
||||
if (roleIdMatch) return roleIdMatch[1];
|
||||
if (roleIdMatch) return roleIdMatch[1] as Snowflake;
|
||||
|
||||
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 {
|
||||
try {
|
||||
return inputPatternToRegExp(value);
|
||||
} 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) {
|
||||
if (!isValidTimezone(value)) {
|
||||
throw new TypeConversionError(`Invalid timezone: ${disableInlineCode(value)}`);
|
||||
throw new TypeConversionError(`Invalid timezone: ${Util.escapeInlineCode(value)}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -112,9 +108,9 @@ export const commandTypeHelpers = {
|
|||
delay: createTypeHelper<number>(commandTypes.delay),
|
||||
resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser),
|
||||
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),
|
||||
anyId: createTypeHelper<Promise<string>>(commandTypes.anyId),
|
||||
anyId: createTypeHelper<Promise<Snowflake>>(commandTypes.anyId),
|
||||
regex: createTypeHelper<RegExp>(commandTypes.regex),
|
||||
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 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>();
|
||||
for (const plugin of guildPlugins) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AllowedGuild } from "./entities/AllowedGuild";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { ApiPermissionTypes } from "./ApiPermissionAssignments";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { AllowedGuild } from "./entities/AllowedGuild";
|
||||
|
||||
export class AllowedGuilds extends BaseRepository {
|
||||
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 moment from "moment-timezone";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import uuidv4 from "uuid/v4";
|
||||
import { DAYS, DBDateFormat } from "../utils";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { ApiLogin } from "./entities/ApiLogin";
|
||||
|
||||
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 { getRepository, Repository } from "typeorm";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { ApiPermissionAssignment } from "./entities/ApiPermissionAssignment";
|
||||
|
||||
export enum ApiPermissionTypes {
|
||||
User = "USER",
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import moment from "moment-timezone";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { ApiUserInfo as ApiUserInfoEntity, ApiUserInfoData } from "./entities/ApiUserInfo";
|
||||
import { DBDateFormat } from "../utils";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { connection } from "./db";
|
||||
import moment from "moment-timezone";
|
||||
import { DBDateFormat } from "../utils";
|
||||
import { ApiUserInfo as ApiUserInfoEntity, ApiUserInfoData } from "./entities/ApiUserInfo";
|
||||
|
||||
export class ApiUserInfo extends BaseRepository {
|
||||
private apiUserInfo: Repository<ApiUserInfoEntity>;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Config } from "./entities/Config";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { connection } from "./db";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { isAPI } from "../globals";
|
||||
import { HOURS, SECONDS } from "../utils";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { cleanupConfigs } from "./cleanup/configs";
|
||||
import { connection } from "./db";
|
||||
import { Config } from "./entities/Config";
|
||||
|
||||
if (isAPI()) {
|
||||
const CLEANUP_INTERVAL = 1 * HOURS;
|
||||
|
|
|
@ -24,11 +24,15 @@
|
|||
|
||||
"CHANNEL_CREATE": "🖊 Channel {channelMention(channel)} was created",
|
||||
"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_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_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_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}`",
|
||||
|
||||
"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 { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { AntiraidLevel } from "./entities/AntiraidLevel";
|
||||
|
||||
export class GuildAntiraidLevels extends BaseGuildRepository {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Guild, Snowflake } from "discord.js";
|
||||
import moment from "moment-timezone";
|
||||
import { ArchiveEntry } from "./entities/ArchiveEntry";
|
||||
import { isDefaultSticker } from "src/utils/isDefaultSticker";
|
||||
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 { trimLines } from "../utils";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { ArchiveEntry } from "./entities/ArchiveEntry";
|
||||
import { SavedMessage } from "./entities/SavedMessage";
|
||||
|
||||
const DEFAULT_EXPIRY_DAYS = 30;
|
||||
|
||||
|
@ -13,7 +14,7 @@ const MESSAGE_ARCHIVE_HEADER_FORMAT = trimLines(`
|
|||
Server: {guild.name} ({guild.id})
|
||||
`);
|
||||
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 {
|
||||
protected archives: Repository<ArchiveEntry>;
|
||||
|
@ -73,13 +74,19 @@ export class GuildArchives extends BaseGuildRepository {
|
|||
protected async renderLinesFromSavedMessages(savedMessages: SavedMessage[], guild: Guild) {
|
||||
const msgLines: string[] = [];
|
||||
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 line = await renderTemplate(MESSAGE_ARCHIVE_MESSAGE_FORMAT, {
|
||||
id: msg.id,
|
||||
timestamp: moment.utc(msg.posted_at).format("YYYY-MM-DD HH:mm:ss"),
|
||||
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,
|
||||
channel,
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { AutoReaction } from "./entities/AutoReaction";
|
||||
|
||||
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 { 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 { connection } from "./db";
|
||||
|
||||
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 { DAYS, DBDateFormat, HOURS, MINUTES } from "../utils";
|
||||
import { connection } from "./db";
|
||||
import { FindConditions, getRepository, In, IsNull, Not, Repository } from "typeorm";
|
||||
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_COUNTER_TRIGGERS_AFTER = 1 * DAYS;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
|
||||
export class GuildEvents extends BaseGuildRepository {
|
||||
private queuedEventEmitter: QueuedEventEmitter;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { MemberTimezone } from "./entities/MemberTimezone";
|
||||
import { getRepository, Repository } from "typeorm/index";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { connection } from "./db";
|
||||
import { MemberTimezone } from "./entities/MemberTimezone";
|
||||
|
||||
export class GuildMemberTimezones extends BaseGuildRepository {
|
||||
protected memberTimezones: Repository<MemberTimezone>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import moment from "moment-timezone";
|
||||
import { Mute } from "./entities/Mute";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { Brackets, getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { Mute } from "./entities/Mute";
|
||||
|
||||
export class GuildMutes extends BaseGuildRepository {
|
||||
private mutes: Repository<Mute>;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, In, Repository } from "typeorm";
|
||||
import { NicknameHistoryEntry } from "./entities/NicknameHistoryEntry";
|
||||
import { MINUTES, SECONDS } from "../utils";
|
||||
import { isAPI } from "../globals";
|
||||
import { MINUTES, SECONDS } from "../utils";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { cleanupNicknames } from "./cleanup/nicknames";
|
||||
import { NicknameHistoryEntry } from "./entities/NicknameHistoryEntry";
|
||||
|
||||
if (!isAPI()) {
|
||||
const CLEANUP_INTERVAL = 5 * MINUTES;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { PersistedData } from "./entities/PersistedData";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { PersistedData } from "./entities/PersistedData";
|
||||
|
||||
export interface IPartialPersistData {
|
||||
roles?: string[];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { PingableRole } from "./entities/PingableRole";
|
||||
|
||||
export class GuildPingableRoles extends BaseGuildRepository {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ReactionRole } from "./entities/ReactionRole";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { ReactionRole } from "./entities/ReactionRole";
|
||||
|
||||
export class GuildReactionRoles extends BaseGuildRepository {
|
||||
private reactionRoles: Repository<ReactionRole>;
|
||||
|
@ -24,6 +24,9 @@ export class GuildReactionRoles extends BaseGuildRepository {
|
|||
guild_id: this.guildId,
|
||||
message_id: messageId,
|
||||
},
|
||||
order: {
|
||||
order: "ASC",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -50,7 +53,14 @@ export class GuildReactionRoles extends BaseGuildRepository {
|
|||
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({
|
||||
guild_id: this.guildId,
|
||||
channel_id: channelId,
|
||||
|
@ -58,6 +68,7 @@ export class GuildReactionRoles extends BaseGuildRepository {
|
|||
emoji,
|
||||
role_id: roleId,
|
||||
is_exclusive: Boolean(exclusive),
|
||||
order: position,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { Reminder } from "./entities/Reminder";
|
||||
|
||||
export class GuildReminders extends BaseGuildRepository {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
|
||||
import { QueuedEventEmitter } from "../QueuedEventEmitter";
|
||||
import { GuildChannel, Message, PossiblyUncachedTextableChannel } from "eris";
|
||||
import { GuildChannel, Message } from "discord.js";
|
||||
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 { QueuedEventEmitter } from "../QueuedEventEmitter";
|
||||
import { MINUTES, SECONDS } from "../utils";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { cleanupMessages } from "./cleanup/messages";
|
||||
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
|
||||
|
||||
if (!isAPI()) {
|
||||
const CLEANUP_INTERVAL = 5 * MINUTES;
|
||||
|
@ -34,19 +35,19 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
|||
this.toBePermanent = new Set();
|
||||
}
|
||||
|
||||
public msgToSavedMessageData(msg: Message<PossiblyUncachedTextableChannel>): ISavedMessageData {
|
||||
public msgToSavedMessageData(msg: Message): ISavedMessageData {
|
||||
const data: ISavedMessageData = {
|
||||
author: {
|
||||
username: msg.author.username,
|
||||
discriminator: msg.author.discriminator,
|
||||
},
|
||||
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.stickers?.length) data.stickers = msg.stickers;
|
||||
if (msg.stickers?.size) data.stickers = [...msg.stickers.values()];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -139,12 +140,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
|||
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);
|
||||
if (existingSavedMsg) return;
|
||||
|
||||
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 = {
|
||||
id: msg.id,
|
||||
|
@ -159,6 +160,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
|||
return this.create({ ...data, ...overrides });
|
||||
}
|
||||
|
||||
async createFromMessages(messages: Message[], overrides = {}) {
|
||||
for (const msg of messages) {
|
||||
await this.createFromMsg(msg, overrides);
|
||||
}
|
||||
}
|
||||
|
||||
async markAsDeleted(id) {
|
||||
await this.messages
|
||||
.createQueryBuilder("messages")
|
||||
|
@ -211,10 +218,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
|||
|
||||
const newMessage = { ...oldMessage, data: newData };
|
||||
|
||||
// @ts-ignore
|
||||
await this.messages.update(
|
||||
// FIXME?
|
||||
{ id },
|
||||
{
|
||||
data: newData,
|
||||
data: newData as QueryDeepPartialEntity<ISavedMessageData>,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -222,7 +231,7 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
|||
this.events.emit(`update:${id}`, [newMessage, oldMessage]);
|
||||
}
|
||||
|
||||
async saveEditFromMsg(msg: Message<PossiblyUncachedTextableChannel>) {
|
||||
async saveEditFromMsg(msg: Message) {
|
||||
const newData = this.msgToSavedMessageData(msg);
|
||||
return this.saveEdit(msg.id, newData);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { ScheduledPost } from "./entities/ScheduledPost";
|
||||
|
||||
export class GuildScheduledPosts extends BaseGuildRepository {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import moment from "moment-timezone";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { SlowmodeChannel } from "./entities/SlowmodeChannel";
|
||||
import { SlowmodeUser } from "./entities/SlowmodeUser";
|
||||
import moment from "moment-timezone";
|
||||
|
||||
export class GuildSlowmodes extends BaseGuildRepository {
|
||||
private slowmodeChannels: Repository<SlowmodeChannel>;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { StarboardMessage } from "./entities/StarboardMessage";
|
||||
|
||||
export class GuildStarboardMessages extends BaseGuildRepository {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { StarboardReaction } from "./entities/StarboardReaction";
|
||||
|
||||
export class GuildStarboardReactions extends BaseGuildRepository {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { StatValue } from "./entities/StatValue";
|
||||
|
||||
export class GuildStats extends BaseGuildRepository {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Tag } from "./entities/Tag";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { Tag } from "./entities/Tag";
|
||||
import { TagResponse } from "./entities/TagResponse";
|
||||
|
||||
export class GuildTags extends BaseGuildRepository {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import moment from "moment-timezone";
|
||||
import { Mute } from "./entities/Mute";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { Brackets, getRepository, Repository } from "typeorm";
|
||||
import { Tempban } from "./entities/Tempban";
|
||||
|
||||
export class GuildTempbans extends BaseGuildRepository {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseGuildRepository } from "./BaseGuildRepository";
|
||||
import { VCAlert } from "./entities/VCAlert";
|
||||
|
||||
export class GuildVCAlerts extends BaseGuildRepository {
|
||||
|
|
|
@ -18,9 +18,15 @@ export enum LogType {
|
|||
|
||||
CHANNEL_CREATE,
|
||||
CHANNEL_DELETE,
|
||||
CHANNEL_UPDATE,
|
||||
|
||||
THREAD_CREATE,
|
||||
THREAD_DELETE,
|
||||
THREAD_UPDATE,
|
||||
|
||||
ROLE_CREATE,
|
||||
ROLE_DELETE,
|
||||
ROLE_UPDATE,
|
||||
|
||||
MESSAGE_EDIT,
|
||||
MESSAGE_DELETE,
|
||||
|
@ -31,6 +37,18 @@ export enum LogType {
|
|||
VOICE_CHANNEL_LEAVE,
|
||||
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,
|
||||
|
||||
MESSAGE_SPAM_DETECTED,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseRepository } from "./BaseRepository";
|
||||
import { getRepository, Repository } from "typeorm";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { Supporter } from "./entities/Supporter";
|
||||
|
||||
export class Supporters extends BaseRepository {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { getRepository, In, Repository } from "typeorm";
|
||||
import { UsernameHistoryEntry } from "./entities/UsernameHistoryEntry";
|
||||
import { isAPI } from "../globals";
|
||||
import { MINUTES, SECONDS } from "../utils";
|
||||
import { BaseRepository } from "./BaseRepository";
|
||||
import { isAPI } from "../globals";
|
||||
import { cleanupUsernames } from "./cleanup/usernames";
|
||||
import { UsernameHistoryEntry } from "./entities/UsernameHistoryEntry";
|
||||
|
||||
if (!isAPI()) {
|
||||
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 { getRepository, In } from "typeorm";
|
||||
import { DBDateFormat } from "../../utils";
|
||||
import { connection } from "../db";
|
||||
import { Config } from "../entities/Config";
|
||||
|
||||
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 { getRepository, In } from "typeorm";
|
||||
import { DAYS, DBDateFormat, MINUTES } from "../../utils";
|
||||
import { connection } from "../db";
|
||||
import { SavedMessage } from "../entities/SavedMessage";
|
||||
|
||||
/**
|
||||
* 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 { NicknameHistoryEntry } from "../entities/NicknameHistoryEntry";
|
||||
import { getRepository, In } from "typeorm";
|
||||
import { DAYS, DBDateFormat } from "../../utils";
|
||||
import { connection } from "../db";
|
||||
import { NicknameHistoryEntry } from "../entities/NicknameHistoryEntry";
|
||||
|
||||
export const NICKNAME_RETENTION_PERIOD = 30 * DAYS;
|
||||
const CLEAN_PER_LOOP = 500;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { getRepository, In } from "typeorm";
|
||||
import moment from "moment-timezone";
|
||||
import { UsernameHistoryEntry } from "../entities/UsernameHistoryEntry";
|
||||
import { getRepository, In } from "typeorm";
|
||||
import { DAYS, DBDateFormat } from "../../utils";
|
||||
import { connection } from "../db";
|
||||
import { UsernameHistoryEntry } from "../entities/UsernameHistoryEntry";
|
||||
|
||||
export const USERNAME_RETENTION_PERIOD = 30 * DAYS;
|
||||
const CLEAN_PER_LOOP = 500;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { SimpleError } from "../SimpleError";
|
||||
import { Connection, createConnection } from "typeorm";
|
||||
import { SimpleError } from "../SimpleError";
|
||||
|
||||
let connectionPromise: Promise<Connection>;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { decrypt, encrypt } from "../utils/crypt";
|
||||
import { ValueTransformer } from "typeorm";
|
||||
import { decrypt, encrypt } from "../utils/crypt";
|
||||
|
||||
interface EncryptedJsonTransformer<T> extends ValueTransformer {
|
||||
from(dbValue: any): T;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { decrypt, encrypt } from "../utils/crypt";
|
||||
import { ValueTransformer } from "typeorm";
|
||||
import { decrypt, encrypt } from "../utils/crypt";
|
||||
|
||||
interface EncryptedTextTransformer extends ValueTransformer {
|
||||
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];
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -21,4 +21,6 @@ export class ReactionRole {
|
|||
@Column() role_id: string;
|
||||
|
||||
@Column() is_exclusive: boolean;
|
||||
|
||||
@Column() order: number;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { MessageAttachment, Sticker } from "discord.js";
|
||||
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||
import { createEncryptedJsonTransformer } from "../encryptedJsonTransformer";
|
||||
import { Attachment, Sticker } from "eris";
|
||||
|
||||
export interface ISavedMessageData {
|
||||
attachments?: Attachment[];
|
||||
attachments?: MessageAttachment[];
|
||||
author: {
|
||||
username: string;
|
||||
discriminator: string;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { MessageAttachment } from "discord.js";
|
||||
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||
import { Attachment } from "eris";
|
||||
import { StrictMessageContent } from "../../utils";
|
||||
|
||||
@Entity("scheduled_posts")
|
||||
|
@ -18,7 +18,7 @@ export class ScheduledPost {
|
|||
|
||||
@Column("simple-json") content: StrictMessageContent;
|
||||
|
||||
@Column("simple-json") attachments: Attachment[];
|
||||
@Column("simple-json") attachments: MessageAttachment[];
|
||||
|
||||
@Column({ type: String, nullable: true }) post_at: string | null;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { getRepository, Repository } from "typeorm";
|
||||
import { SavedMessage } from "./entities/SavedMessage";
|
||||
import { Repository, getRepository } from "typeorm";
|
||||
|
||||
let repository: Repository<SavedMessage>;
|
||||
|
||||
|
|
|
@ -1,32 +1,24 @@
|
|||
import "./loadEnv";
|
||||
|
||||
import path from "path";
|
||||
import { Client, Intents, TextChannel } from "discord.js";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
import fs from "fs";
|
||||
import { Knub, PluginError } from "knub";
|
||||
import { SimpleError } from "./SimpleError";
|
||||
|
||||
import { Configs } from "./data/Configs";
|
||||
import { PluginLoadError } from "knub/dist/plugins/PluginLoadError";
|
||||
// Always use UTC internally
|
||||
// This is also enforced for the database in data/db.ts
|
||||
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 { ZeppelinGlobalConfig, ZeppelinGuildConfig } from "./types";
|
||||
import { RecoverablePluginError } from "./RecoverablePluginError";
|
||||
import { Configs } from "./data/Configs";
|
||||
import { connect } from "./data/db";
|
||||
import { GuildLogs } from "./data/GuildLogs";
|
||||
import { LogType } from "./data/LogType";
|
||||
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
||||
import { DiscordJSError } from "./DiscordJSError";
|
||||
import "./loadEnv";
|
||||
import { logger } from "./logger";
|
||||
import { PluginLoadError } from "knub/dist/plugins/PluginLoadError";
|
||||
import { ErisError } from "./ErisError";
|
||||
|
||||
const fsp = fs.promises;
|
||||
import { baseGuildPlugins, globalPlugins, guildPlugins } from "./plugins/availablePlugins";
|
||||
import { RecoverablePluginError } from "./RecoverablePluginError";
|
||||
import { SimpleError } from "./SimpleError";
|
||||
import { ZeppelinGlobalConfig, ZeppelinGuildConfig } from "./types";
|
||||
import { startUptimeCounter } from "./uptime";
|
||||
import { errorMessage, isDiscordAPIError, isDiscordHTTPError, successMessage } from "./utils";
|
||||
|
||||
if (!process.env.KEY) {
|
||||
// tslint:disable-next-line:no-console
|
||||
|
@ -86,7 +78,7 @@ function errorHandler(err) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (err instanceof ErisError) {
|
||||
if (err instanceof DiscordJSError) {
|
||||
if (err.code && SAFE_TO_IGNORE_ERIS_ERROR_CODES.includes(err.code)) {
|
||||
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
|
||||
// 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);
|
||||
|
@ -118,7 +110,7 @@ function errorHandler(err) {
|
|||
console.error(`Exiting after ${RECENT_PLUGIN_ERROR_EXIT_THRESHOLD} plugin errors`);
|
||||
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
|
||||
// We still bail if we get a ton of them in a short amount of time
|
||||
if (++recentDiscordErrors >= RECENT_DISCORD_ERROR_EXIT_THRESHOLD) {
|
||||
|
@ -151,48 +143,42 @@ moment.tz.setDefault("UTC");
|
|||
|
||||
logger.info("Connecting to database");
|
||||
connect().then(async () => {
|
||||
const client = new Client(`Bot ${process.env.TOKEN}`, {
|
||||
getAllUsers: false,
|
||||
restMode: true,
|
||||
compress: false,
|
||||
guildCreateTimeout: 0,
|
||||
rest: {
|
||||
ratelimiterOffset: 150,
|
||||
},
|
||||
const client = new Client({
|
||||
partials: ["USER", "CHANNEL", "GUILD_MEMBER", "MESSAGE", "REACTION"],
|
||||
restTimeOffset: 150,
|
||||
restGlobalRateLimit: 50,
|
||||
// Disable mentions by default
|
||||
allowedMentions: {
|
||||
everyone: false,
|
||||
users: false,
|
||||
roles: false,
|
||||
parse: [],
|
||||
users: [],
|
||||
roles: [],
|
||||
repliedUser: false,
|
||||
},
|
||||
intents: [
|
||||
// Privileged
|
||||
"guildMembers",
|
||||
// "guildPresences",
|
||||
"guildMessageTyping",
|
||||
Intents.FLAGS.GUILD_MEMBERS,
|
||||
// Intents.FLAGS.GUILD_PRESENCES,
|
||||
Intents.FLAGS.GUILD_MESSAGE_TYPING,
|
||||
|
||||
// Regular
|
||||
"directMessages",
|
||||
"guildBans",
|
||||
"guildEmojis",
|
||||
"guildInvites",
|
||||
"guildMessageReactions",
|
||||
"guildMessages",
|
||||
"guilds",
|
||||
"guildVoiceStates",
|
||||
Intents.FLAGS.DIRECT_MESSAGES,
|
||||
Intents.FLAGS.GUILD_BANS,
|
||||
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS,
|
||||
Intents.FLAGS.GUILD_INVITES,
|
||||
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
|
||||
Intents.FLAGS.GUILD_MESSAGES,
|
||||
Intents.FLAGS.GUILDS,
|
||||
Intents.FLAGS.GUILD_VOICE_STATES,
|
||||
],
|
||||
});
|
||||
client.setMaxListeners(200);
|
||||
|
||||
client.on("debug", message => {
|
||||
if (message.includes(" 429 ")) {
|
||||
logger.info(`[429] ${message}`);
|
||||
}
|
||||
client.on("rateLimit", rateLimitData => {
|
||||
logger.info(`[429] ${JSON.stringify(rateLimitData)}`);
|
||||
});
|
||||
|
||||
client.on("error", (err, shardId) => {
|
||||
errorHandler(new ErisError(err.message, (err as any).code, shardId));
|
||||
client.on("error", err => {
|
||||
errorHandler(new DiscordJSError(err.message, (err as any).code, 0));
|
||||
});
|
||||
|
||||
const allowedGuilds = new AllowedGuilds();
|
||||
|
@ -257,13 +243,13 @@ connect().then(async () => {
|
|||
sendSuccessMessageFn(channel, body) {
|
||||
const guildId = channel instanceof TextChannel ? channel.guild.id : undefined;
|
||||
const emoji = guildId ? bot.getLoadedGuild(guildId)!.config.success_emoji : undefined;
|
||||
channel.createMessage(successMessage(body, emoji));
|
||||
channel.send(successMessage(body, emoji));
|
||||
},
|
||||
|
||||
sendErrorMessageFn(channel, body) {
|
||||
const guildId = channel instanceof TextChannel ? channel.guild.id : 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();
|
||||
});
|
||||
|
||||
logger.info("Starting the bot");
|
||||
bot.run();
|
||||
bot.initialize();
|
||||
logger.info("Bot Initialized");
|
||||
logger.info("Logging in...");
|
||||
await client.login(process.env.TOKEN);
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// tslint:disable:no-console
|
||||
import { connect } from "./data/db";
|
||||
import { Configs } from "./data/Configs";
|
||||
import path from "path";
|
||||
import * as _fs from "fs";
|
||||
import path from "path";
|
||||
import { Configs } from "./data/Configs";
|
||||
import { connect } from "./data/db";
|
||||
|
||||
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 {
|
||||
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)
|
||||
*/
|
||||
|
||||
import { AdvancedMessageContent, AllowedMentions, GuildTextableChannel, Member, Message, TextableChannel } from "eris";
|
||||
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 { GuildMember, Message, MessageMentionOptions, MessageOptions, TextChannel } from "discord.js";
|
||||
import * as t from "io-ts";
|
||||
import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub";
|
||||
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 { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
||||
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;
|
||||
|
||||
export function canActOn(pluginData: GuildPluginData<any>, member1: Member, member2: Member, allowSameLevel = false) {
|
||||
if (member2.id === pluginData.client.user.id) {
|
||||
export function canActOn(
|
||||
pluginData: GuildPluginData<any>,
|
||||
member1: GuildMember,
|
||||
member2: GuildMember,
|
||||
allowSameLevel = false,
|
||||
) {
|
||||
if (member2.id === pluginData.client.user!.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -178,45 +183,43 @@ export function getPluginConfigPreprocessor(
|
|||
};
|
||||
}
|
||||
|
||||
export function sendSuccessMessage(
|
||||
export async function sendSuccessMessage(
|
||||
pluginData: AnyPluginData<any>,
|
||||
channel: TextableChannel,
|
||||
channel: TextChannel,
|
||||
body: string,
|
||||
allowedMentions?: AllowedMentions,
|
||||
allowedMentions?: MessageMentionOptions,
|
||||
): Promise<Message | undefined> {
|
||||
const emoji = pluginData.fullConfig.success_emoji || undefined;
|
||||
const formattedBody = successMessage(body, emoji);
|
||||
const content: AdvancedMessageContent = allowedMentions
|
||||
const content: MessageOptions = allowedMentions
|
||||
? { content: formattedBody, allowedMentions }
|
||||
: { content: formattedBody };
|
||||
|
||||
return channel
|
||||
.createMessage(content) // Force line break
|
||||
.send({ ...content }) // Force line break
|
||||
.catch(err => {
|
||||
const channelInfo = (channel as GuildTextableChannel).guild
|
||||
? `${channel.id} (${(channel as GuildTextableChannel).guild.id})`
|
||||
: `${channel.id}`;
|
||||
const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||
logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`);
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
export function sendErrorMessage(
|
||||
export async function sendErrorMessage(
|
||||
pluginData: AnyPluginData<any>,
|
||||
channel: TextableChannel,
|
||||
channel: TextChannel,
|
||||
body: string,
|
||||
allowedMentions?: AllowedMentions,
|
||||
allowedMentions?: MessageMentionOptions,
|
||||
): Promise<Message | undefined> {
|
||||
const emoji = pluginData.fullConfig.error_emoji || undefined;
|
||||
const formattedBody = errorMessage(body, emoji);
|
||||
const content: AdvancedMessageContent = allowedMentions
|
||||
const content: MessageOptions = allowedMentions
|
||||
? { content: formattedBody, allowedMentions }
|
||||
: { content: formattedBody };
|
||||
|
||||
return channel
|
||||
.createMessage(content) // Force line break
|
||||
.send({ ...content }) // Force line break
|
||||
.catch(err => {
|
||||
const channelInfo = (channel as GuildTextableChannel).guild
|
||||
? `${channel.id} (${(channel as GuildTextableChannel).guild.id})`
|
||||
: `${channel.id}`;
|
||||
const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||
logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`);
|
||||
return undefined;
|
||||
});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { PluginOptions } from "knub";
|
||||
import { AutoDeletePluginType, ConfigSchema } from "./types";
|
||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||
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 { onMessageDelete } from "./util/onMessageDelete";
|
||||
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk";
|
||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||
|
||||
const defaultOptions: PluginOptions<AutoDeletePluginType> = {
|
||||
config: {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as t from "io-ts";
|
||||
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||
import { tDelayString, MINUTES } from "../../utils";
|
||||
import { BasePluginType } from "knub";
|
||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||
import { GuildLogs } from "../../data/GuildLogs";
|
||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||
import { MINUTES, tDelayString } from "../../utils";
|
||||
import Timeout = NodeJS.Timeout;
|
||||
|
||||
export const MAX_DELAY = 5 * MINUTES;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { GuildPluginData } from "knub";
|
||||
import { AutoDeletePluginType } from "../types";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||
import { sorter } from "../../../utils";
|
||||
import { AutoDeletePluginType } from "../types";
|
||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||
|
||||
export function addMessageToDeletionQueue(
|
||||
pluginData: GuildPluginData<AutoDeletePluginType>,
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { Permissions, Snowflake, TextChannel } from "discord.js";
|
||||
import { GuildPluginData } from "knub";
|
||||
import { AutoDeletePluginType } from "../types";
|
||||
import moment from "moment-timezone";
|
||||
import { channelToConfigAccessibleChannel, userToConfigAccessibleUser } from "../../../utils/configAccessibleObjects";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { resolveUser, stripObjectToScalars, verboseChannelMention } from "../../../utils";
|
||||
import { logger } from "../../../logger";
|
||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
||||
import { resolveUser, verboseChannelMention } from "../../../utils";
|
||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||
import { Constants } from "eris";
|
||||
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>) {
|
||||
const [itemToDelete] = pluginData.state.deletionQueue.splice(0, 1);
|
||||
|
@ -16,16 +17,16 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
|||
|
||||
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) {
|
||||
// Channel was deleted, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
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, {
|
||||
body: `Missing permissions to read messages or message history in auto-delete channel ${verboseChannelMention(
|
||||
channel,
|
||||
|
@ -34,7 +35,7 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
|||
return;
|
||||
}
|
||||
|
||||
if (!hasDiscordPermissions(perms, Constants.Permissions.manageMessages)) {
|
||||
if (!hasDiscordPermissions(perms, Permissions.FLAGS.MANAGE_MESSAGES)) {
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
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);
|
||||
|
||||
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) {
|
||||
// "Unknown Message", probably already deleted by automod or another bot, ignore
|
||||
return;
|
||||
|
@ -60,8 +61,8 @@ export async function deleteNextItem(pluginData: GuildPluginData<AutoDeletePlugi
|
|||
|
||||
pluginData.state.guildLogs.log(LogType.MESSAGE_DELETE_AUTO, {
|
||||
message: itemToDelete.message,
|
||||
user: stripObjectToScalars(user),
|
||||
channel: stripObjectToScalars(channel),
|
||||
user: userToConfigAccessibleUser(user),
|
||||
channel: channelToConfigAccessibleChannel(channel),
|
||||
messageDate,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { AutoDeletePluginType, MAX_DELAY } from "../types";
|
||||
import { GuildPluginData } from "knub";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||
import { convertDelayStringToMS, resolveMember } from "../../../utils";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { convertDelayStringToMS, resolveMember } from "../../../utils";
|
||||
import { AutoDeletePluginType, MAX_DELAY } from "../types";
|
||||
import { addMessageToDeletionQueue } from "./addMessageToDeletionQueue";
|
||||
|
||||
export async function onMessageCreate(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GuildPluginData } from "knub";
|
||||
import { AutoDeletePluginType } from "../types";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||
import { AutoDeletePluginType } from "../types";
|
||||
import { scheduleNextDeletion } from "./scheduleNextDeletion";
|
||||
|
||||
export function onMessageDelete(pluginData: GuildPluginData<AutoDeletePluginType>, msg: SavedMessage) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { AutoDeletePluginType } from "../types";
|
||||
import { GuildPluginData } from "knub";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||
import { AutoDeletePluginType } from "../types";
|
||||
import { onMessageDelete } from "./onMessageDelete";
|
||||
|
||||
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 { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
|
||||
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
|
||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||
import { AddReactionsEvt } from "./events/AddReactionsEvt";
|
||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||
import { trimPluginDescription } from "../../utils";
|
||||
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> = {
|
||||
config: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { autoReactionsCmd } from "../types";
|
||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||
import { autoReactionsCmd } from "../types";
|
||||
|
||||
export const DisableAutoReactionsCmd = autoReactionsCmd({
|
||||
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 { canUseEmoji, customEmojiRegex, isEmoji } from "../../../utils";
|
||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||
import { canUseEmoji, customEmojiRegex, isEmoji } from "../../../utils";
|
||||
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
|
||||
import { Constants, GuildChannel } from "eris";
|
||||
import { readChannelPermissions } from "../../../utils/readChannelPermissions";
|
||||
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({
|
||||
trigger: "auto_reactions",
|
||||
|
@ -22,7 +22,7 @@ export const NewAutoReactionsCmd = autoReactionsCmd({
|
|||
async run({ message: msg, args, pluginData }) {
|
||||
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);
|
||||
if (missingPermissions) {
|
||||
sendErrorMessage(
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { autoReactionsEvt } from "../types";
|
||||
import { isDiscordRESTError } from "../../../utils";
|
||||
import { GuildChannel, Permissions } from "discord.js";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { logger } from "../../../logger";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { Constants, GuildChannel } from "eris";
|
||||
import { isDiscordAPIError } from "../../../utils";
|
||||
import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
|
||||
import { readChannelPermissions } from "../../../utils/readChannelPermissions";
|
||||
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({
|
||||
event: "messageCreate",
|
||||
|
@ -19,11 +18,11 @@ export const AddReactionsEvt = autoReactionsEvt({
|
|||
const autoReaction = await pluginData.state.autoReactions.getForChannel(message.channel.id);
|
||||
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(
|
||||
me,
|
||||
message.channel as GuildChannel,
|
||||
readChannelPermissions | p.addReactions,
|
||||
readChannelPermissions | p.ADD_REACTIONS,
|
||||
);
|
||||
if (missingPermissions) {
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
||||
|
@ -35,9 +34,9 @@ export const AddReactionsEvt = autoReactionsEvt({
|
|||
|
||||
for (const reaction of autoReaction.reactions) {
|
||||
try {
|
||||
await message.addReaction(reaction);
|
||||
await message.react(reaction);
|
||||
} catch (e) {
|
||||
if (isDiscordRESTError(e)) {
|
||||
if (isDiscordAPIError(e)) {
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
||||
if (e.code === 10008) {
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as t from "io-ts";
|
||||
import { BasePluginType, typedGuildCommand, typedGuildEventListener } from "knub";
|
||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||
import { GuildLogs } from "../../data/GuildLogs";
|
||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||
|
||||
export const ConfigSchema = t.type({
|
||||
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 { availableTriggers } from "./triggers/availableTriggers";
|
||||
import { StrictValidationError } from "../../validatorUtils";
|
||||
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 { 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 { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
|
||||
import { MutesPlugin } from "../Mutes/MutesPlugin";
|
||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||
import { availableActions } from "./actions/availableActions";
|
||||
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
|
||||
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
|
||||
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 { RunAutomodOnJoinEvt, RunAutomodOnLeaveEvt } from "./events/RunAutomodOnJoinLeaveEvt";
|
||||
import { RunAutomodOnMemberUpdate } from "./events/RunAutomodOnMemberUpdate";
|
||||
import { runAutomodOnMessage } from "./events/runAutomodOnMessage";
|
||||
import { runAutomodOnModAction } from "./events/runAutomodOnModAction";
|
||||
import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap";
|
||||
import { unregisterEventListenersFromMap } from "../../utils/unregisterEventListenersFromMap";
|
||||
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
|
||||
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 = {
|
||||
config: {
|
||||
|
@ -179,6 +176,7 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
|||
events: [
|
||||
RunAutomodOnJoinEvt,
|
||||
RunAutomodOnMemberUpdate,
|
||||
RunAutomodOnLeaveEvt,
|
||||
// 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 { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
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 { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||
import { ignoreRoleChange } from "../functions/ignoredRoleChanges";
|
||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||
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({
|
||||
configType: t.array(t.string),
|
||||
|
@ -19,9 +18,9 @@ export const AddRolesAction = automodAction({
|
|||
|
||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||
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) {
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
@ -42,7 +41,7 @@ export const AddRolesAction = automodAction({
|
|||
|
||||
if (rolesWeCannotAssign.length) {
|
||||
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);
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
@ -54,13 +53,13 @@ export const AddRolesAction = automodAction({
|
|||
|
||||
await Promise.all(
|
||||
members.map(async member => {
|
||||
const memberRoles = new Set(member.roles);
|
||||
const memberRoles = new Set(member.roles.cache.keys());
|
||||
for (const roleId of rolesToAssign) {
|
||||
memberRoles.add(roleId);
|
||||
memberRoles.add(roleId as Snowflake);
|
||||
ignoreRoleChange(pluginData, member.id, roleId);
|
||||
}
|
||||
|
||||
if (memberRoles.size === member.roles.length) {
|
||||
if (memberRoles.size === member.roles.cache.size) {
|
||||
// No role changes
|
||||
return;
|
||||
}
|
||||
|
@ -71,7 +70,6 @@ export const AddRolesAction = automodAction({
|
|||
await member.edit({
|
||||
roles: rolesArr,
|
||||
});
|
||||
member.roles = rolesArr; // Make sure we know of the new roles internally as well
|
||||
|
||||
memberRoleLock.unlock();
|
||||
}),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const AddToCounterAction = automodAction({
|
||||
configType: t.type({
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
import { Snowflake, TextChannel } from "discord.js";
|
||||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { renderTemplate, TemplateParseError } from "../../../templateFormatter";
|
||||
import {
|
||||
asyncMap,
|
||||
createChunkedMessage,
|
||||
isDiscordRESTError,
|
||||
messageLink,
|
||||
resolveMember,
|
||||
stripObjectToScalars,
|
||||
tAllowedMentions,
|
||||
tNormalizedNullOptional,
|
||||
tNullable,
|
||||
verboseChannelMention,
|
||||
} 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 { automodAction } from "../helpers";
|
||||
|
||||
export const AlertAction = automodAction({
|
||||
configType: t.type({
|
||||
|
@ -29,7 +24,7 @@ export const AlertAction = automodAction({
|
|||
defaultConfig: {},
|
||||
|
||||
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);
|
||||
|
||||
if (channel && channel instanceof TextChannel) {
|
||||
|
@ -73,7 +68,11 @@ export const AlertAction = automodAction({
|
|||
}
|
||||
|
||||
try {
|
||||
await createChunkedMessage(channel, rendered, actionConfig.allowed_mentions);
|
||||
await createChunkedMessage(
|
||||
channel,
|
||||
rendered,
|
||||
erisAllowedMentionsToDjsMentionOptions(actionConfig.allowed_mentions),
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.code === 50001) {
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import * as t from "io-ts";
|
||||
import { CleanAction } from "./clean";
|
||||
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 { RemoveRolesAction } from "./removeRoles";
|
||||
import { SetAntiraidLevelAction } from "./setAntiraidLevel";
|
||||
import { ReplyAction } from "./reply";
|
||||
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 { SetSlowmodeAction } from "./setSlowmode";
|
||||
import { WarnAction } from "./warn";
|
||||
|
||||
export const availableActions: Record<string, AutomodActionBlueprint<any>> = {
|
||||
clean: CleanAction,
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
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 { convertDelayStringToMS, nonNullish, tDelayString, tNullable, unique } from "../../../utils";
|
||||
import { CaseArgs } from "../../Cases/types";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const BanAction = automodAction({
|
||||
configType: t.type({
|
||||
|
@ -37,7 +28,7 @@ export const BanAction = automodAction({
|
|||
const deleteMessageDays = actionConfig.deleteMessageDays || undefined;
|
||||
|
||||
const caseArgs: Partial<CaseArgs> = {
|
||||
modId: pluginData.client.user.id,
|
||||
modId: pluginData.client.user!.id,
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
automatic: true,
|
||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { nonNullish, unique } from "../../../utils";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const ChangeNicknameAction = automodAction({
|
||||
configType: t.union([
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Snowflake, TextChannel } from "discord.js";
|
||||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { noop } from "../../../utils";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const CleanAction = automodAction({
|
||||
configType: t.boolean,
|
||||
|
@ -29,7 +30,8 @@ export const CleanAction = automodAction({
|
|||
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 { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { CaseArgs } from "../../Cases/types";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const KickAction = automodAction({
|
||||
configType: t.type({
|
||||
|
@ -25,7 +24,7 @@ export const KickAction = automodAction({
|
|||
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
||||
|
||||
const caseArgs: Partial<CaseArgs> = {
|
||||
modId: pluginData.client.user.id,
|
||||
modId: pluginData.client.user!.id,
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
automatic: true,
|
||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { stripObjectToScalars, unique } from "../../../utils";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const LogAction = automodAction({
|
||||
configType: t.boolean,
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
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 { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { convertDelayStringToMS, nonNullish, tDelayString, tNullable, unique } from "../../../utils";
|
||||
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({
|
||||
configType: t.type({
|
||||
|
@ -42,7 +33,7 @@ export const MuteAction = automodAction({
|
|||
const rolesToRestore = actionConfig.restore_roles_on_mute;
|
||||
|
||||
const caseArgs: Partial<CaseArgs> = {
|
||||
modId: pluginData.client.user.id,
|
||||
modId: pluginData.client.user!.id,
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
automatic: true,
|
||||
postInCaseLogOverride: actionConfig.postInCaseLog ?? undefined,
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import { Permissions, Snowflake } from "discord.js";
|
||||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, 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 { nonNullish, unique } from "../../../utils";
|
||||
import { canAssignRole } from "../../../utils/canAssignRole";
|
||||
import { Constants } from "eris";
|
||||
import { ignoreRoleChange } from "../functions/ignoredRoleChanges";
|
||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||
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({
|
||||
configType: t.array(t.string),
|
||||
|
@ -21,9 +19,9 @@ export const RemoveRolesAction = automodAction({
|
|||
|
||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||
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) {
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
@ -44,7 +42,7 @@ export const RemoveRolesAction = automodAction({
|
|||
|
||||
if (rolesWeCannotRemove.length) {
|
||||
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);
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
@ -56,13 +54,13 @@ export const RemoveRolesAction = automodAction({
|
|||
|
||||
await Promise.all(
|
||||
members.map(async member => {
|
||||
const memberRoles = new Set(member.roles);
|
||||
const memberRoles = new Set(member.roles.cache.keys());
|
||||
for (const roleId of rolesToRemove) {
|
||||
memberRoles.delete(roleId);
|
||||
memberRoles.delete(roleId as Snowflake);
|
||||
ignoreRoleChange(pluginData, member.id, roleId);
|
||||
}
|
||||
|
||||
if (memberRoles.size === member.roles.length) {
|
||||
if (memberRoles.size === member.roles.cache.size) {
|
||||
// No role changes
|
||||
return;
|
||||
}
|
||||
|
@ -73,7 +71,6 @@ export const RemoveRolesAction = automodAction({
|
|||
await member.edit({
|
||||
roles: rolesArr,
|
||||
});
|
||||
member.roles = rolesArr; // Make sure we know of the new roles internally as well
|
||||
|
||||
memberRoleLock.unlock();
|
||||
}),
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
import { MessageOptions, Permissions, Snowflake, TextChannel, User } from "discord.js";
|
||||
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 {
|
||||
convertDelayStringToMS,
|
||||
noop,
|
||||
renderRecursively,
|
||||
StrictMessageContent,
|
||||
stripObjectToScalars,
|
||||
tDelayString,
|
||||
tMessageContent,
|
||||
tNullable,
|
||||
unique,
|
||||
verboseChannelMention,
|
||||
} from "../../../utils";
|
||||
import { AdvancedMessageContent, Constants, MessageContent, TextChannel, User } from "eris";
|
||||
import { AutomodContext } from "../types";
|
||||
import { renderTemplate } from "../../../templateFormatter";
|
||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { automodAction } from "../helpers";
|
||||
import { AutomodContext } from "../types";
|
||||
|
||||
export const ReplyAction = automodAction({
|
||||
configType: t.union([
|
||||
|
@ -32,7 +31,7 @@ export const ReplyAction = automodAction({
|
|||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||
const contextsWithTextChannels = contexts
|
||||
.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) => {
|
||||
if (!map.has(context.message!.channel_id)) {
|
||||
|
@ -49,21 +48,21 @@ export const ReplyAction = automodAction({
|
|||
|
||||
const renderReplyText = async str =>
|
||||
renderTemplate(str, {
|
||||
user: stripObjectToScalars(user),
|
||||
user: userToConfigAccessibleUser(user),
|
||||
});
|
||||
const formatted =
|
||||
typeof actionConfig === "string"
|
||||
? await renderReplyText(actionConfig)
|
||||
: ((await renderRecursively(actionConfig.text, renderReplyText)) as AdvancedMessageContent);
|
||||
: ((await renderRecursively(actionConfig.text, renderReplyText)) as MessageOptions);
|
||||
|
||||
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
|
||||
if (
|
||||
!hasDiscordPermissions(
|
||||
channel.permissionsOf(pluginData.client.user.id),
|
||||
Constants.Permissions.sendMessages | Constants.Permissions.readMessages,
|
||||
channel.permissionsFor(pluginData.client.user!.id),
|
||||
Permissions.FLAGS.SEND_MESSAGES | Permissions.FLAGS.VIEW_CHANNEL,
|
||||
)
|
||||
) {
|
||||
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 (
|
||||
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, {
|
||||
body: `Missing permissions to reply **with an embed** in ${verboseChannelMention(
|
||||
|
@ -85,8 +84,8 @@ export const ReplyAction = automodAction({
|
|||
continue;
|
||||
}
|
||||
|
||||
const messageContent: StrictMessageContent = typeof formatted === "string" ? { content: formatted } : formatted;
|
||||
const replyMsg = await channel.createMessage({
|
||||
const messageContent: MessageOptions = typeof formatted === "string" ? { content: formatted } : formatted;
|
||||
const replyMsg = await channel.send({
|
||||
...messageContent,
|
||||
allowedMentions: {
|
||||
users: [user.id],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||
import { tNullable } from "../../../utils";
|
||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const SetAntiraidLevelAction = automodAction({
|
||||
configType: tNullable(t.string),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const SetCounterAction = automodAction({
|
||||
configType: t.type({
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { Snowflake, TextChannel } from "discord.js";
|
||||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { convertDelayStringToMS, isDiscordRESTError, tDelayString, tNullable } from "../../../utils";
|
||||
import { ChannelTypeStrings } from "src/types";
|
||||
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({
|
||||
configType: t.type({
|
||||
|
@ -18,24 +19,23 @@ export const SetSlowmodeAction = automodAction({
|
|||
const slowmodeMs = Math.max(actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : 0, 0);
|
||||
|
||||
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
|
||||
if (
|
||||
!channel ||
|
||||
!(channel.type === Constants.ChannelTypes.GUILD_TEXT || channel.type === Constants.ChannelTypes.GUILD_CATEGORY)
|
||||
) {
|
||||
if (!channel || !(channel.type === ChannelTypeStrings.TEXT || ChannelTypeStrings.CATEGORY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let channelsToSlowmode: TextChannel[] = [];
|
||||
if (channel.type === Constants.ChannelTypes.GUILD_CATEGORY) {
|
||||
const channelsToSlowmode: TextChannel[] = [];
|
||||
if (channel.type === ChannelTypeStrings.CATEGORY) {
|
||||
// Find all text channels within the category
|
||||
channelsToSlowmode = pluginData.guild.channels.filter(
|
||||
ch => ch.parentID === channel.id && ch.type === Constants.ChannelTypes.GUILD_TEXT,
|
||||
) as TextChannel[];
|
||||
for (const ch of pluginData.guild.channels.cache.values()) {
|
||||
if (ch.parentId === channel.id && ch.type === ChannelTypeStrings.TEXT) {
|
||||
channelsToSlowmode.push(ch as TextChannel);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
channelsToSlowmode.push(channel);
|
||||
channelsToSlowmode.push(channel as TextChannel);
|
||||
}
|
||||
|
||||
const slowmodeSeconds = Math.ceil(slowmodeMs / 1000);
|
||||
|
@ -49,7 +49,7 @@ export const SetSlowmodeAction = automodAction({
|
|||
} catch (e) {
|
||||
// Check for invalid form body -> indicates duration was too large
|
||||
const errorMessage =
|
||||
isDiscordRESTError(e) && e.code === 50035
|
||||
isDiscordAPIError(e) && e.code === 50035
|
||||
? `Duration is greater than maximum native slowmode duration`
|
||||
: e.message;
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import * as t from "io-ts";
|
||||
import { automodAction } from "../helpers";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { CaseArgs } from "../../Cases/types";
|
||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||
import { automodAction } from "../helpers";
|
||||
|
||||
export const WarnAction = automodAction({
|
||||
configType: t.type({
|
||||
|
@ -25,7 +24,7 @@ export const WarnAction = automodAction({
|
|||
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
||||
|
||||
const caseArgs: Partial<CaseArgs> = {
|
||||
modId: pluginData.client.user.id,
|
||||
modId: pluginData.client.user!.id,
|
||||
extraNotes: matchResult.fullSummary ? [matchResult.fullSummary] : [],
|
||||
automatic: true,
|
||||
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