3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +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", "iamshoXy",
"Scraayp", "Scraayp",
"app/dependabot", "app/dependabot",
"dependabot[bot]",
"zayKenyon", "zayKenyon",
"rukogit", "rukogit",
"Obliie", "Obliie",
"brawaru", "brawaru",
"Benricheson101", "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!" "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", "service": "devenv",
"remoteUser": "ubuntu", "remoteUser": "ubuntu",
"workspaceFolder": "/home/ubuntu/zeppelin" "workspaceFolder": "/workspace/zeppelin"
} }

View file

@ -1,11 +1,44 @@
.git **/.git
.github **/.github
.idea **/.idea
.devcontainer **/.devcontainer
/docker/development/data /docker/development/data
/docker/production/data /docker/production/data
node_modules **/node_modules
/backend/dist **/dist
/dashboard/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 # 32 character encryption key
KEY= KEY=
@ -17,58 +21,64 @@ STAFF=
# A comma-separated list of server IDs that should be allowed by default # A comma-separated list of server IDs that should be allowed by default
DEFAULT_ALLOWED_SERVERS= 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 # Only required if relevant feature is used
#PHISHERMAN_API_KEY= #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) # DEVELOPMENT
# NOTE: You only need to fill in these values for running the development environment. See production config further below. # 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, # The MySQL database running in the container is exposed to the host on this port,
# allowing access with database tools such as DBeaver # allowing access with database tools such as DBeaver
DOCKER_DEV_MYSQL_PORT=3001 DEVELOPMENT_MYSQL_PORT=3356
# Password for the Zeppelin database user # Password for the Zeppelin database user
DOCKER_DEV_MYSQL_PASSWORD= DEVELOPMENT_MYSQL_PASSWORD=password
# Password for the MySQL root user # 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. # 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. # This is the port that server is exposed to the host on.
DOCKER_DEV_SSH_PORT=3002 DEVELOPMENT_SSH_PORT=3022
DOCKER_DEV_SSH_PASSWORD=password 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 # 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, # The MySQL database running in the container is exposed to the host on this port,
# allowing access with database tools such as DBeaver # allowing access with database tools such as DBeaver
DOCKER_PROD_MYSQL_PORT=3001 STANDALONE_MYSQL_PORT=3356
# Password for the Zeppelin database user # Password for the Zeppelin database user
DOCKER_PROD_MYSQL_PASSWORD= STANDALONE_MYSQL_PASSWORD=
# Password for the MySQL root user # 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= # PRODUCTION - LIGHTWEIGHT
#DB_USER= # NOTE: You only need to fill in these values for running the lightweight production environment
#DB_PASSWORD= # ==========================
#DB_DATABASE=
# 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-errors.txt
/config-schema.json /config-schema.json
*.tsbuildinfo
# Legacy data folders
/docker/development/data
/docker/production/data

View file

@ -1,71 +1 @@
# Zeppelin development environment Moved to [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)
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

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 Moved to [docs/MANAGEMENT.md](docs/MANAGEMENT.md)
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...>
```

View file

@ -1,34 +1 @@
# Zeppelin production environment Moved to [docs/PRODUCTION.md](docs/PRODUCTION.md)
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`

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 For information on how to use the bot, see https://zeppelin.gg/docs
## Development ## 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 ## 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": "", "description": "",
"private": true, "private": true,
"scripts": { "scripts": {
"watch": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node start-dev.js\"", "watch": "tsc-watch --build --onSuccess \"node start-dev.js\"",
"watch-yaml-parse-test": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node dist/backend/src/yamlParseTest.js\"", "watch-yaml-parse-test": "tsc-watch --build --onSuccess \"node dist/yamlParseTest.js\"",
"build": "rimraf dist && tsc", "build": "tsc --build",
"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": "node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/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-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": "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": "node --enable-source-maps --stack-trace-limit=30 dist/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", "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": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-bot-dev\"", "watch-bot": "tsc-watch --build --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": "node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/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-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": "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": "node --enable-source-maps --stack-trace-limit=30 dist/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", "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": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-api-dev\"", "watch-api": "tsc-watch --build --onSuccess \"npm run start-api-dev\"",
"typeorm": "node -r ./register-tsconfig-paths.js ./node_modules/typeorm/cli.js", "typeorm": "node ../node_modules/typeorm/cli.js",
"migrate": "npm run typeorm -- migration:run -d dist/backend/src/data/dataSource.js", "migrate": "npm run typeorm -- migration:run -d dist/data/dataSource.js",
"migrate-prod": "cross-env NODE_ENV=production npm run migrate", "migrate-prod": "npm run migrate",
"migrate-dev": "cross-env NODE_ENV=development npm run build && npm run migrate", "migrate-dev": "npm run build && npm run migrate",
"migrate-rollback": "npm run typeorm -- migration:revert -d dist/backend/src/data/dataSource.js", "migrate-rollback": "npm run typeorm -- migration:revert -d dist/data/dataSource.js",
"migrate-rollback-prod": "cross-env NODE_ENV=production npm run migrate", "migrate-rollback-prod": "npm run migrate-rollback",
"migrate-rollback-dev": "cross-env NODE_ENV=development npm run build && npm run migrate", "migrate-rollback-dev": "npm run build && npm run migrate-rollback",
"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", "validate-active-configs": "node --enable-source-maps dist/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", "export-config-json-schema": "node --enable-source-maps dist/exportSchemas.js > ../config-schema.json",
"test": "npm run build && npm run run-tests", "test": "npm run build && npm run run-tests",
"run-tests": "ava", "run-tests": "ava",
"test-watch": "tsc-watch --onSuccess \"npx ava\"" "test-watch": "tsc-watch --build --onSuccess \"npx ava\""
}, },
"dependencies": { "dependencies": {
"@silvia-odwyer/photon-node": "^0.3.1", "@silvia-odwyer/photon-node": "^0.3.1",
@ -45,7 +45,7 @@
"fp-ts": "^2.0.1", "fp-ts": "^2.0.1",
"humanize-duration": "^3.15.0", "humanize-duration": "^3.15.0",
"js-yaml": "^3.13.1", "js-yaml": "^3.13.1",
"knub": "^32.0.0-next.16", "knub": "^32.0.0-next.21",
"knub-command-manager": "^9.1.0", "knub-command-manager": "^9.1.0",
"last-commit-log": "^2.1.0", "last-commit-log": "^2.1.0",
"lodash.chunk": "^4.2.0", "lodash.chunk": "^4.2.0",
@ -56,7 +56,7 @@
"lodash.pick": "^4.4.0", "lodash.pick": "^4.4.0",
"moment-timezone": "^0.5.21", "moment-timezone": "^0.5.21",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql": "^2.16.0", "mysql2": "^3.9.3",
"parse-color": "^1.0.0", "parse-color": "^1.0.0",
"passport": "^0.6.0", "passport": "^0.6.0",
"passport-custom": "^1.0.5", "passport-custom": "^1.0.5",
@ -102,7 +102,7 @@
}, },
"ava": { "ava": {
"files": [ "files": [
"dist/backend/src/**/*.test.js" "dist/**/*.test.js"
], ],
"require": [ "require": [
"./register-tsconfig-paths.js" "./register-tsconfig-paths.js"

View file

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

View file

@ -51,8 +51,8 @@ function simpleDiscordAPIRequest(bearerToken, path): Promise<any> {
}); });
} }
export function initAuth(app: express.Express) { export function initAuth(router: express.Router) {
app.use(passport.initialize()); router.use(passport.initialize());
passport.serializeUser((user, done) => done(null, user)); passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user as IPassportApiUser)); 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")); router.get("/auth/login", passport.authenticate("oauth2"));
app.get( router.get(
"/auth/oauth-callback", "/auth/oauth-callback",
passport.authenticate("oauth2", { failureRedirect: "/", session: false }), passport.authenticate("oauth2", { failureRedirect: "/", session: false }),
(req: Request, res: Response) => { (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; const key = req.body.key;
if (!key) { if (!key) {
return res.status(400).json({ error: "No key supplied" }); return res.status(400).json({ error: "No key supplied" });
@ -135,14 +135,14 @@ export function initAuth(app: express.Express) {
res.json({ valid: true, userId }); 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); await apiLogins.expireApiKey(req.user!.apiKey);
return ok(res); return ok(res);
}); });
// API route to refresh the given API token's expiry time // 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 // 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); return ok(res);
}); });
} }

View file

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

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions"; import { ApiPermissions } from "@zeppelinbot/shared";
import express, { Request, Response } from "express"; import express, { Request, Response } from "express";
import { YAMLException } from "js-yaml"; import { YAMLException } from "js-yaml";
import moment from "moment-timezone"; 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 express, { Request, Response } from "express";
import moment from "moment-timezone"; import moment from "moment-timezone";
import { z } from "zod"; import { z } from "zod";

View file

