From 0c9000a48c92ca46c8876f6175a83540744c0c1e Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 16:20:12 +0100 Subject: [PATCH 01/17] Reduce branding --- src/tools/defaultEmbeds.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/defaultEmbeds.ts b/src/tools/defaultEmbeds.ts index 8c916a6..0b8c1b2 100644 --- a/src/tools/defaultEmbeds.ts +++ b/src/tools/defaultEmbeds.ts @@ -8,7 +8,7 @@ import { Color, Emoji } from "./design"; export default function getDefaultEmbed(): EmbedBuilder { const embed = new EmbedBuilder(); embed.setFooter({ - text: `Channel filter V${pack.version} by AstroGD®`, + text: `Channel filter V${pack.version}`, iconURL: client.user?.avatarURL() || undefined, }); embed.setTimestamp(new Date()); -- 2.45.2 From 7a5d7f46b6a26a0e35503665c22720c1ec65913d Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 16:55:27 +0100 Subject: [PATCH 02/17] cli command guild delete closes #3 --- src/cli/guild.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/cli/guild.ts b/src/cli/guild.ts index 9c98555..42c58db 100644 --- a/src/cli/guild.ts +++ b/src/cli/guild.ts @@ -124,6 +124,21 @@ export default async function execute(args: string[]) { break; } + case "delete": { + if (!args[1]) return printHelp(); + + await database.getRepository(GuildSetting).delete({ + id: args[1] + }); + + await database.getRepository(Badword).delete({ + guildID: args[1] + }); + + console.log(`Deleted all data for guild ${args[1]}`); + break; + } + default: { printHelp(); break; @@ -137,7 +152,8 @@ function printHelp() { guild info [GUILDID] guild setPremium [GUILDID] [YYYY-MM-DD or NULL] -guild words [get|add|remove|clear]`); +guild words [get|add|remove|clear] +guild delete [GUILDID]`); } function printWordHelp() { -- 2.45.2 From ca29f047e91e0ab338057e8246110eff3a8f2bd8 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 17:16:10 +0100 Subject: [PATCH 03/17] Add data model changes --- src/data/migrations/1669392941776-data.ts | 19 +++++++++++++++++++ src/data/model/guildSetting.ts | 3 +++ src/tools/data.ts | 1 + 3 files changed, 23 insertions(+) create mode 100644 src/data/migrations/1669392941776-data.ts diff --git a/src/data/migrations/1669392941776-data.ts b/src/data/migrations/1669392941776-data.ts new file mode 100644 index 0000000..418aaf2 --- /dev/null +++ b/src/data/migrations/1669392941776-data.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class data1669392941776 implements MigrationInterface { + name = 'data1669392941776' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE "guild_setting" + ADD "preserveDataOnGuildLeave" boolean NOT NULL DEFAULT false + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE "guild_setting" DROP COLUMN "preserveDataOnGuildLeave" + `); + } + +} diff --git a/src/data/model/guildSetting.ts b/src/data/model/guildSetting.ts index 45c83ad..65c032c 100644 --- a/src/data/model/guildSetting.ts +++ b/src/data/model/guildSetting.ts @@ -10,4 +10,7 @@ export class GuildSetting { @Column("timestamp", { nullable: true, default: null }) isPremiumUntil!: Date | null; + + @Column("boolean", { default: false }) + preserveDataOnGuildLeave!: boolean } \ No newline at end of file diff --git a/src/tools/data.ts b/src/tools/data.ts index a12e1ee..0addaf6 100644 --- a/src/tools/data.ts +++ b/src/tools/data.ts @@ -12,6 +12,7 @@ export async function getGuildSetting(guildID: string): Promise { guildSetting.id = guildID; guildSetting.isPremiumUntil = null; guildSetting.notificationChannelID = null; + guildSetting.preserveDataOnGuildLeave = false; } return guildSetting; -- 2.45.2 From df2548dba690e6528413b11fddad35dd5782d41f Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 17:41:57 +0100 Subject: [PATCH 04/17] Bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 180c170..1f33256 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eu.astrogd.white-leopard", - "version": "1.0.0-beta.2", + "version": "1.0.0-alpha.6", "description": "A Discord bot that checks channel names for blacklisted words and reverts the changes if necessary", "main": "build/index.js", "scripts": { -- 2.45.2 From fda61664836a0c5c7d88bd47fa2862487183344e Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 17:44:21 +0100 Subject: [PATCH 05/17] /preservesettings command --- src/commands/ci.ts | 3 +- src/commands/index.ts | 2 + src/commands/preserveSettings.ts | 66 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/commands/preserveSettings.ts diff --git a/src/commands/ci.ts b/src/commands/ci.ts index 4372998..0c6db03 100644 --- a/src/commands/ci.ts +++ b/src/commands/ci.ts @@ -1,8 +1,9 @@ import * as notification from "./notification"; import * as blocklist from "./blocklist"; import * as info from "./info"; +import * as preserveSettings from "./preserveSettings"; -const array = [notification.builder.toJSON(), blocklist.builder.toJSON(), info.builder.toJSON()]; +const array = [notification.builder.toJSON(), blocklist.builder.toJSON(), info.builder.toJSON(), preserveSettings.builder.toJSON()]; export { array diff --git a/src/commands/index.ts b/src/commands/index.ts index ce8064a..589dcfd 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -2,6 +2,7 @@ import { ChatInputCommandInteraction, Collection, Events, SlashCommandBuilder } import * as notification from "./notification"; import * as blocklist from "./blocklist"; import * as info from "./info"; +import * as preserveSettings from "./preserveSettings"; import client from "../client"; import getDefaultEmbed from "../tools/defaultEmbeds"; @@ -9,6 +10,7 @@ const commands = new Collection { if (!interaction.isChatInputCommand()) return; diff --git a/src/commands/preserveSettings.ts b/src/commands/preserveSettings.ts new file mode 100644 index 0000000..c8cc94a --- /dev/null +++ b/src/commands/preserveSettings.ts @@ -0,0 +1,66 @@ +import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionFlagsBits } from "discord.js"; +import { database, GuildSetting } from "../data"; +import { getGuildSetting } from "../tools/data"; +import getDefaultEmbed, { getSuccessEmbed } from "../tools/defaultEmbeds"; +import { Color, Emoji } from "../tools/design"; +import { getGuildChannel } from "../tools/discord"; + +const builder = new SlashCommandBuilder(); +builder.setName("preservesettings"); +builder.setDescription("Sets if the bot should save the server settings and blocklist if it leaves the server or delete it"); +builder.addStringOption((option) => { + option.addChoices({ + name: "Keep data when bot leaves the server", + value: "keep" + }, { + name: "Delete data when bot leaves the server", + value: "delete" + }); + option.setName("behaviour"); + option.setDescription("How the bot behaves when leaving the server"); + option.setRequired(true); + return option; +}); +builder.setDMPermission(false); +builder.setDefaultMemberPermissions(PermissionFlagsBits.Administrator); + +async function execute(interaction: ChatInputCommandInteraction): Promise { + if (!interaction.inGuild()) throw new Error("Command was executed outside guild context"); + + const settings = await getGuildSetting(interaction.guildId); + const option = interaction.options.getString("behaviour", true).toLowerCase(); + + if (option !== "keep" && option !== "delete") throw new TypeError(`option "behaviour" expected to be of type "keep" | "delete" but was "${option}"`); + + settings.preserveDataOnGuildLeave = option === "keep"; + + await database.getRepository(GuildSetting).save(settings); + + const embed = getSuccessEmbed(); + embed.setDescription(`Preserve settings on server leave is now ${settings.preserveDataOnGuildLeave ? "ENABLED" : "DISABLED"}`); + + interaction.reply({ + embeds: [embed], + ephemeral: true + }).catch(); + + if (!settings.notificationChannelID) return; + const logChannel = await getGuildChannel(interaction.guildId, settings.notificationChannelID); + if (!logChannel || !logChannel.isTextBased()) return; + const logEmbed = getDefaultEmbed(); + logEmbed.setTitle(`${Emoji.SETTINGS} Settings changed`); + logEmbed.setDescription(`Preserve settings on server leave is now ${settings.preserveDataOnGuildLeave ? "ENABLED" : "DISABLED"}`); + logEmbed.addFields({ + name: "This action was performed by", + value: `${interaction.user.tag} (${interaction.user.id})` + }); + + logChannel.send({ + embeds: [logEmbed] + }).catch(); +} + +export { + builder, + execute +} \ No newline at end of file -- 2.45.2 From 71b401dbee478c06967938d02248dcf76378efae Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 17:46:39 +0100 Subject: [PATCH 06/17] Update cli guild info command --- src/cli/guild.ts | 1 + src/commands/preserveSettings.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/guild.ts b/src/cli/guild.ts index 42c58db..9a95e85 100644 --- a/src/cli/guild.ts +++ b/src/cli/guild.ts @@ -22,6 +22,7 @@ export default async function execute(args: string[]) { console.log(`Guild ${args[1]}: - Premium: ${isPremium ? `ACTIVE for ${moment(settings.isPremiumUntil).fromNow(true)}` : "INACTIVE"} + - Preserve Settings: ${settings.preserveDataOnGuildLeave ? "ENABLED" : "DISABLED"} - Logchannel: ${settings.notificationChannelID ? `ENABLED (${settings.notificationChannelID})` : "DISABLED"} - blocked Words: ${wordCount}`); break; diff --git a/src/commands/preserveSettings.ts b/src/commands/preserveSettings.ts index c8cc94a..90f0bfd 100644 --- a/src/commands/preserveSettings.ts +++ b/src/commands/preserveSettings.ts @@ -2,7 +2,7 @@ import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionFlagsBits } import { database, GuildSetting } from "../data"; import { getGuildSetting } from "../tools/data"; import getDefaultEmbed, { getSuccessEmbed } from "../tools/defaultEmbeds"; -import { Color, Emoji } from "../tools/design"; +import { Emoji } from "../tools/design"; import { getGuildChannel } from "../tools/discord"; const builder = new SlashCommandBuilder(); -- 2.45.2 From d9c81ef3f2c39a03ee8542fbb81ef24aa1312c57 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 17:51:37 +0100 Subject: [PATCH 07/17] Delete data on guild delete --- src/events/guildDelete.ts | 17 +++++++++++++++++ src/events/index.ts | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/events/guildDelete.ts diff --git a/src/events/guildDelete.ts b/src/events/guildDelete.ts new file mode 100644 index 0000000..8ee42a1 --- /dev/null +++ b/src/events/guildDelete.ts @@ -0,0 +1,17 @@ +import client from "../client"; +import { Events } from "discord.js"; +import { getGuildSetting } from "../tools/data"; +import { Badword, database, GuildSetting } from "../data"; + +client.on(Events.GuildDelete, async (guild) => { + const settings = await getGuildSetting(guild.id); + if (settings.preserveDataOnGuildLeave) return; + + await database.getRepository(GuildSetting).delete({ + id: guild.id + }); + + await database.getRepository(Badword).delete({ + guildID: guild.id + }); +}); \ No newline at end of file diff --git a/src/events/index.ts b/src/events/index.ts index f427567..ab87147 100644 --- a/src/events/index.ts +++ b/src/events/index.ts @@ -1 +1,2 @@ -import "./channelUpdate"; \ No newline at end of file +import "./channelUpdate"; +import "./guildDelete"; \ No newline at end of file -- 2.45.2 From 8b72326419a532b5574788d7370fbe3af90c9df4 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 18:28:42 +0100 Subject: [PATCH 08/17] Cleanup on bot start --- src/client/init.ts | 3 +++ src/service/cleanup.ts | 39 +++++++++++++++++++++++++++++++++++++++ src/service/index.ts | 7 ++++++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/service/cleanup.ts diff --git a/src/client/init.ts b/src/client/init.ts index bfa5e6e..f21b2d5 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -1,3 +1,4 @@ +import { runCleanup } from "../service"; import client from "./index"; const token = process.env["TOKEN"]; @@ -7,4 +8,6 @@ client.login(token); client.on("ready", () => { console.log(`Connected to Discord API. Bot account is ${client.user?.tag} (${client.user?.id})`); + + runCleanup(); }); \ No newline at end of file diff --git a/src/service/cleanup.ts b/src/service/cleanup.ts new file mode 100644 index 0000000..68cd410 --- /dev/null +++ b/src/service/cleanup.ts @@ -0,0 +1,39 @@ +import { Badword, database, GuildSetting } from "../data"; +import client from "../client"; +import { DiscordAPIError } from "discord.js"; + +export default async function execute(): Promise { + const guilds = await database.getRepository(GuildSetting).find({ + where: { + preserveDataOnGuildLeave: false + } + }); + + for (const guild of guilds) { + try { + await client.guilds.fetch(guild.id); + } catch (error) { + if (!(error instanceof DiscordAPIError)) { + console.error(`service.cleanup failed: ${error}`); + return; + } + + const id = guild.id; + + // 5001 = Missing access + if (error.code.toString() !== "50001") { + console.warn(`Guild ${guild.id} is unavailable but not because of error 5001:\n${error}`); + continue; + } + + await database.getRepository(Badword).delete({ + guildID: guild.id + }); + + await database.getRepository(GuildSetting).remove(guild); + console.log(`Removed data for guild ${id}`); + } + } + + console.log("Cleanup completed"); +} \ No newline at end of file diff --git a/src/service/index.ts b/src/service/index.ts index f45bde5..4b9405c 100644 --- a/src/service/index.ts +++ b/src/service/index.ts @@ -1 +1,6 @@ -import "./uptime"; \ No newline at end of file +import "./uptime"; +import runCleanup from "./cleanup"; + +export { + runCleanup +} \ No newline at end of file -- 2.45.2 From 27f625155edd3128e6b0228c9b7a2f4f5a11fb1b Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 18:30:48 +0100 Subject: [PATCH 09/17] Update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 196842c..19c40e0 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,12 @@ Removes the word from the server specific blocklist ### /info Returns general information about the bot and the servers stats +### /preservesettings +Changes the behaviour when the bot leaves the server. +Options are: +- Keep settings persistent even if the bot leaves +- Delete setting when the bot leaves the server [default] + ## Environment variables | Name | Description | Required | Example | | :--------------- | :------------------------------------------------------------------------------ | :------: | :------------------ | -- 2.45.2 From 966625bac430316f9f553d33f93d7fe099a2c26a Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 18:41:15 +0100 Subject: [PATCH 10/17] Change logchannel default permission --- src/commands/ci.ts | 2 +- src/commands/index.ts | 2 +- src/commands/{notification.ts => logchannel.ts} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/commands/{notification.ts => logchannel.ts} (98%) diff --git a/src/commands/ci.ts b/src/commands/ci.ts index 0c6db03..118f6a9 100644 --- a/src/commands/ci.ts +++ b/src/commands/ci.ts @@ -1,4 +1,4 @@ -import * as notification from "./notification"; +import * as notification from "./logchannel"; import * as blocklist from "./blocklist"; import * as info from "./info"; import * as preserveSettings from "./preserveSettings"; diff --git a/src/commands/index.ts b/src/commands/index.ts index 589dcfd..1c75687 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,5 +1,5 @@ import { ChatInputCommandInteraction, Collection, Events, SlashCommandBuilder } from "discord.js"; -import * as notification from "./notification"; +import * as notification from "./logchannel"; import * as blocklist from "./blocklist"; import * as info from "./info"; import * as preserveSettings from "./preserveSettings"; diff --git a/src/commands/notification.ts b/src/commands/logchannel.ts similarity index 98% rename from src/commands/notification.ts rename to src/commands/logchannel.ts index edf73c7..d9ac245 100644 --- a/src/commands/notification.ts +++ b/src/commands/logchannel.ts @@ -9,7 +9,7 @@ const builder = new SlashCommandBuilder(); builder.setName("logchannel"); builder.setDescription("Configures the log channel"); builder.setDMPermission(false); -builder.setDefaultMemberPermissions(PermissionFlagsBits.ManageChannels); +builder.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild); builder.addChannelOption((option) => { option.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement); option.setName("channel"); -- 2.45.2 From 545bda9bee5394fe6b68112d95d61af1f9512bb7 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 18:41:34 +0100 Subject: [PATCH 11/17] Document default permissions --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 19c40e0..ade423b 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ A Discord bot that checks Discord channel names for banned words and prevents renaming of them ## Commands -### /logchanel [channel?] +### /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. -### /blocklist +### /blocklist `Permission: MANAGE_GUILD` #### /blocklist get Gets the global and server specific banned word list and returns it @@ -15,10 +15,10 @@ Adds the word to the server specific blocklist #### /blocklist remove [word] Removes the word from the server specific blocklist -### /info +### /info `Permission: EVERYONE` Returns general information about the bot and the servers stats -### /preservesettings +### /preservesettings `Permission: ADMINISTRATOR` Changes the behaviour when the bot leaves the server. Options are: - Keep settings persistent even if the bot leaves -- 2.45.2 From 24d39d471ef06d9097b55d2bbbcb8e8986fb6359 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 18:53:03 +0100 Subject: [PATCH 12/17] /showblocklist --- README.md | 5 ++++- src/commands/blocklist.ts | 20 ++--------------- src/commands/ci.ts | 3 ++- src/commands/index.ts | 2 ++ src/commands/showblocklist.ts | 41 +++++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/commands/showblocklist.ts diff --git a/README.md b/README.md index ade423b..24c5b95 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Sets the channel where the bot will log if a channel meets the banned word crite ### /blocklist `Permission: MANAGE_GUILD` #### /blocklist get -Gets the global and server specific banned word list and returns it +Gets the global and server specific banned word list and returns it (Same behaviour as /showblocklist) #### /blocklist add [word] Adds the word to the server specific blocklist @@ -24,6 +24,9 @@ Options are: - Keep settings persistent even if the bot leaves - Delete setting when the bot leaves the server [default] +### /showblocklist `Permission: MANAGE_CHANNELS` +Gets the global and server specific banned word list and returns it + ## Environment variables | Name | Description | Required | Example | | :--------------- | :------------------------------------------------------------------------------ | :------: | :------------------ | diff --git a/src/commands/blocklist.ts b/src/commands/blocklist.ts index a90b102..6d6878f 100644 --- a/src/commands/blocklist.ts +++ b/src/commands/blocklist.ts @@ -5,6 +5,7 @@ import { getGuildSetting, isPremiumActive } from "../tools/data"; import getDefaultEmbed, { getFailedEmbed, getSuccessEmbed } from "../tools/defaultEmbeds"; import { getGuildChannel } from "../tools/discord"; import { Color, Emoji } from "../tools/design"; +import { execute as showBlocklistRunner } from "./showblocklist"; const builder = new SlashCommandBuilder(); builder.setName("blocklist"); @@ -51,24 +52,7 @@ async function execute(interaction: ChatInputCommandInteraction): Promise switch (interaction.options.getSubcommand(true)) { case "get": { - const guildBadWords = await database.getRepository(Badword).find({ - select: { - value: true - }, - where: { - guildID: interaction.guildId - } - }); - const globalBadWords = await database.getRepository(Badword).find({ - where: { - guildID: IsNull() - } - }); - - interaction.reply({ - content: `\`\`\`Global bad word list\`\`\`\n||${globalBadWords.map((word) => word.value).reduce((prev, next) => prev + ", " + next, "").slice(2)} ||\n\`\`\`Local server bad word list (${guildBadWords.length}/${isPremium ? 100 : 10})\`\`\`\n||${guildBadWords.map((word) => word.value).reduce((prev, next) => prev + ", " + next, "").slice(2)} ||`, - ephemeral: true - }).catch(); + await showBlocklistRunner(interaction); break; } diff --git a/src/commands/ci.ts b/src/commands/ci.ts index 118f6a9..b32cf65 100644 --- a/src/commands/ci.ts +++ b/src/commands/ci.ts @@ -2,8 +2,9 @@ import * as notification from "./logchannel"; import * as blocklist from "./blocklist"; import * as info from "./info"; import * as preserveSettings from "./preserveSettings"; +import * as showBlocklist from "./showblocklist"; -const array = [notification.builder.toJSON(), blocklist.builder.toJSON(), info.builder.toJSON(), preserveSettings.builder.toJSON()]; +const array = [notification.builder.toJSON(), blocklist.builder.toJSON(), info.builder.toJSON(), preserveSettings.builder.toJSON(), showBlocklist.builder.toJSON()]; export { array diff --git a/src/commands/index.ts b/src/commands/index.ts index 1c75687..c9fc2f5 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -3,6 +3,7 @@ import * as notification from "./logchannel"; import * as blocklist from "./blocklist"; import * as info from "./info"; import * as preserveSettings from "./preserveSettings"; +import * as showBlocklist from "./showblocklist"; import client from "../client"; import getDefaultEmbed from "../tools/defaultEmbeds"; @@ -11,6 +12,7 @@ commands.set(notification.builder.name, notification); commands.set(blocklist.builder.name, blocklist); commands.set(info.builder.name, info); commands.set(preserveSettings.builder.name, preserveSettings); +commands.set(showBlocklist.builder.name, showBlocklist); client.on(Events.InteractionCreate, async (interaction) => { if (!interaction.isChatInputCommand()) return; diff --git a/src/commands/showblocklist.ts b/src/commands/showblocklist.ts new file mode 100644 index 0000000..347f9a4 --- /dev/null +++ b/src/commands/showblocklist.ts @@ -0,0 +1,41 @@ +import { ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from "discord.js"; +import { IsNull } from "typeorm"; +import { Badword, database } from "../data"; +import { getGuildSetting, isPremiumActive } from "../tools/data"; + +const builder = new SlashCommandBuilder(); +builder.setName("showblocklist"); +builder.setDescription("Shows the blocklist of this server"); +builder.setDMPermission(false); +builder.setDefaultMemberPermissions(PermissionFlagsBits.ManageChannels); + +async function execute(interaction: ChatInputCommandInteraction): Promise { + if (!interaction.inGuild()) throw new Error("Command was executed outside guild context"); + + const settings = await getGuildSetting(interaction.guildId); + const isPremium = isPremiumActive(settings.isPremiumUntil); + + const guildBadWords = await database.getRepository(Badword).find({ + select: { + value: true + }, + where: { + guildID: interaction.guildId + } + }); + const globalBadWords = await database.getRepository(Badword).find({ + where: { + guildID: IsNull() + } + }); + + interaction.reply({ + content: `\`\`\`Global bad word list\`\`\`\n||${globalBadWords.map((word) => word.value).reduce((prev, next) => prev + ", " + next, "").slice(2)} ||\n\`\`\`Local server bad word list (${guildBadWords.length}/${isPremium ? 100 : 10})\`\`\`\n||${guildBadWords.map((word) => word.value).reduce((prev, next) => prev + ", " + next, "").slice(2)} ||`, + ephemeral: true + }).catch(); +} + +export { + builder, + execute +} \ No newline at end of file -- 2.45.2 From 52a349c1b9f0e43441709ba1063e1317207d85cc Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 18:56:47 +0100 Subject: [PATCH 13/17] Bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1f33256..a1f1fab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eu.astrogd.white-leopard", - "version": "1.0.0-alpha.6", + "version": "1.0.0-alpha.7", "description": "A Discord bot that checks channel names for blacklisted words and reverts the changes if necessary", "main": "build/index.js", "scripts": { -- 2.45.2 From 21812157f8a224fb47eab81d0f536abc3f8e328c Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 19:28:05 +0100 Subject: [PATCH 14/17] /showsettings --- README.md | 7 +++-- src/commands/ci.ts | 11 ++++++- src/commands/index.ts | 2 ++ src/commands/showSettings.ts | 61 ++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/commands/showSettings.ts diff --git a/README.md b/README.md index 24c5b95..ff0c8a5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Sets the channel where the bot will log if a channel meets the banned word crite ### /blocklist `Permission: MANAGE_GUILD` #### /blocklist get -Gets 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] Adds the word to the server specific blocklist @@ -25,7 +25,10 @@ Options are: - Delete setting when the bot leaves the server [default] ### /showblocklist `Permission: MANAGE_CHANNELS` -Gets 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` +Returns the current settings for the server ## Environment variables | Name | Description | Required | Example | diff --git a/src/commands/ci.ts b/src/commands/ci.ts index b32cf65..ae52bbf 100644 --- a/src/commands/ci.ts +++ b/src/commands/ci.ts @@ -3,8 +3,17 @@ import * as blocklist from "./blocklist"; import * as info from "./info"; import * as preserveSettings from "./preserveSettings"; import * as showBlocklist from "./showblocklist"; +import * as showSettings from "./showSettings"; -const array = [notification.builder.toJSON(), blocklist.builder.toJSON(), info.builder.toJSON(), preserveSettings.builder.toJSON(), showBlocklist.builder.toJSON()]; +const commands = []; +commands.push(notification); +commands.push(blocklist); +commands.push(info); +commands.push(preserveSettings); +commands.push(showBlocklist); +commands.push(showSettings); + +const array = commands.map((command) => command.builder.toJSON()); export { array diff --git a/src/commands/index.ts b/src/commands/index.ts index c9fc2f5..78761e7 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -4,6 +4,7 @@ import * as blocklist from "./blocklist"; import * as info from "./info"; import * as preserveSettings from "./preserveSettings"; import * as showBlocklist from "./showblocklist"; +import * as showSettings from "./showSettings"; import client from "../client"; import getDefaultEmbed from "../tools/defaultEmbeds"; @@ -13,6 +14,7 @@ commands.set(blocklist.builder.name, blocklist); commands.set(info.builder.name, info); commands.set(preserveSettings.builder.name, preserveSettings); commands.set(showBlocklist.builder.name, showBlocklist); +commands.set(showSettings.builder.name, showSettings); client.on(Events.InteractionCreate, async (interaction) => { if (!interaction.isChatInputCommand()) return; diff --git a/src/commands/showSettings.ts b/src/commands/showSettings.ts new file mode 100644 index 0000000..4903fe1 --- /dev/null +++ b/src/commands/showSettings.ts @@ -0,0 +1,61 @@ +import { ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from "discord.js"; +import { Badword, database } from "../data"; +import { getGuildSetting, isPremiumActive } from "../tools/data"; +import getDefaultEmbed from "../tools/defaultEmbeds"; +import moment from "moment"; +import { Color, Emoji } from "../tools/design"; +import { getGuildChannel } from "../tools/discord"; + +const builder = new SlashCommandBuilder(); +builder.setName("showsettings"); +builder.setDescription("Show the current settings of this guild"); +builder.setDMPermission(false); +builder.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild); + +async function execute(interaction: ChatInputCommandInteraction): Promise { + if (!interaction.inGuild()) throw new Error("Interaction was performed outside guild context"); + + const settings = await getGuildSetting(interaction.guildId); + const isPremium = await isPremiumActive(settings.isPremiumUntil); + const wordCount = await database.getRepository(Badword).count({ + where: { + guildID: interaction.guildId + } + }); + + const logChannel = settings.notificationChannelID ? await getGuildChannel(interaction.guildId, settings.notificationChannelID) : null; + + const embed = getDefaultEmbed(); + embed.setTitle(`Settings from guild ${interaction.guild?.name || ""} (${interaction.guildId})`); + embed.setDescription(isPremium ? `${Emoji.PREMIUM} your subscription ends in ${moment(settings.isPremiumUntil).fromNow(true)}` : `Consider Premium status to get an increased blocklist`); + embed.setColor(Color.INFORMING_BLUE); + embed.addFields({ + name: "Premium", + value: isPremium ? `${Emoji.PREMIUM} active` : `${Emoji.SWITCH_OFF} inactive`, + inline: true + }, { + name: "Logchannel", + value: logChannel && logChannel.isTextBased() ? `<#${logChannel.id}>` : "Not configured", + inline: true + }, { + name: "Words in Blocklist", + value: `${wordCount}/${isPremium ? "100" : "10"}`, + inline: true + }, { + name: `Preserve data on server leave is ${settings.preserveDataOnGuildLeave ? "active" : "inactive"}`, + value: settings.preserveDataOnGuildLeave ? "Your settings will be saved even if the bot gets kicked" : "Your settings will be deleted as soon as the bot leaves this server" + }, { + name: `${Emoji.WAVING} Found a bug? Want to request a feature? Say hello?`, + value: "Join the support server at https://go.astrogd.eu/discord" + }); + + interaction.reply({ + embeds: [embed], + ephemeral: true + }).catch(); +} + +export { + builder, + execute +} \ No newline at end of file -- 2.45.2 From 005b9bd69c99e3917fff6d1598386b531ccb4013 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 19:30:57 +0100 Subject: [PATCH 15/17] Update embed color for /showsettings --- src/commands/showSettings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/showSettings.ts b/src/commands/showSettings.ts index 4903fe1..2455fb3 100644 --- a/src/commands/showSettings.ts +++ b/src/commands/showSettings.ts @@ -28,7 +28,7 @@ async function execute(interaction: ChatInputCommandInteraction): Promise const embed = getDefaultEmbed(); embed.setTitle(`Settings from guild ${interaction.guild?.name || ""} (${interaction.guildId})`); embed.setDescription(isPremium ? `${Emoji.PREMIUM} your subscription ends in ${moment(settings.isPremiumUntil).fromNow(true)}` : `Consider Premium status to get an increased blocklist`); - embed.setColor(Color.INFORMING_BLUE); + embed.setColor(isPremium ? Color.PREMIUM_ORANGE : Color.INFORMING_BLUE); embed.addFields({ name: "Premium", value: isPremium ? `${Emoji.PREMIUM} active` : `${Emoji.SWITCH_OFF} inactive`, -- 2.45.2 From 88834703ef3295e4dd29c7115768a1f0ac02f052 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 19:47:41 +0100 Subject: [PATCH 16/17] Bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a1f1fab..e8558f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eu.astrogd.white-leopard", - "version": "1.0.0-alpha.7", + "version": "1.0.0-beta.3", "description": "A Discord bot that checks channel names for blacklisted words and reverts the changes if necessary", "main": "build/index.js", "scripts": { -- 2.45.2 From d853fa55d39f809ca26c281edf3583346ac1b246 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 19:47:52 +0100 Subject: [PATCH 17/17] Add changelog --- Changelog.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Changelog.md diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..d1929df --- /dev/null +++ b/Changelog.md @@ -0,0 +1,20 @@ +# Changelog +This file is used to list changes made to this software. + +## V1.0.0 [`unreleased`] +_Current development version: **1.0.0-beta.3**_ +### Features +- /info +- /logchannel +- /blocklist get +- /blocklist add +- /blocklist remove +- /preservesettings +- /showblocklist +- /showsettings +- Data will be deleted by default when the bot leaves the server +- Server admins can change the behaviour of the bot when it leaves the server to keep the data persistent +- Scans for blocked words in channel names and renames channels to "CENSORED" if found +- When settings are changed or channels are censored, notifications to a logchannel can be enabled +- CLI to change settings and get information during runtime by attaching to the apps docker container +- API for automated uptime checks to prevent the bot from going offline unnoticed \ No newline at end of file -- 2.45.2