Improved some messages and prepared them for i18n

This commit is contained in:
2025-04-26 18:21:09 +02:00
parent a17b1cd768
commit ca1e47b55a
16 changed files with 167 additions and 172 deletions

View File

@@ -1,17 +1,17 @@
from datetime import datetime
from logging import Logger
from pathlib import Path
from typing import Any, override, List, Dict
from typing import Any, Dict, List, override
from zoneinfo import ZoneInfo
from bson import ObjectId
from discord import Guild, User, TextChannel, Attachment, File
from discord import Attachment, File, Guild, TextChannel, User
from libbot.cache.classes import CacheMemcached, CacheRedis
from libbot.cache.manager import create_cache_client
from libbot.pycord.classes import PycordBot as LibPycordBot
from classes import PycordEvent, PycordEventStage, PycordGuild, PycordUser
from modules.database import col_users, col_events
from modules.database import col_events, col_users
from modules.utils import get_logger
logger: Logger = get_logger(__name__)
@@ -53,9 +53,7 @@ class PycordBot(LibPycordBot):
await super().close(**kwargs)
async def _schedule_tasks(self) -> None:
self.scheduler.add_job(
self._execute_event_controller, trigger="cron", minute="*/1", id="event_controller"
)
self.scheduler.add_job(self._execute_event_controller, trigger="cron", minute="*/1", id="event_controller")
async def _execute_event_controller(self) -> None:
await self._process_events_start()
@@ -105,9 +103,7 @@ class PycordBot(LibPycordBot):
first_stage_files: List[File] | None = first_stage.get_media_files()
await user_channel.send(
f"First stage...\n\n{first_stage.question}", files=first_stage_files
)
await user_channel.send(f"First stage...\n\n{first_stage.question}", files=first_stage_files)
# TODO Make a nice message
await self.notify_admins(
@@ -126,7 +122,7 @@ class PycordBot(LibPycordBot):
for event in events:
guild: Guild = self.get_guild(event.guild_id)
pycord_guild: PycordGuild = await self.find_guild(guild)
stages: List[PycordEventStage] = await self._get_event_stages(event)
stages: List[PycordEventStage] = await self.get_event_stages(event)
# TODO Make a nice message
stages_string: str = "\n\n".join(
@@ -174,7 +170,8 @@ class PycordBot(LibPycordBot):
return users
async def _get_event_stages(self, event: PycordEvent) -> List[PycordEventStage]:
# TODO Add documentation
async def get_event_stages(self, event: PycordEvent) -> List[PycordEventStage]:
return [(await self.find_event_stage(stage_id)) for stage_id in event.stage_ids]
# TODO Add documentation
@@ -254,9 +251,7 @@ class PycordBot(LibPycordBot):
return event_stage
# TODO Document this method
async def find_event(
self, event_id: str | ObjectId | None = None, event_name: str | None = None
) -> PycordEvent:
async def find_event(self, event_id: str | ObjectId | None = None, event_name: str | None = None) -> PycordEvent:
if event_id is None and event_name is None:
raise AttributeError("Either event's ID or name must be provided!")

View File

@@ -286,9 +286,7 @@ class PycordEvent:
stage_index: int = self.stage_ids.index(event_stage_id)
old_stage_index: int = old_stage_ids.index(event_stage_id)
logger.debug(
"Indexes for %s: was %s and is now %s", event_stage_id, old_stage_index, stage_index
)
logger.debug("Indexes for %s: was %s and is now %s", event_stage_id, old_stage_index, stage_index)
if stage_index != old_stage_index:
await (await bot.find_event_stage(event_stage_id)).update(cache, sequence=stage_index)

View File

@@ -4,7 +4,15 @@ from logging import Logger
from typing import Any, Dict, List, Optional
from bson import ObjectId
from discord import Bot, Guild, Member, PermissionOverwrite, TextChannel, Forbidden, Role
from discord import (
Bot,
Forbidden,
Guild,
Member,
PermissionOverwrite,
Role,
TextChannel,
)
from discord.abc import GuildChannel
from libbot.cache.classes import Cache
from pymongo.results import InsertOneResult
@@ -106,12 +114,8 @@ class PycordUser:
"guild_id": self.guild_id,
"event_channels": self.event_channels,
"is_jailed": self.is_jailed,
"current_event_id": (
self.current_event_id if not json_compatible else str(self.current_event_id)
),
"current_stage_id": (
self.current_stage_id if not json_compatible else str(self.current_stage_id)
),
"current_event_id": (self.current_event_id if not json_compatible else str(self.current_event_id)),
"current_stage_id": (self.current_stage_id if not json_compatible else str(self.current_stage_id)),
"registered_event_ids": (
self.registered_event_ids
if not json_compatible
@@ -367,9 +371,7 @@ class PycordUser:
# TODO Add documentation
async def set_event_stage(self, stage_id: str | ObjectId | None, cache: Optional[Cache] = None) -> None:
await self._set(
cache, current_stage_id=stage_id if isinstance(stage_id, str) else ObjectId(stage_id)
)
await self._set(cache, current_stage_id=stage_id if isinstance(stage_id, str) else ObjectId(stage_id))
async def jail(self, cache: Optional[Cache] = None) -> None:
await self._set(cache, is_jailed=True)

View File

@@ -9,14 +9,14 @@ from discord import (
)
from discord.ext.commands import Cog
from discord.utils import basic_autocomplete
from libbot.i18n import in_every_locale, _
from libbot.i18n import _, in_every_locale
from classes import PycordGuild
from classes.pycord_bot import PycordBot
from modules.utils import autocomplete_timezones
from modules.utils import autocomplete_timezones, is_operation_confirmed
class Config(Cog):
class CogConfig(Cog):
"""Cog with guild configuration commands."""
def __init__(self, bot: PycordBot):
@@ -36,18 +36,14 @@ class Config(Cog):
@option(
"category",
description=_("description", "commands", "config_set", "options", "category"),
description_localizations=in_every_locale(
"description", "commands", "config_set", "options", "category"
),
description_localizations=in_every_locale("description", "commands", "config_set", "options", "category"),
required=True,
)
@option("channel", description="Text channel for admin notifications", required=True)
@option(
"timezone",
description=_("description", "commands", "config_set", "options", "timezone"),
description_localizations=in_every_locale(
"description", "commands", "config_set", "options", "timezone"
),
description_localizations=in_every_locale("description", "commands", "config_set", "options", "timezone"),
autocomplete=basic_autocomplete(autocomplete_timezones),
required=True,
)
@@ -63,9 +59,7 @@ class Config(Cog):
try:
timezone_parsed: ZoneInfo = ZoneInfo(timezone)
except ZoneInfoNotFoundError:
await ctx.respond(
self.bot._("timezone_invalid", "messages", locale=ctx.locale).format(timezone=timezone)
)
await ctx.respond(self.bot._("timezone_invalid", "messages", locale=ctx.locale).format(timezone=timezone))
return
await guild.update(
@@ -85,14 +79,11 @@ class Config(Cog):
@option(
"confirm",
description=_("description", "commands", "config_reset", "options", "confirm"),
description_localizations=in_every_locale(
"description", "commands", "config_reset", "options", "confirm"
),
description_localizations=in_every_locale("description", "commands", "config_reset", "options", "confirm"),
required=False,
)
async def command_config_reset(self, ctx: ApplicationContext, confirm: bool = False) -> None:
if confirm is None or not confirm:
await ctx.respond(self.bot._("operation_unconfirmed", "messages", locale=ctx.locale))
if not (await is_operation_confirmed(ctx, confirm)):
return
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
@@ -123,4 +114,4 @@ class Config(Cog):
def setup(bot: PycordBot) -> None:
bot.add_cog(Config(bot))
bot.add_cog(CogConfig(bot))

View File

@@ -1,5 +1,5 @@
from datetime import datetime
from typing import Dict, List, Any
from typing import Any, Dict, List
from zoneinfo import ZoneInfo
from bson.errors import InvalidId
@@ -12,12 +12,17 @@ from discord import (
from discord.ext.commands import Cog
from discord.utils import basic_autocomplete
from classes import PycordEvent, PycordGuild
from classes import PycordEvent, PycordEventStage, PycordGuild
from classes.pycord_bot import PycordBot
from modules.utils import autocomplete_active_events, validate_event_validity
from modules.utils import (
autocomplete_active_events,
get_unix_timestamp,
is_operation_confirmed,
validate_event_validity,
)
class Event(Cog):
class CogEvent(Cog):
"""Cog with event management commands."""
def __init__(self, bot: PycordBot):
@@ -46,8 +51,7 @@ class Event(Cog):
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale))
return
guild_timezone: ZoneInfo = ZoneInfo(guild.timezone)
@@ -59,8 +63,10 @@ class Event(Cog):
start_date = start_date.replace(tzinfo=guild_timezone)
end_date = end_date.replace(tzinfo=guild_timezone)
except ValueError:
# TODO Make a nice message
await ctx.respond("Could not parse start and end dates.")
# TODO Introduce i18n
await ctx.respond(
"Could not parse start and end dates. Please, make sure these are provided in `DD.MM.YYYY HH:MM` format."
)
return
await validate_event_validity(ctx, name, start_date, end_date, guild_timezone)
@@ -78,8 +84,10 @@ class Event(Cog):
thumbnail=processed_media[0] if thumbnail else None,
)
# TODO Make a nice message
await ctx.respond("Event has been created.")
# TODO Introduce i18n
await ctx.respond(
f"Event **{event.name}** has been created and will take place <t:{get_unix_timestamp(event.starts)}:R>."
)
# TODO Introduce i18n
@command_group.command(
@@ -115,8 +123,7 @@ class Event(Cog):
return
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale))
return
guild_timezone: ZoneInfo = ZoneInfo(guild.timezone)
@@ -132,9 +139,7 @@ class Event(Cog):
return
try:
end_date: datetime = (
pycord_event.ends if end is None else datetime.strptime(end, "%d.%m.%Y %H:%M")
)
end_date: datetime = pycord_event.ends if end is None else datetime.strptime(end, "%d.%m.%Y %H:%M")
end_date = end_date.replace(tzinfo=guild_timezone)
except ValueError:
# TODO Make a nice message
@@ -155,8 +160,12 @@ class Event(Cog):
thumbnail=pycord_event.thumbnail if thumbnail is None else processed_media[0],
)
# TODO Notify participants about time changes
# TODO Make a nice message
await ctx.respond("Event has been updated.")
await ctx.respond(
f"Event **{pycord_event.name}** has been updated and will take place <t:{get_unix_timestamp(pycord_event.starts)}:R>."
)
# TODO Introduce i18n
@command_group.command(
@@ -176,9 +185,7 @@ class Event(Cog):
event: str,
confirm: bool = False,
) -> None:
if confirm is None or not confirm:
# TODO Make a nice message
await ctx.respond("Operation not confirmed.")
if not (await is_operation_confirmed(ctx, confirm)):
return
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
@@ -191,8 +198,7 @@ class Event(Cog):
return
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale))
return
start_date: datetime = pycord_event.starts.replace(tzinfo=ZoneInfo("UTC"))
@@ -210,8 +216,10 @@ class Event(Cog):
await pycord_event.cancel()
# TODO Notify participants about cancellation
# TODO Make a nice message
await ctx.respond("Event was cancelled.")
await ctx.respond(f"Event **{pycord_event.name}** was cancelled.")
# TODO Introduce i18n
@command_group.command(
@@ -237,11 +245,21 @@ class Event(Cog):
starts_date: datetime = pycord_event.starts.replace(tzinfo=ZoneInfo("UTC"))
ends_date: datetime = pycord_event.ends.replace(tzinfo=ZoneInfo("UTC"))
stages: List[PycordEventStage] = await self.bot.get_event_stages(pycord_event)
# TODO Make a nice message
stages_string: str = "\n\n".join(
f"**Stage {stage.sequence+1}**\nQuestion: {stage.question}\nAnswer: ||{stage.answer}||"
for stage in stages
)
# TODO Show users registered for the event
# TODO Introduce i18n
await ctx.respond(
f"**Event details**\n\nName: {pycord_event.name}\nStarts: <t:{int(starts_date.timestamp())}>\nEnds: <t:{int(ends_date.timestamp())}>"
f"**Event details**\n\nName: {pycord_event.name}\nStarts: <t:{get_unix_timestamp(starts_date)}>\nEnds: <t:{get_unix_timestamp(ends_date)}>\n\nStages:\n{stages_string}"
)
def setup(bot: PycordBot) -> None:
bot.add_cog(Event(bot))
bot.add_cog(CogEvent(bot))

View File

@@ -2,13 +2,13 @@ from typing import List
from bson import ObjectId
from bson.errors import InvalidId
from discord import ApplicationContext, Cog, option, slash_command, File
from discord import ApplicationContext, Cog, File, option, slash_command
from classes import PycordEvent, PycordUser, PycordGuild, PycordEventStage
from classes import PycordEvent, PycordEventStage, PycordGuild, PycordUser
from classes.pycord_bot import PycordBot
class Guess(Cog):
class CogGuess(Cog):
"""Cog with the guessing command."""
def __init__(self, bot: PycordBot):
@@ -24,17 +24,14 @@ class Guess(Cog):
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured", "messages", locale=ctx.locale))
return
user: PycordUser = await self.bot.find_user(ctx.author, ctx.guild)
if user.is_jailed:
# TODO Make a nice message
await ctx.respond(
"You are jailed and cannot interact with events. Please, contact the administrator."
)
await ctx.respond("You are jailed and cannot interact with events. Please, contact the administrator.")
return
if user.current_event_id is None or user.current_stage_id is None:
@@ -47,9 +44,7 @@ class Guess(Cog):
stage: PycordEventStage = await self.bot.find_event_stage(user.current_stage_id)
except (InvalidId, RuntimeError):
# TODO Make a nice message
await ctx.respond(
"Your event could not be found. Please, report this issue to the event's management."
)
await ctx.respond("Your event could not be found. Please, report this issue to the event's management.")
return
if ctx.channel_id != user.event_channels[str(event._id)]:
@@ -107,4 +102,4 @@ class Guess(Cog):
def setup(bot: PycordBot) -> None:
bot.add_cog(Guess(bot))
bot.add_cog(CogGuess(bot))

View File

@@ -1,15 +1,13 @@
from zoneinfo import ZoneInfo
from bson.errors import InvalidId
from discord import ApplicationContext, Cog, option, slash_command
from discord.utils import basic_autocomplete
from classes import PycordEvent, PycordGuild, PycordUser
from classes.pycord_bot import PycordBot
from modules.utils import autocomplete_active_events
from modules.utils import autocomplete_active_events, get_unix_timestamp
class Register(Cog):
class CogRegister(Cog):
"""Cog with the event registration command."""
def __init__(self, bot: PycordBot):
@@ -36,17 +34,14 @@ class Register(Cog):
return
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured", "messages", locale=ctx.locale))
return
user: PycordUser = await self.bot.find_user(ctx.author, ctx.guild)
if user.is_jailed:
# TODO Make a nice message
await ctx.respond(
"You are jailed and cannot interact with events. Please, contact the administrator."
)
await ctx.respond("You are jailed and cannot interact with events. Please, contact the administrator.")
return
if pycord_event._id in user.registered_event_ids:
@@ -58,9 +53,9 @@ class Register(Cog):
# TODO Make a nice message
await ctx.respond(
f"You are now registered for the event **{pycord_event.name}**.\n\nNew channel will be created for you and further instructions will be provided as soon as the event starts <t:{int((pycord_event.starts.replace(tzinfo=ZoneInfo('UTC'))).timestamp())}:R>. Good luck!"
f"You are now registered for the event **{pycord_event.name}**.\n\nNew channel will be created for you and further instructions will be provided as soon as the event starts <t:{get_unix_timestamp(pycord_event.starts)}:R>. Good luck!"
)
def setup(bot: PycordBot) -> None:
bot.add_cog(Register(bot))
bot.add_cog(CogRegister(bot))

View File

@@ -1,6 +1,4 @@
from datetime import datetime
from typing import List, Dict, Any
from zoneinfo import ZoneInfo
from typing import Any, Dict, List
from bson.errors import InvalidId
from discord import ApplicationContext, Attachment, SlashCommandGroup, option
@@ -9,31 +7,15 @@ from discord.utils import basic_autocomplete
from classes import PycordEvent, PycordEventStage, PycordGuild
from classes.pycord_bot import PycordBot
from modules.utils import autocomplete_active_events, autocomplete_event_stages
from modules.utils import (
autocomplete_active_events,
autocomplete_event_stages,
is_event_status_valid,
is_operation_confirmed,
)
async def validate_event_status(
ctx: ApplicationContext,
event: PycordEvent,
) -> bool:
if event.is_cancelled:
# TODO Make a nice message
await ctx.respond("This event was cancelled.")
return False
if (
event.starts.replace(tzinfo=ZoneInfo("UTC"))
<= datetime.now(tz=ZoneInfo("UTC"))
<= event.ends.replace(tzinfo=ZoneInfo("UTC"))
):
# TODO Make a nice message
await ctx.respond("Ongoing events cannot be modified.")
return False
return True
class Stage(Cog):
class CogStage(Cog):
"""Cog with event stage management commands."""
def __init__(self, bot: PycordBot):
@@ -67,8 +49,7 @@ class Stage(Cog):
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale))
return
try:
@@ -78,12 +59,10 @@ class Stage(Cog):
await ctx.respond("Event was not found.")
return
if not (await validate_event_status(ctx, pycord_event)):
if not (await is_event_status_valid(ctx, pycord_event)):
return
processed_media: List[Dict[str, Any]] = (
[] if media is None else await self.bot.process_attachments([media])
)
processed_media: List[Dict[str, Any]] = [] if media is None else await self.bot.process_attachments([media])
event_stage: PycordEventStage = await self.bot.create_event_stage(
event=pycord_event,
@@ -137,8 +116,7 @@ class Stage(Cog):
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale))
return
try:
@@ -148,7 +126,7 @@ class Stage(Cog):
await ctx.respond("Event was not found.")
return
if not (await validate_event_status(ctx, pycord_event)):
if not (await is_event_status_valid(ctx, pycord_event)):
return
try:
@@ -163,9 +141,7 @@ class Stage(Cog):
await ctx.respond("Stage sequence out of range.")
return
processed_media: List[Dict[str, Any]] = (
[] if media is None else await self.bot.process_attachments([media])
)
processed_media: List[Dict[str, Any]] = [] if media is None else await self.bot.process_attachments([media])
if not (question is None and answer is None and media is None and remove_media is False):
await event_stage.update(
@@ -201,16 +177,13 @@ class Stage(Cog):
async def command_stage_delete(
self, ctx: ApplicationContext, event: str, stage: str, confirm: bool = False
) -> None:
if confirm is None or not confirm:
# TODO Make a nice message
await ctx.respond("Operation not confirmed.")
if not (await is_operation_confirmed(ctx, confirm)):
return
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale))
return
try:
@@ -220,7 +193,7 @@ class Stage(Cog):
await ctx.respond("Event was not found.")
return
if not (await validate_event_status(ctx, pycord_event)):
if not (await is_event_status_valid(ctx, pycord_event)):
return
try:
@@ -238,4 +211,4 @@ class Stage(Cog):
def setup(bot: PycordBot) -> None:
bot.add_cog(Stage(bot))
bot.add_cog(CogStage(bot))

