Skip to content

Commit

Permalink
Add testing signup
Browse files Browse the repository at this point in the history
  • Loading branch information
cbrxyz committed Feb 16, 2024
1 parent eab2682 commit 3a2f04f
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async def setup_hook(self) -> None:
"src.reports",
"src.roles",
"src.welcome",
"src.testing",
)
for i, extension in enumerate(extensions):
try:
Expand Down
112 changes: 112 additions & 0 deletions src/testing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from __future__ import annotations

import datetime
from typing import TYPE_CHECKING, Literal

import discord
from discord import app_commands
from discord.ext import commands

from src.utils import DateTransformer, EmojiEmbed, TimeTransformer

from .views import MILBotView

if TYPE_CHECKING:
from .bot import MILBot


class TestingSignUpSelect(discord.ui.Select):
def __init__(self, vehicle: str):
options = [
discord.SelectOption(label="I cannot come", value="no", emoji="❌"),
discord.SelectOption(
label="I can come, but need a ride",
value="cannotdrive",
emoji="🚶",
),
discord.SelectOption(
label="I can come, and will bring my car",
value="candrive",
emoji="🚗",
),
]
if vehicle == "SubjuGator":
options.append(
discord.SelectOption(
label="I can come, and drive the sub",
value="candrivesub",
emoji="🤿",
),
)
super().__init__(
custom_id="testing_signup:select",
placeholder="Please respond with your availability...",
max_values=1,
options=options,
)


class TestingSignUpView(MILBotView):
def __init__(self, vehicle: str):
super().__init__(timeout=None)
self.add_item(TestingSignUpSelect(vehicle))


class TestingCog(commands.Cog):
def __init__(self, bot: MILBot):
self.bot = bot

@app_commands.command()
@app_commands.checks.has_role("Leaders")
async def testing(
self,
interaction: discord.Interaction,
vehicle: Literal["SubjuGator", "NaviGator", "Other"],
date: app_commands.Transform[datetime.date, DateTransformer],
location: str,
arrive_time: app_commands.Transform[datetime.time, TimeTransformer],
max_people: int = 10,
):
embed = EmojiEmbed(
title="Upcoming Testing: Are you going?",
color=discord.Color.from_str("0x5BCEFA"),
description="A leader has indicated that a testing is taking place soon. Having members come to testing is super helpful to streamlining the testing process, and for making the testing experience great for everyone. We'd appreciate if you could make it!",
)
arrive_dt = datetime.datetime.combine(date, arrive_time)
prep_dt = arrive_dt - datetime.timedelta(minutes=60)
date_str = f"{discord.utils.format_dt(arrive_dt, 'D')} ({discord.utils.format_dt(arrive_dt, 'R')})"
embed.add_field(emoji="🚀", name="Vehicle", value=vehicle, inline=True)
embed.add_field(emoji="📍", name="Location", value=location, inline=True)
embed.add_field(
emoji="👥",
name="Max People",
value=f"{max_people} people",
inline=True,
)
embed.add_field(emoji="📅", name="Date", value=date_str, inline=True)
embed.add_field(
emoji="⏰",
name="Prep Time",
value=discord.utils.format_dt(prep_dt, "t"),
inline=True,
)
embed.add_field(
emoji="⏰",
name="Testing Starts",
value=discord.utils.format_dt(arrive_dt, "t"),
inline=True,
)
mention = (
self.bot.leaders_role.mention
if interaction.channel == self.bot.leaders_channel
else self.bot.egn4912_role
)
await interaction.response.send_message(
mention,
embed=embed,
view=TestingSignUpView(vehicle),
)


async def setup(bot: MILBot):
await bot.add_cog(TestingCog(bot))
89 changes: 89 additions & 0 deletions src/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import datetime
import re

import discord
from discord import app_commands

from .constants import SEMESTERS

Expand All @@ -15,6 +19,91 @@ def is_active() -> bool:
return False


def emoji_header(emoji: str, title: str) -> str:
return f"{emoji} __{title}__"


class EmojiEmbed(discord.Embed):
def add_field(
self,
emoji: str,
name: str,
value: str,
*,
inline: bool = False,
) -> None:
super().add_field(name=emoji_header(emoji, name), value=value, inline=inline)


class DateTransformer(app_commands.Transformer):
async def transform(
self,
interaction: discord.Interaction,
value: str,
) -> datetime.date:
# Supports the following formats:
# 2021-09-01
# 9/1/2021
# 9/1/21
# 9-1-2021
# 9-1-21
# 9/1
# 9-1

value = value.replace(" ", "")

# Define regex patterns for different date formats
patterns = {
r"^(\d{4})-(\d{2})-(\d{2})$": "%Y-%m-%d", # 2021-09-01
r"^(\d{1,2})/(\d{1,2})/(\d{4})$": "%m/%d/%Y", # 9/1/2021
r"^(\d{1,2})/(\d{1,2})/(\d{2})$": "%m/%d/%y", # 9/1/21
r"^(\d{1,2})-(\d{1,2})-(\d{4})$": "%m-%d-%Y", # 9-1-2021
r"^(\d{1,2})-(\d{1,2})-(\d{2})$": "%m-%d-%y", # 9-1-21
r"^(\d{1,2})/(\d{1,2})$": "%m/%d", # 9/1
r"^(\d{1,2})-(\d{1,2})$": "%m-%d", # 9-1
}

for pattern, date_format in patterns.items():
if re.match(pattern, value):
# Convert matched value to datetime.date object
date_value = datetime.datetime.strptime(value, date_format).date()
return date_value

# If no pattern matches, you might want to raise an error or handle it gracefully
raise ValueError("Invalid date format. Please enter a valid date.")


class TimeTransformer(app_commands.Transformer):
async def transform(
self,
interaction: discord.Interaction,
value: str,
) -> datetime.time:
# Supports the following formats:
# 09:00
# 9:00 AM
# 9:00 am
# 9AM

value = value.replace(" ", "").lower()

# Define regex patterns for different time formats
patterns = {
r"^(\d{1,2}):(\d{2})$": "%H:%M", # 09:00
r"^(\d{1,2}):(\d{2})(am|pm)$": "%I:%M%p", # 9:00am
r"^(\d{1,2})(am|pm)$": "%I%p", # 9am
}

for pattern, time_format in patterns.items():
if re.match(pattern, value):
# Convert matched value to datetime.time object
time_value = datetime.datetime.strptime(value, time_format).time()
return time_value

# If no pattern matches, you might want to raise an error or handle it gracefully
raise ValueError("Invalid time format. Please enter a valid time.")


def capped_str(parts: list[str], cap: int = 1024) -> str:
"""
Joins the most parts possible with a new line between them. If the resulting
Expand Down

0 comments on commit 3a2f04f

Please sign in to comment.