Quellcode durchsuchen

Putting email and username modes behind flags

pull/35/head
Rocketsoup vor 2 Wochen
Ursprung
Commit
5fc9d7c4c3
1 geänderte Dateien mit 91 neuen und 58 gelöschten Zeilen
  1. 91
    58
      rocketbot/cogs/kickstartercog.py

+ 91
- 58
rocketbot/cogs/kickstartercog.py Datei anzeigen

@@ -23,10 +23,12 @@ from rocketbot.utils import (
23 23
 	is_email_address,
24 24
 )
25 25
 
26
-PERMITTED_GUILD_IDS = [
26
+_PERMITTED_GUILD_IDS = [
27 27
 	405011810937339905,
28 28
 	900805482825007104,  # test server
29 29
 ]
30
+_EMAIL_MODE = True
31
+_USERNAME_MODE = False
30 32
 class KickstarterCog(BaseCog):
31 33
 	"""
32 34
 	Provides a way for Discord users to self-identify the email address they
@@ -87,14 +89,26 @@ class KickstarterCog(BaseCog):
87 89
 		Self = KickstarterCog
88 90
 		self.set_guild_setting(role.guild, Self.SETTING_ROLE, role.id)
89 91
 
92
+	async def __misconfigured(self, interaction: Interaction):
93
+		await interaction.response.send_message(f"{CONFIG['failure_emoji']} Feature misconfigured", ephemeral=True)
94
+
95
+
90 96
 	# -- Member commands -----
91 97
 
92 98
 	@command(
93
-		description='Links your Kickstarter email address to your Discord user'
99
+		description='Grants you access to Kickstarter backer-only areas'
94 100
 	)
95 101
 	@guild_only()
96
-	@guilds(PERMITTED_GUILD_IDS)
97
-	async def link_email(self, interaction: Interaction):
102
+	@guilds(*_PERMITTED_GUILD_IDS)
103
+	async def link(self, interaction: Interaction):
104
+		if _EMAIL_MODE:
105
+			await self.__link_email_command(interaction)
106
+		elif _USERNAME_MODE:
107
+			await self.__link_username_command(interaction)
108
+		else:
109
+			await self.__misconfigured(interaction)
110
+
111
+	async def __link_email_command(self, interaction: Interaction):
98 112
 		# If possible, try to check if they're already a backer before opening
99 113
 		# a modal.
100 114
 		guild = interaction.guild
@@ -112,12 +126,7 @@ class KickstarterCog(BaseCog):
112 126
 
113 127
 		await interaction.response.send_modal(_LinkModal())
114 128
 
115
-	@command(
116
-		description='Grants you access to Kickstarter backer-only areas'
117
-	)
118
-	@guild_only()
119
-	@guilds(PERMITTED_GUILD_IDS)
120
-	async def link_username(self, interaction: Interaction):
129
+	async def __link_username_command(self, interaction: Interaction):
121 130
 		await interaction.response.defer(ephemeral=True, thinking=True)
122 131
 		try:
123 132
 			backer_role = await self.__fetch_backer_role(interaction.guild)
@@ -158,7 +167,7 @@ class KickstarterCog(BaseCog):
158 167
 			'user and removes the backer role.'
159 168
 	)
160 169
 	@guild_only()
161
-	@guilds(PERMITTED_GUILD_IDS)
170
+	@guilds(*_PERMITTED_GUILD_IDS)
162 171
 	async def unlink(self, interaction: Interaction):
163 172
 		await interaction.response.defer(ephemeral=True, thinking=True)
164 173
 		guild = interaction.guild
@@ -175,16 +184,17 @@ class KickstarterCog(BaseCog):
175 184
 			await member.remove_roles(backer_role)
176 185
 		self.__delete_member_link(guild.id, member.id)
177 186
 		text = f"{CONFIG['success_emoji']} Unlinked as Kickstarter backer. Use " \
178
-			"`/link` if you change your mind."
187
+			"`/link` again if you change your mind."
179 188
 		await interaction.followup.send(text, ephemeral=True)
180 189
 
190
+
181 191
 	# -- Admin commands -----
182 192
 
183 193
 	kickstarter = Group(
184 194
 		name='kickstarter',
185 195
 		description='Manages roles for users identified as Kickstarter backers.',
186 196
 		guild_only=True,
187
-		guild_ids=PERMITTED_GUILD_IDS,
197
+		guild_ids=_PERMITTED_GUILD_IDS,
188 198
 		default_permissions=MOD_PERMISSIONS
189 199
 	)
190 200
 
@@ -199,17 +209,22 @@ class KickstarterCog(BaseCog):
199 209
 	@kickstarter.command(
200 210
 		description='Checks the database for users to assign the backer role to.'
201 211
 	)
202
-	async def sync_emails(self, interaction: Interaction):
212
+	async def sync(self, interaction: Interaction):
213
+		if _EMAIL_MODE:
214
+			await self.__sync_emails_command(interaction)
215
+		elif _USERNAME_MODE:
216
+			await self.__sync_usernames_command(interaction)
217
+		else:
218
+			await self.__misconfigured(interaction)
219
+
220
+	async def __sync_emails_command(self, interaction: Interaction):
203 221
 		await interaction.response.defer(ephemeral=True, thinking=True)
204 222
 		sync_result: _SyncEmailsResult = await self.__sync_by_email(interaction.guild)
205 223
 		text = f"{CONFIG['success_emoji']} Sync complete.\n" + \
206 224
 			sync_result.summary_markdown()
207 225
 		await interaction.followup.send(text, ephemeral=True)
208
-
209
-	@kickstarter.command(
210
-		description='Checks the database for users to assign the backer role to.'
211
-	)
212
-	async def sync_usernames(self, interaction: Interaction):
226
+	
227
+	async def __sync_usernames_command(self, interaction: Interaction):
213 228
 		await interaction.response.defer(ephemeral=True, thinking=True)
214 229
 		sync_result: _SyncUsernamesResult = await self.__sync_by_username(interaction.guild)
215 230
 		text = f"{CONFIG['success_emoji']} Sync complete.\n" + \
@@ -217,14 +232,6 @@ class KickstarterCog(BaseCog):
217 232
 		await interaction.followup.send(text, ephemeral=True)
218 233
 
219 234
 	@kickstarter.command(
220
-		description='DEV TEST - testing timeout'
221
-	)
222
-	async def timeout_test(self, interaction: Interaction):
223
-		await interaction.response.defer(ephemeral=True, thinking=True)
224
-		await sleep(300)
225
-		await interaction.followup.send("5m timer done", ephemeral=True)
226
-
227
-	@kickstarter.command(
228 235
 		description='Shows info about Kickstarter linked Discord members.'
229 236
 	)
230 237
 	async def info(self, interaction: Interaction):
@@ -269,52 +276,67 @@ class KickstarterCog(BaseCog):
269 276
 			return
270 277
 
271 278
 		if backer_role in member.roles:
272
-			text = f"{CONFIG['info_emoji']} Member {member.name} has `{backer_role.name}` role."
279
+			text = f"{CONFIG['info_emoji']} Member {member.name} has " \
280
+				f"`{backer_role.name}` role."
273 281
 			await interaction.followup.send(text, ephemeral=True)
274 282
 			return
275 283
 
284
+		if _USERNAME_MODE:
285
+			await self.__find_member_username_mode(interaction, member, backer_role)
286
+		elif _EMAIL_MODE:
287
+			await self.__find_member_email_mode(interaction, member, backer_role)
288
+		else:
289
+			await self.__misconfigured(interaction)
290
+
291
+	async def __find_member_username_mode(self, interaction: Interaction, member: Member, backer_role: Role):
292
+		guild = interaction.guild
276 293
 		username_record = self.__fetch_kickstarter_username(username=member.name)
277 294
 		if username_record is not None:
278 295
 			await member.add_roles(backer_role)
279 296
 			username_record.lookup_status = _LookupStatus.member_found
280 297
 			self.__update_kickstarter_username(username_record)
281
-			text = f"{CONFIG['success_emoji']} Member's username found in Kickstarter export. Assigned `{backer_role.name}` role."
298
+			text = f"{CONFIG['success_emoji']} Member's username found in " \
299
+				f"Kickstarter export. The `{backer_role.name}` role has now " \
300
+				"been assigned to them."
282 301
 			await interaction.followup.send(text, ephemeral=True)
283 302
 			return
303
+		stats = self.__fetch_stats(guild.id)
304
+		text = f"{CONFIG['info_emoji']} Member's username is not in the " \
305
+			f"Kickstarter export. (Last import <t:{stats.username_last_imported_at}:f>)"
306
+		await interaction.followup.send(text, ephemeral=True)
284 307
 
285
-		# FIXME: Sorta splitting the difference between email and username model here
286
-
308
+	async def __find_member_email_mode(self, interaction: Interaction, member: Member, backer_role: Role):
309
+		guild = interaction.guild
287 310
 		member_link = self.__fetch_member_link_by_member_id(guild.id, member.id)
288 311
 		if member_link is None:
289
-			text = f"No record found for member {member.mention}. Possible reasons:\n" \
312
+			text = f"{CONFIG['info_emoji']} No record found for member " \
313
+				f"{member.mention}.\n" \
314
+				"\n" \
315
+				"Possible reasons:\n" \
290 316
 				"- They haven't used the `/link` command yet to provide their " \
291 317
 				"Kickstarter email address\n" \
292 318
 				"- They linked using a different Discord account. (You can " \
293 319
 				"search by email with `/find_email`)\n" \
294
-				"- They used the `/unlink` after being linked"
320
+				"- They used the `/unlink` command after being linked"
295 321
 			await interaction.followup.send(text, ephemeral=True)
296 322
 			return
297 323
 
298
-		text = f"Member {member.mention} successfully used the `/link` command"
299
-		if backer_role in member.roles:
300
-			text += f", and they already have the {backer_role.name} Discord role. " \
301
-				"They should already have access to backer-only areas. If they " \
302
-				"still can't see them, some possible reasons:\n" \
303
-				"- Its channel group is collapsed in the channel list.\n" \
304
-				"- Some channels are hidden. Direct them to the Browse Channels " \
305
-				"area in the channel list to see if it's listed and checked visible.\n" \
306
-				"- Their client may need to be refreshed. Have them restart Discord " \
307
-				"and see if the channel shows up."
324
+		text = f"{CONFIG['info_emoji']} Member record found for {member.mention}.\n" \
325
+			"\n" \
326
+			"- User provided an email address with the `/link` command.\n"
327
+		is_backer = self.__is_kickstarter_email_hash(interaction.guild.id, member_link.email_hash)
328
+		if is_backer:
329
+			await member.add_roles(backer_role)
330
+			text += "- Provided email is in the Kickstarter backer list but " \
331
+				f"we hadn't given them the {backer_role.name} role yet.\n" \
332
+				f"- Member granted {backer_role.name} role just now."
308 333
 		else:
309
-			is_backer = self.__is_kickstarter_email_hash(interaction.guild.id, member_link.email_hash)
310
-			if is_backer:
311
-				await member.add_roles(backer_role)
312
-				text += f", and their email address is in the Kickstarter backer list, " \
313
-					f"but they didn't have the {backer_role.name} role yet! **This was " \
314
-					"just now corrected.** Ask them to check again."
315
-			else:
316
-				text += ", but we don't have the address they provided in the " \
317
-					"Kickstarter backer list yet. Have we refreshed it recently?"
334
+			stats = self.__fetch_stats(guild.id)
335
+			text += "- Provided email is _not_ in the Kickstarter backer list.\n" \
336
+				"   - Did they provide the same email as Kickstarter and " \
337
+				"spell it correctly?\n" \
338
+				"   - Have we imported addresses recently? Last import on " \
339
+				f"<t:{stats.email_last_imported_at}:f>."
318 340
 		await interaction.followup.send(text, ephemeral=True)
319 341
 
320 342
 	@kickstarter.command(
@@ -380,15 +402,20 @@ class KickstarterCog(BaseCog):
380 402
 		await interaction.followup.send(text, ephemeral=True)
381 403
 
382 404
 	@kickstarter.command(
383
-		description='Uploads an export of Kickstarter backer email addresses.'
405
+		description='Uploads an export of Kickstarter backers.'
384 406
 	)
385
-	async def upload_emails(self, interaction: Interaction):
407
+	async def upload(self, interaction: Interaction):
408
+		if _EMAIL_MODE:
409
+			await self.__upload_emails_command(interaction)
410
+		elif _USERNAME_MODE:
411
+			await self.__upload_usernames_command(interaction)
412
+		else:
413
+			await self.__misconfigured(interaction)
414
+
415
+	async def __upload_emails_command(self, interaction: Interaction):
386 416
 		await interaction.response.send_modal(_UploadEmailsModal())
387 417
 
388
-	@kickstarter.command(
389
-		description='Uploads an export of backer Discord usernames.'
390
-	)
391
-	async def upload_usernames(self, interaction: Interaction):
418
+	async def __upload_usernames_command(self, interaction: Interaction):
392 419
 		await interaction.response.send_modal(_UploadUsernamesModal())
393 420
 
394 421
 	async def interaction_check(self, interaction: Interaction) -> bool:
@@ -396,6 +423,9 @@ class KickstarterCog(BaseCog):
396 423
 			self.__trace(interaction.guild, f"@{interaction.user.name} used /{interaction.command.qualified_name}")
397 424
 		return True
398 425
 
426
+
427
+	# -- UI callbacks -----
428
+
399 429
 	async def on_email_upload_submit(self, interaction: Interaction, attachment: Attachment):
400 430
 		"""Callback for email upload modal."""
401 431
 		await interaction.response.defer(ephemeral=True, thinking=True)
@@ -477,6 +507,9 @@ class KickstarterCog(BaseCog):
477 507
 
478 508
 		await interaction.followup.send(text, ephemeral=True)
479 509
 
510
+
511
+	# -- Operations -----
512
+
480 513
 	async def __link_member(self, guild: Guild, member: Member, email: str) -> '_LinkResult':
481 514
 		if not is_email_address(email.strip()):
482 515
 			return _LinkResult(_LinkResultStatus.malformed_address)

Laden…
Abbrechen
Speichern