Delete modules/reaction_role/reaction_role.py
This commit is contained in:
		
							parent
							
								
									5b2aa79b9f
								
							
						
					
					
						commit
						c88edf1fdd
					
				@ -1,219 +0,0 @@
 | 
				
			|||||||
import discord
 | 
					 | 
				
			||||||
from discord.ext import commands
 | 
					 | 
				
			||||||
from modules.common.emoji_accept import is_accept
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CHECKMARK = '✅'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ReactionRoleCog(commands.Cog):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Records agreements and manages Full Access.
 | 
					 | 
				
			||||||
    Nickname flow:
 | 
					 | 
				
			||||||
      • Add accept on nickname message -> mark agreed + pending (idempotent) and open ONE review
 | 
					 | 
				
			||||||
      • Remove accept on nickname message -> clear only if user has no accept reactions left
 | 
					 | 
				
			||||||
    Full Access: granted when Rules ✅ + RoE ✅ + Nickname *claimed* (pending or verified).
 | 
					 | 
				
			||||||
    Revoked when any of the three is missing.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, bot):
 | 
					 | 
				
			||||||
        self.bot = bot
 | 
					 | 
				
			||||||
        cfg = bot.config['DEFAULT']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _i(key):
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                v = cfg.get(key)
 | 
					 | 
				
			||||||
                return int(v) if v else 0
 | 
					 | 
				
			||||||
            except Exception:
 | 
					 | 
				
			||||||
                return 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.rules_msg_id = _i('rules_message_id')
 | 
					 | 
				
			||||||
        self.engage_msg_id = _i('engagement_message_id')
 | 
					 | 
				
			||||||
        self.nick_msg_id = _i('nickname_message_id')
 | 
					 | 
				
			||||||
        self.rules_role = _i('rules_role_id')
 | 
					 | 
				
			||||||
        self.engage_role = _i('engagement_role_id')
 | 
					 | 
				
			||||||
        self.full_access_role = _i('full_access_role_id')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # ---- helpers ----
 | 
					 | 
				
			||||||
    def _has_rules(self, member_id: int) -> bool:
 | 
					 | 
				
			||||||
        return member_id in self.bot.data_manager.get('agreed_rules')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _has_engage(self, member_id: int) -> bool:
 | 
					 | 
				
			||||||
        return member_id in self.bot.data_manager.get('agreed_engagement')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _has_nick_claim(self, member_id: int) -> bool:
 | 
					 | 
				
			||||||
        """Claimed = agreed_nickname; pending/verified tracked separately."""
 | 
					 | 
				
			||||||
        return member_id in self.bot.data_manager.get('agreed_nickname')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def maybe_apply_full_access(self, member: discord.Member):
 | 
					 | 
				
			||||||
        """Grant when Rules+RoE+Nickname *claimed*; revoke when any missing."""
 | 
					 | 
				
			||||||
        guild = member.guild
 | 
					 | 
				
			||||||
        role = guild.get_role(self.full_access_role) if self.full_access_role else None
 | 
					 | 
				
			||||||
        if not role:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        has_all = self._has_rules(member.id) and self._has_engage(member.id) and self._has_nick_claim(member.id)
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            if has_all and role not in member.roles:
 | 
					 | 
				
			||||||
                await member.add_roles(role, reason="All agreements completed (nickname may be pending)")
 | 
					 | 
				
			||||||
            elif not has_all and role in member.roles:
 | 
					 | 
				
			||||||
                await member.remove_roles(role, reason="Agreements incomplete or nickname unclaimed")
 | 
					 | 
				
			||||||
        except discord.Forbidden:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
        except Exception:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Best-effort: refresh user card
 | 
					 | 
				
			||||||
        cards = self.bot.get_cog('UserCardsCog')
 | 
					 | 
				
			||||||
        if cards:
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                await cards.refresh_card(member)
 | 
					 | 
				
			||||||
            except Exception:
 | 
					 | 
				
			||||||
                pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def _get_member(self, guild: discord.Guild, user_id: int):
 | 
					 | 
				
			||||||
        if not guild:
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
        m = guild.get_member(user_id)
 | 
					 | 
				
			||||||
        if m is None:
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                m = await guild.fetch_member(user_id)
 | 
					 | 
				
			||||||
            except Exception:
 | 
					 | 
				
			||||||
                return None
 | 
					 | 
				
			||||||
        return m
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def _user_has_any_accept(self, guild: discord.Guild, channel_id: int, message_id: int, user_id: int) -> bool:
 | 
					 | 
				
			||||||
        """Return True if the user still has at least one 'accept' reaction on the message."""
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            ch = guild.get_channel(channel_id)
 | 
					 | 
				
			||||||
            if not ch:
 | 
					 | 
				
			||||||
                return False
 | 
					 | 
				
			||||||
            msg = await ch.fetch_message(message_id)
 | 
					 | 
				
			||||||
            for rxn in msg.reactions:
 | 
					 | 
				
			||||||
                if is_accept(rxn.emoji):
 | 
					 | 
				
			||||||
                    async for u in rxn.users(limit=None):
 | 
					 | 
				
			||||||
                        if u.id == user_id:
 | 
					 | 
				
			||||||
                            return True
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
        except Exception:
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # ---- commands (hybrid = prefix + slash) ----
 | 
					 | 
				
			||||||
    @commands.hybrid_command(name='nick_same', description='Claim that your global display name matches your in-game name (triggers mod review)')
 | 
					 | 
				
			||||||
    async def nick_same(self, ctx: commands.Context):
 | 
					 | 
				
			||||||
        member = ctx.author if isinstance(ctx.author, discord.Member) else None
 | 
					 | 
				
			||||||
        if not member or not ctx.guild:
 | 
					 | 
				
			||||||
            return await ctx.reply("Use this in a server.", ephemeral=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        dm = self.bot.data_manager
 | 
					 | 
				
			||||||
        if member.id not in dm.get('agreed_nickname'):
 | 
					 | 
				
			||||||
            dm.add('agreed_nickname', int(member.id))
 | 
					 | 
				
			||||||
        # Mark pending (clear verified if present)
 | 
					 | 
				
			||||||
        dm.remove('nick_verified', lambda x: x == member.id)
 | 
					 | 
				
			||||||
        newly_pending = False
 | 
					 | 
				
			||||||
        if member.id not in dm.get('nick_claim_pending'):
 | 
					 | 
				
			||||||
            dm.add('nick_claim_pending', int(member.id))
 | 
					 | 
				
			||||||
            newly_pending = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Open/refresh a review with NickNudge (only on first transition to pending)
 | 
					 | 
				
			||||||
        if newly_pending:
 | 
					 | 
				
			||||||
            nn = self.bot.get_cog('NickNudgeCog')
 | 
					 | 
				
			||||||
            if nn and hasattr(nn, 'start_nick_review'):
 | 
					 | 
				
			||||||
                try:
 | 
					 | 
				
			||||||
                    await nn.start_nick_review(ctx.guild, member, source="nick_same")
 | 
					 | 
				
			||||||
                except Exception:
 | 
					 | 
				
			||||||
                    pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self.maybe_apply_full_access(member)
 | 
					 | 
				
			||||||
        await ctx.reply("Thanks — your nickname claim was sent for moderator review.", ephemeral=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # ---- listeners ----
 | 
					 | 
				
			||||||
    @commands.Cog.listener()
 | 
					 | 
				
			||||||
    async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
 | 
					 | 
				
			||||||
        if not payload.guild_id or not is_accept(payload.emoji):
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        guild = self.bot.get_guild(payload.guild_id)
 | 
					 | 
				
			||||||
        member = await self._get_member(guild, payload.user_id)
 | 
					 | 
				
			||||||
        if not member or member.bot:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        dm = self.bot.data_manager
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            if payload.message_id == self.rules_msg_id:
 | 
					 | 
				
			||||||
                role = guild.get_role(self.rules_role)
 | 
					 | 
				
			||||||
                if role:
 | 
					 | 
				
			||||||
                    await member.add_roles(role, reason="Agreed to rules")
 | 
					 | 
				
			||||||
                if member.id not in dm.get('agreed_rules'):
 | 
					 | 
				
			||||||
                    dm.add('agreed_rules', int(member.id))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            elif payload.message_id == self.engage_msg_id:
 | 
					 | 
				
			||||||
                role = guild.get_role(self.engage_role)
 | 
					 | 
				
			||||||
                if role:
 | 
					 | 
				
			||||||
                    await member.add_roles(role, reason="Agreed to engagement")
 | 
					 | 
				
			||||||
                if member.id not in dm.get('agreed_engagement'):
 | 
					 | 
				
			||||||
                    dm.add('agreed_engagement', int(member.id))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            elif payload.message_id == self.nick_msg_id:
 | 
					 | 
				
			||||||
                # Claim nickname via reaction -> mark agreed + pending (idempotent)
 | 
					 | 
				
			||||||
                newly_pending = False
 | 
					 | 
				
			||||||
                if member.id not in dm.get('agreed_nickname'):
 | 
					 | 
				
			||||||
                    dm.add('agreed_nickname', int(member.id))
 | 
					 | 
				
			||||||
                dm.remove('nick_verified', lambda x: x == member.id)
 | 
					 | 
				
			||||||
                if member.id not in dm.get('nick_claim_pending'):
 | 
					 | 
				
			||||||
                    dm.add('nick_claim_pending', int(member.id))
 | 
					 | 
				
			||||||
                    newly_pending = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # Only open a review when we just transitioned to pending
 | 
					 | 
				
			||||||
                if newly_pending:
 | 
					 | 
				
			||||||
                    nn = self.bot.get_cog('NickNudgeCog')
 | 
					 | 
				
			||||||
                    if nn and hasattr(nn, 'start_nick_review'):
 | 
					 | 
				
			||||||
                        try:
 | 
					 | 
				
			||||||
                            await nn.start_nick_review(guild, member, source="claim")
 | 
					 | 
				
			||||||
                        except Exception:
 | 
					 | 
				
			||||||
                            pass
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
        except Exception:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self.maybe_apply_full_access(member)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @commands.Cog.listener()
 | 
					 | 
				
			||||||
    async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent):
 | 
					 | 
				
			||||||
        if not payload.guild_id or not is_accept(payload.emoji):
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        guild = self.bot.get_guild(payload.guild_id)
 | 
					 | 
				
			||||||
        member = await self._get_member(guild, payload.user_id)
 | 
					 | 
				
			||||||
        if not member or member.bot:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        dm = self.bot.data_manager
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            if payload.message_id == self.rules_msg_id:
 | 
					 | 
				
			||||||
                dm.remove('agreed_rules', lambda x: x == member.id)
 | 
					 | 
				
			||||||
                role = guild.get_role(self.rules_role)
 | 
					 | 
				
			||||||
                if role:
 | 
					 | 
				
			||||||
                    await member.remove_roles(role, reason="Rules un-ticked")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            elif payload.message_id == self.engage_msg_id:
 | 
					 | 
				
			||||||
                dm.remove('agreed_engagement', lambda x: x == member.id)
 | 
					 | 
				
			||||||
                role = guild.get_role(self.engage_role)
 | 
					 | 
				
			||||||
                if role:
 | 
					 | 
				
			||||||
                    await member.remove_roles(role, reason="Engagement un-ticked")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            elif payload.message_id == self.nick_msg_id:
 | 
					 | 
				
			||||||
                # Clear only if the user has NO accept reactions left on the message
 | 
					 | 
				
			||||||
                still_has_accept = await self._user_has_any_accept(
 | 
					 | 
				
			||||||
                    guild, payload.channel_id, payload.message_id, member.id
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                if not still_has_accept:
 | 
					 | 
				
			||||||
                    dm.remove('agreed_nickname', lambda x: x == member.id)
 | 
					 | 
				
			||||||
                    dm.remove('nick_claim_pending', lambda x: x == member.id)
 | 
					 | 
				
			||||||
                    dm.remove('nick_verified', lambda x: x == member.id)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
        except Exception:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self.maybe_apply_full_access(member)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def setup(bot):
 | 
					 | 
				
			||||||
    await bot.add_cog(ReactionRoleCog(bot))
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user