Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
b485b5d420 | |||
1c50e818b0 | |||
8cb74a1291 | |||
4bf782cddf | |||
c6a4577872 | |||
3594c2ea8c | |||
538d039c5c | |||
da1996f2ff | |||
d5b75b12c8 | |||
|
a71dbecf8c | ||
|
f528d107da | ||
9510116a37 | |||
b8508a4a82 | |||
ccf2fd9361 | |||
cb4bddf983 | |||
b1b087e32c | |||
451b414fba | |||
|
b53c08a553 | ||
f34e06d31f | |||
173438395e | |||
59429ea548 | |||
dbb64baae3 | |||
eccb379b51 | |||
cb5516246f | |||
|
63c67f4992 |
3
.npmrc
Normal file
3
.npmrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@astrogd:registry=https://git.astrogd.cloud/api/packages/packages/npm/
|
||||||
|
@internal:registry=https://git.astrogd.cloud/api/packages/internal/npm/
|
||||||
|
//git.astrogd.cloud/api/packages/internal/npm/:_authToken=${NPM_TOKEN}
|
25
Changelog.md
25
Changelog.md
@ -1,9 +1,30 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
This file is used to list changes made to this software.
|
This file is used to list changes made to this software.
|
||||||
|
|
||||||
## V1.0.0 [2022-11-29]
|
_Current development release: 1.1.1_
|
||||||
_Current development version: **1.0.0**_
|
|
||||||
|
## V1.1.1 [2023-09-16]
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
- Updated packages to latest versions
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- Fixed a bug where the bot would crash on startup if the database connection establishment took too long
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- Renamed db service in docker compose file from database to db
|
||||||
|
|
||||||
|
## V1.1.0 [2022-11-29]
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
- If a channel gets deleted and the responsible user has been detected, a message will be sent to that user informing him of the deletion
|
||||||
|
|
||||||
|
## V1.0.0 [2022-11-29]
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
- /info
|
- /info
|
||||||
- /logchannel
|
- /logchannel
|
||||||
- /blocklist get
|
- /blocklist get
|
||||||
|
20
README.md
20
README.md
@ -1,40 +1,53 @@
|
|||||||
# eu.astrogd.white-leopard
|
# eu.astrogd.white-leopard
|
||||||
|
|
||||||
A Discord bot that checks Discord channel names for banned words and prevents renaming of them
|
A Discord bot that checks Discord channel names for banned words and prevents renaming of them
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
### /logchanel [channel?] `Permission: MANAGE_GUILD`
|
### /logchanel [channel?] `Permission: MANAGE_GUILD`
|
||||||
|
|
||||||
Sets the channel where the bot will log if a channel meets the banned word criteria. If channel is omitted, the log channel will be disabled.
|
Sets the channel where the bot will log if a channel meets the banned word criteria. If channel is omitted, the log channel will be disabled.
|
||||||
|
|
||||||
### /blocklist `Permission: MANAGE_GUILD`
|
### /blocklist `Permission: MANAGE_GUILD`
|
||||||
|
|
||||||
#### /blocklist get
|
#### /blocklist get
|
||||||
|
|
||||||
Returns the global and server specific banned word list and returns it (Same behaviour as /showblocklist)
|
Returns the global and server specific banned word list and returns it (Same behaviour as /showblocklist)
|
||||||
|
|
||||||
#### /blocklist add [word]
|
#### /blocklist add [word]
|
||||||
|
|
||||||
Adds the word to the server specific blocklist
|
Adds the word to the server specific blocklist
|
||||||
|
|
||||||
#### /blocklist remove [word]
|
#### /blocklist remove [word]
|
||||||
|
|
||||||
Removes the word from the server specific blocklist
|
Removes the word from the server specific blocklist
|
||||||
|
|
||||||
### /info `Permission: EVERYONE`
|
### /info `Permission: EVERYONE`
|
||||||
|
|
||||||
Returns general information about the bot and the servers stats
|
Returns general information about the bot and the servers stats
|
||||||
|
|
||||||
### /preservesettings `Permission: ADMINISTRATOR`
|
### /preservesettings `Permission: ADMINISTRATOR`
|
||||||
|
|
||||||
Changes the behaviour when the bot leaves the server.
|
Changes the behaviour when the bot leaves the server.
|
||||||
Options are:
|
Options are:
|
||||||
|
|
||||||
- Keep settings persistent even if the bot leaves
|
- Keep settings persistent even if the bot leaves
|
||||||
- Delete setting when the bot leaves the server [default]
|
- Delete setting when the bot leaves the server [default]
|
||||||
|
|
||||||
### /showblocklist `Permission: MANAGE_CHANNELS`
|
### /showblocklist `Permission: MANAGE_CHANNELS`
|
||||||
|
|
||||||
Returns the global and server specific banned word list and returns it
|
Returns the global and server specific banned word list and returns it
|
||||||
|
|
||||||
### /showsettings `Permission: MANAGE_GUILD`
|
### /showsettings `Permission: MANAGE_GUILD`
|
||||||
|
|
||||||
Returns the current settings for the server
|
Returns the current settings for the server
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
| Name | Description | Required | Example |
|
| Name | Description | Required | Example |
|
||||||
| :--------------- | :------------------------------------------------------------------------------ | :------: | :------------------ |
|
| :--------------- | :------------------------------------------------------------------------------ | :------: | :------------------ |
|
||||||
| TOKEN | Discord bot token to log into the API with | ▶️/🚀 | NzYzMDP3MzE1Mzky... |
|
| TOKEN | Discord bot token to log into the API with | ▶️/🚀 | NzYzMDP3MzE1Mzky... |
|
||||||
| DB_HOST | Hostname of the database | ▶️ | 127.0.0.1:3546 |
|
| DB_HOST | Hostname of the database | ▶️ | 127.0.0.1 |
|
||||||
| DB_USERNAME | Username of the database | ▶️ | root |
|
| DB_USERNAME | Username of the database | ▶️ | root |
|
||||||
| DB_PASSWORD | Password of the database | ▶️ | abc123 |
|
| DB_PASSWORD | Password of the database | ▶️ | abc123 |
|
||||||
| DB_DATABASE | Database name | ▶️ | white-leopard |
|
| DB_DATABASE | Database name | ▶️ | white-leopard |
|
||||||
@ -42,6 +55,7 @@ Returns the current settings for the server
|
|||||||
| DEPLOY_TOKEN | Production Discord bot token to log into the API with | 🚀 | NzYzMDP3MzE1Mzky... |
|
| DEPLOY_TOKEN | Production Discord bot token to log into the API with | 🚀 | NzYzMDP3MzE1Mzky... |
|
||||||
| DEPLOY_CLIENT_ID | Production Client ID of the Discord appication associated with the deploy token | 🚀 | 763035392692274 |
|
| DEPLOY_CLIENT_ID | Production Client ID of the Discord appication associated with the deploy token | 🚀 | 763035392692274 |
|
||||||
|
|
||||||
### Icon explanation:
|
### Icon explanation
|
||||||
|
|
||||||
- ▶️ = Required in runtime
|
- ▶️ = Required in runtime
|
||||||
- 🚀 = Required during CI/CD
|
- 🚀 = Required during CI/CD
|
||||||
|
@ -8,15 +8,16 @@ services:
|
|||||||
tty: true
|
tty: true
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- TOKEN=$TOKEN
|
- TOKEN=$TOKEN
|
||||||
- DB_HOST=database
|
- DB_HOST=db
|
||||||
- DB_USERNAME=$DB_USERNAME
|
- DB_USERNAME=$DB_USERNAME
|
||||||
- DB_PASSWORD=$DB_PASSWORD
|
- DB_PASSWORD=$DB_PASSWORD
|
||||||
- DB_DATABASE=$DB_DATABASE
|
- DB_DATABASE=$DB_DATABASE
|
||||||
database:
|
- MONITOR_URL=$MONITOR_URL
|
||||||
|
db:
|
||||||
image: postgres:latest
|
image: postgres:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
1356
package-lock.json
generated
1356
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -1,22 +1,27 @@
|
|||||||
{
|
{
|
||||||
"name": "eu.astrogd.white-leopard",
|
"name": "eu.astrogd.white-leopard",
|
||||||
"version": "1.0.0",
|
"version": "1.2.0",
|
||||||
"description": "A Discord bot that checks channel names for blacklisted words and reverts the changes if necessary",
|
"description": "A Discord bot that checks channel names for blacklisted words and reverts the changes if necessary",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "tsc && shx cp package-lock.json build/package-lock.json",
|
"build": "tsc && shx cp package-lock.json build/package-lock.json",
|
||||||
"start:rebuild": "npm run build && node --enable-source-maps .",
|
"start:rebuild": "npm run build && node --enable-source-maps .",
|
||||||
|
"version:dev": "npm version prerelease --preid dev --no-commit-hooks --no-git-tag-version",
|
||||||
|
"version:patch": "npm version prepatch --preid dev --no-commit-hooks --no-git-tag-version",
|
||||||
|
"version:minor": "npm version preminor --preid dev --no-commit-hooks --no-git-tag-version",
|
||||||
|
"version:major": "npm version premajor --preid dev --no-commit-hooks --no-git-tag-version",
|
||||||
|
"version:release": "npm version patch --no-commit-hooks --no-git-tag-version",
|
||||||
"deploy-commands:dev": "ts-node ci/devDeploy.ts",
|
"deploy-commands:dev": "ts-node ci/devDeploy.ts",
|
||||||
"deploy-commands:prod": "ts-node ci/deploy.ts",
|
"deploy-commands:prod": "ts-node ci/deploy.ts",
|
||||||
"deploy:dev": "npm run build && npm run deploy-commands:dev && docker compose build && docker compose up -d",
|
"deploy:dev": "npm run build && npm run deploy-commands:dev && docker compose build && docker compose up -d",
|
||||||
"deploy:prod": "rimraf build && npm run build && npm run deploy-commands:prod && docker build -t astrogd/white-leopard:latest . && docker push astrogd/white-leopard:latest",
|
"deploy:prod": "rimraf build && npm run build && npm run deploy-commands:prod && docker build -t astrogd/white-leopard:latest . && docker push astrogd/white-leopard:latest",
|
||||||
"start": "npm run build && npm run deploy-commands:dev && docker-compose up --no-start && docker compose start database && node --enable-source-maps .",
|
"start": "npm run build && npm run deploy-commands:dev && docker-compose up -d db && node --enable-source-maps .",
|
||||||
"migration:create": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:generate -d src/data/dataSource.ts -p src/data/migrations/data",
|
"migration:create": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:generate -d src/data/dataSource.migration.ts -p src/data/migrations/data",
|
||||||
"migration:run": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:run -d src/data/dataSource.ts",
|
"migration:run": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:run -d src/data/dataSource.migration.ts",
|
||||||
"migration:revert": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:revert -d src/data/dataSource.ts",
|
"migration:revert": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:revert -d src/data/dataSource.migration.ts",
|
||||||
"migration:show": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:show -d src/data/dataSource.ts",
|
"migration:show": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:show -d src/data/dataSource.migration.ts",
|
||||||
"migration:check": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:generate --check -d src/data/dataSource.ts src/data/migrations/data"
|
"migration:check": "node --require ts-node/register ./node_modules/typeorm/cli.js migration:generate --check -d src/data/dataSource.migration.ts src/data/migrations/data"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -30,15 +35,16 @@
|
|||||||
"homepage": "https://github.com/r-Overwatch2/eu.astrogd.white-leopard#readme",
|
"homepage": "https://github.com/r-Overwatch2/eu.astrogd.white-leopard#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.14",
|
"@types/express": "^4.17.14",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^11.0.2",
|
||||||
"@types/node": "^18.11.9",
|
"@types/node": "^18.17.17",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^5.0.1",
|
||||||
"shx": "^0.3.4",
|
"shx": "^0.3.4",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^4.9.3"
|
"typescript": "^5.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^14.6.0",
|
"@astrogd/eu.astrogd.uptime-kuma-push-monitor": "^1.0.0-dev.3",
|
||||||
|
"discord.js": "^14.13.0",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"fs-extra": "^11.0.0",
|
"fs-extra": "^11.0.0",
|
||||||
|
@ -1,13 +1,25 @@
|
|||||||
import { runCleanup } from "../service";
|
import { runCleanup } from "../service";
|
||||||
import client from "./index";
|
import client from "./index";
|
||||||
|
import { initPromise } from "../data/dataSource";
|
||||||
|
import pushMonitor from "@astrogd/eu.astrogd.uptime-kuma-push-monitor";
|
||||||
|
|
||||||
const token = process.env["TOKEN"];
|
const token = process.env["TOKEN"];
|
||||||
if (!token) throw new ReferenceError("TOKEN environment variable is missing");
|
if (!token) throw new ReferenceError("TOKEN environment variable is missing");
|
||||||
|
|
||||||
client.login(token);
|
async function run() {
|
||||||
|
console.log("Establishing database connection");
|
||||||
|
await initPromise;
|
||||||
|
console.log("Connection established\nAuthenticating with Discord API");
|
||||||
|
client.login(token);
|
||||||
|
}
|
||||||
|
|
||||||
client.on("ready", () => {
|
client.on("ready", async () => {
|
||||||
console.log(`Connected to Discord API. Bot account is ${client.user?.tag} (${client.user?.id})`);
|
console.log(`Connected to Discord API. Bot account is ${client.user?.tag} (${client.user?.id})`);
|
||||||
|
if (process.env["MONITOR_URL"]) pushMonitor.register(process.env["MONITOR_URL"], 120);
|
||||||
|
pushMonitor.enableShutdownNotifications();
|
||||||
|
pushMonitor.setPerformanceHandler(() => client.ws.ping);
|
||||||
|
|
||||||
runCleanup();
|
runCleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
run();
|
3
src/data/dataSource.migration.ts
Normal file
3
src/data/dataSource.migration.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import dataSource from "./dataSource";
|
||||||
|
|
||||||
|
export default dataSource;
|
@ -28,6 +28,9 @@ const dataSource = new DataSource({
|
|||||||
migrationsTransactionMode: "each"
|
migrationsTransactionMode: "each"
|
||||||
});
|
});
|
||||||
|
|
||||||
dataSource.initialize();
|
const initPromise = dataSource.initialize();
|
||||||
|
|
||||||
export default dataSource;
|
export default dataSource;
|
||||||
|
export {
|
||||||
|
initPromise
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { AuditLogEvent, Events, GuildAuditLogsEntry, PermissionFlagsBits, User }
|
|||||||
import { getGuildSetting } from "../tools/data";
|
import { getGuildSetting } from "../tools/data";
|
||||||
import { Badword, database } from "../data";
|
import { Badword, database } from "../data";
|
||||||
import { IsNull } from "typeorm";
|
import { IsNull } from "typeorm";
|
||||||
import getDefaultEmbed, { getFailedEmbed } from "../tools/defaultEmbeds";
|
import getDefaultEmbed, { getFailedEmbed, getUserReportEmbed } from "../tools/defaultEmbeds";
|
||||||
import { getGuildChannel } from "../tools/discord";
|
import { getGuildChannel } from "../tools/discord";
|
||||||
import { Color, Emoji } from "../tools/design";
|
import { Color, Emoji } from "../tools/design";
|
||||||
|
|
||||||
@ -89,6 +89,13 @@ client.on(Events.ChannelCreate, async (newChannel) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (responsibleUser) {
|
||||||
|
const embed = getUserReportEmbed(guild.name, newChannel.name);
|
||||||
|
responsibleUser.send({
|
||||||
|
embeds: [embed]
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
if (!logChannel || !logChannel.isTextBased()) return;
|
if (!logChannel || !logChannel.isTextBased()) return;
|
||||||
const embed = getDefaultEmbed();
|
const embed = getDefaultEmbed();
|
||||||
embed.setTitle(`${Emoji.SECURITY_CHALLENGE_FAILED} Blocked word detected`);
|
embed.setTitle(`${Emoji.SECURITY_CHALLENGE_FAILED} Blocked word detected`);
|
||||||
|
@ -3,7 +3,7 @@ import { AuditLogEvent, Events, GuildAuditLogsEntry, PermissionFlagsBits, User }
|
|||||||
import { getGuildSetting } from "../tools/data";
|
import { getGuildSetting } from "../tools/data";
|
||||||
import { Badword, database } from "../data";
|
import { Badword, database } from "../data";
|
||||||
import { IsNull } from "typeorm";
|
import { IsNull } from "typeorm";
|
||||||
import getDefaultEmbed, { getFailedEmbed } from "../tools/defaultEmbeds";
|
import getDefaultEmbed, { getFailedEmbed, getUserReportEmbed } from "../tools/defaultEmbeds";
|
||||||
import { getGuildChannel } from "../tools/discord";
|
import { getGuildChannel } from "../tools/discord";
|
||||||
import { Color, Emoji } from "../tools/design";
|
import { Color, Emoji } from "../tools/design";
|
||||||
|
|
||||||
@ -89,6 +89,13 @@ client.on(Events.ChannelUpdate, async (oldChannel, newChannel) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (responsibleUser) {
|
||||||
|
const embed = getUserReportEmbed(guild.name, newChannel.name);
|
||||||
|
responsibleUser.send({
|
||||||
|
embeds: [embed]
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
if (!logChannel || !logChannel.isTextBased()) return;
|
if (!logChannel || !logChannel.isTextBased()) return;
|
||||||
const embed = getDefaultEmbed();
|
const embed = getDefaultEmbed();
|
||||||
embed.setTitle(`${Emoji.SECURITY_CHALLENGE_FAILED} Blocked word detected`);
|
embed.setTitle(`${Emoji.SECURITY_CHALLENGE_FAILED} Blocked word detected`);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import "./uptime";
|
|
||||||
import runCleanup from "./cleanup";
|
import runCleanup from "./cleanup";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import express from "express";
|
|
||||||
import pack from "../../package.json";
|
|
||||||
import startupTime from "../tools/startupTime";
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
|
|
||||||
app.get("/", (_req, res) => {
|
|
||||||
res.status(200).json({
|
|
||||||
running: true,
|
|
||||||
version: pack.version,
|
|
||||||
runningSince: startupTime.toISOString()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.all("*", (_req, res) => {
|
|
||||||
res.status(404).end();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(80);
|
|
@ -28,5 +28,16 @@ export function getFailedEmbed(): EmbedBuilder {
|
|||||||
const embed = getDefaultEmbed();
|
const embed = getDefaultEmbed();
|
||||||
embed.setTitle(`${Emoji.CHAT_DENY} Failed`);
|
embed.setTitle(`${Emoji.CHAT_DENY} Failed`);
|
||||||
embed.setColor(Color.STOPSIGN_RED);
|
embed.setColor(Color.STOPSIGN_RED);
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserReportEmbed(guildName: string, channelName: string): EmbedBuilder {
|
||||||
|
const embed = getDefaultEmbed();
|
||||||
|
embed.setColor(Color.STOPSIGN_RED);
|
||||||
|
embed.setTitle(`${Emoji.SECURITY_CHALLENGE_FAILED} A channel you modified has been deleted`);
|
||||||
|
embed.setDescription(`Hey there ${Emoji.WAVING}
|
||||||
|
Your channel (#${channelName}) on the "${guildName}" server contained a blacklisted word and was deleted automatically.
|
||||||
|
Please make sure to keep channel names friendly for everyone!`);
|
||||||
|
|
||||||
return embed;
|
return embed;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user