Skip to content

Commit

Permalink
begin work on adding comments to functions
Browse files Browse the repository at this point in the history
  • Loading branch information
imtherealF1 committed Jan 3, 2025
1 parent 2c90d3a commit fc522bc
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 0 deletions.
5 changes: 5 additions & 0 deletions ballsdex/packages/admin/balls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@


async def save_file(attachment: discord.Attachment) -> Path:
"""
Saves an uploaded Discord attachment to the server's file system.
Ensures that the file does not overwrite any existing files by appending
a numeric suffix to the filename if necessary.
"""
path = Path(f"./static/uploads/{attachment.filename}")
match = FILENAME_RE.match(attachment.filename)
if not match:
Expand Down
3 changes: 3 additions & 0 deletions ballsdex/packages/admin/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def __init__(self, entries: Iterable[BlacklistHistory], user_id: int, bot: "Ball
super().__init__(entries, per_page=1)

async def format_page(self, menu: Pages, blacklist: BlacklistHistory) -> discord.Embed:
"""
Formats an embed page to display blacklist history for a user.
"""
embed = discord.Embed(
title=f"Blacklist History for {self.header}",
description=f"Type: {blacklist.action_type}\nReason: {blacklist.reason}",
Expand Down
12 changes: 12 additions & 0 deletions ballsdex/packages/balls/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ def __init__(
self.new_player = new_player

async def interaction_check(self, interaction: discord.Interaction, /) -> bool:
"""
Validates whether the user interacting with a menu is authorized to do so.
"""
if interaction.user.id != self.new_player.discord_id:
await interaction.response.send_message(
"You are not allowed to interact with this menu.", ephemeral=True
Expand All @@ -52,6 +55,9 @@ async def interaction_check(self, interaction: discord.Interaction, /) -> bool:
return True

async def on_timeout(self):
"""
Handles the event when the menu times out due to inactivity.
"""
for item in self.children:
item.disabled = True # type: ignore
try:
Expand All @@ -66,6 +72,9 @@ async def on_timeout(self):
style=discord.ButtonStyle.success, emoji="\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}"
)
async def accept(self, interaction: discord.Interaction, button: Button):
"""
Handles the acceptance of a donation.
"""
self.stop()
for item in self.children:
item.disabled = True # type: ignore
Expand All @@ -89,6 +98,9 @@ async def accept(self, interaction: discord.Interaction, button: Button):
emoji="\N{HEAVY MULTIPLICATION X}\N{VARIATION SELECTOR-16}",
)
async def deny(self, interaction: discord.Interaction, button: Button):
"""
Handles the rejection of a donation.
"""
self.stop()
for item in self.children:
item.disabled = True # type: ignore
Expand Down
32 changes: 32 additions & 0 deletions ballsdex/packages/balls/countryballs_paginator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@


class CountryballsSource(menus.ListPageSource):
"""
A data source for paginating a list of BallInstance objects.
This class provides logic for formatting and managing a paginated view
of countryballs for display in Discord embeds.
"""
def __init__(self, entries: List[BallInstance]):
super().__init__(entries, per_page=25)

Expand All @@ -22,13 +28,23 @@ async def format_page(self, menu: CountryballsSelector, balls: List[BallInstance


class CountryballsSelector(Pages):
"""
A pagination menu for displaying and selecting countryballs.
This class uses the `Pages` paginator and integrates a dropdown menu
for users to select a countryball.
"""

def __init__(self, interaction: discord.Interaction["BallsDexBot"], balls: List[BallInstance]):
self.bot = interaction.client
source = CountryballsSource(balls)
super().__init__(source, interaction=interaction)
self.add_item(self.select_ball_menu)

def set_options(self, balls: List[BallInstance]):
"""
Formats a page of countryballs and signals the selector to update.
"""
options: List[discord.SelectOption] = []
for ball in balls:
emoji = self.bot.get_emoji(int(ball.countryball.emoji_id))
Expand All @@ -50,18 +66,34 @@ def set_options(self, balls: List[BallInstance]):

@discord.ui.select()
async def select_ball_menu(self, interaction: discord.Interaction, item: discord.ui.Select):
"""
Handles the selection of a countryball from the dropdown menu.
"""
await interaction.response.defer(thinking=True)
ball_instance = await BallInstance.get(
id=int(interaction.data.get("values")[0]) # type: ignore
)
await self.ball_selected(interaction, ball_instance)

async def ball_selected(self, interaction: discord.Interaction, ball_instance: BallInstance):
"""
A placeholder method for handling selected countryballs.
"""
raise NotImplementedError()


class CountryballsViewer(CountryballsSelector):
"""
A specialized version of CountryballsSelector for viewing countryballs.
Overrides the `ball_selected` method to handle displaying information
about a selected countryball.
"""

async def ball_selected(self, interaction: discord.Interaction, ball_instance: BallInstance):
"""
Handles the display of a selected countryball.
"""
content, file = await ball_instance.prepare_for_message(interaction)
await interaction.followup.send(content=content, file=file)
file.close()
9 changes: 9 additions & 0 deletions ballsdex/packages/config/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def __init__(
)

async def interaction_check(self, interaction: discord.Interaction) -> bool:
"""
Validates whether the user interacting with a menu is authorized to do so.
"""
if interaction.user.id != self.new_player.id:
await interaction.response.send_message(
"You are not allowed to interact with this menu.", ephemeral=True
Expand All @@ -53,6 +56,9 @@ async def interaction_check(self, interaction: discord.Interaction) -> bool:
emoji="\N{HEAVY CHECK MARK}\N{VARIATION SELECTOR-16}",
)
async def accept_button(self, interaction: discord.Interaction, button: discord.ui.Button):
"""
Handles the acceptance of the configuration embed.
"""
config, created = await GuildConfig.get_or_create(guild_id=interaction.guild_id)
config.spawn_channel = self.channel.id # type: ignore
config.enabled = True
Expand All @@ -74,6 +80,9 @@ async def accept_button(self, interaction: discord.Interaction, button: discord.
)

async def on_timeout(self) -> None:
"""
Handles the event when the menu times out due to inactivity.
"""
if self.message:
for item in self.children:
if isinstance(item, discord.ui.Button):
Expand Down
8 changes: 8 additions & 0 deletions ballsdex/packages/countryballs/ab_spawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def get_manager(self, guild: "discord.Guild") -> BaseSpawnManager:
return self.manager_b

async def handle_message(self, message: "discord.Message") -> bool | tuple[Literal[True], str]:
"""
Handles an incoming message, processes it through the manager,
and returns the result along with a message.
"""
assert message.guild
manager = self.get_manager(message.guild)
result = await manager.handle_message(message)
Expand All @@ -64,6 +68,10 @@ async def handle_message(self, message: "discord.Message") -> bool | tuple[Liter
async def admin_explain(
self, interaction: "discord.Interaction[BallsDexBot]", guild: "discord.Guild"
):
"""
Explains the server's manager assignment and sends a follow-up message
to the admin with the relevant information.
"""
manager = self.get_manager(guild)
await manager.admin_explain(interaction, guild)
if manager == self.manager_a:
Expand Down
4 changes: 4 additions & 0 deletions ballsdex/packages/countryballs/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def __init__(self, bot: "BallsDexBot"):
self.spawn_manager = spawn_manager(bot)

async def load_cache(self):
"""
Loads the cache with guild spawn channel data for all enabled guilds
with a non-null spawn channel.
"""
i = 0
async for config in GuildConfig.filter(enabled=True, spawn_channel__isnull=False).only(
"guild_id", "spawn_channel"
Expand Down
15 changes: 15 additions & 0 deletions ballsdex/packages/countryballs/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def __init__(self, ball: "CountryBall", button: Button):
self.button = button

async def on_error(self, interaction: discord.Interaction, error: Exception, /) -> None:
"""
Gracefully handle the case where an error occurs.
"""
log.exception("An error occured in countryball catching prompt", exc_info=error)
if interaction.response.is_done():
await interaction.followup.send(
Expand All @@ -46,6 +49,9 @@ async def on_error(self, interaction: discord.Interaction, error: Exception, /)
)

async def on_submit(self, interaction: discord.Interaction["BallsDexBot"]):
"""
Handle the submitted guesses of users.
"""
# TODO: use lock
await interaction.response.defer(thinking=True)

Expand Down Expand Up @@ -97,6 +103,9 @@ async def on_submit(self, interaction: discord.Interaction["BallsDexBot"]):
async def catch_ball(
self, bot: "BallsDexBot", user: discord.Member
) -> tuple[BallInstance, bool]:
"""
This functions gives the countryball to the fastest user to catch.
"""
player, created = await Player.get_or_create(discord_id=user.id)

# stat may vary by +/- 20% of base stat
Expand Down Expand Up @@ -167,6 +176,9 @@ async def interaction_check(self, interaction: discord.Interaction["BallsDexBot"
return await interaction.client.blacklist_check(interaction)

async def on_timeout(self):
"""
Handle the timeout of the view.
"""
self.catch_button.disabled = True
if self.ball.message:
try:
Expand All @@ -176,6 +188,9 @@ async def on_timeout(self):

@button(style=discord.ButtonStyle.primary, label="Catch me!")
async def catch_button(self, interaction: discord.Interaction["BallsDexBot"], button: Button):
"""
Format the 'Catch me!' button and handle the catching of the countryball.
"""
if self.ball.catched:
await interaction.response.send_message("I was caught already!", ephemeral=True)
else:
Expand Down
15 changes: 15 additions & 0 deletions ballsdex/packages/countryballs/spawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ class SpawnCooldown:
message_cache: deque[CachedMessage] = field(default_factory=lambda: deque(maxlen=100))

def reset(self, time: datetime):
"""
Resets the manager's state to default values.
"""
self.scaled_message_count = 1.0
self.threshold = random.randint(*SPAWN_CHANCE_RANGE)
try:
Expand All @@ -116,6 +119,10 @@ def reset(self, time: datetime):
self.time = time

async def increase(self, message: discord.Message) -> bool:
"""
Increases the message count based on various conditions, affecting the
spawn manager's behavior.
"""
# this is a deque, not a list
# its property is that, once the max length is reached (100 for us),
# the oldest element is removed, thus we only have the last 100 messages in memory
Expand Down Expand Up @@ -149,6 +156,10 @@ def __init__(self, bot: "BallsDexBot"):
self.cooldowns: dict[int, SpawnCooldown] = {}

async def handle_message(self, message: discord.Message) -> bool:
"""
Handles a message by checking if spawn conditions are met and whether
a spawn should occur.
"""
guild = message.guild
if not guild:
return False
Expand Down Expand Up @@ -191,6 +202,10 @@ async def handle_message(self, message: discord.Message) -> bool:
async def admin_explain(
self, interaction: discord.Interaction["BallsDexBot"], guild: discord.Guild
):
"""
Provides an explanation to the admin regarding spawn conditions and
the current state of the spawn manager for a guild.
"""
cooldown = self.cooldowns.get(guild.id)
if not cooldown:
await interaction.response.send_message(
Expand Down

0 comments on commit fc522bc

Please sign in to comment.