View File

@@ -4,10 +4,10 @@ from discord.utils import basic_autocomplete
from classes import PycordEvent, PycordGuild, PycordUser
from classes.pycord_bot import PycordBot
from modules.utils import autocomplete_user_registered_events
from modules.utils import autocomplete_user_registered_events, is_operation_confirmed
class Unregister(Cog):
class CogUnregister(Cog):
"""Cog with the event unregistration command."""
def __init__(self, bot: PycordBot):
@@ -25,9 +25,7 @@ class Unregister(Cog):
)
@option("confirm", description="Confirmation of the operation", required=False)
async def command_unregister(self, ctx: ApplicationContext, event: str, confirm: bool = False) -> None:
if confirm is None or not confirm:
# TODO Make a nice message
await ctx.respond("Operation not confirmed.")
if not (await is_operation_confirmed(ctx, confirm)):
return
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
@@ -40,17 +38,14 @@ class Unregister(Cog):
return
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
await ctx.respond(self.bot._("guild_unconfigured", "messages", locale=ctx.locale))
return
user: PycordUser = await self.bot.find_user(ctx.author, ctx.guild)
if user.is_jailed:
# TODO Make a nice message
await ctx.respond(
"You are jailed and cannot interact with events. Please, contact the administrator."
)
await ctx.respond("You are jailed and cannot interact with events. Please, contact the administrator.")
return
if pycord_event._id not in user.registered_event_ids:
@@ -66,4 +61,4 @@ class Unregister(Cog):
def setup(bot: PycordBot) -> None:
bot.add_cog(Unregister(bot))
bot.add_cog(CogUnregister(bot))

