Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to mark whether swimming or not in testing embed #29

Merged
merged 1 commit into from
Mar 5, 2024
Merged
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
144 changes: 104 additions & 40 deletions src/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@
from .bot import MILBot


@dataclass
class TestingMember:
member: discord.Member
swimming: bool

def embed_str(self) -> str:
return f"* {self.member.mention}{' (swimming)' if self.swimming else ''}"

def __str__(self) -> str:
return f"TestingMember(member={self.member}, swimming={self.swimming})"

__repr__ = __str__


class MemberTestingAttendance(Enum):
CANNOT = "cannot"
CANNOTDRIVE = "cannotdrive"
Expand Down Expand Up @@ -45,25 +59,57 @@ def emoji(self) -> str:

@dataclass
class TestingAttendance:
cannot: list[discord.Member]
cannotdrive: list[discord.Member]
candrive: list[discord.Member]
candrivesub: list[discord.Member]
cannot: list[TestingMember]
cannotdrive: list[TestingMember]
candrive: list[TestingMember]
candrivesub: list[TestingMember]

def __post_init__(self):
self.associations: dict[MemberTestingAttendance, list[TestingMember]] = {
MemberTestingAttendance.CANNOT: self.cannot,
MemberTestingAttendance.CANNOTDRIVE: self.cannotdrive,
MemberTestingAttendance.CANDRIVE: self.candrive,
MemberTestingAttendance.CANDRIVESUB: self.candrivesub,
}

@property
def attending(self) -> list[discord.Member]:
def attending(self) -> list[TestingMember]:
return self.candrive + self.candrivesub + self.cannotdrive

def members_with_state(
self,
state: MemberTestingAttendance,
) -> list[discord.Member]:
return {
MemberTestingAttendance.CANNOT: self.cannot,
MemberTestingAttendance.CANNOTDRIVE: self.cannotdrive,
MemberTestingAttendance.CANDRIVE: self.candrive,
MemberTestingAttendance.CANDRIVESUB: self.candrivesub,
}[state]
) -> list[TestingMember]:
return self.associations[state]

def update_members(
self,
state: MemberTestingAttendance,
members: list[TestingMember],
):
self.associations[state] = members


class SwimmingView(MILBotView):

swimming: bool | None

def __init__(self, bot: MILBot):
self.bot = bot
self.swimming = None
super().__init__()

@discord.ui.button(label="Yes", style=discord.ButtonStyle.green)
async def yes(self, interaction: discord.Interaction, _):
self.swimming = True
await interaction.response.defer()
self.stop()

@discord.ui.button(label="No", style=discord.ButtonStyle.red)
async def no(self, interaction: discord.Interaction, _):
self.swimming = False
await interaction.response.defer()
self.stop()


class TestingSignUpSelect(discord.ui.Select):
Expand Down Expand Up @@ -92,7 +138,7 @@ async def parse_embed_field(
self,
embed: discord.Embed,
field_name: str,
) -> list[discord.Member]:
) -> list[TestingMember]:
"""
Parses the value of the embed, assuming that it is a new-line Markdown
bulleted list of member mentions.
Expand All @@ -101,12 +147,13 @@ async def parse_embed_field(
if value == "":
return []
raw_mentions = value.split("\n")
ids = []
members: list[TestingMember] = []
for mention_str in raw_mentions:
id = re.findall(r"<@!?(\d+)>", mention_str)
swimming = "(swimming)" in mention_str
if id:
ids.append(int(id[0]))
members = [await self.bot.get_member(id) for id in ids]
member = await self.bot.get_member(int(id[0]))
members.append(TestingMember(member, swimming))
return members

def get_field_named(self, embed: discord.Embed, field_name: str) -> str:
Expand Down Expand Up @@ -143,10 +190,10 @@ def replace_embed_value(
embed.set_field_at(i, name=field.name, value=new_value, inline=False)
break

def format_members(self, members: list[discord.Member]) -> str:
def format_members(self, members: list[TestingMember]) -> str:
if not members:
return "_No members yet._"
return "\n".join([f"* {member.mention}" for member in members])
return "\n".join([member.embed_str() for member in members])

async def callback(self, interaction: discord.Interaction):
message = interaction.message
Expand All @@ -171,38 +218,55 @@ async def callback(self, interaction: discord.Interaction):
embed_field_name = state.english_title
members_with_state = attendance.members_with_state(state)

# If member already in list, remove them. Otherwise, add them.
if interaction.user in members_with_state:
members_with_state.remove(interaction.user)
self.replace_embed_value(
embed,
embed_field_name,
self.format_members(members_with_state),
)
swimming_view = SwimmingView(self.bot)
if state is not MemberTestingAttendance.CANNOT:
await interaction.response.send_message(
"You have been removed from the list.",
"Are you planning on swimming?",
view=swimming_view,
ephemeral=True,
)
await swimming_view.wait()

# Remove the member from every list
members_previous_state = None
was_swimming = None
for available_state in MemberTestingAttendance:
cur_state = attendance.members_with_state(available_state)
if interaction.user in [m.member for m in cur_state]:
was_swimming = next(
m.swimming for m in cur_state if m.member == interaction.user
)
cur_state = [m for m in cur_state if m.member != interaction.user]
members_previous_state = available_state
attendance.update_members(available_state, cur_state)
self.replace_embed_value(
embed,
available_state.english_title,
self.format_members(cur_state),
)

response = None
if state == members_previous_state and was_swimming == (
swimming_view.swimming or False
):
response = "You have been removed from the list."
else:
# If the user is already in another list, remove them from that list.
for state in MemberTestingAttendance:
cur_state = attendance.members_with_state(state)
if interaction.user in cur_state:
cur_state.remove(interaction.user)
self.replace_embed_value(
embed,
state.english_title,
self.format_members(cur_state),
)

members_with_state.append(interaction.user)
members_with_state = attendance.members_with_state(state)
members_with_state.append(
TestingMember(interaction.user, swimming_view.swimming or False),
)
self.replace_embed_value(
embed,
embed_field_name,
self.format_members(members_with_state),
)
response = "Your response was recorded!"

if state is not MemberTestingAttendance.CANNOT:
await interaction.edit_original_response(content=response, view=None)
else:
await interaction.response.send_message(
"Your response was recorded!",
response,
ephemeral=True,
)

Expand Down
Loading