Bladeren bron

Putting email and username modes behind flags

pull/35/head
Rocketsoup 2 weken geleden
bovenliggende
commit
5fc9d7c4c3
1 gewijzigde bestanden met toevoegingen van 91 en 58 verwijderingen
  1. 91
    58
      rocketbot/cogs/kickstartercog.py

+ 91
- 58
rocketbot/cogs/kickstartercog.py Bestand weergeven

23
 	is_email_address,
23
 	is_email_address,
24
 )
24
 )
25
 
25
 
26
-PERMITTED_GUILD_IDS = [
26
+_PERMITTED_GUILD_IDS = [
27
 	405011810937339905,
27
 	405011810937339905,
28
 	900805482825007104,  # test server
28
 	900805482825007104,  # test server
29
 ]
29
 ]
30
+_EMAIL_MODE = True
31
+_USERNAME_MODE = False
30
 class KickstarterCog(BaseCog):
32
 class KickstarterCog(BaseCog):
31
 	"""
33
 	"""
32
 	Provides a way for Discord users to self-identify the email address they
34
 	Provides a way for Discord users to self-identify the email address they
87
 		Self = KickstarterCog
89
 		Self = KickstarterCog
88
 		self.set_guild_setting(role.guild, Self.SETTING_ROLE, role.id)
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
 	# -- Member commands -----
96
 	# -- Member commands -----
91
 
97
 
92
 	@command(
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
 	@guild_only()
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
 		# If possible, try to check if they're already a backer before opening
112
 		# If possible, try to check if they're already a backer before opening
99
 		# a modal.
113
 		# a modal.
100
 		guild = interaction.guild
114
 		guild = interaction.guild
112
 
126
 
113
 		await interaction.response.send_modal(_LinkModal())
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
 		await interaction.response.defer(ephemeral=True, thinking=True)
130
 		await interaction.response.defer(ephemeral=True, thinking=True)
122
 		try:
131
 		try:
123
 			backer_role = await self.__fetch_backer_role(interaction.guild)
132
 			backer_role = await self.__fetch_backer_role(interaction.guild)
158
 			'user and removes the backer role.'
167
 			'user and removes the backer role.'
159
 	)
168
 	)
160
 	@guild_only()
169
 	@guild_only()
161
-	@guilds(PERMITTED_GUILD_IDS)
170
+	@guilds(*_PERMITTED_GUILD_IDS)
162
 	async def unlink(self, interaction: Interaction):
171
 	async def unlink(self, interaction: Interaction):
163
 		await interaction.response.defer(ephemeral=True, thinking=True)
172
 		await interaction.response.defer(ephemeral=True, thinking=True)
164
 		guild = interaction.guild
173
 		guild = interaction.guild
175
 			await member.remove_roles(backer_role)
184
 			await member.remove_roles(backer_role)
176
 		self.__delete_member_link(guild.id, member.id)
185
 		self.__delete_member_link(guild.id, member.id)
177
 		text = f"{CONFIG['success_emoji']} Unlinked as Kickstarter backer. Use " \
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
 		await interaction.followup.send(text, ephemeral=True)
188
 		await interaction.followup.send(text, ephemeral=True)
180
 
189
 
190
+
181
 	# -- Admin commands -----
191
 	# -- Admin commands -----
182
 
192
 
183
 	kickstarter = Group(
193
 	kickstarter = Group(
184
 		name='kickstarter',
194
 		name='kickstarter',
185
 		description='Manages roles for users identified as Kickstarter backers.',
195
 		description='Manages roles for users identified as Kickstarter backers.',
186
 		guild_only=True,
196
 		guild_only=True,
187
-		guild_ids=PERMITTED_GUILD_IDS,
197
+		guild_ids=_PERMITTED_GUILD_IDS,
188
 		default_permissions=MOD_PERMISSIONS
198
 		default_permissions=MOD_PERMISSIONS
189
 	)
199
 	)
190
 
200
 