View File

@@ -8,9 +8,10 @@ from discord.ext.commands import Cog
from classes import PycordUser
from classes.pycord_bot import PycordBot
from modules.utils import is_operation_confirmed
class User(Cog):
class CogUser(Cog):
"""Cog with user management commands."""
def __init__(self, bot: PycordBot):
@@ -53,9 +54,7 @@ class User(Cog):
description="Selected user",
)
@option("confirm", description="Confirmation of the operation", required=False)
async def command_user_delete_channel(
self, ctx: ApplicationContext, user: User, confirm: bool = False
) -> None:
async def command_user_delete_channel(self, ctx: ApplicationContext, user: User, confirm: bool = False) -> None:
await ctx.respond("Not implemented.")
# TODO Introduce i18n
@@ -69,23 +68,20 @@ class User(Cog):
)
@option("confirm", description="Confirmation of the operation", required=False)
async def command_user_jail(self, ctx: ApplicationContext, user: User, confirm: bool = False) -> None:
if confirm is None or not confirm:
await ctx.respond(self.bot._("operation_unconfirmed", "messages", locale=ctx.locale))
if not (await is_operation_confirmed(ctx, confirm)):
return
pycord_user: PycordUser = await self.bot.find_user(user, ctx.guild)
if pycord_user.is_jailed:
# TODO Make a nice message
# TODO Introduce i18n
await ctx.respond(f"User **{user.display_name}** is already jailed.")
return
await pycord_user.jail(self.bot.cache)
# TODO Make a nice message
await ctx.respond(
f"User **{user.display_name}** has been jailed and cannot interact with events anymore."
)
# TODO Introduce i18n
await ctx.respond(f"User **{user.display_name}** has been jailed and cannot interact with events anymore.")
# TODO Introduce i18n
@command_group.command(
@@ -98,24 +94,21 @@ class User(Cog):
)
@option("confirm", description="Confirmation of the operation", required=False)
async def command_user_unjail(self, ctx: ApplicationContext, user: User, confirm: bool = False) -> None:
if confirm is None or not confirm:
await ctx.respond(self.bot._("operation_unconfirmed", "messages", locale=ctx.locale))
if not (await is_operation_confirmed(ctx, confirm)):
return
pycord_user: PycordUser = await self.bot.find_user(user, ctx.guild)
if not pycord_user.is_jailed:
# TODO Make a nice message
# TODO Introduce i18n
await ctx.respond(f"User **{user.display_name}** is not jailed.")
return
await pycord_user.unjail(self.bot.cache)
# TODO Make a nice message
await ctx.respond(
f"User **{user.display_name}** has been unjailed and can interact with events again."
)
# TODO Introduce i18n
await ctx.respond(f"User **{user.display_name}** has been unjailed and can interact with events again.")
def setup(bot: PycordBot) -> None:
bot.add_cog(User(bot))
bot.add_cog(CogUser(bot))

