From ca29f047e91e0ab338057e8246110eff3a8f2bd8 Mon Sep 17 00:00:00 2001 From: Lukas | AstroGD Date: Fri, 25 Nov 2022 17:16:10 +0100 Subject: [PATCH 1/7] 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 2/7] 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 3/7] /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 4/7] 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 5/7] 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 6/7] 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 7/7] 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