Skip to content

Commit

Permalink
Added new method for dynamic options
Browse files Browse the repository at this point in the history
  • Loading branch information
Marko259 committed Sep 27, 2024
1 parent eee2b8e commit e777287
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 21 deletions.
6 changes: 5 additions & 1 deletion bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@
@bot.event
async def on_ready() -> None:
print(f'Bot started. \nUsername: {bot.user.name}. \nID: {bot.user.id}', flush=True)
guild = bot.get_guild(GUILD_ID)

try:
await bot.change_presence(activity=config.activity(), status=config.status())
await bot.tree.sync()
if guild:
await bot.tree.sync(guild=guild) # Sync commands to a specific guild for faster deployment
else:
await bot.tree.sync() # Sync global commands (might take up to 1 hour to reflect globally)
except BadArgument as e:
print(f'Error changing presence. Exception - {e}', flush=True)

Expand Down
48 changes: 42 additions & 6 deletions cogs/staffings.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from typing_extensions import Literal
import discord
import asyncio
import re

from discord import app_commands, TextChannel
from discord import app_commands, TextChannel, Interaction
from discord.ext import commands, tasks

from datetime import datetime

from typing_extensions import Literal, List

from helpers.booking import Booking
from helpers.message import staff_roles, is_obs
from helpers.staffing_async import StaffingAsync
Expand All @@ -34,10 +35,16 @@ def cog_unload(self):
# SLASH COMMAND FUNCTIONS
# ----------------------------------
#

# A function to dynamically fetch and return a list of titles as choices
async def get_title_choices(self) -> List[app_commands.Choice[str]]:
titles = StaffingAsync._get_titles()
return [app_commands.Choice(name=title, value=title) for title in titles]

