diff --git a/src/application/core/src/User.ts b/src/application/core/src/User.ts index d7f604bd..2b3ed39d 100644 --- a/src/application/core/src/User.ts +++ b/src/application/core/src/User.ts @@ -86,4 +86,8 @@ export class User extends Base { return null; } + + public async setActivity() { + await this.state.discord.user.setActivity(); + } } diff --git a/src/infrastructure/discord/src/Controller/UserController.ts b/src/infrastructure/discord/src/Controller/UserController.ts index 319c1224..0a0904f4 100644 --- a/src/infrastructure/discord/src/Controller/UserController.ts +++ b/src/infrastructure/discord/src/Controller/UserController.ts @@ -1,3 +1,5 @@ +import { ActivityType } from "discord.js"; + import type { User } from "../types/User"; import { Base } from "./Base"; @@ -25,4 +27,15 @@ export class UserController extends Base { const avatarUrl = this.client.users.cache.get(userId)?.avatarURL() ?? null; return avatarUrl; } + + public async setActivity() { + if (!this.client.isReady()) { + return; + } + + this.client.user.setActivity({ + name: `${this.client.guilds.cache.size}server | ${this.client.users.cache.size}users | distopia.top`, + type: ActivityType.Playing, + }); + } } diff --git a/src/presentation/bot/src/EventHandler/MessageCreateHandler.ts b/src/presentation/bot/src/EventHandler/MessageCreateHandler.ts index 4665f137..7bf5b4c4 100644 --- a/src/presentation/bot/src/EventHandler/MessageCreateHandler.ts +++ b/src/presentation/bot/src/EventHandler/MessageCreateHandler.ts @@ -1,5 +1,6 @@ import type { Message, OmitPartialGroupDMChannel } from "discord.js"; +import { detectSpamMessage } from "../utils/message"; import { BaseHandler } from "./BaseHandler"; export class MessageCreateHandler extends BaseHandler< @@ -8,42 +9,14 @@ export class MessageCreateHandler extends BaseHandler< public override async handle( message: OmitPartialGroupDMChannel>, ): Promise { - const content = message.content; - const settings = message.guildId ? await this.core.guild.getSetting(message.guildId) : null; + const isDetected = await detectSpamMessage(this.core, message); - if (settings?.inviteLinkBlock && !message.member?.permissions.has("Administrator")) { - const inviteLinks = await this.core.message.includeInviteLink(content); - if (inviteLinks.length) { - if (message.deletable) { - await message.delete(); - } - return; - } - - const embedInviteLinks = await this.core.state.discord.embed.detectInviteLinks( - message.embeds, - ); - if (embedInviteLinks.length) { - const messages = (await message.channel.messages.fetch({ limit: 30 })).values().toArray(); - - for (const msg of messages) { - for (const inviteLink of embedInviteLinks) { - if (msg.content.includes(inviteLink) && msg.deletable) { - await msg.delete(); - } - } - } - - if (message.deletable) { - await message.delete(); - } - - return; - } + if (isDetected) { + return; } if (message.guildId && message.member?.id) { - await this.core.message.increase(message.guildId, message.member.id, content); + await this.core.message.increase(message.guildId, message.member.id, message.content); } } } diff --git a/src/presentation/bot/src/EventHandler/MessageUpdateHandler.ts b/src/presentation/bot/src/EventHandler/MessageUpdateHandler.ts new file mode 100644 index 00000000..1cfa06df --- /dev/null +++ b/src/presentation/bot/src/EventHandler/MessageUpdateHandler.ts @@ -0,0 +1,22 @@ +import type { Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js"; + +import { detectSpamMessage } from "../utils/message"; +import { BaseHandler } from "./BaseHandler"; + +export class MessageUpdateHandler extends BaseHandler< + ( + oldMessage: OmitPartialGroupDMChannel | PartialMessage>, + newMessage: OmitPartialGroupDMChannel>, + ) => void +> { + public override async handle( + _oldMessage: OmitPartialGroupDMChannel | PartialMessage>, + newMessage: OmitPartialGroupDMChannel>, + ): Promise { + const isDetected = await detectSpamMessage(this.core, newMessage); + + if (isDetected) { + return; + } + } +} diff --git a/src/presentation/bot/src/index.ts b/src/presentation/bot/src/index.ts index b4045a64..b148759f 100644 --- a/src/presentation/bot/src/index.ts +++ b/src/presentation/bot/src/index.ts @@ -1,20 +1,19 @@ import type { AppCore } from "app-core"; -import { ActivityType, type Client } from "discord.js"; +import type { Client } from "discord.js"; import { GuildMemberAddHandler } from "./EventHandler/GuildMemberAddHandler"; import { InteractionCreateHandler } from "./EventHandler/InteractionCreateHandler/index"; import { MessageCreateHandler } from "./EventHandler/MessageCreateHandler"; +import { MessageUpdateHandler } from "./EventHandler/MessageUpdateHandler"; export function handleClient(client: Client, core: AppCore) { const interactionCreateHandler = new InteractionCreateHandler(core); const messageCreateHandler = new MessageCreateHandler(core); + const messageUpdateHandler = new MessageUpdateHandler(core); const guildMemberAddHandler = new GuildMemberAddHandler(core); client.on("clientReady", async (client) => { - client.user.setActivity({ - name: `${client.guilds.cache.size}server | ${client.users.cache.size}users | distopia.top`, - type: ActivityType.Playing, - }); + await core.user.setActivity(); const commands = interactionCreateHandler.commands.chatInput.map((command) => command.register); @@ -30,6 +29,11 @@ export function handleClient(client: Client, core: AppCore) { client.on("messageCreate", async (message) => await messageCreateHandler.handle(message)); + client.on( + "messageUpdate", + async (oldMsg, newMsg) => await messageUpdateHandler.handle(oldMsg, newMsg), + ); + client.on("guildMemberAdd", async (member) => await guildMemberAddHandler.handle(member)); return client; diff --git a/src/presentation/bot/src/utils/message.ts b/src/presentation/bot/src/utils/message.ts new file mode 100644 index 00000000..3fe17e31 --- /dev/null +++ b/src/presentation/bot/src/utils/message.ts @@ -0,0 +1,44 @@ +import type { AppCore } from "app-core"; +import type { Message, OmitPartialGroupDMChannel } from "discord.js"; + +export async function detectSpamMessage( + core: AppCore, + message: OmitPartialGroupDMChannel>, +): Promise { + const content = message.content; + const settings = message.guildId ? await core.guild.getSetting(message.guildId) : null; + + if (settings?.inviteLinkBlock && !message.member?.permissions.has("Administrator")) { + const inviteLinks = await core.message.includeInviteLink(content); + if (inviteLinks.length) { + if (message.deletable) { + await message.delete(); + } + return true; + } + + const embedInviteLinks = await core.state.discord.embed.detectInviteLinks(message.embeds); + if (embedInviteLinks.length) { + const messages = message.channel.messages.cache + .values() + .toArray() + .filter((msg) => msg.author.id === message.author.id); + + for (const msg of messages) { + for (const inviteLink of embedInviteLinks) { + if (msg.content.includes(inviteLink) && msg.deletable) { + await msg.delete(); + } + } + } + + if (message.deletable) { + await message.delete(); + } + + return true; + } + } + + return false; +} diff --git a/src/presentation/web/src/hooks.server.ts b/src/presentation/web/src/hooks.server.ts index 59befe4e..f552d938 100644 --- a/src/presentation/web/src/hooks.server.ts +++ b/src/presentation/web/src/hooks.server.ts @@ -80,6 +80,7 @@ async function start() { ); await core.record.update(); await updatePanels(); + await core.user.setActivity(); }, // This job's runtime scales with guild count (sequential Discord API // calls); without noOverlap a slow run can still be executing when the