3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-14 21:31:50 +00:00

Merge branch 'master' of github.com:ZeppelinBot/Zeppelin into feat/application-commands

This commit is contained in:
Lily Bergonzat 2024-04-15 12:39:01 +02:00
commit 0be54912c4
164 changed files with 22402 additions and 25686 deletions

View file

@ -23,12 +23,15 @@
"iamshoXy",
"Scraayp",
"app/dependabot",
"dependabot[bot]",
"zayKenyon",
"rukogit",
"Obliie",
"brawaru",
"Benricheson101",
"hawkeye7662"
"hawkeye7662",
"LilyBergonzat",
"martinbndr"
],
"message": "Thank you for contributing to Zeppelin! We require contributors to sign our Contributor License Agreement (CLA). To let us review and merge your code, please visit https://github.com/ZeppelinBot/CLA to sign the CLA!"
}

View file

@ -5,5 +5,5 @@
"service": "devenv",
"remoteUser": "ubuntu",
"workspaceFolder": "/home/ubuntu/zeppelin"
"workspaceFolder": "/workspace/zeppelin"
}

View file

@ -1,11 +1,44 @@
.git
.github
.idea
.devcontainer
**/.git
**/.github
**/.idea
**/.devcontainer
/docker/development/data
/docker/production/data
node_modules
/backend/dist
/dashboard/dist
**/node_modules
**/dist
**/*.log
**/npm-debug.log*
**/yarn-debug.log*
**/yarn-error.log*
**/.clinic
**/.clinic-bot
**/.clinic-api
# dotenv environment variables file
**/*.env
**/.env
# windows folder options
**/desktop.ini
# PHPStorm
**/.idea
# Misc
**/npm-ls.txt
**/npm-audit.txt
**/.cache
# Debug files
**/*.debug.ts
**/*.debug.js
**/.vscode
config-errors.txt
/config-schema.json
**/*.tsbuildinfo

View file

@ -1,3 +1,7 @@
# ==========================
# GENERAL OPTIONS
# ==========================
# 32 character encryption key
KEY=
@ -17,58 +21,64 @@ STAFF=
# A comma-separated list of server IDs that should be allowed by default
DEFAULT_ALLOWED_SERVERS=
# When using the Docker-based development environment, this is only used internally. The API will be available at localhost:DOCKER_DEV_WEB_PORT/api.
API_PORT=3000
# Only required if relevant feature is used
#PHISHERMAN_API_KEY=
# The user ID and group ID that should be used within the Docker containers
# This should match your own user ID and group ID. Run `id -u` and `id -g` to find them.
DOCKER_USER_UID=
DOCKER_USER_GID=
#
# DOCKER (DEVELOPMENT)
# NOTE: You only need to fill in these values for running the development environment. See production config further below.
#
# ==========================
# DEVELOPMENT
# NOTE: You only need to fill in these values for running the development environment
# ==========================
DOCKER_DEV_WEB_PORT=3300
DEVELOPMENT_WEB_PORT=3300
# The MySQL database running in the container is exposed to the host on this port,
# allowing access with database tools such as DBeaver
DOCKER_DEV_MYSQL_PORT=3001
DEVELOPMENT_MYSQL_PORT=3356
# Password for the Zeppelin database user
DOCKER_DEV_MYSQL_PASSWORD=
DEVELOPMENT_MYSQL_PASSWORD=password
# Password for the MySQL root user
DOCKER_DEV_MYSQL_ROOT_PASSWORD=
DEVELOPMENT_MYSQL_ROOT_PASSWORD=password
# The development environment container has an SSH server that you can connect to.
# This is the port that server is exposed to the host on.
DOCKER_DEV_SSH_PORT=3002
DOCKER_DEV_SSH_PASSWORD=password
DEVELOPMENT_SSH_PORT=3022
DEVELOPMENT_SSH_PASSWORD=password
# If your user has a different UID than 1000, you might have to fill that in here to avoid permission issues
#DOCKER_DEV_UID=1000
#DEVELOPMENT_UID=1000
#
# DOCKER (PRODUCTION)
# NOTE: You only need to fill in these values for running the production environment. See development config above.
#
DOCKER_PROD_DOMAIN=
DOCKER_PROD_WEB_PORT=443
# ==========================
# PRODUCTION - STANDALONE
# NOTE: You only need to fill in these values for running the standalone production environment
# ==========================
STANDALONE_WEB_PORT=80
# The MySQL database running in the container is exposed to the host on this port,
# allowing access with database tools such as DBeaver
DOCKER_PROD_MYSQL_PORT=3001
STANDALONE_MYSQL_PORT=3356
# Password for the Zeppelin database user
DOCKER_PROD_MYSQL_PASSWORD=
STANDALONE_MYSQL_PASSWORD=
# Password for the MySQL root user
DOCKER_PROD_MYSQL_ROOT_PASSWORD=
STANDALONE_MYSQL_ROOT_PASSWORD=
# You only need to set these if you're running an external database.
# In a standard setup, the database is run in a docker container.
#DB_HOST=
#DB_USER=
#DB_PASSWORD=
#DB_DATABASE=
# ==========================
# PRODUCTION - LIGHTWEIGHT
# NOTE: You only need to fill in these values for running the lightweight production environment
# ==========================
# Ports where the API/dashboard are exposed on the host
LIGHTWEIGHT_API_PORT=3001
LIGHTWEIGHT_DASHBOARD_PORT=3002
LIGHTWEIGHT_DB_HOST=
LIGHTWEIGHT_DB_PORT=
LIGHTWEIGHT_DB_USER=
LIGHTWEIGHT_DB_PASSWORD=
LIGHTWEIGHT_DB_DATABASE=
# If you want to add a prefix to API paths, such as /api, you can set that here
LIGHTWEIGHT_API_PATH_PREFIX=

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
package-lock.json binary

6
.gitignore vendored
View file

@ -85,3 +85,9 @@ npm-audit.txt
config-errors.txt
/config-schema.json
*.tsbuildinfo
# Legacy data folders
/docker/development/data
/docker/production/data

View file

@ -1,71 +1 @@
# Zeppelin development environment
Zeppelin's development environment runs entirely within a Docker container.
Below you can find instructions for setting up the environment and getting started with development!
**Note:** If you'd just like to run the bot for your own server, see 👉 **[PRODUCTION.md](./PRODUCTION.md)** 👈
## Starting the development environment
### Using VSCode devcontainers
1. Install Docker
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env`
4. In VSCode: Install the `Remote - Containers` plugin
5. In VSCode: Run `Remote-Containers: Open Folder in Container...` and select the Zeppelin folder
### Using VSCode remote SSH plugin
1. Install Docker
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env`
4. Run `docker compose -f docker-compose.development.yml up` to start the development environment
5. In VSCode: Install the `Remote - SSH` plugin
6. In VSCode: Run `Remote-SSH: Connect to Host...`
* As the address, use `ubuntu@127.0.0.1:3002` (where `3002` matches `DOCKER_DEV_SSH_PORT` in `.env`)
* Use the password specified in `.env` as `DOCKER_DEV_SSH_PASSWORD`
7. In VSCode: Once connected, click `Open folder...` and select `/home/ubuntu/zeppelin`
### Using JetBrains Gateway
1. Install Docker
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env`
4. Run `docker compose -f docker-compose.development.yml up` to start the development environment
5. Choose `Connect via SSH` and create a new connection:
* Username: `ubuntu`
* Host: `127.0.0.1`
* Port: `3002` (matching the `DOCKER_DEV_SSH_PORT` value in `.env`)
6. Click `Check Connection and Continue` and enter the password specified in `.env` as `DOCKER_DEV_SSH_PASSWORD` when asked
7. In the next pane:
* IDE version: WebStorm, PHPStorm, or IntelliJ IDEA
* Project directory: `/home/ubuntu/zeppelin`
8. Click `Download and Start IDE`
### Using any other IDE with SSH development support
1. Install Docker
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env`
4. Run `docker compose -f docker-compose.development.yml up` to start the development environment
5. Use the following credentials for connecting with your IDE:
* Host: `127.0.0.1`
* Port: `3002` (matching the `DOCKER_DEV_SSH_PORT` value in `.env`)
* Username: `ubuntu`
* Password: As specified in `.env` as `DOCKER_DEV_SSH_PASSWORD`
## Starting the project
### Starting the backend (bot + api)
These commands are run inside the dev container. You should be able to open a terminal in your IDE after connecting.
1. `cd ~/zeppelin/backend`
2. `npm ci`
3. `npm run migrate-dev`
4. `npm run watch`
### Starting the dashboard
These commands are run inside the dev container. You should be able to open a terminal in your IDE after connecting.
1. `cd ~/zeppelin/dashboard`
2. `npm ci`
3. `npm run watch-build`
### Opening the dashboard
Browse to https://localhost:3300 to view the dashboard
Moved to [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)

34
Dockerfile Normal file
View file

@ -0,0 +1,34 @@
FROM node:20
RUN mkdir /zeppelin
RUN chown node:node /zeppelin
USER node
ARG API_URL
# Install dependencies before copying over any other files
COPY --chown=node:node package.json package-lock.json /zeppelin
RUN mkdir /zeppelin/backend
COPY --chown=node:node backend/package.json /zeppelin/backend
RUN mkdir /zeppelin/shared
COPY --chown=node:node shared/package.json /zeppelin/shared
RUN mkdir /zeppelin/dashboard
COPY --chown=node:node dashboard/package.json /zeppelin/dashboard
WORKDIR /zeppelin
RUN npm ci
COPY --chown=node:node . /zeppelin
# Build backend
WORKDIR /zeppelin/backend
RUN npm run build
# Build dashboard
WORKDIR /zeppelin/dashboard
RUN npm run build
# Prune dev dependencies
WORKDIR /zeppelin
RUN npm prune --omit=dev

View file

@ -1,34 +1 @@
# Management
After starting Zeppelin -- either in the [development](./DEVELOPMENT.md) or [production](./PRODUCTION.md) environment -- you have several tools available to manage it.
## Note
Make sure to add yourself to the list of staff members (`STAFF`) in `.env` and allow at least one server by default (`DEFAULT_ALLOWED_SERVERS`). Then, invite the bot to the server.
In all examples below, `@Bot` refers to a user mention of the bot user. Make sure to run the commands on a server with the bot, in a channel that the bot can see.
In the command parameters, `<this>` refers to a required parameter (don't include the `< >` symbols) and `[this]` refers to an optional parameter (don't include the `[ ]` symbols). `<this...>` refers to being able to list multiple values, e.g. `value1 value2 value3`.
## Allow a server to invite the bot
Run the following command:
```
@Bot allow_server <serverId> [userId]
```
When specifying a user ID, that user will be given "Bot manager" level access to the server's dashboard, allowing them to manage access for other users.
## Disallow a server
Run the following command:
```
@Bot disallow_server <serverId>
```
## Grant access to a server's dashboard
Run the following command:
```
@Bot add_dashboard_user <serverId> <userId...>
```
## Remove access to a server's dashboard
Run the following command:
```
@Bot remove_dashboard_user <serverId> <userId...>
```
Moved to [docs/MANAGEMENT.md](docs/MANAGEMENT.md)

View file

@ -1,34 +1 @@
# Zeppelin production environment
Zeppelin's production environment - that is, the **bot, API, and dashboard** - uses Docker.
## Starting the production environment
1. Install Docker on the machine running the bot
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env`
4. Run `docker compose -f docker-compose.production.yml build`
5. Run `docker compose -f docker-compose.production.yml up -d`
**Note:** The dashboard and API are exposed with a self-signed certificate. It is recommended to set up a proxy with a proper certificate in front of them. Cloudflare is a popular choice here.
## Updating the bot
### One-click script
If you've downloaded the bot's files by cloning the git repository, you can use `update.sh` to update the bot.
### Manual instructions
1. Shut the bot down: `docker compose -f docker-compose.production.yml down`
2. Update the files (e.g. `git pull`)
3. Build new images: `docker compose -f docker-compose.production.yml build`
3. Start the bot again: `docker compose -f docker-compose.production.yml up -d`
### Ephemeral hotfixes
If you need to make a hotfix to the bot's source files directly on the server:
1. Shut the bot down: `docker compose -f docker-compose.production.yml down`
2. Make your edits
3. Build new images: `docker compose -f docker-compose.production.yml build`
4. Start the bot again: `docker compose -f docker-compose.production.yml up -d`
Make sure to revert any hotfixes before updating the bot normally.
## View logs
To view real-time logs, run `docker compose -f docker-compose.production.yml logs -t -f`
Moved to [docs/PRODUCTION.md](docs/PRODUCTION.md)

View file

@ -23,11 +23,11 @@ See https://zeppelin.gg/ for more details.
For information on how to use the bot, see https://zeppelin.gg/docs
## Development
See [DEVELOPMENT.md](./DEVELOPMENT.md) for instructions on running the development environment.
See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for instructions on running the development environment.
Once you have the environment up and running, see [MANAGEMENT.md](./MANAGEMENT.md) for how to manage your bot.
Once you have the environment up and running, see [docs/MANAGEMENT.md](docs/MANAGEMENT.md) for how to manage your bot.
## Production
See [PRODUCTION.md](./PRODUCTION.md) for instructions on how to run the bot in production.
See [docs/PRODUCTION.md](docs/PRODUCTION.md) for instructions on how to run the bot in production.
Once you have the environment up and running, see [MANAGEMENT.md](./MANAGEMENT.md) for how to manage your bot.
Once you have the environment up and running, see [docs/MANAGEMENT.md](docs/MANAGEMENT.md) for how to manage your bot.

9123
backend/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,31 +4,31 @@
"description": "",
"private": true,
"scripts": {
"watch": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node start-dev.js\"",
"watch-yaml-parse-test": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node dist/backend/src/yamlParseTest.js\"",
"build": "rimraf dist && tsc",
"start-bot-dev": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
"start-bot-dev-debug": "NODE_ENV=development DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
"start-bot-prod": "cross-env NODE_ENV=production node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 dist/backend/src/index.js",
"start-bot-prod-debug": "NODE_ENV=production DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 dist/backend/src/index.js",
"watch-bot": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-bot-dev\"",
"start-api-dev": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
"start-api-dev-debug": "NODE_ENV=development DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
"start-api-prod": "cross-env NODE_ENV=production node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 dist/backend/src/api/index.js",
"start-api-prod-debug": "NODE_ENV=production DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps --stack-trace-limit=30 dist/backend/src/api/index.js",
"watch-api": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-api-dev\"",
"typeorm": "node -r ./register-tsconfig-paths.js ./node_modules/typeorm/cli.js",
"migrate": "npm run typeorm -- migration:run -d dist/backend/src/data/dataSource.js",
"migrate-prod": "cross-env NODE_ENV=production npm run migrate",
"migrate-dev": "cross-env NODE_ENV=development npm run build && npm run migrate",
"migrate-rollback": "npm run typeorm -- migration:revert -d dist/backend/src/data/dataSource.js",
"migrate-rollback-prod": "cross-env NODE_ENV=production npm run migrate",
"migrate-rollback-dev": "cross-env NODE_ENV=development npm run build && npm run migrate",
"validate-active-configs": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps dist/backend/src/validateActiveConfigs.js > ../config-errors.txt",
"export-config-json-schema": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps dist/backend/src/exportSchemas.js > ../config-schema.json",
"watch": "tsc-watch --build --onSuccess \"node start-dev.js\"",
"watch-yaml-parse-test": "tsc-watch --build --onSuccess \"node dist/yamlParseTest.js\"",
"build": "tsc --build",
"start-bot-dev": "node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/index.js",
"start-bot-dev-debug": "DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/index.js",
"start-bot-prod": "node --enable-source-maps --stack-trace-limit=30 dist/index.js",
"start-bot-prod-debug": "DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node --enable-source-maps --stack-trace-limit=30 dist/index.js",
"watch-bot": "tsc-watch --build --onSuccess \"npm run start-bot-dev\"",
"start-api-dev": "node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/api/index.js",
"start-api-dev-debug": "DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/api/index.js",
"start-api-prod": "node --enable-source-maps --stack-trace-limit=30 dist/api/index.js",
"start-api-prod-debug": "clinic heapprofiler --collect-only --dest .clinic-api -- node --enable-source-maps --stack-trace-limit=30 dist/api/index.js",
"watch-api": "tsc-watch --build --onSuccess \"npm run start-api-dev\"",
"typeorm": "node ../node_modules/typeorm/cli.js",
"migrate": "npm run typeorm -- migration:run -d dist/data/dataSource.js",
"migrate-prod": "npm run migrate",
"migrate-dev": "npm run build && npm run migrate",
"migrate-rollback": "npm run typeorm -- migration:revert -d dist/data/dataSource.js",
"migrate-rollback-prod": "npm run migrate-rollback",
"migrate-rollback-dev": "npm run build && npm run migrate-rollback",
"validate-active-configs": "node --enable-source-maps dist/validateActiveConfigs.js > ../config-errors.txt",
"export-config-json-schema": "node --enable-source-maps dist/exportSchemas.js > ../config-schema.json",
"test": "npm run build && npm run run-tests",
"run-tests": "ava",
"test-watch": "tsc-watch --onSuccess \"npx ava\""
"test-watch": "tsc-watch --build --onSuccess \"npx ava\""
},
"dependencies": {
"@silvia-odwyer/photon-node": "^0.3.1",
@ -45,7 +45,7 @@
"fp-ts": "^2.0.1",
"humanize-duration": "^3.15.0",
"js-yaml": "^3.13.1",
"knub": "^32.0.0-next.16",
"knub": "^32.0.0-next.21",
"knub-command-manager": "^9.1.0",
"last-commit-log": "^2.1.0",
"lodash.chunk": "^4.2.0",
@ -56,7 +56,7 @@
"lodash.pick": "^4.4.0",
"moment-timezone": "^0.5.21",
"multer": "^1.4.5-lts.1",
"mysql": "^2.16.0",
"mysql2": "^3.9.3",
"parse-color": "^1.0.0",
"passport": "^0.6.0",
"passport-custom": "^1.0.5",
@ -102,7 +102,7 @@
},
"ava": {
"files": [
"dist/backend/src/**/*.test.js"
"dist/**/*.test.js"
],
"require": [
"./register-tsconfig-paths.js"

View file

@ -3,15 +3,15 @@ import moment from "moment-timezone";
import { GuildArchives } from "../data/GuildArchives";
import { notFound } from "./responses";
export function initArchives(app: express.Express) {
export function initArchives(router: express.Router) {
const archives = new GuildArchives(null);
// Legacy redirect
app.get("/spam-logs/:id", (req: Request, res: Response) => {
router.get("/spam-logs/:id", (req: Request, res: Response) => {
res.redirect("/archives/" + req.params.id);
});
app.get("/archives/:id", async (req: Request, res: Response) => {
router.get("/archives/:id", async (req: Request, res: Response) => {
const archive = await archives.find(req.params.id);
if (!archive) return notFound(res);

View file

@ -51,8 +51,8 @@ function simpleDiscordAPIRequest(bearerToken, path): Promise<any> {
});
}
export function initAuth(app: express.Express) {
app.use(passport.initialize());
export function initAuth(router: express.Router) {
router.use(passport.initialize());
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user as IPassportApiUser));
@ -110,8 +110,8 @@ export function initAuth(app: express.Express) {
),
);
app.get("/auth/login", passport.authenticate("oauth2"));
app.get(
router.get("/auth/login", passport.authenticate("oauth2"));
router.get(
"/auth/oauth-callback",
passport.authenticate("oauth2", { failureRedirect: "/", session: false }),
(req: Request, res: Response) => {
@ -122,7 +122,7 @@ export function initAuth(app: express.Express) {
}
},
);
app.post("/auth/validate-key", async (req: Request, res: Response) => {
router.post("/auth/validate-key", async (req: Request, res: Response) => {
const key = req.body.key;
if (!key) {
return res.status(400).json({ error: "No key supplied" });
@ -135,14 +135,14 @@ export function initAuth(app: express.Express) {
res.json({ valid: true, userId });
});
app.post("/auth/logout", ...apiTokenAuthHandlers(), async (req: Request, res: Response) => {
router.post("/auth/logout", ...apiTokenAuthHandlers(), async (req: Request, res: Response) => {
await apiLogins.expireApiKey(req.user!.apiKey);
return ok(res);
});
// API route to refresh the given API token's expiry time
// The actual refreshing happens in the api-token passport strategy above, so we just return 200 OK here
app.post("/auth/refresh", ...apiTokenAuthHandlers(), (req, res) => {
router.post("/auth/refresh", ...apiTokenAuthHandlers(), (req, res) => {
return ok(res);
});
}

View file

@ -1,6 +1,7 @@
import express from "express";
import z from "zod";
import { guildPlugins } from "../plugins/availablePlugins";
import { guildPluginInfo } from "../plugins/pluginInfo";
import { indentLines } from "../utils";
import { notFound } from "./responses";
@ -96,30 +97,31 @@ function formatZodConfigSchema(schema: z.ZodTypeAny) {
return "unknown";
}
export function initDocs(app: express.Express) {
const docsPlugins = guildPlugins.filter((plugin) => plugin.showInDocs);
export function initDocs(router: express.Router) {
const docsPluginNames = Object.keys(guildPluginInfo).filter((k) => guildPluginInfo[k].showInDocs);
app.get("/docs/plugins", (req: express.Request, res: express.Response) => {
router.get("/docs/plugins", (req: express.Request, res: express.Response) => {
res.json(
docsPlugins.map((plugin) => {
const thinInfo = plugin.info ? { prettyName: plugin.info.prettyName, legacy: plugin.info.legacy ?? false } : {};
docsPluginNames.map((pluginName) => {
const info = guildPluginInfo[pluginName];
const thinInfo = info ? { prettyName: info.prettyName, legacy: info.legacy ?? false } : {};
return {
name: plugin.name,
name: pluginName,
info: thinInfo,
};
}),
);
});
app.get("/docs/plugins/:pluginName", (req: express.Request, res: express.Response) => {
// prettier-ignore
const plugin = docsPlugins.find(_plugin => _plugin.name === req.params.pluginName);
if (!plugin) {
router.get("/docs/plugins/:pluginName", (req: express.Request, res: express.Response) => {
const name = req.params.pluginName;
const baseInfo = guildPluginInfo[name];
if (!baseInfo) {
return notFound(res);
}
const name = plugin.name;
const info = { ...(plugin.info || {}) };
const plugin = guildPlugins.find((p) => p.name === name)!;
const info = { ...baseInfo };
delete info.configSchema;
const messageCommands = (plugin.messageCommands || []).map((cmd) => ({
@ -132,7 +134,7 @@ export function initDocs(app: express.Express) {
}));
const defaultOptions = plugin.defaultOptions || {};
const configSchema = plugin.info?.configSchema && formatZodConfigSchema(plugin.info.configSchema);
const configSchema = info.configSchema && formatZodConfigSchema(info.configSchema);
res.json({
name,

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import express, { Request, Response } from "express";
import { YAMLException } from "js-yaml";
import moment from "moment-timezone";

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import express, { Request, Response } from "express";
import moment from "moment-timezone";
import { z } from "zod";

View file

@ -3,12 +3,12 @@ import { apiTokenAuthHandlers } from "../auth";
import { initGuildsImportExportAPI } from "./importExport";
import { initGuildsMiscAPI } from "./misc";
export function initGuildsAPI(app: express.Express) {
export function initGuildsAPI(router: express.Router) {
const guildRouter = express.Router();
guildRouter.use(...apiTokenAuthHandlers());
initGuildsMiscAPI(guildRouter);
initGuildsImportExportAPI(guildRouter);
app.use("/guilds", guildRouter);
router.use("/guilds", guildRouter);
}

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import express, { Request, Response } from "express";
import { YAMLException } from "js-yaml";
import moment from "moment-timezone";

View file

@ -1,4 +1,4 @@
import { ApiPermissions, hasPermission, permissionArrToSet } from "@shared/apiPermissions";
import { ApiPermissions, hasPermission, permissionArrToSet } from "@zeppelinbot/shared";
import { Request, Response } from "express";
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
import { isStaff } from "../staff";

View file

@ -10,6 +10,8 @@ import { initGuildsAPI } from "./guilds/index";
import { clientError, error, notFound } from "./responses";
import { startBackgroundTasks } from "./tasks";
const apiPathPrefix = env.API_PATH_PREFIX || (env.NODE_ENV === "development" ? "/api" : "");
const app = express();
app.use(
@ -24,16 +26,20 @@ app.use(
);
app.use(multer().none());
const rootRouter = express.Router();
initAuth(app);
initGuildsAPI(app);
initArchives(app);
initDocs(app);
// Default route
app.get("/", (req, res) => {
rootRouter.get("/", (req, res) => {
res.json({ status: "cookies", with: "milk" });
});
app.use(apiPathPrefix, rootRouter);
// Error response
// eslint-disable-next-line @typescript-eslint/no-unused-vars
app.use((err, req, res, next) => {
@ -51,7 +57,7 @@ app.use((req, res, next) => {
return notFound(res);
});
const port = env.API_PORT;
const port = 3001;
app.listen(port, "0.0.0.0", () => console.log(`API server listening on port ${port}`)); // tslint:disable-line
startBackgroundTasks();

View file

@ -1,11 +1,10 @@
import { BaseConfig, ConfigValidationError, PluginConfigManager } from "knub";
import { BaseConfig, ConfigValidationError, GuildPluginBlueprint, PluginConfigManager } from "knub";
import { ZodError } from "zod";
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
import { guildPlugins } from "./plugins/availablePlugins";
import { zZeppelinGuildConfig } from "./types";
import { formatZodIssue } from "./utils/formatZodIssue";
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
const pluginNameToPlugin = new Map<string, GuildPluginBlueprint<any, any>>();
for (const plugin of guildPlugins) {
pluginNameToPlugin.set(plugin.name, plugin);
}

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import { Repository } from "typeorm";
import { ApiAuditLog } from "./ApiAuditLog";
import { BaseRepository } from "./BaseRepository";

View file

@ -6,16 +6,16 @@ import { backendDir } from "../paths";
moment.tz.setDefault("UTC");
const entities = path.relative(process.cwd(), path.resolve(backendDir, "dist/backend/src/data/entities/*.js"));
const migrations = path.relative(process.cwd(), path.resolve(backendDir, "dist/backend/src/migrations/*.js"));
const entities = path.relative(process.cwd(), path.resolve(backendDir, "dist/data/entities/*.js"));
const migrations = path.relative(process.cwd(), path.resolve(backendDir, "dist/migrations/*.js"));
export const dataSource = new DataSource({
type: "mysql",
host: env.DB_HOST,
port: env.DB_PORT,
username: env.DB_USER,
password: env.DB_PASSWORD,
database: env.DB_DATABASE,
host: env.DB_HOST || "mysql",
port: env.DB_PORT || 3306,
username: env.DB_USER || "zeppelin",
password: env.DB_PASSWORD || env.DEVELOPMENT_MYSQL_PASSWORD,
database: env.DB_DATABASE || "zeppelin",
charset: "utf8mb4",
supportBigNumbers: true,
bigNumberStrings: true,

View file

@ -13,7 +13,6 @@ const envType = z.object({
DASHBOARD_URL: z.string().url(),
API_URL: z.string().url(),
API_PORT: z.preprocess((v) => Number(v), z.number().min(1).max(65535)).default(3000),
STAFF: z
.preprocess(
@ -39,22 +38,22 @@ const envType = z.object({
PHISHERMAN_API_KEY: z.string().optional(),
DOCKER_DEV_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development
DOCKER_PROD_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in production
DB_HOST: z.string().optional(),
DB_PORT: z.preprocess((v) => Number(v), z.number()).optional(),
DB_USER: z.string().optional(),
DB_PASSWORD: z.string().optional(),
DB_DATABASE: z.string().optional(),
DB_HOST: z.string().optional().default("mysql"),
DB_PORT: z
.preprocess((v) => Number(v), z.number())
.optional()
.default(3306),
DB_USER: z.string().optional().default("zeppelin"),
DB_PASSWORD: z.string().optional(), // Default is set to DOCKER_MYSQL_PASSWORD further below
DB_DATABASE: z.string().optional().default("zeppelin"),
DEVELOPMENT_MYSQL_PASSWORD: z.string().optional(),
API_PATH_PREFIX: z.string().optional(),
DEBUG: z
.string()
.optional()
.transform((str) => str === "true"),
NODE_ENV: z.string().default("development"),
});
let toValidate = { ...process.env };
@ -65,11 +64,3 @@ if (fs.existsSync(envPath)) {
}
export const env = envType.parse(toValidate);
if (!env.DB_PASSWORD) {
if (process.env.NODE_ENV === "production" && env.DOCKER_PROD_MYSQL_PASSWORD) {
env.DB_PASSWORD = env.DOCKER_PROD_MYSQL_PASSWORD;
} else if (env.DOCKER_DEV_MYSQL_PASSWORD) {
env.DB_PASSWORD = env.DOCKER_DEV_MYSQL_PASSWORD;
}
}

View file

@ -1,13 +1,12 @@
import { z } from "zod";
import zodToJsonSchema from "zod-to-json-schema";
import { guildPlugins } from "./plugins/availablePlugins";
import { guildPluginInfo } from "./plugins/pluginInfo";
import { zZeppelinGuildConfig } from "./types";
const pluginSchemaMap = guildPlugins.reduce((map, plugin) => {
if (!plugin.info) {
return map;
const pluginSchemaMap = Object.entries(guildPluginInfo).reduce((map, [pluginName, pluginInfo]) => {
if (pluginInfo.configSchema) {
map[pluginName] = pluginInfo.configSchema;
}
map[plugin.name] = plugin.info.configSchema;
return map;
}, {});

View file

@ -164,7 +164,7 @@ if (process.env.NODE_ENV === "production") {
}
// Verify required Node.js version
const REQUIRED_NODE_VERSION = "14.0.0";
const REQUIRED_NODE_VERSION = "16.9.0";
const requiredParts = REQUIRED_NODE_VERSION.split(".").map((v) => parseInt(v, 10));
const actualVersionParts = process.versions.node.split(".").map((v) => parseInt(v, 10));
for (const [i, part] of actualVersionParts.entries()) {
@ -463,7 +463,7 @@ connect().then(async () => {
logger.info("Cleaning up before exit...");
// Force exit after 10sec
setTimeout(() => process.exit(code), 10 * SECONDS);
await bot.stop();
await bot.destroy();
await dataSource.destroy();
logger.info("Done! Exiting now.");
process.exit(code);

View file

@ -10,11 +10,13 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
name: "guild_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "channel_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "slowmode_seconds",
@ -25,7 +27,6 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
indices: [],
}),
);
await queryRunner.createPrimaryKey("slowmode_channels", ["guild_id", "channel_id"]);
await queryRunner.createTable(
new Table({
@ -35,16 +36,19 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
name: "guild_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "channel_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "user_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "expires_at",
@ -58,7 +62,6 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
],
}),
);
await queryRunner.createPrimaryKey("slowmode_users", ["guild_id", "channel_id", "user_id"]);
}
public async down(queryRunner: QueryRunner): Promise<any> {

View file

@ -61,11 +61,13 @@ export class CreateStarboardTable1544887946307 implements MigrationInterface {
name: "starboard_id",
type: "int",
unsigned: true,
isPrimary: true,
},
{
name: "message_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "starboard_message_id",
@ -75,7 +77,6 @@ export class CreateStarboardTable1544887946307 implements MigrationInterface {
],
}),
);
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_id", "message_id"]);
}
public async down(queryRunner: QueryRunner): Promise<any> {

View file

@ -10,11 +10,13 @@ export class CreateAutoReactionsTable1547290549908 implements MigrationInterface
name: "guild_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "channel_id",
type: "bigint",
unsigned: true,
isPrimary: true,
},
{
name: "reactions",
@ -23,7 +25,6 @@ export class CreateAutoReactionsTable1547290549908 implements MigrationInterface
],
}),
);
await queryRunner.createPrimaryKey("auto_reactions", ["guild_id", "channel_id"]);
}
public async down(queryRunner: QueryRunner): Promise<any> {

View file

@ -9,10 +9,12 @@ export class CreateDashboardUsersTable1558804449510 implements MigrationInterfac
{
name: "guild_id",
type: "bigint",
isPrimary: true,
},
{
name: "user_id",
type: "bigint",
isPrimary: true,
},
{
name: "username",
@ -28,7 +30,6 @@ export class CreateDashboardUsersTable1558804449510 implements MigrationInterfac
}),
);
await queryRunner.createPrimaryKey("dashboard_users", ["guild_id", "user_id"]);
await queryRunner.createIndex(
"dashboard_users",
new TableIndex({

View file

@ -2,14 +2,10 @@ import { MigrationInterface, QueryRunner, TableColumn, TableIndex } from "typeor
export class AddTypeAndPermissionsToApiPermissions1573158035867 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
try {
await queryRunner.dropPrimaryKey("api_permissions");
} catch {} // eslint-disable-line no-empty
const table = (await queryRunner.getTable("api_permissions"))!;
if (table.indices.length) {
await queryRunner.dropIndex("api_permissions", table.indices[0]);
}
// We can't use a TableIndex object in dropIndex directly as the table name is included in the generated index name
// and the table name has changed since the original index was created
const originalIndexName = queryRunner.connection.namingStrategy.indexName("dashboard_users", ["user_id"]);
await queryRunner.dropIndex("api_permissions", originalIndexName);
await queryRunner.addColumn(
"api_permissions",
@ -22,7 +18,11 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
await queryRunner.renameColumn("api_permissions", "user_id", "target_id");
await queryRunner.createPrimaryKey("api_permissions", ["guild_id", "type", "target_id"]);
await queryRunner.query(`
ALTER TABLE api_permissions
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`guild_id\`, \`type\`, \`target_id\`);
`);
await queryRunner.dropColumn("api_permissions", "role");
@ -49,7 +49,12 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropIndex("api_permissions", "IDX_e06d750f13e6a4b4d3d6b847a9");
await queryRunner.dropIndex(
"api_permissions",
new TableIndex({
columnNames: ["type", "target_id"],
}),
);
await queryRunner.dropColumn("api_permissions", "permissions");
@ -62,7 +67,11 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
}),
);
await queryRunner.dropPrimaryKey("api_permissions");
await queryRunner.query(`
ALTER TABLE api_permissions
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`guild_id\`, \`type\`);
`);
await queryRunner.renameColumn("api_permissions", "target_id", "user_id");
@ -74,7 +83,5 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
columnNames: ["user_id"],
}),
);
await queryRunner.createPrimaryKey("api_permissions", ["guild_id", "user_id"]);
}
}

View file

@ -2,36 +2,46 @@ import { MigrationInterface, QueryRunner, Table, TableColumn } from "typeorm";
export class MoveStarboardsToConfig1573248462469 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
// Create the new column for the channels id
const chanid_column = new TableColumn({
name: "starboard_channel_id",
type: "bigint",
unsigned: true,
});
await queryRunner.addColumn("starboard_messages", chanid_column);
// Create a new column for the channel's id
await queryRunner.addColumn(
"starboard_messages",
new TableColumn({
name: "starboard_channel_id",
type: "bigint",
unsigned: true,
}),
);
// Since we are removing the guild_id with the starboards table, we might want it here
const guid_column = new TableColumn({
name: "guild_id",
type: "bigint",
unsigned: true,
});
await queryRunner.addColumn("starboard_messages", guid_column);
await queryRunner.addColumn(
"starboard_messages",
new TableColumn({
name: "guild_id",
type: "bigint",
unsigned: true,
}),
);
// Migrate the old starboard_id to the new starboard_channel_id
await queryRunner.query(`
UPDATE starboard_messages AS sm
JOIN starboards AS sb
ON sm.starboard_id = sb.id
SET sm.starboard_channel_id = sb.channel_id, sm.guild_id = sb.guild_id;
`);
UPDATE starboard_messages AS sm
JOIN starboards AS sb
ON sm.starboard_id = sb.id
SET sm.starboard_channel_id = sb.channel_id, sm.guild_id = sb.guild_id;
`);
// Drop the starboard_id column as it is now obsolete
await queryRunner.dropColumn("starboard_messages", "starboard_id");
// Set new Primary Key
await queryRunner.dropPrimaryKey("starboard_messages");
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_message_id"]);
// Finally, drop the starboards channel as it is now obsolete
await queryRunner.query(`
ALTER TABLE starboard_messages
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`starboard_message_id\`);
`);
// Drop the starboard_id column as it is now obsolete
// We can't use queyrRunner.dropColumn() here because TypeORM helpfully thinks that
// starboard_id is still part of the primary key and tries to drop the PK first
await queryRunner.query("ALTER TABLE starboard_messages DROP COLUMN starboard_id");
// Finally, drop the starboards table as it is now obsolete
await queryRunner.dropTable("starboards", true);
}
@ -39,15 +49,20 @@ export class MoveStarboardsToConfig1573248462469 implements MigrationInterface {
await queryRunner.dropColumn("starboard_messages", "starboard_channel_id");
await queryRunner.dropColumn("starboard_messages", "guild_id");
const sbId = new TableColumn({
name: "starboard_id",
type: "int",
unsigned: true,
});
await queryRunner.addColumn("starboard_messages", sbId);
await queryRunner.addColumn(
"starboard_messages",
new TableColumn({
name: "starboard_id",
type: "int",
unsigned: true,
}),
);
await queryRunner.dropPrimaryKey("starboard_messages");
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_id", "message_id"]);
await queryRunner.query(`
ALTER TABLE starboard_messages
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`starboard_id\`, \`message_id\`);
`);
await queryRunner.createTable(
new Table({

View file

@ -12,7 +12,7 @@ import {
TextBasedChannel,
User,
} from "discord.js";
import { AnyPluginData, CommandContext, ExtendedMatchParams, GuildPluginData, helpers } from "knub";
import { AnyPluginData, BasePluginData, CommandContext, ExtendedMatchParams, GuildPluginData, helpers } from "knub";
import { isStaff } from "./staff";
import { TZeppelinKnub } from "./types";
import { Tail } from "./utils/typeUtils";
@ -135,3 +135,16 @@ export function mapToPublicFn<T extends AnyFn>(inputFn: T) {
};
};
}
type FnWithPluginData<TPluginData> = (pluginData: TPluginData, ...args: any[]) => any;
export function makePublicFn<TPluginData extends BasePluginData<any>, T extends FnWithPluginData<TPluginData>>(
pluginData: TPluginData,
fn: T,
) {
return (...args: Tail<Parameters<T>>): ReturnType<T> => {
return fn(pluginData, ...args);
};
}
// ???

View file

@ -1,9 +1,8 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
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, zAutoDeleteConfig } from "./types";
import { onMessageCreate } from "./util/onMessageCreate";
import { onMessageDelete } from "./util/onMessageDelete";
@ -16,15 +15,8 @@ const defaultOptions: PluginOptions<AutoDeletePluginType> = {
},
};
export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()({
export const AutoDeletePlugin = guildPlugin<AutoDeletePluginType>()({
name: "auto_delete",
showInDocs: true,
info: {
prettyName: "Auto-delete",
description: "Allows Zeppelin to auto-delete messages from a channel after a delay",
configurationGuide: "Maximum deletion delay is currently 5 minutes",
configSchema: zAutoDeleteConfig,
},
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: (input) => zAutoDeleteConfig.parse(input),

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
export const autoDeletePluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Auto-delete",
description: "Allows Zeppelin to auto-delete messages from a channel after a delay",
configurationGuide: "Maximum deletion delay is currently 5 minutes",
};

View file

@ -1,9 +1,7 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
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";
@ -23,16 +21,8 @@ const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
],
};
export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>()({
export const AutoReactionsPlugin = guildPlugin<AutoReactionsPluginType>()({
name: "auto_reactions",
showInDocs: true,
info: {
prettyName: "Auto-reactions",
description: trimPluginDescription(`
Allows setting up automatic reactions to all new messages on a channel
`),
configSchema: zAutoReactionsConfig,
},
// prettier-ignore
dependencies: () => [

View file

@ -0,0 +1,10 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
export const autoReactionsInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Auto-reactions",
description: trimPluginDescription(`
Allows setting up automatic reactions to all new messages on a channel
`),
};

View file

@ -1,4 +1,4 @@
import { CooldownManager } from "knub";
import { CooldownManager, guildPlugin } from "knub";
import { Queue } from "../../Queue";
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
import { GuildArchives } from "../../data/GuildArchives";
@ -15,7 +15,6 @@ import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
import { MutesPlugin } from "../Mutes/MutesPlugin";
import { PhishermanPlugin } from "../Phisherman/PhishermanPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
@ -32,7 +31,6 @@ import {
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
import { pluginInfo } from "./info";
import { AutomodPluginType, zAutomodConfig } from "./types";
const defaultOptions = {
@ -58,10 +56,8 @@ const defaultOptions = {
],
};
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
export const AutomodPlugin = guildPlugin<AutomodPluginType>()({
name: "automod",
showInDocs: true,
info: pluginInfo,
// prettier-ignore
dependencies: () => [

View file

@ -1,12 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
import { zAutomodConfig } from "./types";
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
export const automodPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Automod",
description: trimPluginDescription(`
Allows specifying automated actions in response to triggers. Example use cases include word filtering and spam prevention.
`),
`),
configurationGuide: trimPluginDescription(`
The automod plugin is very customizable. For a full list of available triggers, actions, and their options, see Config schema at the bottom of this page.
@ -99,6 +99,5 @@ export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
Bad custom status on user <@!{user.id}>:
{matchSummary}
~~~
`),
configSchema: zAutomodConfig,
`),
};

View file

@ -1,10 +1,10 @@
import { Snowflake, TextChannel } from "discord.js";
import { globalPlugin } from "knub";
import { AllowedGuilds } from "../../data/AllowedGuilds";
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
import { Configs } from "../../data/Configs";
import { GuildArchives } from "../../data/GuildArchives";
import { CommonPlugin } from "../Common/CommonPlugin";
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
import { getActiveReload, resetActiveReload } from "./activeReload";
import { AddDashboardUserCmd } from "./commands/AddDashboardUserCmd";
import { AddServerFromInviteCmd } from "./commands/AddServerFromInviteCmd";
@ -35,7 +35,7 @@ const defaultOptions = {
},
};
export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()({
export const BotControlPlugin = globalPlugin<BotControlPluginType>()({
name: "bot_control",
configParser: (input) => zBotControlConfig.parse(input),
defaultOptions,

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter } from "../../../pluginUtils";
import { renderUsername } from "../../../utils";

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import moment from "moment-timezone";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { DBDateFormat, isGuildInvite, resolveInvite } from "../../../utils";

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions";
import { ApiPermissions } from "@zeppelinbot/shared";
import moment from "moment-timezone";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter } from "../../../pluginUtils";

View file

@ -1,13 +1,10 @@
import { CaseTypes } from "../../data/CaseTypes";
import { Case } from "../../data/entities/Case";
import { guildPlugin } from "knub";
import { GuildArchives } from "../../data/GuildArchives";
import { GuildCases } from "../../data/GuildCases";
import { GuildLogs } from "../../data/GuildLogs";
import { mapToPublicFn } from "../../pluginUtils";
import { trimPluginDescription } from "../../utils";
import { makePublicFn } from "../../pluginUtils";
import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { createCase } from "./functions/createCase";
import { createCaseNote } from "./functions/createCaseNote";
import { getCaseEmbed } from "./functions/getCaseEmbed";
@ -16,7 +13,7 @@ import { getCaseTypeAmountForUserId } from "./functions/getCaseTypeAmountForUser
import { getRecentCasesByMod } from "./functions/getRecentCasesByMod";
import { getTotalCasesByMod } from "./functions/getTotalCasesByMod";
import { postCaseToCaseLogChannel } from "./functions/postToCaseLogChannel";
import { CaseArgs, CaseNoteArgs, CasesPluginType, zCasesConfig } from "./types";
import { CasesPluginType, zCasesConfig } from "./types";
// The `any` cast here is to prevent TypeScript from locking up from the circular dependency
function getLogsPlugin(): Promise<any> {
@ -34,51 +31,24 @@ const defaultOptions = {
},
};
export const CasesPlugin = zeppelinGuildPlugin<CasesPluginType>()({
export const CasesPlugin = guildPlugin<CasesPluginType>()({
name: "cases",
showInDocs: true,
info: {
prettyName: "Cases",
description: trimPluginDescription(`
This plugin contains basic configuration for cases created by other plugins
`),
configSchema: zCasesConfig,
},
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getLogsPlugin()).LogsPlugin],
configParser: (input) => zCasesConfig.parse(input),
defaultOptions,
public: {
createCase(pluginData) {
return (args: CaseArgs) => {
return createCase(pluginData, args);
};
},
createCaseNote(pluginData) {
return (args: CaseNoteArgs) => {
return createCaseNote(pluginData, args);
};
},
postCaseToCaseLogChannel(pluginData) {
return (caseOrCaseId: Case | number) => {
return postCaseToCaseLogChannel(pluginData, caseOrCaseId);
};
},
getCaseTypeAmountForUserId(pluginData) {
return (userID: string, type: CaseTypes) => {
return getCaseTypeAmountForUserId(pluginData, userID, type);
};
},
getTotalCasesByMod: mapToPublicFn(getTotalCasesByMod),
getRecentCasesByMod: mapToPublicFn(getRecentCasesByMod),
getCaseEmbed: mapToPublicFn(getCaseEmbed),
getCaseSummary: mapToPublicFn(getCaseSummary),
public(pluginData) {
return {
createCase: makePublicFn(pluginData, createCase),
createCaseNote: makePublicFn(pluginData, createCaseNote),
postCaseToCaseLogChannel: makePublicFn(pluginData, postCaseToCaseLogChannel),
getCaseTypeAmountForUserId: makePublicFn(pluginData, getCaseTypeAmountForUserId),
getTotalCasesByMod: makePublicFn(pluginData, getTotalCasesByMod),
getRecentCasesByMod: makePublicFn(pluginData, getRecentCasesByMod),
getCaseEmbed: makePublicFn(pluginData, getCaseEmbed),
getCaseSummary: makePublicFn(pluginData, getCaseSummary),
};
},
afterLoad(pluginData) {

View file

@ -0,0 +1,10 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
export const casesPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Cases",
description: trimPluginDescription(`
This plugin contains basic configuration for cases created by other plugins
`),
};

View file

@ -1,10 +1,8 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { CensorPluginType, zCensorConfig } from "./types";
import { onMessageCreate } from "./util/onMessageCreate";
import { onMessageUpdate } from "./util/onMessageUpdate";
@ -43,18 +41,8 @@ const defaultOptions: PluginOptions<CensorPluginType> = {
],
};
export const CensorPlugin = zeppelinGuildPlugin<CensorPluginType>()({
export const CensorPlugin = guildPlugin<CensorPluginType>()({
name: "censor",
showInDocs: true,
info: {
prettyName: "Censor",
description: trimPluginDescription(`
Censor words, tokens, links, regex, etc.
For more advanced filtering, check out the Automod plugin!
`),
legacy: true,
configSchema: zCensorConfig,
},
dependencies: () => [LogsPlugin],
configParser: (input) => zCensorConfig.parse(input),

View file

@ -0,0 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
export const censorPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
legacy: true,
prettyName: "Censor",
description: trimPluginDescription(`
Censor words, tokens, links, regex, etc.
For more advanced filtering, check out the Automod plugin!
`),
};

View file

@ -1,12 +1,11 @@
import { guildPlugin } from "knub";
import z from "zod";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd";
import { ChannelArchiverPluginType } from "./types";
export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginType>()({
export const ChannelArchiverPlugin = guildPlugin<ChannelArchiverPluginType>()({
name: "channel_archiver",
showInDocs: false,
dependencies: () => [TimeAndDatePlugin],
configParser: (input) => z.strictObject({}).parse(input),

View file

@ -1,8 +1,6 @@
import { CooldownManager } from "knub";
import { CooldownManager, guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { VoiceStateUpdateEvt } from "./events/VoiceStateUpdateEvt";
import { CompanionChannelsPluginType, zCompanionChannelsConfig } from "./types";
@ -12,18 +10,8 @@ const defaultOptions = {
},
};
export const CompanionChannelsPlugin = zeppelinGuildPlugin<CompanionChannelsPluginType>()({
export const CompanionChannelsPlugin = guildPlugin<CompanionChannelsPluginType>()({
name: "companion_channels",
showInDocs: true,
info: {
prettyName: "Companion channels",
description: trimPluginDescription(`
Set up 'companion channels' between text and voice channels.
Once set up, any time a user joins one of the specified voice channels,
they'll get channel permissions applied to them for the text channels.
`),
configSchema: zCompanionChannelsConfig,
},
dependencies: () => [LogsPlugin],
configParser: (input) => zCompanionChannelsConfig.parse(input),

View file

@ -0,0 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
export const companionChannelsPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Companion channels",
description: trimPluginDescription(`
Set up 'companion channels' between text and voice channels.
Once set up, any time a user joins one of the specified voice channels,
they'll get channel permissions applied to them for the text channels.
`),
};

View file

@ -1,12 +1,10 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildCases } from "../../data/GuildCases";
import { trimPluginDescription } from "../../utils";
import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
import { MutesPlugin } from "../Mutes/MutesPlugin";
import { UtilityPlugin } from "../Utility/UtilityPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { BanCmd } from "./commands/BanUserCtxCmd";
import { CleanCmd } from "./commands/CleanMessageCtxCmd";
import { ModMenuCmd } from "./commands/ModMenuUserCtxCmd";
@ -33,16 +31,8 @@ const defaultOptions: PluginOptions<ContextMenuPluginType> = {
],
};
export const ContextMenuPlugin = zeppelinGuildPlugin<ContextMenuPluginType>()({
export const ContextMenuPlugin = guildPlugin<ContextMenuPluginType>()({
name: "context_menu",
showInDocs: true,
info: {
prettyName: "Context Menus",
description: trimPluginDescription(`
This plugin provides command shortcuts via context menus
`),
configSchema: zContextMenusConfig,
},
dependencies: () => [CasesPlugin, MutesPlugin, ModActionsPlugin, LogsPlugin, UtilityPlugin],
configParser: (input) => zContextMenusConfig.parse(input),

View file

@ -0,0 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { zContextMenusConfig } from "./types";
export const contextMenuPluginInfo: ZeppelinPluginInfo = {
showInDocs: false,
prettyName: "Context menu",
description: trimPluginDescription(`
This plugin provides command shortcuts via context menus
`),
configSchema: zContextMenusConfig,
};

View file

@ -1,10 +1,9 @@
import { EventEmitter } from "events";
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildCounters } from "../../data/GuildCounters";
import { CounterTrigger, parseCounterConditionString } from "../../data/entities/CounterTrigger";
import { mapToPublicFn } from "../../pluginUtils";
import { makePublicFn } from "../../pluginUtils";
import { MINUTES, convertDelayStringToMS, values } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AddCounterCmd } from "./commands/AddCounterCmd";
import { CountersListCmd } from "./commands/CountersListCmd";
import { ResetAllCounterValuesCmd } from "./commands/ResetAllCounterValuesCmd";
@ -56,35 +55,23 @@ const defaultOptions: PluginOptions<CountersPluginType> = {
* A single trigger can only trigger once per user/channel/in general, depending on how specific the counter is (e.g. a per-user trigger can only trigger once per user).
* After being triggered, a trigger is "reset" if the counter value no longer matches the trigger (e.g. drops to 100 or below in the above example). After this, that trigger can be triggered again.
*/
export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()({
export const CountersPlugin = guildPlugin<CountersPluginType>()({
name: "counters",
showInDocs: true,
info: {
prettyName: "Counters",
description:
"Keep track of per-user, per-channel, or global numbers and trigger specific actions based on this number",
configurationGuide: "See <a href='/docs/setup-guides/counters'>Counters setup guide</a>",
configSchema: zCountersConfig,
},
defaultOptions,
// TODO: Separate input and output types
configParser: (input) => zCountersConfig.parse(input),
public: {
counterExists: mapToPublicFn(counterExists),
// Change a counter's value by a relative amount, e.g. +5
changeCounterValue: mapToPublicFn(changeCounterValue),
// Set a counter's value to an absolute value
setCounterValue: mapToPublicFn(setCounterValue),
getPrettyNameForCounter: mapToPublicFn(getPrettyNameForCounter),
getPrettyNameForCounterTrigger: mapToPublicFn(getPrettyNameForCounterTrigger),
onCounterEvent: mapToPublicFn(onCounterEvent),
offCounterEvent: mapToPublicFn(offCounterEvent),
public(pluginData) {
return {
counterExists: makePublicFn(pluginData, counterExists),
changeCounterValue: makePublicFn(pluginData, changeCounterValue),
setCounterValue: makePublicFn(pluginData, setCounterValue),
getPrettyNameForCounter: makePublicFn(pluginData, getPrettyNameForCounter),
getPrettyNameForCounterTrigger: makePublicFn(pluginData, getPrettyNameForCounterTrigger),
onCounterEvent: makePublicFn(pluginData, onCounterEvent),
offCounterEvent: makePublicFn(pluginData, offCounterEvent),
};
},
// prettier-ignore

View file

@ -0,0 +1,11 @@
import { ZeppelinPluginInfo } from "../../types";
import { zCountersConfig } from "./types";
export const countersPluginInfo: ZeppelinPluginInfo = {
prettyName: "Counters",
showInDocs: true,
description:
"Keep track of per-user, per-channel, or global numbers and trigger specific actions based on this number",
configurationGuide: "See <a href='/docs/setup-guides/counters'>Counters setup guide</a>",
configSchema: zCountersConfig,
};

View file

@ -1,5 +1,5 @@
import { GuildChannel, GuildMember, User } from "discord.js";
import { guildPluginMessageCommand, parseSignature } from "knub";
import { guildPlugin, guildPluginMessageCommand, parseSignature } from "knub";
import { TSignature } from "knub-command-manager";
import { commandTypes } from "../../commandTypes";
import { TemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
@ -12,7 +12,6 @@ import {
userToTemplateSafeUser,
} from "../../utils/templateSafeObjects";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { runEvent } from "./functions/runEvent";
import { CustomEventsPluginType, zCustomEventsConfig } from "./types";
@ -22,9 +21,8 @@ const defaultOptions = {
},
};
export const CustomEventsPlugin = zeppelinGuildPlugin<CustomEventsPluginType>()({
export const CustomEventsPlugin = guildPlugin<CustomEventsPluginType>()({
name: "custom_events",
showInDocs: false,
dependencies: () => [LogsPlugin],
configParser: (input) => zCustomEventsConfig.parse(input),

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const customEventsPluginInfo: ZeppelinPluginInfo = {
prettyName: "Custom events",
showInDocs: false,
};

View file

@ -1,10 +1,9 @@
import { Guild } from "discord.js";
import { BasePluginType, GlobalPluginData, globalPluginEventListener } from "knub";
import { BasePluginType, GlobalPluginData, globalPlugin, globalPluginEventListener } from "knub";
import z from "zod";
import { AllowedGuilds } from "../../data/AllowedGuilds";
import { Configs } from "../../data/Configs";
import { env } from "../../env";
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
interface GuildAccessMonitorPluginType extends BasePluginType {
state: {
@ -23,7 +22,7 @@ async function checkGuild(pluginData: GlobalPluginData<GuildAccessMonitorPluginT
/**
* Global plugin to monitor if Zeppelin is invited to a non-whitelisted server, and leave it
*/
export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorPluginType>()({
export const GuildAccessMonitorPlugin = globalPlugin<GuildAccessMonitorPluginType>()({
name: "guild_access_monitor",
configParser: (input) => z.strictObject({}).parse(input),

View file

@ -1,12 +1,11 @@
import { globalPlugin } from "knub";
import z from "zod";
import { Configs } from "../../data/Configs";
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds";
import { GuildConfigReloaderPluginType } from "./types";
export const GuildConfigReloaderPlugin = zeppelinGlobalPlugin<GuildConfigReloaderPluginType>()({
export const GuildConfigReloaderPlugin = globalPlugin<GuildConfigReloaderPluginType>()({
name: "guild_config_reloader",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input),

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const guildConfigReloaderPluginInfo: ZeppelinPluginInfo = {
prettyName: "Guild config reloader",
showInDocs: false,
};

View file

@ -1,15 +1,13 @@
import { Guild } from "discord.js";
import { guildPluginEventListener } from "knub";
import { guildPlugin, guildPluginEventListener } from "knub";
import z from "zod";
import { AllowedGuilds } from "../../data/AllowedGuilds";
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
import { MINUTES } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { GuildInfoSaverPluginType } from "./types";
export const GuildInfoSaverPlugin = zeppelinGuildPlugin<GuildInfoSaverPluginType>()({
export const GuildInfoSaverPlugin = guildPlugin<GuildInfoSaverPluginType>()({
name: "guild_info_saver",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input),

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const guildInfoSaverPluginInfo: ZeppelinPluginInfo = {
prettyName: "Guild info saver",
showInDocs: false,
};

View file

@ -1,8 +1,8 @@
import { guildPlugin } from "knub";
import z from "zod";
import { GuildMemberCache } from "../../data/GuildMemberCache";
import { mapToPublicFn } from "../../pluginUtils";
import { makePublicFn } from "../../pluginUtils";
import { SECONDS } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { cancelDeletionOnMemberJoin } from "./events/cancelDeletionOnMemberJoin";
import { removeMemberCacheOnMemberLeave } from "./events/removeMemberCacheOnMemberLeave";
import { updateMemberCacheOnMemberUpdate } from "./events/updateMemberCacheOnMemberUpdate";
@ -14,9 +14,8 @@ import { GuildMemberCachePluginType } from "./types";
const PENDING_SAVE_INTERVAL = 30 * SECONDS;
export const GuildMemberCachePlugin = zeppelinGuildPlugin<GuildMemberCachePluginType>()({
export const GuildMemberCachePlugin = guildPlugin<GuildMemberCachePluginType>()({
name: "guild_member_cache",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input),
@ -29,8 +28,10 @@ export const GuildMemberCachePlugin = zeppelinGuildPlugin<GuildMemberCachePlugin
cancelDeletionOnMemberJoin,
],
public: {
getCachedMemberData: mapToPublicFn(getCachedMemberData),
public(pluginData) {
return {
getCachedMemberData: makePublicFn(pluginData, getCachedMemberData),
};
},
beforeLoad(pluginData) {

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const guildMemberCachePluginInfo: ZeppelinPluginInfo = {
prettyName: "Guild member cache",
showInDocs: false,
};

View file

@ -1,9 +1,8 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import z from "zod";
import { Queue } from "../../Queue";
import { Webhooks } from "../../data/Webhooks";
import { mapToPublicFn } from "../../pluginUtils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { makePublicFn } from "../../pluginUtils";
import { editMessage } from "./functions/editMessage";
import { sendMessage } from "./functions/sendMessage";
import { InternalPosterPluginType } from "./types";
@ -13,17 +12,17 @@ const defaultOptions: PluginOptions<InternalPosterPluginType> = {
overrides: [],
};
export const InternalPosterPlugin = zeppelinGuildPlugin<InternalPosterPluginType>()({
export const InternalPosterPlugin = guildPlugin<InternalPosterPluginType>()({
name: "internal_poster",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input),
defaultOptions,
// prettier-ignore
public: {
sendMessage: mapToPublicFn(sendMessage),
editMessage: mapToPublicFn(editMessage),
public(pluginData) {
return {
sendMessage: makePublicFn(pluginData, sendMessage),
editMessage: makePublicFn(pluginData, editMessage),
};
},
async beforeLoad(pluginData) {

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const internalPosterPluginInfo: ZeppelinPluginInfo = {
prettyName: "Internal poster",
showInDocs: false,
};

View file

@ -1,8 +1,6 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { onGuildEvent } from "../../data/GuildEvents";
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
import { trimPluginDescription } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { FollowCmd } from "./commands/FollowCmd";
import { DeleteFollowCmd, ListFollowCmd } from "./commands/ListFollowCmd";
import { WhereCmd } from "./commands/WhereCmd";
@ -28,18 +26,8 @@ const defaultOptions: PluginOptions<LocateUserPluginType> = {
],
};
export const LocateUserPlugin = zeppelinGuildPlugin<LocateUserPluginType>()({
export const LocateUserPlugin = guildPlugin<LocateUserPluginType>()({
name: "locate_user",
showInDocs: true,
info: {
prettyName: "Locate user",
description: trimPluginDescription(`
This plugin allows users with access to the commands the following:
* Instantly receive an invite to the voice channel of a user
* Be notified as soon as a user switches or joins a voice channel
`),
configSchema: zLocateUserConfig,
},
configParser: (input) => zLocateUserConfig.parse(input),
defaultOptions,

View file

@ -0,0 +1,14 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { zLocateUserConfig } from "./types";
export const locateUserPluginInfo: ZeppelinPluginInfo = {
prettyName: "Locate user",
description: trimPluginDescription(`
This plugin allows users with access to the commands the following:
* Instantly receive an invite to the voice channel of a user
* Be notified as soon as a user switches or joins a voice channel
`),
configSchema: zLocateUserConfig,
showInDocs: true,
};

View file

@ -1,4 +1,4 @@
import { CooldownManager, PluginOptions } from "knub";
import { CooldownManager, PluginOptions, guildPlugin } from "knub";
import DefaultLogMessages from "../../data/DefaultLogMessages.json";
import { GuildArchives } from "../../data/GuildArchives";
import { GuildCases } from "../../data/GuildCases";
@ -6,11 +6,10 @@ import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { LogType } from "../../data/LogType";
import { logger } from "../../logger";
import { mapToPublicFn } from "../../pluginUtils";
import { makePublicFn } from "../../pluginUtils";
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
import { TypedTemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
import { createTypedTemplateSafeValueContainer } from "../../templateFormatter";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { LogsChannelCreateEvt, LogsChannelDeleteEvt, LogsChannelUpdateEvt } from "./events/LogsChannelModifyEvts";
import {
LogsEmojiCreateEvt,
@ -31,7 +30,7 @@ import {
import { LogsThreadCreateEvt, LogsThreadDeleteEvt, LogsThreadUpdateEvt } from "./events/LogsThreadModifyEvts";
import { LogsGuildMemberUpdateEvt } from "./events/LogsUserUpdateEvts";
import { LogsVoiceStateUpdateEvt } from "./events/LogsVoiceChannelEvts";
import { FORMAT_NO_TIMESTAMP, ILogTypeData, LogsPluginType, TLogChannel, zLogsConfig } from "./types";
import { FORMAT_NO_TIMESTAMP, LogsPluginType, zLogsConfig } from "./types";
import { getLogMessage } from "./util/getLogMessage";
import { log } from "./util/log";
import { onMessageDelete } from "./util/onMessageDelete";
@ -140,13 +139,8 @@ const defaultOptions: PluginOptions<LogsPluginType> = {
],
};
export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()({
export const LogsPlugin = guildPlugin<LogsPluginType>()({
name: "logs",
showInDocs: true,
info: {
prettyName: "Logs",
configSchema: zLogsConfig,
},
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin],
configParser: (input) => zLogsConfig.parse(input),
@ -178,86 +172,79 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()({
LogsGuildMemberRoleChangeEvt,
],
public: {
getLogMessage: (pluginData) => {
return <TLogType extends keyof ILogTypeData>(
type: TLogType,
data: TypedTemplateSafeValueContainer<ILogTypeData[TLogType]>,
opts?: Pick<TLogChannel, "format" | "timestamp_format" | "include_embed_timestamp">,
) => {
return getLogMessage(pluginData, type, data, opts);
};
},
logAutomodAction: mapToPublicFn(logAutomodAction),
logBotAlert: mapToPublicFn(logBotAlert),
logCaseCreate: mapToPublicFn(logCaseCreate),
logCaseDelete: mapToPublicFn(logCaseDelete),
logCaseUpdate: mapToPublicFn(logCaseUpdate),
logCensor: mapToPublicFn(logCensor),
logChannelCreate: mapToPublicFn(logChannelCreate),
logChannelDelete: mapToPublicFn(logChannelDelete),
logChannelUpdate: mapToPublicFn(logChannelUpdate),
logClean: mapToPublicFn(logClean),
logEmojiCreate: mapToPublicFn(logEmojiCreate),
logEmojiDelete: mapToPublicFn(logEmojiDelete),
logEmojiUpdate: mapToPublicFn(logEmojiUpdate),
logMassBan: mapToPublicFn(logMassBan),
logMassMute: mapToPublicFn(logMassMute),
logMassUnban: mapToPublicFn(logMassUnban),
logMemberBan: mapToPublicFn(logMemberBan),
logMemberForceban: mapToPublicFn(logMemberForceban),
logMemberJoin: mapToPublicFn(logMemberJoin),
logMemberJoinWithPriorRecords: mapToPublicFn(logMemberJoinWithPriorRecords),
logMemberKick: mapToPublicFn(logMemberKick),
logMemberLeave: mapToPublicFn(logMemberLeave),
logMemberMute: mapToPublicFn(logMemberMute),
logMemberMuteExpired: mapToPublicFn(logMemberMuteExpired),
logMemberMuteRejoin: mapToPublicFn(logMemberMuteRejoin),
logMemberNickChange: mapToPublicFn(logMemberNickChange),
logMemberNote: mapToPublicFn(logMemberNote),
logMemberRestore: mapToPublicFn(logMemberRestore),
logMemberRoleAdd: mapToPublicFn(logMemberRoleAdd),
logMemberRoleChanges: mapToPublicFn(logMemberRoleChanges),
logMemberRoleRemove: mapToPublicFn(logMemberRoleRemove),
logMemberTimedBan: mapToPublicFn(logMemberTimedBan),
logMemberTimedMute: mapToPublicFn(logMemberTimedMute),
logMemberTimedUnban: mapToPublicFn(logMemberTimedUnban),
logMemberTimedUnmute: mapToPublicFn(logMemberTimedUnmute),
logMemberUnban: mapToPublicFn(logMemberUnban),
logMemberUnmute: mapToPublicFn(logMemberUnmute),
logMemberWarn: mapToPublicFn(logMemberWarn),
logMessageDelete: mapToPublicFn(logMessageDelete),
logMessageDeleteAuto: mapToPublicFn(logMessageDeleteAuto),
logMessageDeleteBare: mapToPublicFn(logMessageDeleteBare),
logMessageDeleteBulk: mapToPublicFn(logMessageDeleteBulk),
logMessageEdit: mapToPublicFn(logMessageEdit),
logMessageSpamDetected: mapToPublicFn(logMessageSpamDetected),
logOtherSpamDetected: mapToPublicFn(logOtherSpamDetected),
logPostedScheduledMessage: mapToPublicFn(logPostedScheduledMessage),
logRepeatedMessage: mapToPublicFn(logRepeatedMessage),
logRoleCreate: mapToPublicFn(logRoleCreate),
logRoleDelete: mapToPublicFn(logRoleDelete),
logRoleUpdate: mapToPublicFn(logRoleUpdate),
logScheduledMessage: mapToPublicFn(logScheduledMessage),
logScheduledRepeatedMessage: mapToPublicFn(logScheduledRepeatedMessage),
logSetAntiraidAuto: mapToPublicFn(logSetAntiraidAuto),
logSetAntiraidUser: mapToPublicFn(logSetAntiraidUser),
logStageInstanceCreate: mapToPublicFn(logStageInstanceCreate),
logStageInstanceDelete: mapToPublicFn(logStageInstanceDelete),
logStageInstanceUpdate: mapToPublicFn(logStageInstanceUpdate),
logStickerCreate: mapToPublicFn(logStickerCreate),
logStickerDelete: mapToPublicFn(logStickerDelete),
logStickerUpdate: mapToPublicFn(logStickerUpdate),
logThreadCreate: mapToPublicFn(logThreadCreate),
logThreadDelete: mapToPublicFn(logThreadDelete),
logThreadUpdate: mapToPublicFn(logThreadUpdate),
logVoiceChannelForceDisconnect: mapToPublicFn(logVoiceChannelForceDisconnect),
logVoiceChannelForceMove: mapToPublicFn(logVoiceChannelForceMove),
logVoiceChannelJoin: mapToPublicFn(logVoiceChannelJoin),
logVoiceChannelLeave: mapToPublicFn(logVoiceChannelLeave),
logVoiceChannelMove: mapToPublicFn(logVoiceChannelMove),
logDmFailed: mapToPublicFn(logDmFailed),
public(pluginData) {
return {
getLogMessage: makePublicFn(pluginData, getLogMessage),
logAutomodAction: makePublicFn(pluginData, logAutomodAction),
logBotAlert: makePublicFn(pluginData, logBotAlert),
logCaseCreate: makePublicFn(pluginData, logCaseCreate),
logCaseDelete: makePublicFn(pluginData, logCaseDelete),
logCaseUpdate: makePublicFn(pluginData, logCaseUpdate),
logCensor: makePublicFn(pluginData, logCensor),
logChannelCreate: makePublicFn(pluginData, logChannelCreate),
logChannelDelete: makePublicFn(pluginData, logChannelDelete),
logChannelUpdate: makePublicFn(pluginData, logChannelUpdate),
logClean: makePublicFn(pluginData, logClean),
logEmojiCreate: makePublicFn(pluginData, logEmojiCreate),
logEmojiDelete: makePublicFn(pluginData, logEmojiDelete),
logEmojiUpdate: makePublicFn(pluginData, logEmojiUpdate),
logMassBan: makePublicFn(pluginData, logMassBan),
logMassMute: makePublicFn(pluginData, logMassMute),
logMassUnban: makePublicFn(pluginData, logMassUnban),
logMemberBan: makePublicFn(pluginData, logMemberBan),
logMemberForceban: makePublicFn(pluginData, logMemberForceban),
logMemberJoin: makePublicFn(pluginData, logMemberJoin),
logMemberJoinWithPriorRecords: makePublicFn(pluginData, logMemberJoinWithPriorRecords),
logMemberKick: makePublicFn(pluginData, logMemberKick),
logMemberLeave: makePublicFn(pluginData, logMemberLeave),
logMemberMute: makePublicFn(pluginData, logMemberMute),
logMemberMuteExpired: makePublicFn(pluginData, logMemberMuteExpired),
logMemberMuteRejoin: makePublicFn(pluginData, logMemberMuteRejoin),
logMemberNickChange: makePublicFn(pluginData, logMemberNickChange),
logMemberNote: makePublicFn(pluginData, logMemberNote),
logMemberRestore: makePublicFn(pluginData, logMemberRestore),
logMemberRoleAdd: makePublicFn(pluginData, logMemberRoleAdd),
logMemberRoleChanges: makePublicFn(pluginData, logMemberRoleChanges),
logMemberRoleRemove: makePublicFn(pluginData, logMemberRoleRemove),
logMemberTimedBan: makePublicFn(pluginData, logMemberTimedBan),
logMemberTimedMute: makePublicFn(pluginData, logMemberTimedMute),
logMemberTimedUnban: makePublicFn(pluginData, logMemberTimedUnban),
logMemberTimedUnmute: makePublicFn(pluginData, logMemberTimedUnmute),
logMemberUnban: makePublicFn(pluginData, logMemberUnban),
logMemberUnmute: makePublicFn(pluginData, logMemberUnmute),
logMemberWarn: makePublicFn(pluginData, logMemberWarn),
logMessageDelete: makePublicFn(pluginData, logMessageDelete),
logMessageDeleteAuto: makePublicFn(pluginData, logMessageDeleteAuto),
logMessageDeleteBare: makePublicFn(pluginData, logMessageDeleteBare),
logMessageDeleteBulk: makePublicFn(pluginData, logMessageDeleteBulk),
logMessageEdit: makePublicFn(pluginData, logMessageEdit),
logMessageSpamDetected: makePublicFn(pluginData, logMessageSpamDetected),
logOtherSpamDetected: makePublicFn(pluginData, logOtherSpamDetected),
logPostedScheduledMessage: makePublicFn(pluginData, logPostedScheduledMessage),
logRepeatedMessage: makePublicFn(pluginData, logRepeatedMessage),
logRoleCreate: makePublicFn(pluginData, logRoleCreate),
logRoleDelete: makePublicFn(pluginData, logRoleDelete),
logRoleUpdate: makePublicFn(pluginData, logRoleUpdate),
logScheduledMessage: makePublicFn(pluginData, logScheduledMessage),
logScheduledRepeatedMessage: makePublicFn(pluginData, logScheduledRepeatedMessage),
logSetAntiraidAuto: makePublicFn(pluginData, logSetAntiraidAuto),
logSetAntiraidUser: makePublicFn(pluginData, logSetAntiraidUser),
logStageInstanceCreate: makePublicFn(pluginData, logStageInstanceCreate),
logStageInstanceDelete: makePublicFn(pluginData, logStageInstanceDelete),
logStageInstanceUpdate: makePublicFn(pluginData, logStageInstanceUpdate),
logStickerCreate: makePublicFn(pluginData, logStickerCreate),
logStickerDelete: makePublicFn(pluginData, logStickerDelete),
logStickerUpdate: makePublicFn(pluginData, logStickerUpdate),
logThreadCreate: makePublicFn(pluginData, logThreadCreate),
logThreadDelete: makePublicFn(pluginData, logThreadDelete),
logThreadUpdate: makePublicFn(pluginData, logThreadUpdate),
logVoiceChannelForceDisconnect: makePublicFn(pluginData, logVoiceChannelForceDisconnect),
logVoiceChannelForceMove: makePublicFn(pluginData, logVoiceChannelForceMove),
logVoiceChannelJoin: makePublicFn(pluginData, logVoiceChannelJoin),
logVoiceChannelLeave: makePublicFn(pluginData, logVoiceChannelLeave),
logVoiceChannelMove: makePublicFn(pluginData, logVoiceChannelMove),
logDmFailed: makePublicFn(pluginData, logDmFailed),
};
},
beforeLoad(pluginData) {

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { zLogsConfig } from "./types";
export const logsPluginInfo: ZeppelinPluginInfo = {
prettyName: "Logs",
configSchema: zLogsConfig,
showInDocs: true,
};

View file

@ -1,6 +1,5 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { SaveMessagesToDBCmd } from "./commands/SaveMessagesToDB";
import { SavePinsToDBCmd } from "./commands/SavePinsToDB";
import { MessageCreateEvt, MessageDeleteBulkEvt, MessageDeleteEvt, MessageUpdateEvt } from "./events/SaveMessagesEvts";
@ -20,9 +19,8 @@ const defaultOptions: PluginOptions<MessageSaverPluginType> = {
],
};
export const MessageSaverPlugin = zeppelinGuildPlugin<MessageSaverPluginType>()({
export const MessageSaverPlugin = guildPlugin<MessageSaverPluginType>()({
name: "message_saver",
showInDocs: false,
configParser: (input) => zMessageSaverConfig.parse(input),
defaultOptions,

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const messageSaverPluginInfo: ZeppelinPluginInfo = {
prettyName: "Message saver",
showInDocs: false,
};

View file

@ -1,18 +1,18 @@
import { GuildMember, Message, Snowflake } from "discord.js";
import { Message } from "discord.js";
import { EventEmitter } from "events";
import { guildPlugin } from "knub";
import { Queue } from "../../Queue";
import { GuildCases } from "../../data/GuildCases";
import { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildMutes } from "../../data/GuildMutes";
import { GuildTempbans } from "../../data/GuildTempbans";
import { mapToPublicFn } from "../../pluginUtils";
import { MINUTES, trimPluginDescription } from "../../utils";
import { makePublicFn, mapToPublicFn } from "../../pluginUtils";
import { MINUTES } from "../../utils";
import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { MutesPlugin } from "../Mutes/MutesPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AddCaseMsgCmd } from "./commands/addcase/AddCaseMsgCmd";
import { AddCaseSlashCmd } from "./commands/addcase/AddCaseSlashCmd";
import { BanMsgCmd } from "./commands/ban/BanMsgCmd";
@ -71,15 +71,7 @@ import { offModActionsEvent } from "./functions/offModActionsEvent";
import { onModActionsEvent } from "./functions/onModActionsEvent";
import { updateCase } from "./functions/updateCase";
import { warnMember } from "./functions/warnMember";
import {
AttachmentLinkReactionType,
BanOptions,
KickOptions,
ModActionsPluginType,
WarnOptions,
modActionsSlashGroup,
zModActionsConfig,
} from "./types";
import { AttachmentLinkReactionType, ModActionsPluginType, modActionsSlashGroup, zModActionsConfig } from "./types";
const defaultOptions = {
config: {
@ -147,16 +139,8 @@ const defaultOptions = {
],
};
export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
export const ModActionsPlugin = guildPlugin<ModActionsPluginType>()({
name: "mod_actions",
showInDocs: true,
info: {
prettyName: "Mod actions",
description: trimPluginDescription(`
This plugin contains the 'typical' mod actions such as warning, muting, kicking, banning, etc.
`),
configSchema: zModActionsConfig,
},
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
configParser: (input) => zModActionsConfig.parse(input),
@ -218,66 +202,21 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
DeleteCaseMsgCmd,
],
public: {
warnMember(pluginData) {
return (member: GuildMember, reason: string, reasonWithAttachments: string, warnOptions?: WarnOptions) => {
return warnMember(pluginData, member, reason, reasonWithAttachments, warnOptions);
};
},
kickMember(pluginData) {
return (member: GuildMember, reason: string, reasonWithAttachments: string, kickOptions?: KickOptions) => {
kickMember(pluginData, member, reason, reasonWithAttachments, kickOptions);
};
},
banUserId(pluginData) {
return (
userId: string,
reason?: string,
reasonWithAttachments?: string,
banOptions?: BanOptions,
banTime?: number,
) => {
return banUserId(pluginData, userId, reason, reasonWithAttachments, banOptions, banTime);
};
},
updateCase(pluginData) {
return (msg: Message, caseNumber: number | null, note: string) => {
updateCase(pluginData, msg, msg.author, caseNumber ?? undefined, note, [...msg.attachments.values()]);
};
},
hasNotePermission(pluginData) {
return (member: GuildMember, channelId: Snowflake) => {
return hasNotePermission(pluginData, member, channelId);
};
},
hasWarnPermission(pluginData) {
return (member: GuildMember, channelId: Snowflake) => {
return hasWarnPermission(pluginData, member, channelId);
};
},
hasMutePermission(pluginData) {
return (member: GuildMember, channelId: Snowflake) => {
return hasMutePermission(pluginData, member, channelId);
};
},
hasBanPermission(pluginData) {
return (member: GuildMember, channelId: Snowflake) => {
return hasBanPermission(pluginData, member, channelId);
};
},
on: mapToPublicFn(onModActionsEvent),
off: mapToPublicFn(offModActionsEvent),
getEventEmitter(pluginData) {
return () => pluginData.state.events;
},
public(pluginData) {
return {
warnMember: makePublicFn(pluginData, warnMember),
kickMember: makePublicFn(pluginData, kickMember),
banUserId: makePublicFn(pluginData, banUserId),
updateCase: (msg: Message, caseNumber: number | null, note: string) =>
updateCase(pluginData, msg, msg.author, caseNumber ?? undefined, note, [...msg.attachments.values()]),
hasNotePermission: makePublicFn(pluginData, hasNotePermission),
hasWarnPermission: makePublicFn(pluginData, hasWarnPermission),
hasMutePermission: makePublicFn(pluginData, hasMutePermission),
hasBanPermission: makePublicFn(pluginData, hasBanPermission),
on: mapToPublicFn(onModActionsEvent),
off: mapToPublicFn(offModActionsEvent),
getEventEmitter: () => pluginData.state.events,
};
},
beforeLoad(pluginData) {

View file

@ -0,0 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { zModActionsConfig } from "./types";
export const modActionsPluginInfo: ZeppelinPluginInfo = {
prettyName: "Mod actions",
showInDocs: true,
description: trimPluginDescription(`
This plugin contains the 'typical' mod actions such as warning, muting, kicking, banning, etc.
`),
configSchema: zModActionsConfig,
};

View file

@ -1,15 +1,15 @@
import { GuildMember, Snowflake } from "discord.js";
import { EventEmitter } from "events";
import { guildPlugin } from "knub";
import { GuildArchives } from "../../data/GuildArchives";
import { GuildCases } from "../../data/GuildCases";
import { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildMutes } from "../../data/GuildMutes";
import { mapToPublicFn } from "../../pluginUtils";
import { makePublicFn } from "../../pluginUtils";
import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin.js";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { ClearBannedMutesCmd } from "./commands/ClearBannedMutesCmd";
import { ClearMutesCmd } from "./commands/ClearMutesCmd";
import { ClearMutesWithoutRoleCmd } from "./commands/ClearMutesWithoutRoleCmd";
@ -61,13 +61,8 @@ const defaultOptions = {
],
};
export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({
export const MutesPlugin = guildPlugin<MutesPluginType>()({
name: "mutes",
showInDocs: true,
info: {
prettyName: "Mutes",
configSchema: zMutesConfig,
},
dependencies: () => [CasesPlugin, LogsPlugin, RoleManagerPlugin],
configParser: (input) => zMutesConfig.parse(input),
@ -89,21 +84,18 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({
RegisterManualTimeoutsEvt,
],
public: {
muteUser: mapToPublicFn(muteUser),
unmuteUser: mapToPublicFn(unmuteUser),
hasMutedRole(pluginData) {
return (member: GuildMember) => {
public(pluginData) {
return {
muteUser: makePublicFn(pluginData, muteUser),
unmuteUser: makePublicFn(pluginData, unmuteUser),
hasMutedRole: (member: GuildMember) => {
const muteRole = pluginData.config.get().mute_role;
return muteRole ? member.roles.cache.has(muteRole as Snowflake) : false;
};
},
on: mapToPublicFn(onMutesEvent),
off: mapToPublicFn(offMutesEvent),
getEventEmitter(pluginData) {
return () => pluginData.state.events;
},
},
on: makePublicFn(pluginData, onMutesEvent),
off: makePublicFn(pluginData, offMutesEvent),
getEventEmitter: () => pluginData.state.events,
};
},
beforeLoad(pluginData) {

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { zMutesConfig } from "./types";
export const mutesPluginInfo: ZeppelinPluginInfo = {
prettyName: "Mutes",
showInDocs: true,
configSchema: zMutesConfig,
};

View file

@ -1,8 +1,7 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { Queue } from "../../Queue";
import { GuildNicknameHistory } from "../../data/GuildNicknameHistory";
import { UsernameHistory } from "../../data/UsernameHistory";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { NamesCmd } from "./commands/NamesCmd";
import { NameHistoryPluginType, zNameHistoryConfig } from "./types";
@ -20,9 +19,8 @@ const defaultOptions: PluginOptions<NameHistoryPluginType> = {
],
};
export const NameHistoryPlugin = zeppelinGuildPlugin<NameHistoryPluginType>()({
export const NameHistoryPlugin = guildPlugin<NameHistoryPluginType>()({
name: "name_history",
showInDocs: false,
configParser: (input) => zNameHistoryConfig.parse(input),
defaultOptions,

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { zNameHistoryConfig } from "./types";
export const nameHistoryPluginInfo: ZeppelinPluginInfo = {
prettyName: "Name history",
showInDocs: false,
configSchema: zNameHistoryConfig,
};

View file

@ -1,10 +1,8 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildPersistedData } from "../../data/GuildPersistedData";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { LoadDataEvt } from "./events/LoadDataEvt";
import { StoreDataEvt } from "./events/StoreDataEvt";
import { PersistPluginType, zPersistConfig } from "./types";
@ -17,17 +15,8 @@ const defaultOptions: PluginOptions<PersistPluginType> = {
},
};
export const PersistPlugin = zeppelinGuildPlugin<PersistPluginType>()({
export const PersistPlugin = guildPlugin<PersistPluginType>()({
name: "persist",
showInDocs: true,
info: {
prettyName: "Persist",
description: trimPluginDescription(`
Re-apply roles or nicknames for users when they rejoin the server.
Mute roles are re-applied automatically, this plugin is not required for that.
`),
configSchema: zPersistConfig,
},
dependencies: () => [LogsPlugin, RoleManagerPlugin],
configParser: (input) => zPersistConfig.parse(input),

View file

@ -0,0 +1,13 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { zPersistConfig } from "./types";
export const persistPluginInfo: ZeppelinPluginInfo = {
prettyName: "Persist",
description: trimPluginDescription(`
Re-apply roles or nicknames for users when they rejoin the server.
Mute roles are re-applied automatically, this plugin is not required for that.
`),
configSchema: zPersistConfig,
showInDocs: true,
};

View file

@ -1,9 +1,7 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { hasPhishermanMasterAPIKey, phishermanApiKeyIsValid } from "../../data/Phisherman";
import { mapToPublicFn } from "../../pluginUtils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { makePublicFn } from "../../pluginUtils";
import { getDomainInfo } from "./functions/getDomainInfo";
import { pluginInfo } from "./info";
import { PhishermanPluginType, zPhishermanConfig } from "./types";
const defaultOptions: PluginOptions<PhishermanPluginType> = {
@ -13,17 +11,16 @@ const defaultOptions: PluginOptions<PhishermanPluginType> = {
overrides: [],
};
export const PhishermanPlugin = zeppelinGuildPlugin<PhishermanPluginType>()({
export const PhishermanPlugin = guildPlugin<PhishermanPluginType>()({
name: "phisherman",
showInDocs: true,
info: pluginInfo,
configParser: (input) => zPhishermanConfig.parse(input),
defaultOptions,
// prettier-ignore
public: {
getDomainInfo: mapToPublicFn(getDomainInfo),
public(pluginData) {
return {
getDomainInfo: makePublicFn(pluginData, getDomainInfo),
};
},
async beforeLoad(pluginData) {

View file

@ -1,8 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
import { zPhishermanConfig } from "./types";
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
export const phishermanPluginInfo: ZeppelinPluginInfo = {
prettyName: "Phisherman",
description: trimPluginDescription(`
Match scam/phishing links using the Phisherman API. See https://phisherman.gg/ for more details!
@ -40,4 +40,5 @@ export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
~~~
`),
configSchema: zPhishermanConfig,
showInDocs: true,
};

View file

@ -1,6 +1,5 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildPingableRoles } from "../../data/GuildPingableRoles";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { PingableRoleDisableCmd } from "./commands/PingableRoleDisableCmd";
import { PingableRoleEnableCmd } from "./commands/PingableRoleEnableCmd";
import { PingableRolesPluginType, zPingableRolesConfig } from "./types";
@ -19,13 +18,8 @@ const defaultOptions: PluginOptions<PingableRolesPluginType> = {
],
};
export const PingableRolesPlugin = zeppelinGuildPlugin<PingableRolesPluginType>()({
export const PingableRolesPlugin = guildPlugin<PingableRolesPluginType>()({
name: "pingable_roles",
showInDocs: true,
info: {
prettyName: "Pingable roles",
configSchema: zPingableRolesConfig,
},
configParser: (input) => zPingableRolesConfig.parse(input),
defaultOptions,

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { zPingableRolesConfig } from "./types";
export const pingableRolesPluginInfo: ZeppelinPluginInfo = {
prettyName: "Pingable roles",
configSchema: zPingableRolesConfig,
showInDocs: true,
};

View file

@ -1,11 +1,10 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { GuildScheduledPosts } from "../../data/GuildScheduledPosts";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { EditCmd } from "./commands/EditCmd";
import { EditEmbedCmd } from "./commands/EditEmbedCmd";
import { PostCmd } from "./commands/PostCmd";
@ -30,13 +29,8 @@ const defaultOptions: PluginOptions<PostPluginType> = {
],
};
export const PostPlugin = zeppelinGuildPlugin<PostPluginType>()({
export const PostPlugin = guildPlugin<PostPluginType>()({
name: "post",
showInDocs: true,
info: {
prettyName: "Post",
configSchema: zPostConfig,
},
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: (input) => zPostConfig.parse(input),

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { zPostConfig } from "./types";
export const postPluginInfo: ZeppelinPluginInfo = {
prettyName: "Post",
configSchema: zPostConfig,
showInDocs: true,
};

View file

@ -1,9 +1,8 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { Queue } from "../../Queue";
import { GuildReactionRoles } from "../../data/GuildReactionRoles";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { ClearReactionRolesCmd } from "./commands/ClearReactionRolesCmd";
import { InitReactionRolesCmd } from "./commands/InitReactionRolesCmd";
import { RefreshReactionRolesCmd } from "./commands/RefreshReactionRolesCmd";
@ -33,14 +32,8 @@ const defaultOptions: PluginOptions<ReactionRolesPluginType> = {
],
};
export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>()({
export const ReactionRolesPlugin = guildPlugin<ReactionRolesPluginType>()({
name: "reaction_roles",
showInDocs: true,
info: {
prettyName: "Reaction roles",
legacy: "Consider using the [Role buttons](/docs/plugins/role_buttons) plugin instead.",
configSchema: zReactionRolesConfig,
},
dependencies: () => [LogsPlugin],
configParser: (input) => zReactionRolesConfig.parse(input),

View file

@ -0,0 +1,10 @@
import { ZeppelinPluginInfo } from "../../types";
import { zReactionRolesConfig } from "./types";
export const reactionRolesPluginInfo: ZeppelinPluginInfo = {
prettyName: "Reaction roles",
description: "Consider using the [Role buttons](https://zeppelin.gg/docs/plugins/role_buttons) plugin instead.",
legacy: true,
configSchema: zReactionRolesConfig,
showInDocs: true,
};

View file

@ -1,8 +1,7 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { onGuildEvent } from "../../data/GuildEvents";
import { GuildReminders } from "../../data/GuildReminders";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { RemindCmd } from "./commands/RemindCmd";
import { RemindersCmd } from "./commands/RemindersCmd";
import { RemindersDeleteCmd } from "./commands/RemindersDeleteCmd";
@ -23,13 +22,8 @@ const defaultOptions: PluginOptions<RemindersPluginType> = {
],
};
export const RemindersPlugin = zeppelinGuildPlugin<RemindersPluginType>()({
export const RemindersPlugin = guildPlugin<RemindersPluginType>()({
name: "reminders",
showInDocs: true,
info: {
prettyName: "Reminders",
configSchema: zRemindersConfig,
},
dependencies: () => [TimeAndDatePlugin],
configParser: (input) => zRemindersConfig.parse(input),

View file

@ -0,0 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { zRemindersConfig } from "./types";
export const remindersPluginInfo: ZeppelinPluginInfo = {
prettyName: "Reminders",
configSchema: zRemindersConfig,
showInDocs: true,
};

View file

@ -1,17 +1,14 @@
import { guildPlugin } from "knub";
import { GuildRoleButtons } from "../../data/GuildRoleButtons";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { resetButtonsCmd } from "./commands/resetButtons";
import { onButtonInteraction } from "./events/buttonInteraction";
import { applyAllRoleButtons } from "./functions/applyAllRoleButtons";
import { pluginInfo } from "./info";
import { RoleButtonsPluginType, zRoleButtonsConfig } from "./types";
export const RoleButtonsPlugin = zeppelinGuildPlugin<RoleButtonsPluginType>()({
export const RoleButtonsPlugin = guildPlugin<RoleButtonsPluginType>()({
name: "role_buttons",
info: pluginInfo,
showInDocs: true,
defaultOptions: {
config: {

View file

@ -1,8 +1,9 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
import { zRoleButtonsConfig } from "./types";
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
export const roleButtonsPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Role buttons",
description: trimPluginDescription(`
Allow users to pick roles by clicking on buttons

View file

@ -1,7 +1,7 @@
import { guildPlugin } from "knub";
import { GuildRoleQueue } from "../../data/GuildRoleQueue";
import { mapToPublicFn } from "../../pluginUtils";
import { makePublicFn } from "../../pluginUtils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { addPriorityRole } from "./functions/addPriorityRole";
import { addRole } from "./functions/addRole";
import { removePriorityRole } from "./functions/removePriorityRole";
@ -9,18 +9,19 @@ import { removeRole } from "./functions/removeRole";
import { runRoleAssignmentLoop } from "./functions/runRoleAssignmentLoop";
import { RoleManagerPluginType, zRoleManagerConfig } from "./types";
export const RoleManagerPlugin = zeppelinGuildPlugin<RoleManagerPluginType>()({
export const RoleManagerPlugin = guildPlugin<RoleManagerPluginType>()({
name: "role_manager",
showInDocs: false,
dependencies: () => [LogsPlugin],
configParser: (input) => zRoleManagerConfig.parse(input),
public: {
addRole: mapToPublicFn(addRole),
removeRole: mapToPublicFn(removeRole),
addPriorityRole: mapToPublicFn(addPriorityRole),
removePriorityRole: mapToPublicFn(removePriorityRole),
public(pluginData) {
return {
addRole: makePublicFn(pluginData, addRole),
removeRole: makePublicFn(pluginData, removeRole),
addPriorityRole: makePublicFn(pluginData, addPriorityRole),
removePriorityRole: makePublicFn(pluginData, removePriorityRole),
};
},
beforeLoad(pluginData) {

View file

@ -0,0 +1,6 @@
import { ZeppelinPluginInfo } from "../../types";
export const roleManagerPluginInfo: ZeppelinPluginInfo = {
prettyName: "Role manager",
showInDocs: false,
};

View file

@ -1,9 +1,7 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AddRoleCmd } from "./commands/AddRoleCmd";
import { MassAddRoleCmd } from "./commands/MassAddRoleCmd";
import { MassRemoveRoleCmd } from "./commands/MassRemoveRoleCmd";
@ -32,16 +30,8 @@ const defaultOptions: PluginOptions<RolesPluginType> = {
],
};
export const RolesPlugin = zeppelinGuildPlugin<RolesPluginType>()({
export const RolesPlugin = guildPlugin<RolesPluginType>()({
name: "roles",
showInDocs: true,
info: {
prettyName: "Roles",
description: trimPluginDescription(`
Enables authorised users to add and remove whitelisted roles with a command.
`),
configSchema: zRolesConfig,
},
dependencies: () => [LogsPlugin, RoleManagerPlugin],
configParser: (input) => zRolesConfig.parse(input),

View file

@ -0,0 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { zRolesConfig } from "./types";
export const rolesPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Roles",
description: trimPluginDescription(`
Enables authorised users to add and remove whitelisted roles with a command.
`),
configSchema: zRolesConfig,
};

View file

@ -1,6 +1,4 @@
import { CooldownManager, PluginOptions } from "knub";
import { trimPluginDescription } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { CooldownManager, PluginOptions, guildPlugin } from "knub";
import { RoleAddCmd } from "./commands/RoleAddCmd";
import { RoleHelpCmd } from "./commands/RoleHelpCmd";
import { RoleRemoveCmd } from "./commands/RoleRemoveCmd";
@ -13,60 +11,8 @@ const defaultOptions: PluginOptions<SelfGrantableRolesPluginType> = {
},
};
export const SelfGrantableRolesPlugin = zeppelinGuildPlugin<SelfGrantableRolesPluginType>()({
export const SelfGrantableRolesPlugin = guildPlugin<SelfGrantableRolesPluginType>()({
name: "self_grantable_roles",
showInDocs: true,
info: {
prettyName: "Self-grantable roles",
description: trimPluginDescription(`
Allows users to grant themselves roles via a command
`),
configurationGuide: trimPluginDescription(`
### Basic configuration
In this example, users can add themselves platform roles on the channel 473087035574321152 by using the
\`!role\` command. For example, \`!role pc ps4\` to add both the "pc" and "ps4" roles as specified below.
~~~yml
self_grantable_roles:
config:
entries:
basic:
roles:
"543184300250759188": ["pc", "computer"]
"534710505915547658": ["ps4", "ps", "playstation"]
"473085927053590538": ["xbox", "xb1", "xb"]
overrides:
- channel: "473087035574321152"
config:
entries:
basic:
can_use: true
~~~
### Maximum number of roles
This is identical to the basic example above, but users can only choose 1 role.
~~~yml
self_grantable_roles:
config:
entries:
basic:
roles:
"543184300250759188": ["pc", "computer"]
"534710505915547658": ["ps4", "ps", "playstation"]
"473085927053590538": ["xbox", "xb1", "xb"]
max_roles: 1
overrides:
- channel: "473087035574321152"
config:
entries:
basic:
can_use: true
~~~
`),
configSchema: zSelfGrantableRolesConfig,
},
configParser: (input) => zSelfGrantableRolesConfig.parse(input),
defaultOptions,

View file

@ -0,0 +1,55 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils";
import { zSelfGrantableRolesConfig } from "./types";
export const selfGrantableRolesPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Self-grantable roles",
description: trimPluginDescription(`
Allows users to grant themselves roles via a command
`),
configurationGuide: trimPluginDescription(`
### Basic configuration
In this example, users can add themselves platform roles on the channel 473087035574321152 by using the
\`!role\` command. For example, \`!role pc ps4\` to add both the "pc" and "ps4" roles as specified below.
~~~yml
self_grantable_roles:
config:
entries:
basic:
roles:
"543184300250759188": ["pc", "computer"]
"534710505915547658": ["ps4", "ps", "playstation"]
"473085927053590538": ["xbox", "xb1", "xb"]
overrides:
- channel: "473087035574321152"
config:
entries:
basic:
can_use: true
~~~
### Maximum number of roles
This is identical to the basic example above, but users can only choose 1 role.
~~~yml
self_grantable_roles:
config:
entries:
basic:
roles:
"543184300250759188": ["pc", "computer"]
"534710505915547658": ["ps4", "ps", "playstation"]
"473085927053590538": ["xbox", "xb1", "xb"]
max_roles: 1
overrides:
- channel: "473087035574321152"
config:
entries:
basic:
can_use: true
~~~
`),
configSchema: zSelfGrantableRolesConfig,
};

View file

@ -1,10 +1,9 @@
import { PluginOptions } from "knub";
import { PluginOptions, guildPlugin } from "knub";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { GuildSlowmodes } from "../../data/GuildSlowmodes";
import { SECONDS } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { SlowmodeClearCmd } from "./commands/SlowmodeClearCmd";
import { SlowmodeDisableCmd } from "./commands/SlowmodeDisableCmd";
import { SlowmodeGetCmd } from "./commands/SlowmodeGetCmd";
@ -35,13 +34,8 @@ const defaultOptions: PluginOptions<SlowmodePluginType> = {
],
};
export const SlowmodePlugin = zeppelinGuildPlugin<SlowmodePluginType>()({
export const SlowmodePlugin = guildPlugin<SlowmodePluginType>()({
name: "slowmode",
showInDocs: true,
info: {
prettyName: "Slowmode",
configSchema: zSlowmodeConfig,
},
// prettier-ignore
dependencies: () => [

Some files were not shown because too many files have changed in this diff Show more