@app_commands.command(name="setupstaffing", description="Bot setups staffing information")
@app_commands.describe(title="What should the title of the staffing be?", week_int="What should the week interval be? eg. 1 then the date will be selected each week.", section_amount="What should the section amount be? eg. 3 then there will be 3 sections.", restrict_booking="Should the staffing restrict booking to first section before allowing other sections too?")
@app_commands.checks.has_any_role(*staff_roles())
async def setup_staffing(self, interaction: discord.Integration, title: StaffingAsync._get_titles(), week_int: app_commands.Range[int, 1, 4], section_amount: app_commands.Range[int, 1, 4], restrict_booking: Literal["Yes", "No"], channel: TextChannel):
async def setup_staffing(self, interaction: Interaction, title: str, week_int: app_commands.Range[int, 1, 4], section_amount: app_commands.Range[int, 1, 4], restrict_booking: Literal["Yes", "No"], channel: TextChannel):
ctx: commands.Context = await self.bot.get_context(interaction)
interaction._baton = ctx
dates = await StaffingAsync._geteventdate(self, title)
Expand Down Expand Up @@ -93,20 +100,37 @@ async def setup_staffing(self, interaction: discord.Integration, title: Staffing
DB.insert(self=self, table="positions", columns=['position', 'user', 'type', 'local_booking', 'start_time', 'end_time', 'event'], values=[pos, "", j, local[section_positions[x][pos]['local_booking']], section_positions[x][pos]['start_time'], section_positions[x][pos]['end_time'], event])
j += 1

# Link this command to custom autocomplete for titles
@setup_staffing.autocomplete("title")
async def title_autocomplete(self, interaction: Interaction, current: str):
titles = await self.get_title_choices()
return [choice for choice in titles if current.lower() in choice.name.lower()][:25] # Limit to 25 choices (Discord limit)

# A function to dynamically fetch and return a list of titles as choices
async def get_avail_title_choices(self) -> List[app_commands.Choice[str]]:
titles = StaffingAsync._get_avail_titles()
return [app_commands.Choice(name=title, value=title) for title in titles]

@app_commands.command(name="refreshevent", description="Bot refreshes selected event")
@app_commands.describe(title="Which staffing would you like to refresh?")
@app_commands.checks.has_any_role(*staff_roles())
async def refreshevent(self, interaction: discord.Integration, title: StaffingAsync._get_avail_titles()):
async def refreshevent(self, interaction: discord.Integration, title: str):
id = DB.select(table="staffing", columns=['id'], where=['title'], value={'title': title})[0]
await StaffingAsync._updatemessage(self, id)
ctx: commands.Context = await self.bot.get_context(interaction)
interaction._baton = ctx
await ctx.send(f"{ctx.author.mention} Event `{title}` has been refreshed", delete_after=5, ephemeral=True)

# Link this command to custom autocomplete for titles
@refreshevent.autocomplete("title")
async def title_autocomplete(self, interaction: Interaction, current: str):
titles = await self.get_avail_title_choices()
return [choice for choice in titles if current.lower() in choice.name.lower()][:25] # Limit to 25 choices (Discord limit)

@app_commands.command(name="manreset", description="Bot manually resets selected event")
@app_commands.describe(title="Which staffing would you like to manually reset?")
@app_commands.checks.has_any_role(*staff_roles())
async def manreset(self, interaction: discord.Integration, title: StaffingAsync._get_avail_titles()):
async def manreset(self, interaction: discord.Integration, title: str):
await self.bot.wait_until_ready()
ctx: commands.Context = await self.bot.get_context(interaction)
interaction._baton = ctx
Expand All @@ -133,10 +157,16 @@ async def manreset(self, interaction: discord.Integration, title: StaffingAsync.
except Exception as e:
await ctx.send(f"{ctx.author.mention} The bot failed to manual reset `{title}` with error `{e}` at `{str(datetime.now().isoformat())}`", ephemeral=True)

# Link this command to custom autocomplete for titles
@manreset.autocomplete("title")
async def title_autocomplete(self, interaction: Interaction, current: str):
titles = await self.get_avail_title_choices()
return [choice for choice in titles if current.lower() in choice.name.lower()][:25] # Limit to 25 choices (Discord limit)

@app_commands.command(name="updatestaffing", description="Bot updates selected staffing")
@app_commands.describe(title="Which staffing would you like to update?")
@app_commands.checks.has_any_role(*staff_roles())
async def updatestaffing(self, interaction: discord.Integration, title: StaffingAsync._get_avail_titles()):
async def updatestaffing(self, interaction: discord.Integration, title: str):
ctx: commands.Context = await self.bot.get_context(interaction)
interaction._baton = ctx
try:
Expand All @@ -145,6 +175,12 @@ async def updatestaffing(self, interaction: discord.Integration, title: Staffing
except Exception as e:
await ctx.send(f'Error updating staffing {title} - {e}')
raise e

# Link this command to custom autocomplete for titles
@updatestaffing.autocomplete("title")
async def title_autocomplete(self, interaction: Interaction, current: str):
titles = await self.get_avail_title_choices()
return [choice for choice in titles if current.lower() in choice.name.lower()][:25] # Limit to 25 choices (Discord limit)

@app_commands.command(name="book", description="Bot books selected position for selected staffing")
@app_commands.describe(position="Which position would you like to book?")
Expand Down
10 changes: 9 additions & 1 deletion cogs/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,20 @@ async def user_check(self, interaction: discord.Integration):

async def sync_commands(self, override=False):
now = datetime.now().isoformat()
guild = self.bot.get_guild(GUILD_ID)

try:
if DEBUG == True and override == False:
print("sync_commands skipped due to DEBUG ON. You can start manually with command instead.", flush=True)
return

print("sync_commands started at " + str(datetime.now().isoformat()), flush=True)
await self.bot.tree.sync(guild=discord.Object(id=GUILD_ID))

if guild:
await self.bot.tree.sync(guild=guild) # Sync commands to a specific guild for faster deployment
else:
await self.bot.tree.sync() # Sync global commands (might take up to 1 hour to reflect globally)

print("sync_commands finished at " + str(datetime.now().isoformat()), flush=True)
except Exception as e:
print(f'Failed to sync commands with error - {e} - at - {now}', flush=True)
Expand Down
32 changes: 19 additions & 13 deletions helpers/staffing_async.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import re
import requests
from typing import Literal
from typing import Literal, List

from datetime import datetime, timedelta

Expand All @@ -21,36 +21,42 @@ def __init__(self) -> None:
# ASYNC DATA FUNCTIONS
# ----------------------------------
#
def _get_titles() -> Literal:
events = DB.select(table='events', columns=[
'name'], amount='all')
staffings = DB.select(
table="staffing", columns=['title'], amount='all')
formatted_staffings = []
def _get_titles() -> List[str]:
"""
Function to fetch and return a list of unique event titles from the database
excluding titles already used in staffing.
"""
# Fetch event names and staffing titles from the database
events = DB.select(table='events', columns=['name'], amount='all')
staffings = DB.select(table="staffing", columns=['title'], amount='all')

formatted_staffings = set(" ".join(map(str, staffing)) for staffing in staffings)
formatted_events = []

# If no events are found, append a message indicating no availability
if not events:
formatted_events.append('None is available. Please try again later.')
else:
for staffing in staffings:
formatted_staffings.append(" ".join(map(str, staffing)))

for event in events:
formatted_event = " ".join(map(str, event))
# Add the event only if it is not already present in staffing
if formatted_event not in formatted_staffings:
formatted_events.append(formatted_event)
return Literal[tuple(formatted_events)]

# Return a list of unique event titles
return list(set(formatted_events))

def _get_avail_titles() -> Literal:
def _get_avail_titles() -> List[str]:
staffings = DB.select(table="staffing", columns=['title'], amount='all')

formatted_staffings = []
if not staffings:
formatted_staffings.append('None is available. Please try again later.')
else:
for staffing in staffings:
formatted_staffings.append(" ".join(map(str, staffing)))

return Literal[tuple(formatted_staffings)]
return list[set(formatted_staffings)]

async def _get_description(self, ctx):
"""
Expand Down

0 comments on commit e777287

Please sign in to comment.