199
 	@kickstarter.command(
209
 	@kickstarter.command(
200
 		description='Checks the database for users to assign the backer role to.'
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
 		await interaction.response.defer(ephemeral=True, thinking=True)
221
 		await interaction.response.defer(ephemeral=True, thinking=True)
204
 		sync_result: _SyncEmailsResult = await self.__sync_by_email(interaction.guild)
222
 		sync_result: _SyncEmailsResult = await self.__sync_by_email(interaction.guild)
205
 		text = f"{CONFIG['success_emoji']} Sync complete.\n" + \
223
 		text = f"{CONFIG['success_emoji']} Sync complete.\n" + \
206
 			sync_result.summary_markdown()
224
 			sync_result.summary_markdown()
207
 		await interaction.followup.send(text, ephemeral=True)
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
 		await interaction.response.defer(ephemeral=True, thinking=True)
228
 		await interaction.response.defer(ephemeral=True, thinking=True)
214
 		sync_result: _SyncUsernamesResult = await self.__sync_by_username(interaction.guild)
229
 		sync_result: _SyncUsernamesResult = await self.__sync_by_username(interaction.guild)
215
 		text = f"{CONFIG['success_emoji']} Sync complete.\n" + \
230
 		text = f"{CONFIG['success_emoji']} Sync complete.\n" + \
217
 		await interaction.followup.send(text, ephemeral=True)
232
 		await interaction.followup.send(text, ephemeral=True)
218
 
233
 
219
 	@kickstarter.command(
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
 		description='Shows info about Kickstarter linked Discord members.'
235
 		description='Shows info about Kickstarter linked Discord members.'
229
 	)
236
 	)
230
 	async def info(self, interaction: Interaction):
237
 	async def info(self, interaction: Interaction):
269
 			return
276
 			return
270
 
277
 
271
 		if backer_role in member.roles:
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
 			await interaction.followup.send(text, ephemeral=True)
281
 			await interaction.followup.send(text, ephemeral=True)
274
 			return
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
 		username_record = self.__fetch_kickstarter_username(username=member.name)
293
 		username_record = self.__fetch_kickstarter_username(username=member.name)
277
 		if username_record is not None:
294
 		if username_record is not None:
278
 			await member.add_roles(backer_role)
295
 			await member.add_roles(backer_role)
279
 			username_record.lookup_status = _LookupStatus.member_found
296
 			username_record.lookup_status = _LookupStatus.member_found
280
 			self.__update_kickstarter_username(username_record)
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
 			await interaction.followup.send(text, ephemeral=True)
301
 			await interaction.followup.send(text, ephemeral=True)
283
 			return
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
 		member_link = self.__fetch_member_link_by_member_id(guild.id, member.id)
310
 		member_link = self.__fetch_member_link_by_member_id(guild.id, member.id)
288
 		if member_link is None:
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
 				"- They haven't used the `/link` command yet to provide their " \
316
 				"- They haven't used the `/link` command yet to provide their " \
291
 				"Kickstarter email address\n" \
317
 				"Kickstarter email address\n" \
292
 				"- They linked using a different Discord account. (You can " \
318
 				"- They linked using a different Discord account. (You can " \
293
 				"search by email with `/find_email`)\n" \
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
 			await interaction.followup.send(text, ephemeral=True)
321
 			await interaction.followup.send(text, ephemeral=True)
296
 			return
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
 		else:
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
 		await interaction.followup.send(text, ephemeral=True)
340
 		await interaction.followup.send(text, ephemeral=True)
319
 
341
 
320
 	@kickstarter.command(
342
 	@kickstarter.command(
380
 		await interaction.followup.send(text, ephemeral=True)
402
 		await interaction.followup.send(text, ephemeral=True)
381
 
403
 
382
 	@kickstarter.command(
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
 		await interaction.response.send_modal(_UploadEmailsModal())
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
 		await interaction.response.send_modal(_UploadUsernamesModal())
419
 		await interaction.response.send_modal(_UploadUsernamesModal())
393
 
420
 
394
 	async def interaction_check(self, interaction: Interaction) -> bool:
421
 	async def interaction_check(self, interaction: Interaction) -> bool:
396
 			self.__trace(interaction.guild, f"@{interaction.user.name} used /{interaction.command.qualified_name}")
423
 			self.__trace(interaction.guild, f"@{interaction.user.name} used /{interaction.command.qualified_name}")
397
 		return True
424
 		return True
398
 
425
 
426
+
427
+	# -- UI callbacks -----
428
+
399
 	async def on_email_upload_submit(self, interaction: Interaction, attachment: Attachment):
429
 	async def on_email_upload_submit(self, interaction: Interaction, attachment: Attachment):
400
 		"""Callback for email upload modal."""
430
 		"""Callback for email upload modal."""
401
 		await interaction.response.defer(ephemeral=True, thinking=True)
431
 		await interaction.response.defer(ephemeral=True, thinking=True)
477
 
507
 
478
 		await interaction.followup.send(text, ephemeral=True)
508
 		await interaction.followup.send(text, ephemeral=True)
479
 
509
 
510
+
511
+	# -- Operations -----
512
+
480
 	async def __link_member(self, guild: Guild, member: Member, email: str) -> '_LinkResult':
513
 	async def __link_member(self, guild: Guild, member: Member, email: str) -> '_LinkResult':
481
 		if not is_email_address(email.strip()):
514
 		if not is_email_address(email.strip()):
482
 			return _LinkResult(_LinkResultStatus.malformed_address)
515
 			return _LinkResult(_LinkResultStatus.malformed_address)

Laden…
Annuleren
Opslaan