Skip to content

Commit 241a5bc

Browse files
Maybe working
1 parent b05318a commit 241a5bc

1 file changed

Lines changed: 114 additions & 133 deletions

File tree

cogs/make_member.py

Lines changed: 114 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from config import settings
1212
from db.core.models import GroupMadeMember
1313
from exceptions import ApplicantRoleDoesNotExistError, GuestRoleDoesNotExistError
14-
from utils import CommandChecks, TeXBotApplicationContext, TeXBotBaseCog
14+
from utils import CommandChecks, TeXBotBaseCog
1515
from utils.msl import (
1616
fetch_community_group_members_count,
1717
is_id_a_community_group_member,
@@ -22,6 +22,8 @@
2222
from logging import Logger
2323
from typing import Final
2424

25+
from utils import TeXBotApplicationContext
26+
2527
__all__: "Sequence[str]" = (
2628
"MakeMemberCommandCog",
2729
"MakeMemberModalCommandCog",
@@ -56,7 +58,99 @@
5658
)
5759

5860

59-
class MakeMemberCommandCog(TeXBotBaseCog):
61+
class MakeMemberBaseCog(TeXBotBaseCog):
62+
"""Base cog class for make member interactions."""
63+
64+
async def _perform_make_member(
65+
self, user: discord.User | discord.Member, raw_group_member_id: str
66+
) -> tuple[bool, str]:
67+
"""Perform the actions to make a user a member."""
68+
member_role: discord.Role = await self.bot.member_role
69+
discord_member: discord.Member = await self.bot.get_main_guild_member(user)
70+
71+
INVALID_GROUP_MEMBER_ID_MESSAGE: Final[str] = (
72+
f"{raw_group_member_id!r} is not a valid {self.bot.group_member_id_type} ID."
73+
)
74+
75+
if not re.fullmatch(r"\A\d{7}\Z", raw_group_member_id):
76+
return False, INVALID_GROUP_MEMBER_ID_MESSAGE
77+
78+
try:
79+
group_member_id: int = int(raw_group_member_id)
80+
except ValueError:
81+
return False, INVALID_GROUP_MEMBER_ID_MESSAGE
82+
83+
if member_role in discord_member.roles:
84+
return (False, (
85+
":information_source: No changes made. "
86+
"You're already a member - why are you trying this again? :information_source:"
87+
))
88+
89+
if await GroupMadeMember.objects.filter(
90+
hashed_group_member_id=GroupMadeMember.hash_group_member_id(
91+
group_member_id, self.bot.group_member_id_type
92+
)
93+
).aexists():
94+
return False, "This student ID has already been used."
95+
96+
if not await is_id_a_community_group_member(member_id=group_member_id):
97+
return False, (
98+
f"You must be a member of {self.bot.group_full_name} "
99+
"to use this command.\n"
100+
f"The provided {_GROUP_MEMBER_ID_ARGUMENT_NAME} must match "
101+
f"the {self.bot.group_member_id_type} ID "
102+
f"that you purchased your {self.bot.group_short_name} membership with."
103+
)
104+
105+
await discord_member.add_roles(
106+
member_role, reason=f"{discord_member} used TeX-Bot to become a member"
107+
)
108+
109+
try:
110+
await GroupMadeMember.objects.acreate(group_member_id=raw_group_member_id) # type: ignore[misc]
111+
except ValidationError as create_group_made_member_error:
112+
error_is_already_exists: bool = (
113+
"hashed_group_member_id" in create_group_made_member_error.message_dict
114+
and any(
115+
"already exists" in error
116+
for error in create_group_made_member_error.message_dict[
117+
"hashed_group_member_id"
118+
]
119+
)
120+
)
121+
if not error_is_already_exists:
122+
raise
123+
124+
try:
125+
guest_role: discord.Role = await self.bot.guest_role
126+
except GuestRoleDoesNotExistError:
127+
logger.warning(
128+
'"/make-member" command used but the "Guest" role does not exist. '
129+
'Some user\'s may now have the "Member" role without the "Guest" role. '
130+
'Use the "/ensure-members-inducted" command to fix this issue.'
131+
)
132+
else:
133+
if guest_role not in discord_member.roles:
134+
await discord_member.add_roles(
135+
guest_role,
136+
reason=f"{discord_member} used TeX-Bot to become a member.",
137+
)
138+
139+
try:
140+
applicant_role: discord.Role = await self.bot.applicant_role
141+
except ApplicantRoleDoesNotExistError:
142+
pass
143+
else:
144+
if applicant_role in discord_member.roles:
145+
await discord_member.remove_roles(
146+
applicant_role,
147+
reason=f"{discord_member} used TeX-Bot to become a member.",
148+
)
149+
150+
return True, ""
151+
152+
153+
class MakeMemberCommandCog(MakeMemberBaseCog):
60154
"""Cog class that defines the "/make-member" command and its call-back method."""
61155

62156
@discord.slash_command(
@@ -105,112 +199,14 @@ async def make_member(
105199
has purchased a valid membership to your community group,
106200
then gives the member the "Member" role.
107201
"""
108-
# NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent
109-
member_role: discord.Role = await self.bot.member_role
110-
interaction_member: discord.Member = await ctx.bot.get_main_guild_member(ctx.user)
111-
112-
INVALID_GROUP_MEMBER_ID_MESSAGE: Final[str] = (
113-
f"{raw_group_member_id!r} is not a valid {self.bot.group_member_id_type} ID."
114-
)
115-
116-
if not re.fullmatch(r"\A\d{7}\Z", raw_group_member_id):
117-
await self.command_send_error(ctx, message=(INVALID_GROUP_MEMBER_ID_MESSAGE))
118-
return
119-
120-
try:
121-
group_member_id: int = int(raw_group_member_id)
122-
except ValueError:
123-
await self.command_send_error(ctx, message=INVALID_GROUP_MEMBER_ID_MESSAGE)
124-
return
125-
126202
await ctx.defer(ephemeral=True)
127-
async with ctx.typing():
128-
if member_role in interaction_member.roles:
129-
await ctx.followup.send(
130-
content=(
131-
":information_source: No changes made. You're already a member "
132-
"- why are you trying this again? :information_source:"
133-
),
134-
ephemeral=True,
135-
)
136-
return
137203

138-
if await GroupMadeMember.objects.filter(
139-
hashed_group_member_id=GroupMadeMember.hash_group_member_id(
140-
group_member_id, self.bot.group_member_id_type
141-
)
142-
).aexists():
143-
await ctx.followup.send(
144-
content=(
145-
":information_source: No changes made. This student ID has already "
146-
f"been used. Please contact a {
147-
await self.bot.get_mention_string(self.bot.committee_role)
148-
} member if this is an error. :information_source:"
149-
),
150-
ephemeral=True,
151-
)
152-
return
153-
154-
if not await is_id_a_community_group_member(member_id=group_member_id):
155-
await self.command_send_error(
156-
ctx,
157-
message=(
158-
f"You must be a member of {self.bot.group_full_name} "
159-
"to use this command.\n"
160-
f"The provided {_GROUP_MEMBER_ID_ARGUMENT_NAME} must match "
161-
f"the {self.bot.group_member_id_type} ID "
162-
f"that you purchased your {self.bot.group_short_name} membership with."
163-
),
164-
)
165-
return
166-
167-
# NOTE: The "Member" role must be added to the user **before** the "Guest" role to ensure that the welcome message does not include the suggestion to purchase membership
168-
await interaction_member.add_roles(
169-
member_role, reason=f'{ctx.user} used TeX Bot slash-command: "/make-member"'
204+
with ctx.typing():
205+
_, message = await self._perform_make_member(
206+
user=ctx.user, raw_group_member_id=raw_group_member_id
170207
)
171208

172-
try:
173-
await GroupMadeMember.objects.acreate(group_member_id=raw_group_member_id) # type: ignore[misc]
174-
except ValidationError as create_group_made_member_error:
175-
error_is_already_exists: bool = (
176-
"hashed_group_member_id" in create_group_made_member_error.message_dict
177-
and any(
178-
"already exists" in error
179-
for error in create_group_made_member_error.message_dict[
180-
"hashed_group_member_id"
181-
]
182-
)
183-
)
184-
if not error_is_already_exists:
185-
raise
186-
187-
await ctx.followup.send(content="Successfully made you a member!", ephemeral=True)
188-
189-
try:
190-
guest_role: discord.Role = await self.bot.guest_role
191-
except GuestRoleDoesNotExistError:
192-
logger.warning(
193-
'"/make-member" command used but the "Guest" role does not exist. '
194-
'Some user\'s may now have the "Member" role without the "Guest" role. '
195-
'Use the "/ensure-members-inducted" command to fix this issue.'
196-
)
197-
else:
198-
if guest_role not in interaction_member.roles:
199-
await interaction_member.add_roles(
200-
guest_role,
201-
reason=f'{ctx.user} used TeX Bot slash-command: "/make-member"',
202-
)
203-
applicant_role: discord.Role | None
204-
try:
205-
applicant_role = await ctx.bot.applicant_role
206-
except ApplicantRoleDoesNotExistError:
207-
applicant_role = None
208-
209-
if applicant_role and applicant_role in interaction_member.roles:
210-
await interaction_member.remove_roles(
211-
applicant_role,
212-
reason=f'{ctx.user} used TeX Bot slash-command: "/make-member"',
213-
)
209+
await ctx.followup.send(content=message, ephemeral=True)
214210

215211

216212
class MemberCountCommandCog(TeXBotBaseCog):
@@ -232,7 +228,7 @@ async def member_count(self, ctx: "TeXBotApplicationContext") -> None:
232228
)
233229

234230

235-
class MakeMemberModalActual(Modal):
231+
class MakeMemberModalActual(Modal, MakeMemberBaseCog):
236232
"""A discord.Modal containing a the input box for make member user interaction."""
237233

238234
@override
@@ -257,26 +253,25 @@ async def callback(self, interaction: discord.Interaction) -> None:
257253
)
258254
return
259255

260-
try:
261-
student_id: int = int(raw_student_id)
262-
except ValueError:
256+
if not interaction.user:
263257
await interaction.response.send_message(
264-
content="Student ID must be a number.", ephemeral=True
258+
content="Something went wrong, contact a committee member if this persists.",
259+
ephemeral=True,
265260
)
266-
return
267-
268-
if await is_id_a_community_group_member(member_id=student_id):
269-
await MakeMemberModalCommandCog.give_member_role(
270-
self=MakeMemberModalCommandCog(bot=interaction.client), # type: ignore[arg-type]
271-
interaction=interaction,
261+
logger.debug(
262+
"Interaction user was unexpectedly None in MakeMemberModal. Interaction: %s",
263+
interaction.data,
272264
)
273-
await interaction.response.send_message(content="Action complete.")
274265
return
275266

276-
await interaction.response.send_message(
277-
content="Student ID not found.", ephemeral=True
267+
await interaction.response.defer(ephemeral=True)
268+
269+
_, message = await self._perform_make_member(
270+
user=interaction.user, raw_group_member_id=raw_student_id
278271
)
279272

273+
await interaction.followup.send(content=message, ephemeral=True)
274+
280275

281276
class OpenMemberVerifyModalView(View):
282277
"""A discord.View containing a button to open a new member verification modal."""
@@ -293,28 +288,14 @@ async def verify_new_member_button_callback( # type: ignore[misc]
293288
await interaction.response.send_modal(MakeMemberModalActual())
294289

295290

296-
class MakeMemberModalCommandCog(TeXBotBaseCog):
291+
class MakeMemberModalCommandCog(MakeMemberBaseCog):
297292
"""Cog class that defines the "/make-member-modal" command and its call-back method."""
298293

299294
@TeXBotBaseCog.listener()
300295
async def on_ready(self) -> None:
301296
"""Add OpenMemberVerifyModalView to the bot's list of permanent views."""
302297
self.bot.add_view(OpenMemberVerifyModalView())
303298

304-
async def give_member_role(self, interaction: discord.Interaction) -> None:
305-
"""Give the member role to the user who interacted with the modal."""
306-
if not isinstance(interaction.user, discord.Member):
307-
await self.command_send_error(
308-
ctx=TeXBotApplicationContext(bot=interaction.client, interaction=interaction), # type: ignore[arg-type]
309-
message="User is not a member.",
310-
)
311-
return
312-
313-
await interaction.user.add_roles(
314-
await self.bot.member_role,
315-
reason=f'{interaction.user} used TeX Bot modal: "Make Member"',
316-
)
317-
318299
async def _open_make_new_member_modal(
319300
self,
320301
button_callback_channel: discord.TextChannel | discord.DMChannel,

0 commit comments

Comments
 (0)