From a593e05f5c30ff7357327f288a6a9150bdaf644c Mon Sep 17 00:00:00 2001 From: CL TheDreWen Date: Mon, 3 Nov 2025 11:45:42 +0100 Subject: [PATCH] feat(follow): add host option for notifications and update follow entity --- README.md | 2 +- src/commands/utility/follow.command.ts | 39 ++++++++++++++++++-------- src/entity/follow.entity.ts | 3 ++ src/services/status.service.ts | 11 ++++---- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index da6e773..22359ad 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A status bot and other features for protojx. | Notification system in case of downtime. | 🌐 | | Ability to create persistent status messages that update automatically. (/live_status) | 🌐 | | Deployment workflow on Oracle VPS. | āž– | -| Filter for notifs. | āž– | +| Filter for notifs. | āœ… | - 🌐 -> In production - āœ… -> Done diff --git a/src/commands/utility/follow.command.ts b/src/commands/utility/follow.command.ts index 1a0dba8..45100d1 100644 --- a/src/commands/utility/follow.command.ts +++ b/src/commands/utility/follow.command.ts @@ -2,6 +2,7 @@ import { ApplicationIntegrationType, ChatInputCommandInteraction, InteractionCon import { CommandDefinition } from "../../type"; import { AppDataSource } from "../../data-source"; import { Follow } from "../../entity/follow.entity"; +import statusService from "../../services/status.service"; const cmd : CommandDefinition = { data: new SlashCommandBuilder() @@ -14,25 +15,39 @@ const cmd : CommandDefinition = { InteractionContextType.BotDM, InteractionContextType.Guild, InteractionContextType.PrivateChannel + ) + .addStringOption((option) => + option + .setRequired(true) + .addChoices(...statusService.hosts.filter((v) => v.notify).map((s) => ({name: s.name, value: s.host}))) + .setName('host') + .setDescription('Host enable/disable.') ), async execute(interaction : ChatInputCommandInteraction) { const userRepo = AppDataSource.getRepository(Follow); + const hostvalue = interaction.options.getString('host'); + + const realHost = statusService.hosts.filter((v) => v.host == hostvalue); + if(!hostvalue || realHost.length == 0) { + await interaction.reply({content: 'āš ļø Host not found !', flags: [MessageFlags.Ephemeral]}); + }else{ + let follow = await userRepo.findOne({where: {user_discord: interaction.user.id, host: hostvalue}}); + if(!follow) { + follow = new Follow(); + follow.user_discord = interaction.user.id; + follow.host = hostvalue; + await userRepo.save(follow); + } + + follow.enable = !follow.enable; - let follow = await userRepo.findOne({where: {user_discord: interaction.user.id}}); - if(!follow) { - follow = new Follow(); - follow.user_discord = interaction.user.id; await userRepo.save(follow); - } - - follow.enable = !follow.enable; - await userRepo.save(follow); + await interaction.reply({content: `āœ… Notification successfully ${follow.enable ? 'enabled šŸ””' : 'disabled šŸ”•'} for ${realHost[0]?.name}!`, flags: [MessageFlags.Ephemeral]}); - await interaction.reply({content: `āœ… Notification successfully ${follow.enable ? 'enabled šŸ””' : 'disabled šŸ”•'}!`, flags: [MessageFlags.Ephemeral]}); - - if(follow.enable) { - await interaction.user.send({content: 'šŸ”” Notifications have been successfully enabled! To disable: /follow'}) + if(follow.enable) { + await interaction.user.send({content: `šŸ”” Notifications have been successfully enabled for ${realHost[0]?.name} ! To disable: /follow host:${realHost[0]?.name}`}) + } } } } diff --git a/src/entity/follow.entity.ts b/src/entity/follow.entity.ts index 6e83ea3..4655c22 100644 --- a/src/entity/follow.entity.ts +++ b/src/entity/follow.entity.ts @@ -8,6 +8,9 @@ export class Follow { @Column() user_discord: string; + @Column() + host: string; + @Column({default: false}) enable: boolean; } \ No newline at end of file diff --git a/src/services/status.service.ts b/src/services/status.service.ts index 83da78c..0c1fa82 100644 --- a/src/services/status.service.ts +++ b/src/services/status.service.ts @@ -8,7 +8,7 @@ import { Repository } from "typeorm"; import { Follow } from "../entity/follow.entity"; import { Guild } from "../entity/guild.entity"; -type Nofity = {time: Date, name : string, alive : boolean, type : InfraType}; +type Nofity = {time: Date, name : string, alive : boolean, type : InfraType, host: string}; export class StatusService { @@ -204,7 +204,7 @@ export class StatusService { this.hostsLogRepo.save(log); if(latestLog && host.notify) { - notifs.push({alive: host.alive, name: host.name, time: new Date(), type: host.type}); + notifs.push({alive: host.alive, name: host.name, time: new Date(), type: host.type, host: host.host}); } } @@ -233,14 +233,15 @@ export class StatusService { // ? Notification System (part 2 !): const container = new ContainerBuilder() .addTextDisplayComponents((t) => t.setContent(`### šŸ”” Status change alert`)); - + notifs.map(async (n) => { container.addSeparatorComponents((s)=>s); container.addTextDisplayComponents((text) => text.setContent(`${n.alive ? process.env.EMOJI_STATUS_ONLINE : process.env.EMOJI_STATUS_OFFLINE} **${n.name}** is now **${n.alive ? 'online' : 'offline'}**\nšŸ·ļø Type : ${n.type}\nšŸ•’ Time : `)); }); - const users = await this.followRepo.find({where: {enable: true}}); - users.forEach(async (user) => { + const users = await this.followRepo.find(); + const hosts = notifs.map((n) => n.host); + users.filter(v => hosts.includes(v.host)).forEach(async (user) => { try { const userdc = await this.client?.users.fetch(user.user_discord); if(userdc) {