Closes #11
This commit is contained in:
@@ -18,6 +18,7 @@ from classes.errors import (
|
|||||||
EventStageMissingSequenceError,
|
EventStageMissingSequenceError,
|
||||||
EventStageNotFoundError,
|
EventStageNotFoundError,
|
||||||
GuildNotFoundError,
|
GuildNotFoundError,
|
||||||
|
DiscordGuildMemberNotFoundError,
|
||||||
)
|
)
|
||||||
from modules.database import col_events, col_users
|
from modules.database import col_events, col_users
|
||||||
from modules.utils import get_logger
|
from modules.utils import get_logger
|
||||||
@@ -118,9 +119,25 @@ class PycordBot(LibPycordBot):
|
|||||||
await user._set(self.cache, current_event_id=event._id, current_stage_id=first_stage._id)
|
await user._set(self.cache, current_event_id=event._id, current_stage_id=first_stage._id)
|
||||||
|
|
||||||
# Create a channel for each participant
|
# Create a channel for each participant
|
||||||
user_channel: TextChannel | None = await user.setup_event_channel(
|
try:
|
||||||
self, guild, pycord_guild, event, cache=self.cache
|
user_channel: TextChannel | None = await user.setup_event_channel(
|
||||||
)
|
self, guild, pycord_guild, event, cache=self.cache
|
||||||
|
)
|
||||||
|
except DiscordGuildMemberNotFoundError:
|
||||||
|
logger.error(
|
||||||
|
"Could not create and configure event channel for user %s in %s (event %s): user not found in the guild",
|
||||||
|
user.id,
|
||||||
|
guild.id,
|
||||||
|
event._id,
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.notify_admins(
|
||||||
|
guild,
|
||||||
|
pycord_guild,
|
||||||
|
f"Event channel could not be created for user with ID `{user.id}` (<@{user.id}>) and event **{event.name}**: user was not found on the server.",
|
||||||
|
)
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
if user_channel is None:
|
if user_channel is None:
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -374,3 +391,25 @@ class PycordBot(LibPycordBot):
|
|||||||
processed_attachments.append({"id": attachment.id, "filename": attachment.filename})
|
processed_attachments.append({"id": attachment.id, "filename": attachment.filename})
|
||||||
|
|
||||||
return processed_attachments
|
return processed_attachments
|
||||||
|
|
||||||
|
# TODO Add documentation
|
||||||
|
async def send_stage_question(
|
||||||
|
self,
|
||||||
|
channel: TextChannel,
|
||||||
|
event: PycordEvent,
|
||||||
|
stage: Optional[PycordEventStage] = None,
|
||||||
|
use_first_stage: bool = False,
|
||||||
|
) -> None:
|
||||||
|
stage: PycordEventStage = (
|
||||||
|
stage
|
||||||
|
if not use_first_stage or stage is not None
|
||||||
|
else await self.find_event_stage(event.stage_ids[0])
|
||||||
|
)
|
||||||
|
|
||||||
|
stage_files: List[File] | None = stage.get_media_files()
|
||||||
|
|
||||||
|
question_chunks: List[str] = stage.get_question_chunked(2000)
|
||||||
|
question_chunks_length: int = len(question_chunks)
|
||||||
|
|
||||||
|
for index, chunk in enumerate(question_chunks):
|
||||||
|
await channel.send(chunk, files=None if index != question_chunks_length - 1 else stage_files)
|
||||||
|
@@ -275,9 +275,10 @@ class PycordUser:
|
|||||||
guild: Guild,
|
guild: Guild,
|
||||||
pycord_guild: "PycordGuild",
|
pycord_guild: "PycordGuild",
|
||||||
pycord_event: "PycordEvent",
|
pycord_event: "PycordEvent",
|
||||||
|
ignore_exists: bool = False,
|
||||||
cache: Optional[Cache] = None,
|
cache: Optional[Cache] = None,
|
||||||
) -> TextChannel | None:
|
) -> TextChannel | None:
|
||||||
if str(pycord_event._id) in self.event_channels.keys():
|
if not ignore_exists and str(pycord_event._id) in self.event_channels.keys():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
discord_member: Member | None = guild.get_member(self.id)
|
discord_member: Member | None = guild.get_member(self.id)
|
||||||
@@ -314,6 +315,43 @@ class PycordUser:
|
|||||||
|
|
||||||
return channel
|
return channel
|
||||||
|
|
||||||
|
# TODO Add documentation
|
||||||
|
async def fix_event_channel(
|
||||||
|
self,
|
||||||
|
bot: Bot,
|
||||||
|
guild: Guild,
|
||||||
|
pycord_guild: "PycordGuild",
|
||||||
|
pycord_event: "PycordEvent",
|
||||||
|
cache: Optional[Cache] = None,
|
||||||
|
) -> TextChannel | None:
|
||||||
|
# Configure channel if not set
|
||||||
|
if str(pycord_event._id) not in self.event_channels.keys():
|
||||||
|
return await self.setup_event_channel(bot, guild, pycord_guild, pycord_event, cache=cache)
|
||||||
|
|
||||||
|
discord_member: Member | None = guild.get_member(self.id)
|
||||||
|
|
||||||
|
if discord_member is None:
|
||||||
|
raise DiscordGuildMemberNotFoundError(self.id, guild.id)
|
||||||
|
|
||||||
|
channel: TextChannel = guild.get_channel(self.event_channels[str(pycord_event._id)])
|
||||||
|
|
||||||
|
if channel is None:
|
||||||
|
return await self.setup_event_channel(
|
||||||
|
bot, guild, pycord_guild, pycord_event, ignore_exists=True, cache=cache
|
||||||
|
)
|
||||||
|
|
||||||
|
await channel.set_permissions(
|
||||||
|
discord_member,
|
||||||
|
overwrite=PermissionOverwrite(
|
||||||
|
view_channel=True,
|
||||||
|
send_messages=True,
|
||||||
|
use_application_commands=True,
|
||||||
|
),
|
||||||
|
reason=f"Updated event channel of {self.id} for event {pycord_event._id}",
|
||||||
|
)
|
||||||
|
|
||||||
|
return channel
|
||||||
|
|
||||||
# TODO Add documentation
|
# TODO Add documentation
|
||||||
async def lock_event_channel(
|
async def lock_event_channel(
|
||||||
self,
|
self,
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from bson.errors import InvalidId
|
from bson.errors import InvalidId
|
||||||
from discord import ApplicationContext, Cog, File, TextChannel, option, slash_command
|
from discord import ApplicationContext, Cog, TextChannel, option, slash_command, File
|
||||||
from discord.utils import basic_autocomplete
|
from discord.utils import basic_autocomplete
|
||||||
from libbot.i18n import _, in_every_locale
|
from libbot.i18n import _, in_every_locale
|
||||||
|
|
||||||
@@ -126,15 +125,7 @@ class CogRegister(Cog):
|
|||||||
|
|
||||||
await user.set_event_stage(first_stage._id, cache=self.bot.cache)
|
await user.set_event_stage(first_stage._id, cache=self.bot.cache)
|
||||||
|
|
||||||
first_stage_files: List[File] | None = first_stage.get_media_files()
|
await self.bot.send_stage_question(user_channel, pycord_event, first_stage)
|
||||||
|
|
||||||
question_chunks: List[str] = first_stage.get_question_chunked(2000)
|
|
||||||
question_chunks_length: int = len(question_chunks)
|
|
||||||
|
|
||||||
for index, chunk in enumerate(question_chunks):
|
|
||||||
await user_channel.send(
|
|
||||||
chunk, files=None if index != question_chunks_length - 1 else first_stage_files
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: PycordBot) -> None:
|
def setup(bot: PycordBot) -> None:
|
||||||
|
@@ -1,8 +1,17 @@
|
|||||||
|
from datetime import datetime
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, List
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from discord import Activity, ActivityType, Cog, Member
|
from bson import ObjectId
|
||||||
|
from bson.errors import InvalidId
|
||||||
|
from discord import Activity, ActivityType, Cog, Member, TextChannel, File
|
||||||
|
|
||||||
|
from classes import PycordEvent, PycordGuild, PycordUser
|
||||||
|
from classes.errors import GuildNotFoundError
|
||||||
from classes.pycord_bot import PycordBot
|
from classes.pycord_bot import PycordBot
|
||||||
|
from modules.database import col_users
|
||||||
from modules.utils import get_logger
|
from modules.utils import get_logger
|
||||||
|
|
||||||
logger: Logger = get_logger(__name__)
|
logger: Logger = get_logger(__name__)
|
||||||
@@ -53,10 +62,78 @@ class CogUtility(Cog):
|
|||||||
|
|
||||||
logger.info("Set activity type to %s with message %s", activity_type, activity_message)
|
logger.info("Set activity type to %s with message %s", activity_type, activity_message)
|
||||||
|
|
||||||
# TODO Implement #11
|
@Cog.listener("on_member_join")
|
||||||
@Cog.listener()
|
|
||||||
async def on_member_join(self, member: Member) -> None:
|
async def on_member_join(self, member: Member) -> None:
|
||||||
pass
|
try:
|
||||||
|
guild: PycordGuild = await self.bot.find_guild(member.guild.id)
|
||||||
|
except (InvalidId, GuildNotFoundError) as exc:
|
||||||
|
logger.error(
|
||||||
|
"Could not process member join event for %s in %s due to: %s",
|
||||||
|
member.id,
|
||||||
|
member.guild.id,
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
user: PycordUser = await self.bot.find_user(member.id, member.guild.id)
|
||||||
|
events: List[PycordEvent] = []
|
||||||
|
|
||||||
|
pipeline: List[Dict[str, Any]] = [
|
||||||
|
{"$match": {"id": user.id}},
|
||||||
|
{
|
||||||
|
"$lookup": {
|
||||||
|
"from": "events",
|
||||||
|
"localField": "registered_event_ids",
|
||||||
|
"foreignField": "_id",
|
||||||
|
"as": "registered_events",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$match": {
|
||||||
|
"registered_events.ended": None,
|
||||||
|
"registered_events.ends": {"$gt": datetime.now(tz=ZoneInfo("UTC"))},
|
||||||
|
"registered_events.starts": {"$lt": datetime.now(tz=ZoneInfo("UTC"))},
|
||||||
|
"registered_events.is_cancelled": False,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
async for result in col_users.aggregate(pipeline):
|
||||||
|
for registered_event in result["registered_events"]:
|
||||||
|
events.append(PycordEvent(**registered_event))
|
||||||
|
|
||||||
|
for event in events:
|
||||||
|
if user.current_event_id is not None and user.current_event_id != event._id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if user.current_event_id is None:
|
||||||
|
await user.set_event(event._id, cache=self.bot.cache)
|
||||||
|
|
||||||
|
channel: TextChannel | None = await user.fix_event_channel(
|
||||||
|
self.bot, member.guild, guild, event, cache=self.bot.cache
|
||||||
|
)
|
||||||
|
|
||||||
|
if channel is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
thumbnail: File | None = (
|
||||||
|
None
|
||||||
|
if event.thumbnail is None
|
||||||
|
else File(Path(f"data/{event.thumbnail['id']}"), event.thumbnail["filename"])
|
||||||
|
)
|
||||||
|
|
||||||
|
await channel.send(
|
||||||
|
self.bot._("register_already_started", "messages").format(event_name=event.name),
|
||||||
|
file=thumbnail,
|
||||||
|
)
|
||||||
|
|
||||||
|
stage_id: ObjectId = (
|
||||||
|
event.stage_ids[0] if user.current_stage_id is None else user.current_stage_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await user.set_event_stage(stage_id, cache=self.bot.cache)
|
||||||
|
|
||||||
|
await self.bot.send_stage_question(channel, event, await self.bot.find_event_stage(stage_id))
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: PycordBot) -> None:
|
def setup(bot: PycordBot) -> None:
|
||||||
|
@@ -50,6 +50,7 @@ async def autocomplete_user_registered_events(ctx: AutocompleteContext) -> List[
|
|||||||
"""Return list of active events user is registered in"""
|
"""Return list of active events user is registered in"""
|
||||||
|
|
||||||
pipeline: List[Dict[str, Any]] = [
|
pipeline: List[Dict[str, Any]] = [
|
||||||
|
{"$match": {"id": ctx.interaction.user.id}},
|
||||||
{
|
{
|
||||||
"$lookup": {
|
"$lookup": {
|
||||||
"from": "events",
|
"from": "events",
|
||||||
|
Reference in New Issue
Block a user