View File

@@ -6,7 +6,7 @@ from os import makedirs
from pathlib import Path
from sys import exit
from discord import LoginFailure, Intents
from discord import Intents, LoginFailure
from libbot.utils import config_get
from classes.pycord_bot import PycordBot

View File

@@ -7,5 +7,7 @@ from .autocomplete_utils import (
autocomplete_user_registered_events,
)
from .cache_utils import restore_from_cache
from .datetime_utils import get_unix_timestamp
from .event_utils import validate_event_validity
from .logging_utils import get_logger, get_logging_config
from .validation_utils import is_event_status_valid, is_operation_confirmed

View File

@@ -92,8 +92,6 @@ async def autocomplete_event_stages(ctx: AutocompleteContext) -> List[OptionChoi
event_stages: List[OptionChoice] = []
async for result in col_stages.find(query).sort([("sequence", ASCENDING)]):
event_stages.append(
OptionChoice(f"{result['sequence']+1} ({result['question']})", str(result["_id"]))
)
event_stages.append(OptionChoice(f"{result['sequence']+1} ({result['question']})", str(result["_id"])))
return event_stages

View File

@@ -0,0 +1,7 @@
from datetime import datetime
from zoneinfo import ZoneInfo
# TODO Add documentation
def get_unix_timestamp(date: datetime) -> int:
return int((date.replace(tzinfo=ZoneInfo("UTC"))).timestamp())

View File

@@ -0,0 +1,33 @@
from datetime import datetime
from zoneinfo import ZoneInfo
from discord import ApplicationContext
async def is_operation_confirmed(ctx: ApplicationContext, confirm: bool) -> bool:
if confirm is None or not confirm:
await ctx.respond(ctx.bot._("operation_unconfirmed", "messages", locale=ctx.locale))
return False
return True
async def is_event_status_valid(
ctx: ApplicationContext,
event: "PycordEvent",
) -> bool:
if event.is_cancelled:
# TODO Make a nice message
await ctx.respond("This event was cancelled.")
return False
if (
event.starts.replace(tzinfo=ZoneInfo("UTC"))
<= datetime.now(tz=ZoneInfo("UTC"))
<= event.ends.replace(tzinfo=ZoneInfo("UTC"))
):
# TODO Make a nice message
await ctx.respond("Ongoing events cannot be modified.")
return False
return True

View File

@@ -5,7 +5,7 @@ readme = "README.md"
requires-python = ">=3.11"
[tool.black]
line-length = 108
line-length = 118
target-version = ["py311", "py312", "py313"]
[tool.isort]