@ -3,12 +3,12 @@ import { apiTokenAuthHandlers } from "../auth";
import { initGuildsImportExportAPI } from "./importExport"; import { initGuildsImportExportAPI } from "./importExport";
import { initGuildsMiscAPI } from "./misc"; import { initGuildsMiscAPI } from "./misc";
export function initGuildsAPI(app: express.Express) { export function initGuildsAPI(router: express.Router) {
const guildRouter = express.Router(); const guildRouter = express.Router();
guildRouter.use(...apiTokenAuthHandlers()); guildRouter.use(...apiTokenAuthHandlers());
initGuildsMiscAPI(guildRouter); initGuildsMiscAPI(guildRouter);
initGuildsImportExportAPI(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 express, { Request, Response } from "express";
import { YAMLException } from "js-yaml"; import { YAMLException } from "js-yaml";
import moment from "moment-timezone"; 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 { Request, Response } from "express";
import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments"; import { ApiPermissionAssignments } from "../data/ApiPermissionAssignments";
import { isStaff } from "../staff"; import { isStaff } from "../staff";

View file

@ -10,6 +10,8 @@ import { initGuildsAPI } from "./guilds/index";
import { clientError, error, notFound } from "./responses"; import { clientError, error, notFound } from "./responses";
import { startBackgroundTasks } from "./tasks"; import { startBackgroundTasks } from "./tasks";
const apiPathPrefix = env.API_PATH_PREFIX || (env.NODE_ENV === "development" ? "/api" : "");
const app = express(); const app = express();
app.use( app.use(
@ -24,16 +26,20 @@ app.use(
); );
app.use(multer().none()); app.use(multer().none());
const rootRouter = express.Router();
initAuth(app); initAuth(app);
initGuildsAPI(app); initGuildsAPI(app);
initArchives(app); initArchives(app);
initDocs(app); initDocs(app);
// Default route // Default route
app.get("/", (req, res) => { rootRouter.get("/", (req, res) => {
res.json({ status: "cookies", with: "milk" }); res.json({ status: "cookies", with: "milk" });
}); });
app.use(apiPathPrefix, rootRouter);
// Error response // Error response
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
@ -51,7 +57,7 @@ app.use((req, res, next) => {
return notFound(res); 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 app.listen(port, "0.0.0.0", () => console.log(`API server listening on port ${port}`)); // tslint:disable-line
startBackgroundTasks(); 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 { ZodError } from "zod";
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
import { guildPlugins } from "./plugins/availablePlugins"; import { guildPlugins } from "./plugins/availablePlugins";
import { zZeppelinGuildConfig } from "./types"; import { zZeppelinGuildConfig } from "./types";
import { formatZodIssue } from "./utils/formatZodIssue"; import { formatZodIssue } from "./utils/formatZodIssue";
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>(); const pluginNameToPlugin = new Map<string, GuildPluginBlueprint<any, any>>();
for (const plugin of guildPlugins) { for (const plugin of guildPlugins) {
pluginNameToPlugin.set(plugin.name, plugin); 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 { Repository } from "typeorm";
import { ApiAuditLog } from "./ApiAuditLog"; import { ApiAuditLog } from "./ApiAuditLog";
import { BaseRepository } from "./BaseRepository"; import { BaseRepository } from "./BaseRepository";

View file

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

View file

@ -13,7 +13,6 @@ const envType = z.object({
DASHBOARD_URL: z.string().url(), DASHBOARD_URL: z.string().url(),
API_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 STAFF: z
.preprocess( .preprocess(
@ -39,22 +38,22 @@ const envType = z.object({
PHISHERMAN_API_KEY: z.string().optional(), PHISHERMAN_API_KEY: z.string().optional(),
DOCKER_DEV_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development DB_HOST: z.string().optional(),
DOCKER_PROD_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in production 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"), DEVELOPMENT_MYSQL_PASSWORD: z.string().optional(),
DB_PORT: z
.preprocess((v) => Number(v), z.number()) API_PATH_PREFIX: z.string().optional(),
.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"),
DEBUG: z DEBUG: z
.string() .string()
.optional() .optional()
.transform((str) => str === "true"), .transform((str) => str === "true"),
NODE_ENV: z.string().default("development"),
}); });
let toValidate = { ...process.env }; let toValidate = { ...process.env };
@ -65,11 +64,3 @@ if (fs.existsSync(envPath)) {
} }
export const env = envType.parse(toValidate); 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 { z } from "zod";
import zodToJsonSchema from "zod-to-json-schema"; import zodToJsonSchema from "zod-to-json-schema";
import { guildPlugins } from "./plugins/availablePlugins"; import { guildPluginInfo } from "./plugins/pluginInfo";
import { zZeppelinGuildConfig } from "./types"; import { zZeppelinGuildConfig } from "./types";
const pluginSchemaMap = guildPlugins.reduce((map, plugin) => { const pluginSchemaMap = Object.entries(guildPluginInfo).reduce((map, [pluginName, pluginInfo]) => {
if (!plugin.info) { if (pluginInfo.configSchema) {
return map; map[pluginName] = pluginInfo.configSchema;
} }
map[plugin.name] = plugin.info.configSchema;
return map; return map;
}, {}); }, {});

View file

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

View file

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

View file

@ -61,11 +61,13 @@ export class CreateStarboardTable1544887946307 implements MigrationInterface {
name: "starboard_id", name: "starboard_id",
type: "int", type: "int",
unsigned: true, unsigned: true,
isPrimary: true,
}, },
{ {
name: "message_id", name: "message_id",
type: "bigint", type: "bigint",
unsigned: true, unsigned: true,
isPrimary: true,
}, },
{ {
name: "starboard_message_id", 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> { public async down(queryRunner: QueryRunner): Promise<any> {

View file

@ -10,11 +10,13 @@ export class CreateAutoReactionsTable1547290549908 implements MigrationInterface
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true, unsigned: true,
isPrimary: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true, unsigned: true,
isPrimary: true,
}, },
{ {
name: "reactions", 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> { public async down(queryRunner: QueryRunner): Promise<any> {

View file

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

View file

@ -2,14 +2,10 @@ import { MigrationInterface, QueryRunner, TableColumn, TableIndex } from "typeor
export class AddTypeAndPermissionsToApiPermissions1573158035867 implements MigrationInterface { export class AddTypeAndPermissionsToApiPermissions1573158035867 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> { public async up(queryRunner: QueryRunner): Promise<any> {
try { // We can't use a TableIndex object in dropIndex directly as the table name is included in the generated index name
await queryRunner.dropPrimaryKey("api_permissions"); // and the table name has changed since the original index was created
} catch {} // eslint-disable-line no-empty const originalIndexName = queryRunner.connection.namingStrategy.indexName("dashboard_users", ["user_id"]);
await queryRunner.dropIndex("api_permissions", originalIndexName);
const table = (await queryRunner.getTable("api_permissions"))!;
if (table.indices.length) {
await queryRunner.dropIndex("api_permissions", table.indices[0]);
}
await queryRunner.addColumn( await queryRunner.addColumn(
"api_permissions", "api_permissions",
@ -22,7 +18,11 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
await queryRunner.renameColumn("api_permissions", "user_id", "target_id"); 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"); await queryRunner.dropColumn("api_permissions", "role");
@ -49,7 +49,12 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
} }
public async down(queryRunner: QueryRunner): Promise<any> { 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"); 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"); await queryRunner.renameColumn("api_permissions", "target_id", "user_id");
@ -74,7 +83,5 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
columnNames: ["user_id"], 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 { export class MoveStarboardsToConfig1573248462469 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> { public async up(queryRunner: QueryRunner): Promise<any> {
// Create the new column for the channels id // Create a new column for the channel's id
const chanid_column = new TableColumn({ await queryRunner.addColumn(
name: "starboard_channel_id", "starboard_messages",
type: "bigint", new TableColumn({
unsigned: true, name: "starboard_channel_id",
}); type: "bigint",
await queryRunner.addColumn("starboard_messages", chanid_column); unsigned: true,
}),
);
// Since we are removing the guild_id with the starboards table, we might want it here // Since we are removing the guild_id with the starboards table, we might want it here
const guid_column = new TableColumn({ await queryRunner.addColumn(
name: "guild_id", "starboard_messages",
type: "bigint", new TableColumn({
unsigned: true, name: "guild_id",
}); type: "bigint",
await queryRunner.addColumn("starboard_messages", guid_column); unsigned: true,
}),
);
// Migrate the old starboard_id to the new starboard_channel_id // Migrate the old starboard_id to the new starboard_channel_id
await queryRunner.query(` await queryRunner.query(`
UPDATE starboard_messages AS sm UPDATE starboard_messages AS sm
JOIN starboards AS sb JOIN starboards AS sb
ON sm.starboard_id = sb.id ON sm.starboard_id = sb.id
SET sm.starboard_channel_id = sb.channel_id, sm.guild_id = sb.guild_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 // Set new Primary Key
await queryRunner.dropPrimaryKey("starboard_messages"); await queryRunner.query(`
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_message_id"]); ALTER TABLE starboard_messages
// Finally, drop the starboards channel as it is now obsolete 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); 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", "starboard_channel_id");
await queryRunner.dropColumn("starboard_messages", "guild_id"); await queryRunner.dropColumn("starboard_messages", "guild_id");
const sbId = new TableColumn({ await queryRunner.addColumn(
name: "starboard_id", "starboard_messages",
type: "int", new TableColumn({
unsigned: true, name: "starboard_id",
}); type: "int",
await queryRunner.addColumn("starboard_messages", sbId); unsigned: true,
}),
);
await queryRunner.dropPrimaryKey("starboard_messages"); await queryRunner.query(`
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_id", "message_id"]); ALTER TABLE starboard_messages
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`starboard_id\`, \`message_id\`);
`);
await queryRunner.createTable( await queryRunner.createTable(
new Table({ new Table({

View file

@ -12,7 +12,7 @@ import {
TextBasedChannel, TextBasedChannel,
User, User,
} from "discord.js"; } 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 { isStaff } from "./staff";
import { TZeppelinKnub } from "./types"; import { TZeppelinKnub } from "./types";
import { Tail } from "./utils/typeUtils"; 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 { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AutoDeletePluginType, zAutoDeleteConfig } from "./types"; import { AutoDeletePluginType, zAutoDeleteConfig } from "./types";
import { onMessageCreate } from "./util/onMessageCreate"; import { onMessageCreate } from "./util/onMessageCreate";
import { onMessageDelete } from "./util/onMessageDelete"; 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", 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], dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: (input) => zAutoDeleteConfig.parse(input), 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 { GuildAutoReactions } from "../../data/GuildAutoReactions";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd"; import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd"; import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
import { AddReactionsEvt } from "./events/AddReactionsEvt"; 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", 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 // prettier-ignore
dependencies: () => [ 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 { Queue } from "../../Queue";
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels"; import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
import { GuildArchives } from "../../data/GuildArchives"; import { GuildArchives } from "../../data/GuildArchives";
@ -15,7 +15,6 @@ import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
import { MutesPlugin } from "../Mutes/MutesPlugin"; import { MutesPlugin } from "../Mutes/MutesPlugin";
import { PhishermanPlugin } from "../Phisherman/PhishermanPlugin"; import { PhishermanPlugin } from "../Phisherman/PhishermanPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin"; import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd"; import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd"; import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd"; import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
@ -32,7 +31,6 @@ import {
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges"; import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
import { clearOldRecentActions } from "./functions/clearOldRecentActions"; import { clearOldRecentActions } from "./functions/clearOldRecentActions";
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam"; import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
import { pluginInfo } from "./info";
import { AutomodPluginType, zAutomodConfig } from "./types"; import { AutomodPluginType, zAutomodConfig } from "./types";
const defaultOptions = { const defaultOptions = {
@ -58,10 +56,8 @@ const defaultOptions = {
], ],
}; };
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({ export const AutomodPlugin = guildPlugin<AutomodPluginType>()({
name: "automod", name: "automod",
showInDocs: true,
info: pluginInfo,
// prettier-ignore // prettier-ignore
dependencies: () => [ dependencies: () => [

View file

@ -1,12 +1,12 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils"; 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", prettyName: "Automod",
description: trimPluginDescription(` description: trimPluginDescription(`
Allows specifying automated actions in response to triggers. Example use cases include word filtering and spam prevention. Allows specifying automated actions in response to triggers. Example use cases include word filtering and spam prevention.
`), `),
configurationGuide: trimPluginDescription(` 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. 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}>: Bad custom status on user <@!{user.id}>:
{matchSummary} {matchSummary}
~~~ ~~~
`), `),
configSchema: zAutomodConfig,
}; };

View file

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

View file

@ -1,4 +1,4 @@
import { ApiPermissions } from "@shared/apiPermissions"; import { ApiPermissions } from "@zeppelinbot/shared";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter } from "../../../pluginUtils"; import { isStaffPreFilter } from "../../../pluginUtils";
import { renderUsername } from "../../../utils"; 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 moment from "moment-timezone";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { DBDateFormat, isGuildInvite, resolveInvite } from "../../../utils"; 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 moment from "moment-timezone";
import { commandTypeHelpers as ct } from "../../../commandTypes"; import { commandTypeHelpers as ct } from "../../../commandTypes";
import { isStaffPreFilter } from "../../../pluginUtils"; import { isStaffPreFilter } from "../../../pluginUtils";

View file

@ -1,13 +1,10 @@
import { CaseTypes } from "../../data/CaseTypes"; import { guildPlugin } from "knub";
import { Case } from "../../data/entities/Case";
import { GuildArchives } from "../../data/GuildArchives"; import { GuildArchives } from "../../data/GuildArchives";
import { GuildCases } from "../../data/GuildCases"; import { GuildCases } from "../../data/GuildCases";
import { GuildLogs } from "../../data/GuildLogs"; import { GuildLogs } from "../../data/GuildLogs";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { trimPluginDescription } from "../../utils";
import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin"; import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { createCase } from "./functions/createCase"; import { createCase } from "./functions/createCase";
import { createCaseNote } from "./functions/createCaseNote"; import { createCaseNote } from "./functions/createCaseNote";
import { getCaseEmbed } from "./functions/getCaseEmbed"; import { getCaseEmbed } from "./functions/getCaseEmbed";
@ -16,7 +13,7 @@ import { getCaseTypeAmountForUserId } from "./functions/getCaseTypeAmountForUser
import { getRecentCasesByMod } from "./functions/getRecentCasesByMod"; import { getRecentCasesByMod } from "./functions/getRecentCasesByMod";
import { getTotalCasesByMod } from "./functions/getTotalCasesByMod"; import { getTotalCasesByMod } from "./functions/getTotalCasesByMod";
import { postCaseToCaseLogChannel } from "./functions/postToCaseLogChannel"; 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 // The `any` cast here is to prevent TypeScript from locking up from the circular dependency
function getLogsPlugin(): Promise<any> { function getLogsPlugin(): Promise<any> {
@ -34,51 +31,24 @@ const defaultOptions = {
}, },
}; };
export const CasesPlugin = zeppelinGuildPlugin<CasesPluginType>()({ export const CasesPlugin = guildPlugin<CasesPluginType>()({
name: "cases", 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], dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getLogsPlugin()).LogsPlugin],
configParser: (input) => zCasesConfig.parse(input), configParser: (input) => zCasesConfig.parse(input),
defaultOptions, defaultOptions,
public: { public(pluginData) {
createCase(pluginData) { return {
return (args: CaseArgs) => { createCase: makePublicFn(pluginData, createCase),
return createCase(pluginData, args); createCaseNote: makePublicFn(pluginData, createCaseNote),
}; postCaseToCaseLogChannel: makePublicFn(pluginData, postCaseToCaseLogChannel),
}, getCaseTypeAmountForUserId: makePublicFn(pluginData, getCaseTypeAmountForUserId),
getTotalCasesByMod: makePublicFn(pluginData, getTotalCasesByMod),
createCaseNote(pluginData) { getRecentCasesByMod: makePublicFn(pluginData, getRecentCasesByMod),
return (args: CaseNoteArgs) => { getCaseEmbed: makePublicFn(pluginData, getCaseEmbed),
return createCaseNote(pluginData, args); getCaseSummary: makePublicFn(pluginData, getCaseSummary),
}; };
},
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),
}, },
afterLoad(pluginData) { 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 { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners"; import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { CensorPluginType, zCensorConfig } from "./types"; import { CensorPluginType, zCensorConfig } from "./types";
import { onMessageCreate } from "./util/onMessageCreate"; import { onMessageCreate } from "./util/onMessageCreate";
import { onMessageUpdate } from "./util/onMessageUpdate"; 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", 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], dependencies: () => [LogsPlugin],
configParser: (input) => zCensorConfig.parse(input), 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 z from "zod";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd"; import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd";
import { ChannelArchiverPluginType } from "./types"; import { ChannelArchiverPluginType } from "./types";
export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginType>()({ export const ChannelArchiverPlugin = guildPlugin<ChannelArchiverPluginType>()({
name: "channel_archiver", name: "channel_archiver",
showInDocs: false,
dependencies: () => [TimeAndDatePlugin], dependencies: () => [TimeAndDatePlugin],
configParser: (input) => z.strictObject({}).parse(input), 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 { GuildLogs } from "../../data/GuildLogs";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { VoiceStateUpdateEvt } from "./events/VoiceStateUpdateEvt"; import { VoiceStateUpdateEvt } from "./events/VoiceStateUpdateEvt";
import { CompanionChannelsPluginType, zCompanionChannelsConfig } from "./types"; import { CompanionChannelsPluginType, zCompanionChannelsConfig } from "./types";
@ -12,18 +10,8 @@ const defaultOptions = {
}, },
}; };
export const CompanionChannelsPlugin = zeppelinGuildPlugin<CompanionChannelsPluginType>()({ export const CompanionChannelsPlugin = guildPlugin<CompanionChannelsPluginType>()({
name: "companion_channels", 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], dependencies: () => [LogsPlugin],
configParser: (input) => zCompanionChannelsConfig.parse(input), 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 { GuildCases } from "../../data/GuildCases";
import { trimPluginDescription } from "../../utils";
import { CasesPlugin } from "../Cases/CasesPlugin"; import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { ModActionsPlugin } from "../ModActions/ModActionsPlugin"; import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
import { MutesPlugin } from "../Mutes/MutesPlugin"; import { MutesPlugin } from "../Mutes/MutesPlugin";
import { UtilityPlugin } from "../Utility/UtilityPlugin"; import { UtilityPlugin } from "../Utility/UtilityPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { BanCmd } from "./commands/BanUserCtxCmd"; import { BanCmd } from "./commands/BanUserCtxCmd";
import { CleanCmd } from "./commands/CleanMessageCtxCmd"; import { CleanCmd } from "./commands/CleanMessageCtxCmd";
import { ModMenuCmd } from "./commands/ModMenuUserCtxCmd"; 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", 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], dependencies: () => [CasesPlugin, MutesPlugin, ModActionsPlugin, LogsPlugin, UtilityPlugin],
configParser: (input) => zContextMenusConfig.parse(input), 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 { EventEmitter } from "events";
import { PluginOptions } from "knub"; import { PluginOptions, guildPlugin } from "knub";
import { GuildCounters } from "../../data/GuildCounters"; import { GuildCounters } from "../../data/GuildCounters";
import { CounterTrigger, parseCounterConditionString } from "../../data/entities/CounterTrigger"; import { CounterTrigger, parseCounterConditionString } from "../../data/entities/CounterTrigger";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { MINUTES, convertDelayStringToMS, values } from "../../utils"; import { MINUTES, convertDelayStringToMS, values } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AddCounterCmd } from "./commands/AddCounterCmd"; import { AddCounterCmd } from "./commands/AddCounterCmd";
import { CountersListCmd } from "./commands/CountersListCmd"; import { CountersListCmd } from "./commands/CountersListCmd";
import { ResetAllCounterValuesCmd } from "./commands/ResetAllCounterValuesCmd"; 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). * A single trigger can only trigger once per user/channel/in general, depending on how specific the counter is (e.g. a per-user trigger can only trigger once per user).
* After being triggered, a trigger is "reset" if the counter value no longer matches the trigger (e.g. drops to 100 or below in the above example). After this, that trigger can be triggered again. * After being triggered, a trigger is "reset" if the counter value no longer matches the trigger (e.g. drops to 100 or below in the above example). After this, that trigger can be triggered again.
*/ */
export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()({ export const CountersPlugin = guildPlugin<CountersPluginType>()({
name: "counters", 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, defaultOptions,
// TODO: Separate input and output types // TODO: Separate input and output types
configParser: (input) => zCountersConfig.parse(input), configParser: (input) => zCountersConfig.parse(input),
public: { public(pluginData) {
counterExists: mapToPublicFn(counterExists), return {
counterExists: makePublicFn(pluginData, counterExists),
// Change a counter's value by a relative amount, e.g. +5 changeCounterValue: makePublicFn(pluginData, changeCounterValue),
changeCounterValue: mapToPublicFn(changeCounterValue), setCounterValue: makePublicFn(pluginData, setCounterValue),
getPrettyNameForCounter: makePublicFn(pluginData, getPrettyNameForCounter),
// Set a counter's value to an absolute value getPrettyNameForCounterTrigger: makePublicFn(pluginData, getPrettyNameForCounterTrigger),
setCounterValue: mapToPublicFn(setCounterValue), onCounterEvent: makePublicFn(pluginData, onCounterEvent),
offCounterEvent: makePublicFn(pluginData, offCounterEvent),
getPrettyNameForCounter: mapToPublicFn(getPrettyNameForCounter), };
getPrettyNameForCounterTrigger: mapToPublicFn(getPrettyNameForCounterTrigger),
onCounterEvent: mapToPublicFn(onCounterEvent),
offCounterEvent: mapToPublicFn(offCounterEvent),
}, },
// prettier-ignore // 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 { GuildChannel, GuildMember, User } from "discord.js";
import { guildPluginMessageCommand, parseSignature } from "knub"; import { guildPlugin, guildPluginMessageCommand, parseSignature } from "knub";
import { TSignature } from "knub-command-manager"; import { TSignature } from "knub-command-manager";
import { commandTypes } from "../../commandTypes"; import { commandTypes } from "../../commandTypes";
import { TemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter"; import { TemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
@ -12,7 +12,6 @@ import {
userToTemplateSafeUser, userToTemplateSafeUser,
} from "../../utils/templateSafeObjects"; } from "../../utils/templateSafeObjects";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { runEvent } from "./functions/runEvent"; import { runEvent } from "./functions/runEvent";
import { CustomEventsPluginType, zCustomEventsConfig } from "./types"; import { CustomEventsPluginType, zCustomEventsConfig } from "./types";
@ -22,9 +21,8 @@ const defaultOptions = {
}, },
}; };
export const CustomEventsPlugin = zeppelinGuildPlugin<CustomEventsPluginType>()({ export const CustomEventsPlugin = guildPlugin<CustomEventsPluginType>()({
name: "custom_events", name: "custom_events",
showInDocs: false,
dependencies: () => [LogsPlugin], dependencies: () => [LogsPlugin],
configParser: (input) => zCustomEventsConfig.parse(input), 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 { Guild } from "discord.js";
import { BasePluginType, GlobalPluginData, globalPluginEventListener } from "knub"; import { BasePluginType, GlobalPluginData, globalPlugin, globalPluginEventListener } from "knub";
import z from "zod"; import z from "zod";
import { AllowedGuilds } from "../../data/AllowedGuilds"; import { AllowedGuilds } from "../../data/AllowedGuilds";
import { Configs } from "../../data/Configs"; import { Configs } from "../../data/Configs";
import { env } from "../../env"; import { env } from "../../env";
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
interface GuildAccessMonitorPluginType extends BasePluginType { interface GuildAccessMonitorPluginType extends BasePluginType {
state: { 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 * 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", name: "guild_access_monitor",
configParser: (input) => z.strictObject({}).parse(input), configParser: (input) => z.strictObject({}).parse(input),

View file

@ -1,12 +1,11 @@
import { globalPlugin } from "knub";
import z from "zod"; import z from "zod";
import { Configs } from "../../data/Configs"; import { Configs } from "../../data/Configs";
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds"; import { reloadChangedGuilds } from "./functions/reloadChangedGuilds";
import { GuildConfigReloaderPluginType } from "./types"; import { GuildConfigReloaderPluginType } from "./types";
export const GuildConfigReloaderPlugin = zeppelinGlobalPlugin<GuildConfigReloaderPluginType>()({ export const GuildConfigReloaderPlugin = globalPlugin<GuildConfigReloaderPluginType>()({
name: "guild_config_reloader", name: "guild_config_reloader",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input), 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 { Guild } from "discord.js";
import { guildPluginEventListener } from "knub"; import { guildPlugin, guildPluginEventListener } from "knub";
import z from "zod"; import z from "zod";
import { AllowedGuilds } from "../../data/AllowedGuilds"; import { AllowedGuilds } from "../../data/AllowedGuilds";
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments"; import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
import { MINUTES } from "../../utils"; import { MINUTES } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { GuildInfoSaverPluginType } from "./types"; import { GuildInfoSaverPluginType } from "./types";
export const GuildInfoSaverPlugin = zeppelinGuildPlugin<GuildInfoSaverPluginType>()({ export const GuildInfoSaverPlugin = guildPlugin<GuildInfoSaverPluginType>()({
name: "guild_info_saver", name: "guild_info_saver",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input), 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 z from "zod";
import { GuildMemberCache } from "../../data/GuildMemberCache"; import { GuildMemberCache } from "../../data/GuildMemberCache";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { SECONDS } from "../../utils"; import { SECONDS } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { cancelDeletionOnMemberJoin } from "./events/cancelDeletionOnMemberJoin"; import { cancelDeletionOnMemberJoin } from "./events/cancelDeletionOnMemberJoin";
import { removeMemberCacheOnMemberLeave } from "./events/removeMemberCacheOnMemberLeave"; import { removeMemberCacheOnMemberLeave } from "./events/removeMemberCacheOnMemberLeave";
import { updateMemberCacheOnMemberUpdate } from "./events/updateMemberCacheOnMemberUpdate"; import { updateMemberCacheOnMemberUpdate } from "./events/updateMemberCacheOnMemberUpdate";
@ -14,9 +14,8 @@ import { GuildMemberCachePluginType } from "./types";
const PENDING_SAVE_INTERVAL = 30 * SECONDS; const PENDING_SAVE_INTERVAL = 30 * SECONDS;
export const GuildMemberCachePlugin = zeppelinGuildPlugin<GuildMemberCachePluginType>()({ export const GuildMemberCachePlugin = guildPlugin<GuildMemberCachePluginType>()({
name: "guild_member_cache", name: "guild_member_cache",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input), configParser: (input) => z.strictObject({}).parse(input),
@ -29,8 +28,10 @@ export const GuildMemberCachePlugin = zeppelinGuildPlugin<GuildMemberCachePlugin
cancelDeletionOnMemberJoin, cancelDeletionOnMemberJoin,
], ],
public: { public(pluginData) {
getCachedMemberData: mapToPublicFn(getCachedMemberData), return {
getCachedMemberData: makePublicFn(pluginData, getCachedMemberData),
};
}, },
beforeLoad(pluginData) { 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 z from "zod";
import { Queue } from "../../Queue"; import { Queue } from "../../Queue";
import { Webhooks } from "../../data/Webhooks"; import { Webhooks } from "../../data/Webhooks";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { editMessage } from "./functions/editMessage"; import { editMessage } from "./functions/editMessage";
import { sendMessage } from "./functions/sendMessage"; import { sendMessage } from "./functions/sendMessage";
import { InternalPosterPluginType } from "./types"; import { InternalPosterPluginType } from "./types";
@ -13,17 +12,17 @@ const defaultOptions: PluginOptions<InternalPosterPluginType> = {
overrides: [], overrides: [],
}; };
export const InternalPosterPlugin = zeppelinGuildPlugin<InternalPosterPluginType>()({ export const InternalPosterPlugin = guildPlugin<InternalPosterPluginType>()({
name: "internal_poster", name: "internal_poster",
showInDocs: false,
configParser: (input) => z.strictObject({}).parse(input), configParser: (input) => z.strictObject({}).parse(input),
defaultOptions, defaultOptions,
// prettier-ignore public(pluginData) {
public: { return {
sendMessage: mapToPublicFn(sendMessage), sendMessage: makePublicFn(pluginData, sendMessage),
editMessage: mapToPublicFn(editMessage), editMessage: makePublicFn(pluginData, editMessage),
};
}, },
async beforeLoad(pluginData) { 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 { onGuildEvent } from "../../data/GuildEvents";
import { GuildVCAlerts } from "../../data/GuildVCAlerts"; import { GuildVCAlerts } from "../../data/GuildVCAlerts";
import { trimPluginDescription } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { FollowCmd } from "./commands/FollowCmd"; import { FollowCmd } from "./commands/FollowCmd";
import { DeleteFollowCmd, ListFollowCmd } from "./commands/ListFollowCmd"; import { DeleteFollowCmd, ListFollowCmd } from "./commands/ListFollowCmd";
import { WhereCmd } from "./commands/WhereCmd"; 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", 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), configParser: (input) => zLocateUserConfig.parse(input),
defaultOptions, 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 DefaultLogMessages from "../../data/DefaultLogMessages.json";
import { GuildArchives } from "../../data/GuildArchives"; import { GuildArchives } from "../../data/GuildArchives";
import { GuildCases } from "../../data/GuildCases"; import { GuildCases } from "../../data/GuildCases";
@ -6,11 +6,10 @@ import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { LogType } from "../../data/LogType"; import { LogType } from "../../data/LogType";
import { logger } from "../../logger"; import { logger } from "../../logger";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners"; import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
import { TypedTemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter"; import { createTypedTemplateSafeValueContainer } from "../../templateFormatter";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { LogsChannelCreateEvt, LogsChannelDeleteEvt, LogsChannelUpdateEvt } from "./events/LogsChannelModifyEvts"; import { LogsChannelCreateEvt, LogsChannelDeleteEvt, LogsChannelUpdateEvt } from "./events/LogsChannelModifyEvts";
import { import {
LogsEmojiCreateEvt, LogsEmojiCreateEvt,
@ -31,7 +30,7 @@ import {
import { LogsThreadCreateEvt, LogsThreadDeleteEvt, LogsThreadUpdateEvt } from "./events/LogsThreadModifyEvts"; import { LogsThreadCreateEvt, LogsThreadDeleteEvt, LogsThreadUpdateEvt } from "./events/LogsThreadModifyEvts";
import { LogsGuildMemberUpdateEvt } from "./events/LogsUserUpdateEvts"; import { LogsGuildMemberUpdateEvt } from "./events/LogsUserUpdateEvts";
import { LogsVoiceStateUpdateEvt } from "./events/LogsVoiceChannelEvts"; 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 { getLogMessage } from "./util/getLogMessage";
import { log } from "./util/log"; import { log } from "./util/log";
import { onMessageDelete } from "./util/onMessageDelete"; 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", name: "logs",
showInDocs: true,
info: {
prettyName: "Logs",
configSchema: zLogsConfig,
},
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin], dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin],
configParser: (input) => zLogsConfig.parse(input), configParser: (input) => zLogsConfig.parse(input),
@ -178,86 +172,79 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()({
LogsGuildMemberRoleChangeEvt, LogsGuildMemberRoleChangeEvt,
], ],
public: { public(pluginData) {
getLogMessage: (pluginData) => { return {
return <TLogType extends keyof ILogTypeData>( getLogMessage: makePublicFn(pluginData, getLogMessage),
type: TLogType, logAutomodAction: makePublicFn(pluginData, logAutomodAction),
data: TypedTemplateSafeValueContainer<ILogTypeData[TLogType]>, logBotAlert: makePublicFn(pluginData, logBotAlert),
opts?: Pick<TLogChannel, "format" | "timestamp_format" | "include_embed_timestamp">, logCaseCreate: makePublicFn(pluginData, logCaseCreate),
) => { logCaseDelete: makePublicFn(pluginData, logCaseDelete),
return getLogMessage(pluginData, type, data, opts); logCaseUpdate: makePublicFn(pluginData, logCaseUpdate),
}; logCensor: makePublicFn(pluginData, logCensor),
}, logChannelCreate: makePublicFn(pluginData, logChannelCreate),
logChannelDelete: makePublicFn(pluginData, logChannelDelete),
logAutomodAction: mapToPublicFn(logAutomodAction), logChannelUpdate: makePublicFn(pluginData, logChannelUpdate),
logBotAlert: mapToPublicFn(logBotAlert), logClean: makePublicFn(pluginData, logClean),
logCaseCreate: mapToPublicFn(logCaseCreate), logEmojiCreate: makePublicFn(pluginData, logEmojiCreate),
logCaseDelete: mapToPublicFn(logCaseDelete), logEmojiDelete: makePublicFn(pluginData, logEmojiDelete),
logCaseUpdate: mapToPublicFn(logCaseUpdate), logEmojiUpdate: makePublicFn(pluginData, logEmojiUpdate),
logCensor: mapToPublicFn(logCensor), logMassBan: makePublicFn(pluginData, logMassBan),
logChannelCreate: mapToPublicFn(logChannelCreate), logMassMute: makePublicFn(pluginData, logMassMute),
logChannelDelete: mapToPublicFn(logChannelDelete), logMassUnban: makePublicFn(pluginData, logMassUnban),
logChannelUpdate: mapToPublicFn(logChannelUpdate), logMemberBan: makePublicFn(pluginData, logMemberBan),
logClean: mapToPublicFn(logClean), logMemberForceban: makePublicFn(pluginData, logMemberForceban),
logEmojiCreate: mapToPublicFn(logEmojiCreate), logMemberJoin: makePublicFn(pluginData, logMemberJoin),
logEmojiDelete: mapToPublicFn(logEmojiDelete), logMemberJoinWithPriorRecords: makePublicFn(pluginData, logMemberJoinWithPriorRecords),
logEmojiUpdate: mapToPublicFn(logEmojiUpdate), logMemberKick: makePublicFn(pluginData, logMemberKick),
logMassBan: mapToPublicFn(logMassBan), logMemberLeave: makePublicFn(pluginData, logMemberLeave),
logMassMute: mapToPublicFn(logMassMute), logMemberMute: makePublicFn(pluginData, logMemberMute),
logMassUnban: mapToPublicFn(logMassUnban), logMemberMuteExpired: makePublicFn(pluginData, logMemberMuteExpired),
logMemberBan: mapToPublicFn(logMemberBan), logMemberMuteRejoin: makePublicFn(pluginData, logMemberMuteRejoin),
logMemberForceban: mapToPublicFn(logMemberForceban), logMemberNickChange: makePublicFn(pluginData, logMemberNickChange),
logMemberJoin: mapToPublicFn(logMemberJoin), logMemberNote: makePublicFn(pluginData, logMemberNote),
logMemberJoinWithPriorRecords: mapToPublicFn(logMemberJoinWithPriorRecords), logMemberRestore: makePublicFn(pluginData, logMemberRestore),
logMemberKick: mapToPublicFn(logMemberKick), logMemberRoleAdd: makePublicFn(pluginData, logMemberRoleAdd),
logMemberLeave: mapToPublicFn(logMemberLeave), logMemberRoleChanges: makePublicFn(pluginData, logMemberRoleChanges),
logMemberMute: mapToPublicFn(logMemberMute), logMemberRoleRemove: makePublicFn(pluginData, logMemberRoleRemove),
logMemberMuteExpired: mapToPublicFn(logMemberMuteExpired), logMemberTimedBan: makePublicFn(pluginData, logMemberTimedBan),
logMemberMuteRejoin: mapToPublicFn(logMemberMuteRejoin), logMemberTimedMute: makePublicFn(pluginData, logMemberTimedMute),
logMemberNickChange: mapToPublicFn(logMemberNickChange), logMemberTimedUnban: makePublicFn(pluginData, logMemberTimedUnban),
logMemberNote: mapToPublicFn(logMemberNote), logMemberTimedUnmute: makePublicFn(pluginData, logMemberTimedUnmute),
logMemberRestore: mapToPublicFn(logMemberRestore), logMemberUnban: makePublicFn(pluginData, logMemberUnban),
logMemberRoleAdd: mapToPublicFn(logMemberRoleAdd), logMemberUnmute: makePublicFn(pluginData, logMemberUnmute),
logMemberRoleChanges: mapToPublicFn(logMemberRoleChanges), logMemberWarn: makePublicFn(pluginData, logMemberWarn),
logMemberRoleRemove: mapToPublicFn(logMemberRoleRemove), logMessageDelete: makePublicFn(pluginData, logMessageDelete),
logMemberTimedBan: mapToPublicFn(logMemberTimedBan), logMessageDeleteAuto: makePublicFn(pluginData, logMessageDeleteAuto),
logMemberTimedMute: mapToPublicFn(logMemberTimedMute), logMessageDeleteBare: makePublicFn(pluginData, logMessageDeleteBare),
logMemberTimedUnban: mapToPublicFn(logMemberTimedUnban), logMessageDeleteBulk: makePublicFn(pluginData, logMessageDeleteBulk),
logMemberTimedUnmute: mapToPublicFn(logMemberTimedUnmute), logMessageEdit: makePublicFn(pluginData, logMessageEdit),
logMemberUnban: mapToPublicFn(logMemberUnban), logMessageSpamDetected: makePublicFn(pluginData, logMessageSpamDetected),
logMemberUnmute: mapToPublicFn(logMemberUnmute), logOtherSpamDetected: makePublicFn(pluginData, logOtherSpamDetected),
logMemberWarn: mapToPublicFn(logMemberWarn), logPostedScheduledMessage: makePublicFn(pluginData, logPostedScheduledMessage),
logMessageDelete: mapToPublicFn(logMessageDelete), logRepeatedMessage: makePublicFn(pluginData, logRepeatedMessage),
logMessageDeleteAuto: mapToPublicFn(logMessageDeleteAuto), logRoleCreate: makePublicFn(pluginData, logRoleCreate),
logMessageDeleteBare: mapToPublicFn(logMessageDeleteBare), logRoleDelete: makePublicFn(pluginData, logRoleDelete),
logMessageDeleteBulk: mapToPublicFn(logMessageDeleteBulk), logRoleUpdate: makePublicFn(pluginData, logRoleUpdate),
logMessageEdit: mapToPublicFn(logMessageEdit), logScheduledMessage: makePublicFn(pluginData, logScheduledMessage),
logMessageSpamDetected: mapToPublicFn(logMessageSpamDetected), logScheduledRepeatedMessage: makePublicFn(pluginData, logScheduledRepeatedMessage),
logOtherSpamDetected: mapToPublicFn(logOtherSpamDetected), logSetAntiraidAuto: makePublicFn(pluginData, logSetAntiraidAuto),
logPostedScheduledMessage: mapToPublicFn(logPostedScheduledMessage), logSetAntiraidUser: makePublicFn(pluginData, logSetAntiraidUser),
logRepeatedMessage: mapToPublicFn(logRepeatedMessage), logStageInstanceCreate: makePublicFn(pluginData, logStageInstanceCreate),
logRoleCreate: mapToPublicFn(logRoleCreate), logStageInstanceDelete: makePublicFn(pluginData, logStageInstanceDelete),
logRoleDelete: mapToPublicFn(logRoleDelete), logStageInstanceUpdate: makePublicFn(pluginData, logStageInstanceUpdate),
logRoleUpdate: mapToPublicFn(logRoleUpdate), logStickerCreate: makePublicFn(pluginData, logStickerCreate),
logScheduledMessage: mapToPublicFn(logScheduledMessage), logStickerDelete: makePublicFn(pluginData, logStickerDelete),
logScheduledRepeatedMessage: mapToPublicFn(logScheduledRepeatedMessage), logStickerUpdate: makePublicFn(pluginData, logStickerUpdate),
logSetAntiraidAuto: mapToPublicFn(logSetAntiraidAuto), logThreadCreate: makePublicFn(pluginData, logThreadCreate),
logSetAntiraidUser: mapToPublicFn(logSetAntiraidUser), logThreadDelete: makePublicFn(pluginData, logThreadDelete),
logStageInstanceCreate: mapToPublicFn(logStageInstanceCreate), logThreadUpdate: makePublicFn(pluginData, logThreadUpdate),
logStageInstanceDelete: mapToPublicFn(logStageInstanceDelete), logVoiceChannelForceDisconnect: makePublicFn(pluginData, logVoiceChannelForceDisconnect),
logStageInstanceUpdate: mapToPublicFn(logStageInstanceUpdate), logVoiceChannelForceMove: makePublicFn(pluginData, logVoiceChannelForceMove),
logStickerCreate: mapToPublicFn(logStickerCreate), logVoiceChannelJoin: makePublicFn(pluginData, logVoiceChannelJoin),
logStickerDelete: mapToPublicFn(logStickerDelete), logVoiceChannelLeave: makePublicFn(pluginData, logVoiceChannelLeave),
logStickerUpdate: mapToPublicFn(logStickerUpdate), logVoiceChannelMove: makePublicFn(pluginData, logVoiceChannelMove),
logThreadCreate: mapToPublicFn(logThreadCreate), logDmFailed: makePublicFn(pluginData, logDmFailed),
logThreadDelete: mapToPublicFn(logThreadDelete), };
logThreadUpdate: mapToPublicFn(logThreadUpdate),
logVoiceChannelForceDisconnect: mapToPublicFn(logVoiceChannelForceDisconnect),
logVoiceChannelForceMove: mapToPublicFn(logVoiceChannelForceMove),
logVoiceChannelJoin: mapToPublicFn(logVoiceChannelJoin),
logVoiceChannelLeave: mapToPublicFn(logVoiceChannelLeave),
logVoiceChannelMove: mapToPublicFn(logVoiceChannelMove),
logDmFailed: mapToPublicFn(logDmFailed),
}, },
beforeLoad(pluginData) { 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 { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { SaveMessagesToDBCmd } from "./commands/SaveMessagesToDB"; import { SaveMessagesToDBCmd } from "./commands/SaveMessagesToDB";
import { SavePinsToDBCmd } from "./commands/SavePinsToDB"; import { SavePinsToDBCmd } from "./commands/SavePinsToDB";
import { MessageCreateEvt, MessageDeleteBulkEvt, MessageDeleteEvt, MessageUpdateEvt } from "./events/SaveMessagesEvts"; 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", name: "message_saver",
showInDocs: false,
configParser: (input) => zMessageSaverConfig.parse(input), configParser: (input) => zMessageSaverConfig.parse(input),
defaultOptions, 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 { EventEmitter } from "events";
import { guildPlugin } from "knub";
import { Queue } from "../../Queue"; import { Queue } from "../../Queue";
import { GuildCases } from "../../data/GuildCases"; import { GuildCases } from "../../data/GuildCases";
import { onGuildEvent } from "../../data/GuildEvents"; import { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs"; import { GuildLogs } from "../../data/GuildLogs";
import { GuildMutes } from "../../data/GuildMutes"; import { GuildMutes } from "../../data/GuildMutes";
import { GuildTempbans } from "../../data/GuildTempbans"; import { GuildTempbans } from "../../data/GuildTempbans";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn, mapToPublicFn } from "../../pluginUtils";
import { MINUTES, trimPluginDescription } from "../../utils"; import { MINUTES } from "../../utils";
import { CasesPlugin } from "../Cases/CasesPlugin"; import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { MutesPlugin } from "../Mutes/MutesPlugin"; import { MutesPlugin } from "../Mutes/MutesPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AddCaseMsgCmd } from "./commands/addcase/AddCaseMsgCmd"; import { AddCaseMsgCmd } from "./commands/addcase/AddCaseMsgCmd";
import { AddCaseSlashCmd } from "./commands/addcase/AddCaseSlashCmd"; import { AddCaseSlashCmd } from "./commands/addcase/AddCaseSlashCmd";
import { BanMsgCmd } from "./commands/ban/BanMsgCmd"; import { BanMsgCmd } from "./commands/ban/BanMsgCmd";
@ -71,15 +71,7 @@ import { offModActionsEvent } from "./functions/offModActionsEvent";
import { onModActionsEvent } from "./functions/onModActionsEvent"; import { onModActionsEvent } from "./functions/onModActionsEvent";
import { updateCase } from "./functions/updateCase"; import { updateCase } from "./functions/updateCase";
import { warnMember } from "./functions/warnMember"; import { warnMember } from "./functions/warnMember";
import { import { AttachmentLinkReactionType, ModActionsPluginType, modActionsSlashGroup, zModActionsConfig } from "./types";
AttachmentLinkReactionType,
BanOptions,
KickOptions,
ModActionsPluginType,
WarnOptions,
modActionsSlashGroup,
zModActionsConfig,
} from "./types";
const defaultOptions = { const defaultOptions = {
config: { config: {
@ -147,16 +139,8 @@ const defaultOptions = {
], ],
}; };
export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({ export const ModActionsPlugin = guildPlugin<ModActionsPluginType>()({
name: "mod_actions", 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], dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
configParser: (input) => zModActionsConfig.parse(input), configParser: (input) => zModActionsConfig.parse(input),
@ -218,66 +202,21 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
DeleteCaseMsgCmd, DeleteCaseMsgCmd,
], ],
public: { public(pluginData) {
warnMember(pluginData) { return {
return (member: GuildMember, reason: string, reasonWithAttachments: string, warnOptions?: WarnOptions) => { warnMember: makePublicFn(pluginData, warnMember),
return warnMember(pluginData, member, reason, reasonWithAttachments, warnOptions); 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()]),
kickMember(pluginData) { hasNotePermission: makePublicFn(pluginData, hasNotePermission),
return (member: GuildMember, reason: string, reasonWithAttachments: string, kickOptions?: KickOptions) => { hasWarnPermission: makePublicFn(pluginData, hasWarnPermission),
kickMember(pluginData, member, reason, reasonWithAttachments, kickOptions); hasMutePermission: makePublicFn(pluginData, hasMutePermission),
}; hasBanPermission: makePublicFn(pluginData, hasBanPermission),
}, on: mapToPublicFn(onModActionsEvent),
off: mapToPublicFn(offModActionsEvent),
banUserId(pluginData) { getEventEmitter: () => pluginData.state.events,
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;
},
}, },
beforeLoad(pluginData) { 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 { GuildMember, Snowflake } from "discord.js";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { guildPlugin } from "knub";
import { GuildArchives } from "../../data/GuildArchives"; import { GuildArchives } from "../../data/GuildArchives";
import { GuildCases } from "../../data/GuildCases"; import { GuildCases } from "../../data/GuildCases";
import { onGuildEvent } from "../../data/GuildEvents"; import { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs"; import { GuildLogs } from "../../data/GuildLogs";
import { GuildMutes } from "../../data/GuildMutes"; import { GuildMutes } from "../../data/GuildMutes";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { CasesPlugin } from "../Cases/CasesPlugin"; import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin.js"; import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin.js";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { ClearBannedMutesCmd } from "./commands/ClearBannedMutesCmd"; import { ClearBannedMutesCmd } from "./commands/ClearBannedMutesCmd";
import { ClearMutesCmd } from "./commands/ClearMutesCmd"; import { ClearMutesCmd } from "./commands/ClearMutesCmd";
import { ClearMutesWithoutRoleCmd } from "./commands/ClearMutesWithoutRoleCmd"; import { ClearMutesWithoutRoleCmd } from "./commands/ClearMutesWithoutRoleCmd";
@ -61,13 +61,8 @@ const defaultOptions = {
], ],
}; };
export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({ export const MutesPlugin = guildPlugin<MutesPluginType>()({
name: "mutes", name: "mutes",
showInDocs: true,
info: {
prettyName: "Mutes",
configSchema: zMutesConfig,
},
dependencies: () => [CasesPlugin, LogsPlugin, RoleManagerPlugin], dependencies: () => [CasesPlugin, LogsPlugin, RoleManagerPlugin],
configParser: (input) => zMutesConfig.parse(input), configParser: (input) => zMutesConfig.parse(input),
@ -89,21 +84,18 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({
RegisterManualTimeoutsEvt, RegisterManualTimeoutsEvt,
], ],
public: { public(pluginData) {
muteUser: mapToPublicFn(muteUser), return {
unmuteUser: mapToPublicFn(unmuteUser), muteUser: makePublicFn(pluginData, muteUser),
hasMutedRole(pluginData) { unmuteUser: makePublicFn(pluginData, unmuteUser),
return (member: GuildMember) => { hasMutedRole: (member: GuildMember) => {
const muteRole = pluginData.config.get().mute_role; const muteRole = pluginData.config.get().mute_role;
return muteRole ? member.roles.cache.has(muteRole as Snowflake) : false; return muteRole ? member.roles.cache.has(muteRole as Snowflake) : false;
}; },
}, on: makePublicFn(pluginData, onMutesEvent),
off: makePublicFn(pluginData, offMutesEvent),
on: mapToPublicFn(onMutesEvent), getEventEmitter: () => pluginData.state.events,
off: mapToPublicFn(offMutesEvent), };
getEventEmitter(pluginData) {
return () => pluginData.state.events;
},
}, },
beforeLoad(pluginData) { 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 { Queue } from "../../Queue";
import { GuildNicknameHistory } from "../../data/GuildNicknameHistory"; import { GuildNicknameHistory } from "../../data/GuildNicknameHistory";
import { UsernameHistory } from "../../data/UsernameHistory"; import { UsernameHistory } from "../../data/UsernameHistory";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { NamesCmd } from "./commands/NamesCmd"; import { NamesCmd } from "./commands/NamesCmd";
import { NameHistoryPluginType, zNameHistoryConfig } from "./types"; 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", name: "name_history",
showInDocs: false,
configParser: (input) => zNameHistoryConfig.parse(input), configParser: (input) => zNameHistoryConfig.parse(input),
defaultOptions, 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 { GuildLogs } from "../../data/GuildLogs";
import { GuildPersistedData } from "../../data/GuildPersistedData"; import { GuildPersistedData } from "../../data/GuildPersistedData";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin"; import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { LoadDataEvt } from "./events/LoadDataEvt"; import { LoadDataEvt } from "./events/LoadDataEvt";
import { StoreDataEvt } from "./events/StoreDataEvt"; import { StoreDataEvt } from "./events/StoreDataEvt";
import { PersistPluginType, zPersistConfig } from "./types"; 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", 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], dependencies: () => [LogsPlugin, RoleManagerPlugin],
configParser: (input) => zPersistConfig.parse(input), 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 { hasPhishermanMasterAPIKey, phishermanApiKeyIsValid } from "../../data/Phisherman";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { getDomainInfo } from "./functions/getDomainInfo"; import { getDomainInfo } from "./functions/getDomainInfo";
import { pluginInfo } from "./info";
import { PhishermanPluginType, zPhishermanConfig } from "./types"; import { PhishermanPluginType, zPhishermanConfig } from "./types";
const defaultOptions: PluginOptions<PhishermanPluginType> = { const defaultOptions: PluginOptions<PhishermanPluginType> = {
@ -13,17 +11,16 @@ const defaultOptions: PluginOptions<PhishermanPluginType> = {
overrides: [], overrides: [],
}; };
export const PhishermanPlugin = zeppelinGuildPlugin<PhishermanPluginType>()({ export const PhishermanPlugin = guildPlugin<PhishermanPluginType>()({
name: "phisherman", name: "phisherman",
showInDocs: true,
info: pluginInfo,
configParser: (input) => zPhishermanConfig.parse(input), configParser: (input) => zPhishermanConfig.parse(input),
defaultOptions, defaultOptions,
// prettier-ignore public(pluginData) {
public: { return {
getDomainInfo: mapToPublicFn(getDomainInfo), getDomainInfo: makePublicFn(pluginData, getDomainInfo),
};
}, },
async beforeLoad(pluginData) { async beforeLoad(pluginData) {

View file

@ -1,8 +1,8 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils"; import { trimPluginDescription } from "../../utils";
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
import { zPhishermanConfig } from "./types"; import { zPhishermanConfig } from "./types";
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = { export const phishermanPluginInfo: ZeppelinPluginInfo = {
prettyName: "Phisherman", prettyName: "Phisherman",
description: trimPluginDescription(` description: trimPluginDescription(`
Match scam/phishing links using the Phisherman API. See https://phisherman.gg/ for more details! 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, 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 { GuildPingableRoles } from "../../data/GuildPingableRoles";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { PingableRoleDisableCmd } from "./commands/PingableRoleDisableCmd"; import { PingableRoleDisableCmd } from "./commands/PingableRoleDisableCmd";
import { PingableRoleEnableCmd } from "./commands/PingableRoleEnableCmd"; import { PingableRoleEnableCmd } from "./commands/PingableRoleEnableCmd";
import { PingableRolesPluginType, zPingableRolesConfig } from "./types"; 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", name: "pingable_roles",
showInDocs: true,
info: {
prettyName: "Pingable roles",
configSchema: zPingableRolesConfig,
},
configParser: (input) => zPingableRolesConfig.parse(input), configParser: (input) => zPingableRolesConfig.parse(input),
defaultOptions, 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 { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs"; import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { GuildScheduledPosts } from "../../data/GuildScheduledPosts"; import { GuildScheduledPosts } from "../../data/GuildScheduledPosts";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { EditCmd } from "./commands/EditCmd"; import { EditCmd } from "./commands/EditCmd";
import { EditEmbedCmd } from "./commands/EditEmbedCmd"; import { EditEmbedCmd } from "./commands/EditEmbedCmd";
import { PostCmd } from "./commands/PostCmd"; 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", name: "post",
showInDocs: true,
info: {
prettyName: "Post",
configSchema: zPostConfig,
},
dependencies: () => [TimeAndDatePlugin, LogsPlugin], dependencies: () => [TimeAndDatePlugin, LogsPlugin],
configParser: (input) => zPostConfig.parse(input), 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 { Queue } from "../../Queue";
import { GuildReactionRoles } from "../../data/GuildReactionRoles"; import { GuildReactionRoles } from "../../data/GuildReactionRoles";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { ClearReactionRolesCmd } from "./commands/ClearReactionRolesCmd"; import { ClearReactionRolesCmd } from "./commands/ClearReactionRolesCmd";
import { InitReactionRolesCmd } from "./commands/InitReactionRolesCmd"; import { InitReactionRolesCmd } from "./commands/InitReactionRolesCmd";
import { RefreshReactionRolesCmd } from "./commands/RefreshReactionRolesCmd"; 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", 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], dependencies: () => [LogsPlugin],
configParser: (input) => zReactionRolesConfig.parse(input), 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 { onGuildEvent } from "../../data/GuildEvents";
import { GuildReminders } from "../../data/GuildReminders"; import { GuildReminders } from "../../data/GuildReminders";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { RemindCmd } from "./commands/RemindCmd"; import { RemindCmd } from "./commands/RemindCmd";
import { RemindersCmd } from "./commands/RemindersCmd"; import { RemindersCmd } from "./commands/RemindersCmd";
import { RemindersDeleteCmd } from "./commands/RemindersDeleteCmd"; 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", name: "reminders",
showInDocs: true,
info: {
prettyName: "Reminders",
configSchema: zRemindersConfig,
},
dependencies: () => [TimeAndDatePlugin], dependencies: () => [TimeAndDatePlugin],
configParser: (input) => zRemindersConfig.parse(input), 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 { GuildRoleButtons } from "../../data/GuildRoleButtons";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin"; import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { resetButtonsCmd } from "./commands/resetButtons"; import { resetButtonsCmd } from "./commands/resetButtons";
import { onButtonInteraction } from "./events/buttonInteraction"; import { onButtonInteraction } from "./events/buttonInteraction";
import { applyAllRoleButtons } from "./functions/applyAllRoleButtons"; import { applyAllRoleButtons } from "./functions/applyAllRoleButtons";
import { pluginInfo } from "./info";
import { RoleButtonsPluginType, zRoleButtonsConfig } from "./types"; import { RoleButtonsPluginType, zRoleButtonsConfig } from "./types";
export const RoleButtonsPlugin = zeppelinGuildPlugin<RoleButtonsPluginType>()({ export const RoleButtonsPlugin = guildPlugin<RoleButtonsPluginType>()({
name: "role_buttons", name: "role_buttons",
info: pluginInfo,
showInDocs: true,
defaultOptions: { defaultOptions: {
config: { config: {

View file

@ -1,8 +1,9 @@
import { ZeppelinPluginInfo } from "../../types";
import { trimPluginDescription } from "../../utils"; import { trimPluginDescription } from "../../utils";
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
import { zRoleButtonsConfig } from "./types"; import { zRoleButtonsConfig } from "./types";
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = { export const roleButtonsPluginInfo: ZeppelinPluginInfo = {
showInDocs: true,
prettyName: "Role buttons", prettyName: "Role buttons",
description: trimPluginDescription(` description: trimPluginDescription(`
Allow users to pick roles by clicking on buttons 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 { GuildRoleQueue } from "../../data/GuildRoleQueue";
import { mapToPublicFn } from "../../pluginUtils"; import { makePublicFn } from "../../pluginUtils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { addPriorityRole } from "./functions/addPriorityRole"; import { addPriorityRole } from "./functions/addPriorityRole";
import { addRole } from "./functions/addRole"; import { addRole } from "./functions/addRole";
import { removePriorityRole } from "./functions/removePriorityRole"; import { removePriorityRole } from "./functions/removePriorityRole";
@ -9,18 +9,19 @@ import { removeRole } from "./functions/removeRole";
import { runRoleAssignmentLoop } from "./functions/runRoleAssignmentLoop"; import { runRoleAssignmentLoop } from "./functions/runRoleAssignmentLoop";
import { RoleManagerPluginType, zRoleManagerConfig } from "./types"; import { RoleManagerPluginType, zRoleManagerConfig } from "./types";
export const RoleManagerPlugin = zeppelinGuildPlugin<RoleManagerPluginType>()({ export const RoleManagerPlugin = guildPlugin<RoleManagerPluginType>()({
name: "role_manager", name: "role_manager",
showInDocs: false,
dependencies: () => [LogsPlugin], dependencies: () => [LogsPlugin],
configParser: (input) => zRoleManagerConfig.parse(input), configParser: (input) => zRoleManagerConfig.parse(input),
public: { public(pluginData) {
addRole: mapToPublicFn(addRole), return {
removeRole: mapToPublicFn(removeRole), addRole: makePublicFn(pluginData, addRole),
addPriorityRole: mapToPublicFn(addPriorityRole), removeRole: makePublicFn(pluginData, removeRole),
removePriorityRole: mapToPublicFn(removePriorityRole), addPriorityRole: makePublicFn(pluginData, addPriorityRole),
removePriorityRole: makePublicFn(pluginData, removePriorityRole),
};
}, },
beforeLoad(pluginData) { 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 { GuildLogs } from "../../data/GuildLogs";
import { trimPluginDescription } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin"; import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { AddRoleCmd } from "./commands/AddRoleCmd"; import { AddRoleCmd } from "./commands/AddRoleCmd";
import { MassAddRoleCmd } from "./commands/MassAddRoleCmd"; import { MassAddRoleCmd } from "./commands/MassAddRoleCmd";
import { MassRemoveRoleCmd } from "./commands/MassRemoveRoleCmd"; 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", 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], dependencies: () => [LogsPlugin, RoleManagerPlugin],
configParser: (input) => zRolesConfig.parse(input), 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 { CooldownManager, PluginOptions, guildPlugin } from "knub";
import { trimPluginDescription } from "../../utils";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { RoleAddCmd } from "./commands/RoleAddCmd"; import { RoleAddCmd } from "./commands/RoleAddCmd";
import { RoleHelpCmd } from "./commands/RoleHelpCmd"; import { RoleHelpCmd } from "./commands/RoleHelpCmd";
import { RoleRemoveCmd } from "./commands/RoleRemoveCmd"; 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", 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), configParser: (input) => zSelfGrantableRolesConfig.parse(input),
defaultOptions, 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 { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { GuildSlowmodes } from "../../data/GuildSlowmodes"; import { GuildSlowmodes } from "../../data/GuildSlowmodes";
import { SECONDS } from "../../utils"; import { SECONDS } from "../../utils";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { SlowmodeClearCmd } from "./commands/SlowmodeClearCmd"; import { SlowmodeClearCmd } from "./commands/SlowmodeClearCmd";
import { SlowmodeDisableCmd } from "./commands/SlowmodeDisableCmd"; import { SlowmodeDisableCmd } from "./commands/SlowmodeDisableCmd";
import { SlowmodeGetCmd } from "./commands/SlowmodeGetCmd"; 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", name: "slowmode",
showInDocs: true,
info: {
prettyName: "Slowmode",
configSchema: zSlowmodeConfig,
},
// prettier-ignore // prettier-ignore
dependencies: () => [ dependencies: () => [

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