GloryBot/cogs/cog_member_join.py

165 lines
5.8 KiB
Python
Raw Permalink Normal View History

2024-06-02 22:51:07 +03:00
import logging
from typing import Union
from discord import Cog, Member, TextChannel, Thread
from discord.abc import GuildChannel
from classes.errors import (
CheckAlreadyAssignedError,
CheckNotFoundError,
GuildChallengesEmptyError,
GuildNotFoundError,
)
from classes.pycord_bot import PycordBot
from classes.pycord_challenge import PycordChallenge
from classes.pycord_check import PycordCheck
from classes.pycord_guild import PycordGuild
from classes.pycord_member import PycordMember
logger = logging.getLogger(__name__)
class CogMemberJoin(Cog):
def __init__(self, client: PycordBot) -> None:
super().__init__()
self.client: PycordBot = client
@Cog.listener()
async def on_member_join(self, member: Member):
"""Process the event of new or returning member joining the guild.
This handler must take care of the new users, returning verified as well as returning banned users.
Guild must exist and be set up correctly in order to use this handler and process the input.
### Args:
* member (`Member`): Member that has joined the guild
"""
# Check whether the guild exists in the database
# We should not create it here when it does not exist. Config will be empty
try:
pycord_guild: PycordGuild = await self.client.find_guild(member.guild.id)
except GuildNotFoundError:
# Let's notify guild admins about this
logger.error(
"Guild %s is not set up properly: guild is missing from the database.",
member.guild.id,
)
return
# Get the member and create if it does not exist
pycord_member: PycordMember = await self.client.find_member(
member.id, pycord_guild._id, create=True
)
# Check whether guild is set up properly
if not pycord_guild.is_valid() or pycord_guild.channels.captcha is None:
# Let's notify guild admins about this
logger.error(
"Guild %s is not set up properly: check %s in database for details.",
member.guild.id,
pycord_guild._id,
)
return
# Check whether member already has an active check
try:
await pycord_member.get_check()
# Let's notify guild admins and user about this
logger.error(
"Member %s of guild %s could not get a check: user already has an active check.",
member.id,
member.guild.id,
)
return
except CheckNotFoundError:
logger.info(
"Member %s of guild %s does bot have a check yet.",
member.id,
member.guild.id,
)
captcha_channel: Union[GuildChannel, None] = member.guild.get_channel(
pycord_guild.channels.captcha
)
# Check whether the channel exists and is a text channel
if captcha_channel is None or not isinstance(captcha_channel, TextChannel):
logger.error(
"Captcha channel of the guild %s either does not exist or is incorrect."
)
return
# Try creating a thread
try:
captcha_thread: Thread = await captcha_channel.create_thread(
name=f"Verification - @{member.name}",
invitable=False,
reason=f"Verification - @{member.name} ({member.id})",
)
except Exception as exc:
logger.error(
"Could not create captcha thread for the channel %s in guild %s (%s) due to %s",
captcha_channel.id,
pycord_guild.id,
pycord_guild._id,
exc,
)
return
try:
check: PycordCheck = await pycord_member.new_check(captcha_thread.id)
challenge: PycordChallenge = await check.get_challenge()
except GuildChallengesEmptyError:
logger.error(
"Guild %s (%s) has no active challenges, check is aborted.",
pycord_guild.id,
pycord_guild._id,
)
await captcha_thread.delete()
return
except CheckAlreadyAssignedError:
logger.error(
"Member %s of the guild %s (%s) already has an active check, check is aborted.",
member.id,
pycord_guild.id,
pycord_guild._id,
)
await captcha_thread.delete()
return
try:
await captcha_thread.send(
f"Welcome, {member.mention}!\n\nTo keep this Discord server safe, we need to verify that you are a human.\n\nPlease, complete the sentence below:\n`{challenge.challenge} ...`\n\nUse the command `/verify` and the verification answer as its argument to pass the check."
)
except Exception as exc:
logger.error(
"Could not send the challenge to the thread %s in guild %s (%s) due to %s",
captcha_thread.id,
pycord_guild.id,
pycord_guild._id,
exc,
)
return
try:
await captcha_channel.send(
f"Welcome, {member.mention}! Please proceed to {captcha_thread.mention} in order to complete the verification.",
delete_after=180,
)
except Exception as exc:
logger.error(
"Could not send a notification about the challenge to the channel %s in guild %s (%s) due to %s",
captcha_channel.id,
pycord_guild.id,
pycord_guild._id,
exc,
)
return
def setup(client: PycordBot):
client.add_cog(CogMemberJoin(client))