From 0d22b4bb33acd8dae3d1d93f01497840e1b2a470 Mon Sep 17 00:00:00 2001 From: zevaryx Date: Wed, 4 May 2022 22:53:12 -0600 Subject: [PATCH] Process member events, closes #138 --- jarvis/client.py | 107 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/jarvis/client.py b/jarvis/client.py index 69bc0f9..acd523e 100644 --- a/jarvis/client.py +++ b/jarvis/client.py @@ -22,17 +22,19 @@ from naff import Client, listen from naff.api.events.discord import ( MemberAdd, MemberRemove, + MemberUpdate, MessageCreate, MessageDelete, MessageUpdate, ) from naff.api.events.internal import Button from naff.client.errors import CommandCheckFailure, CommandOnCooldown, HTTPException -from naff.client.utils.misc_utils import find_all -from naff.models.discord.channel import DMChannel -from naff.models.discord.embed import EmbedField -from naff.models.discord.enums import Permissions +from naff.client.utils.misc_utils import find, find_all, get +from naff.models.discord.channel import DMChannel, GuildText +from naff.models.discord.embed import Embed, EmbedField +from naff.models.discord.enums import AuditLogEventType, Permissions from naff.models.discord.message import Message +from naff.models.discord.user import Member from naff.models.naff.context import Context, InteractionContext, PrefixedContext from naff.models.naff.tasks.task import Task from naff.models.naff.tasks.triggers import IntervalTrigger @@ -291,6 +293,103 @@ class Jarvis(Client): embed.set_footer(text=f"{user.username}#{user.discriminator} | {user.id}") await channel.send(embed=embed) + async def process_verify(self, before: Member, after: Member) -> Embed: + """Process user verification.""" + auditlog = await after.guild.fetch_audit_log(user_id=before.id, action_type=AuditLogEventType.MEMBER_ROLE_UPDATE) + audit_event = get(auditlog.events, reason="Verification passed") + if audit_event: + admin_mention = "[N/A]" + admin_text = "[N/A]" + if admin := await after.guild.fet_member(audit_event.user_id): + admin_mention = admin.mention + admin_text = f"{admin.username}#{admin.discriminator}" + fields = ( + EmbedField(name="Moderator", value=f"{admin_mention} ({admin_text})"), + EmbedField(name="Reason", value=audit_event.reason) + ) + embed = build_embed(title="User Verified", description=f"{after.mention} was verified", fields=fields, color="#fc9e3f") + embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) + embed.set_footer(text=f"{after.username}#{after.discriminator} | {after.id}") + return embed + + async def process_rolechange(self, before: Member, after: Member) -> Embed: + """Process role changes.""" + if before.roles == after.roles: + return + + auditlog = await after.guild.fetch_audit_log(user_id=before.id, action_type=AuditLogEventType.MEMBER_ROLE_UPDATE) + new_roles = {} + removed_roles = {} + + for role in before.roles: + if role not in after.roles: + reason = "N/A" + if entry := find(lambda x: x.new_value == role.id, auditlog.entires): + reason = entry.reason + removed_roles[role] = reason + for role in after.roles: + if role not in before.roles: + reason = "N/A" + if entry := find(lambda x: x.new_value == role.id, auditlog.entires): + reason = entry.reason + new_roles[role] = reason + + new_text = "\n".join(f"k [v]" for k, v in new_roles.items()) or "None" + removed_text = "\n".join(f"k [v]" for k, v in removed_roles.items()) or "None" + + fields = ( + EmbedField(name="Added Roles", value=new_text), + EmbedField(name="Removed Roles", value=removed_text), + ) + embed = build_embed(title="User Roles Changed", description=f"{after.mention} had roles changed", fields=fields, color="#fc9e3f") + embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) + embed.set_footer(text=f"{after.username}#{after.discriminator} | {after.id}") + return embed + + async def process_rename(self, before: Member, after: member) -> None: + """Process name change.""" + if before.nickname == after.nickname and before.discriminator == after.discriminator and before.username == after.username: + return + + fields = ( + EmbedField(name="Before", value=f"{before.display_name} ({before.username}#{before.discriminator})"), + EmbedField(name="After", value=f"{after.display_name} ({after.username}#{after.discriminator})"), + ) + embed = build_embed(title="User Renamed", description=f"{after.mention} changed their name", fields=fields, color="#fc9e3f") + embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) + embed.set_footer(text=f"{after.username}#{after.discriminator} | {after.id}") + return embed + + @listen() + async def on_member_update(self, event: MemberUpdate) -> None: + """Handle on_member_update event.""" + before = event.before + after = event.after + + if (before.display_name == after.display_name and before.roles == after.roles) or (not after or not before): + return + + log = await Setting.find_one(q(guild=guild.id, setting="activitylog")) + if log: + channel = await before.guild.fetch_channel(log.value) + await asyncio.sleep(0.5) # Wait for audit log + embed = None + if before._role_ids != after._role_ids: + verified = await Settings.find_one(q(guild=before.guild.id, setting="verified")) + v_role = None + if verified: + v_role = await before.guild.fetch_role(verified.value) + if not v_role: + self.logger.debug(f"Guild {before.guild.id} verified role no longer exists") + await verified.delete() + else: + if not before.has_role(v_role) and after.has_role(v_role): + embed = await self.process_verify(before, after) + if not embed: + embed = self.process_rolechange(before, after) or self.process_rename(before, after) + if embed: + await channel.send(embed=embed) + # Message async def autopurge(self, message: Message) -> None: """Handle autopurge events."""