Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
intents.message_content = True

class Bot(discord.Client):
"""
The core bot client that manages the help queue, UI views, and scheduled tasks.
Extends discord.Client to handle queue interactions and audio notifications.
"""
def __init__(self):
super().__init__(intents=intents)
self.tree = app_commands.CommandTree(self)
Expand All @@ -31,6 +35,10 @@ def __init__(self):
self._player_task: Optional[asyncio.Task] = None

async def setup_hook(self):
"""
Initializes bot UI components (views) and starts background scheduling tasks
before the bot fully connects to Discord.
"""
# guild = self.get_guild(1503856452027023451)
# print(guild.name)
# self.tree.copy_global_to(guild=guild)
Expand All @@ -52,7 +60,7 @@ async def on_ready(self):
async def get_ta_voice_channel(self) -> discord.VoiceChannel | None:
for guild in self.guilds:
return get(guild.voice_channels, name=TA_VOICE_CHANNEL_NAME)


async def _play_notifications(self) -> None:
"""Join TA voice channel and play random mp3 from resources once per minute until queue empty."""
Expand Down Expand Up @@ -129,7 +137,7 @@ async def build_queue_status(self) -> str:
queue_text = await self.queue.view()
return f"**Help Queue Status: {status}**\n{queue_text}"

async def fetch_or_create_queue_status_message(self) -> discord.Message | None:
async def _get_status_message(self) -> discord.Message | None:
ta_channel = await self.get_ta_channel()
if ta_channel is None:
return None
Expand All @@ -149,8 +157,8 @@ async def fetch_or_create_queue_status_message(self) -> discord.Message | None:
self.queue_status_message_id = status_message.id
return status_message

async def update_queue_status_message(self) -> None:
status_message = await self.fetch_or_create_queue_status_message()
async def _update_status(self) -> None:
status_message = await self._get_status_message()
if status_message is None:
return

Expand All @@ -162,7 +170,7 @@ async def build_help_queue_count(self) -> str:
count = len(self.queue.entries)
return f"**Help Queue Status: {status} — {count} student{'s' if count != 1 else ''} in queue**"

async def fetch_or_create_help_queue_count_message(self) -> discord.Message | None:
async def _get_count_message(self) -> discord.Message | None:
help_channel = await self.get_help_channel()
if help_channel is None:
return None
Expand All @@ -182,14 +190,25 @@ async def fetch_or_create_help_queue_count_message(self) -> discord.Message | No
self.help_queue_count_message_id = count_message.id
return count_message

async def update_help_queue_count_message(self) -> None:
count_message = await self.fetch_or_create_help_queue_count_message()
async def _update_count(self) -> None:
count_message = await self._get_count_message()
if count_message is None:
return

await count_message.edit(content=await self.build_help_queue_count())

async def queue_handler(self, interaction: discord.Interaction, question, is_passoff, in_person, student_name: str):
"""
Processes a new request to join the help queue, creates a QueueEntry,
updates the UI, and triggers the audio notification system if needed.

Args:
interaction (discord.Interaction): The user interaction context.
question (str): The student's question or issue details.
is_passoff (bool): Indicates if this is a required pass-off assignment.
in_person (bool): Indicates if the student is physically present.
student_name (str): The student's actual name.
"""
entry = QueueEntry(
user_id=interaction.user.id,
username=interaction.user.display_name,
Expand Down
21 changes: 19 additions & 2 deletions db.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ async def daily_reset() -> None:


def increment_help(user_id: int, user_name: str, student_name: Optional[str] = None) -> None:
"""
Records a help session for a user, incrementing both their total and daily help counts.
Creates a new user record if one does not exist.

Args:
user_id (int): The Discord user ID.
user_name (str): The user's Discord username.
student_name (Optional[str]): The student's actual name, if provided.
"""
cursor = conn.cursor()
cursor.execute(
"""
Expand All @@ -88,12 +97,20 @@ def increment_help(user_id: int, user_name: str, student_name: Optional[str] = N
)

if student_name:
_update_student_name_if_longer(user_id, student_name)
_update_student_name(user_id, student_name)

conn.commit()


def _update_student_name_if_longer(user_id: int, student_name: str) -> None:
def _update_student_name(user_id: int, student_name: str) -> None:
"""
Updates the student's name in the database if the new name provided is longer
than the currently stored name.

Args:
user_id (int): The Discord user ID of the student.
student_name (str): The new name to evaluate and potentially store.
"""
cursor = conn.cursor()
cursor.execute("SELECT student_name FROM user_stats WHERE user_id=?", (user_id,))
row = cursor.fetchone()
Expand Down
12 changes: 11 additions & 1 deletion ui/helpers/queue_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@
async def already_in_queue(interaction: discord.Interaction)->bool:
return await interaction.client.queue.is_in_queue(interaction.user.id)

async def require_queue_open_and_not_in_queue(interaction: discord.Interaction) -> bool:
async def can_join_queue(interaction: discord.Interaction) -> bool:
"""
Checks if the help queue is currently open and verifies that the user
is not already in it.

Args:
interaction (discord.Interaction): The interaction context from the user.

Returns:
bool: True if the queue is open and the user is not in it, False otherwise.
"""
if not interaction.client.queue.is_open:
await interaction.response.send_message("Queue is closed.", ephemeral=True, delete_after=20)
return False
Expand Down
6 changes: 3 additions & 3 deletions ui/views/queue_view.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import discord
from ui.helpers.queue_helpers import require_queue_open_and_not_in_queue
from ui.helpers.queue_helpers import can_join_queue
from db import get_times_helped_today
from ui.modals import HelpModal, PassoffModal, BotIssueModal
from ui.helpers.constants import DEFAULT_TIMEOUT, SHORT_TIMEOUT
Expand All @@ -12,7 +12,7 @@ def __init__(self):

@discord.ui.button(label="Need Help", style=discord.ButtonStyle.primary, custom_id="need_help", emoji="🙏")
async def help_btn(self, interaction: discord.Interaction, button):
ok = await require_queue_open_and_not_in_queue(interaction)
ok = await can_join_queue(interaction)
if not ok:
return

Expand All @@ -21,7 +21,7 @@ async def help_btn(self, interaction: discord.Interaction, button):

@discord.ui.button(label="Passoff", style=discord.ButtonStyle.success, custom_id="passoff", emoji="💪")
async def passoff_btn(self, interaction: discord.Interaction, button):
ok = await require_queue_open_and_not_in_queue(interaction)
ok = await can_join_queue(interaction)
if not ok:
return

Expand Down