165 lines
5.8 KiB
Python
165 lines
5.8 KiB
Python
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))
|