ソースを参照

Adding factory method for standard BotMessageReactions. Adding bot check to avoid exceptions. Adding more logging.

tags/1.0.1
Rocketsoup 4年前
コミット
996d943ff8
7個のファイルの変更239行の追加66行の削除
  1. 90
    10
      cogs/basecog.py
  2. 15
    24
      cogs/crosspostcog.py
  3. 11
    1
      cogs/generalcog.py
  4. 7
    5
      cogs/joinraidcog.py
  5. 14
    9
      cogs/patterncog.py
  6. 100
    15
      cogs/urlspamcog.py
  7. 2
    2
      rocketbot.py

+ 90
- 10
cogs/basecog.py ファイルの表示

@@ -2,6 +2,7 @@ from discord import Guild, Member, Message, PartialEmoji, RawReactionActionEvent
2 2
 from discord.ext import commands
3 3
 from datetime import datetime, timedelta
4 4
 
5
+from abc import ABC, abstractmethod
5 6
 from config import CONFIG
6 7
 from rscollections import AgeBoundDict
7 8
 from storage import ConfigKey, Storage
@@ -28,6 +29,70 @@ class BotMessageReaction:
28 29
 			other.is_enabled == self.is_enabled and \
29 30
 			other.description == self.description
30 31
 
32
+	@classmethod
33
+	def standard_set(cls,
34
+			did_delete: bool = None,
35
+			message_count: int = 1,
36
+			did_kick: bool = None,
37
+			did_ban: bool = None,
38
+			user_count: int = 1) -> list:
39
+		"""
40
+		Convenience factory for generating any of the three most common
41
+		commands: delete message(s), kick user(s), and ban user(s). All
42
+		arguments are optional. Resulting list can be passed directly to
43
+		`BotMessage.set_reactions()`.
44
+
45
+		Params
46
+		- did_delete     Whether the message(s) have been deleted. Pass True or
47
+		                 False if this applies, omit to leave out delete action.
48
+		- message_count  How many messages there are. Used for pluralizing
49
+		                 description. Defaults to 1. Omit if n/a.
50
+		- did_kick       Whether the user(s) have been kicked. Pass True or
51
+		                 False if this applies, omit to leave out kick action.
52
+		- did_ban        Whether the user(s) have been banned. Pass True or
53
+		                 False if this applies, omit to leave out ban action.
54
+		- user_count     How many users there are. Used for pluralizing
55
+		                 description. Defaults to 1. Omit if n/a.
56
+		"""
57
+		reactions = []
58
+		if did_delete is not None:
59
+			if did_delete:
60
+				reactions.append(BotMessageReaction(
61
+					CONFIG['trash_emoji'],
62
+					False,
63
+					'Message deleted' if message_count == 1 else 'Messages deleted'))
64
+			else:
65
+				reactions.append(BotMessageReaction(
66
+					CONFIG['trash_emoji'],
67
+					True,
68
+					'Delete message' if message_count == 1 else 'Delete messages'))
69
+		if did_kick is not None:
70
+			if did_ban is not None and did_ban:
71
+				# Don't show kick option at all if we also banned
72
+				pass
73
+			elif did_kick:
74
+				reactions.append(BotMessageReaction(
75
+					CONFIG['kick_emoji'],
76
+					False,
77
+					'User kicked' if user_count == 1 else 'Users kicked'))
78
+			else:
79
+				reactions.append(BotMessageReaction(
80
+					CONFIG['kick_emoji'],
81
+					True,
82
+					'Kick user' if user_count == 1 else 'Kick users'))
83
+		if did_ban is not None:
84
+			if did_ban:
85
+				reactions.append(BotMessageReaction(
86
+					CONFIG['ban_emoji'],
87
+					False,
88
+					'User banned' if user_count == 1 else 'Users banned'))
89
+			else:
90
+				reactions.append(BotMessageReaction(
91
+					CONFIG['ban_emoji'],
92
+					True,
93
+					'Ban user' if user_count == 1 else 'Ban users'))
94
+		return reactions
95
+
31 96
 class BotMessage:
32 97
 	"""
33 98
 	Holds state for a bot-generated message. A message is composed, sent via
@@ -55,6 +120,7 @@ class BotMessage:
55 120
 		self.type = type
56 121
 		self.context = context
57 122
 		self.quote = None
123
+		self.source_cog = None  # Set by `BaseCog.post_message()`
58 124
 		self.__posted_text = None  # last text posted, to test for changes
59 125
 		self.__posted_emoji = set()
60 126
 		self.__message = None  # Message
@@ -160,11 +226,11 @@ class BotMessage:
160 226
 			else:
161 227
 				channel_id = Storage.get_config_value(self.guild, ConfigKey.WARNING_CHANNEL_ID)
162 228
 				if channel_id is None:
163
-					BaseCog.guild_trace(self.guild, 'No warning channel set! No warning issued.')
229
+					BaseCog.log(self.guild, '\u0007No warning channel set! No warning issued.')
164 230
 					return
165 231
 				channel: TextChannel = self.guild.get_channel(channel_id)
166 232
 				if channel is None:
167
-					BaseCog.guild_trace(self.guild, 'Configured warning channel does not exist!')
233
+					BaseCog.log(self.guild, '\u0007Configured warning channel does not exist!')
168 234
 					return
169 235
 				self.__message = await channel.send(content=content)
170 236
 				self.__posted_text = content
@@ -205,9 +271,9 @@ class BotMessage:
205 271
 			s += '\n\nAvailable actions:'
206 272
 			for reaction in self.__reactions:
207 273
 				if reaction.is_enabled:
208
-					s += f'\n   {reaction.emoji} {reaction.description}'
274
+					s += f'\n     {reaction.emoji} {reaction.description}'
209 275
 				else:
210
-					s += f'\n   {reaction.description}'
276
+					s += f'\n     {reaction.description}'
211 277
 
212 278
 		return s
213 279
 
@@ -241,10 +307,10 @@ class BaseCog(commands.Cog):
241 307
 			Storage.set_state_value(guild, 'bot_messages', bm)
242 308
 		return bm
243 309
 
244
-	@classmethod
245
-	async def post_message(cls, message: BotMessage) -> bool:
310
+	async def post_message(self, message: BotMessage) -> bool:
311
+		message.source_cog = self
246 312
 		await message._update()
247
-		guild_messages = cls.__bot_messages(message.guild)
313
+		guild_messages = self.__bot_messages(message.guild)
248 314
 		if message.is_sent():
249 315
 			guild_messages[message.message_id()] = message
250 316
 			return True
@@ -279,6 +345,9 @@ class BaseCog(commands.Cog):
279 345
 		if bot_message is None:
280 346
 			# Unknown message (expired or was never tracked)
281 347
 			return
348
+		if self is not bot_message.source_cog:
349
+			# Belongs to a different cog
350
+			return
282 351
 		reaction = bot_message.reaction_for_emoji(payload.emoji)
283 352
 		if reaction is None or not reaction.is_enabled:
284 353
 			# Can't use this reaction with this message
@@ -298,6 +367,8 @@ class BaseCog(commands.Cog):
298 367
 		"""
299 368
 		pass
300 369
 
370
+	# Helpers
371
+
301 372
 	@classmethod
302 373
 	async def validate_param(cls, context: commands.Context, param_name: str, value,
303 374
 		allowed_types: tuple = None,
@@ -330,17 +401,19 @@ class BaseCog(commands.Cog):
330 401
 	@classmethod
331 402
 	async def warn(cls, guild: Guild, message: str) -> Message:
332 403
 		"""
404
+		DEPRECATED. Use post_message.
405
+
333 406
 		Sends a warning message to the configured warning channel for the
334 407
 		given guild. If no warning channel is configured no action is taken.
335 408
 		Returns the Message if successful or None if not.
336 409
 		"""
337 410
 		channel_id = Storage.get_config_value(guild, ConfigKey.WARNING_CHANNEL_ID)
338 411
 		if channel_id is None:
339
-			cls.guild_trace(guild, 'No warning channel set! No warning issued.')
412
+			cls.log(guild, '\u0007No warning channel set! No warning issued.')
340 413
 			return None
341 414
 		channel: TextChannel = guild.get_channel(channel_id)
342 415
 		if channel is None:
343
-			cls.guild_trace(guild, 'Configured warning channel does not exist!')
416
+			cls.log(guild, '\u0007Configured warning channel does not exist!')
344 417
 			return None
345 418
 		mention: str = Storage.get_config_value(guild, ConfigKey.WARNING_MENTION)
346 419
 		text: str = message
@@ -352,6 +425,8 @@ class BaseCog(commands.Cog):
352 425
 	@classmethod
353 426
 	async def update_warn(cls, warn_message: Message, new_text: str) -> None:
354 427
 		"""
428
+		DEPRECATED. Use post_message.
429
+
355 430
 		Updates the text of a previously posted `warn`. Includes configured
356 431
 		mentions if necessary.
357 432
 		"""
@@ -364,5 +439,10 @@ class BaseCog(commands.Cog):
364 439
 		await warn_message.edit(content=text)
365 440
 
366 441
 	@classmethod
367
-	def guild_trace(cls, guild: Guild, message: str) -> None:
442
+	def log(cls, guild: Guild, message) -> None:
443
+		now = datetime.now()
444
+		print(f'[{now.strftime("%Y-%m-%dT%H:%M:%S")}|{cls.__name__}|{guild.name}] {message}')
445
+
446
+	@classmethod
447
+	def deprecated_guild_trace(cls, guild: Guild, message: str) -> None:
368 448
 		print(f'[guild {guild.id}|{guild.name}] {message}')

+ 15
- 24
cogs/crosspostcog.py ファイルの表示

@@ -114,6 +114,7 @@ class CrossPostCog(BaseCog):
114 114
 				context.is_banned = True
115 115
 				context.is_autobanned = True
116 116
 				context.deleted_messages |= context.spam_messages
117
+				self.log(context.member.guild, f'Bot autobanned {context.member.name} ({context.member.id}) for spamming')
117 118
 			else:
118 119
 				# Already banned. Nothing to update in the message.
119 120
 				return
@@ -137,29 +138,11 @@ class CrossPostCog(BaseCog):
137 138
 		else:
138 139
 			await message.set_text(f'User {context.member.mention} posted ' +
139 140
 				f'the same message {spam_count} times.')
140
-			can_delete = spam_count > deleted_count
141
-			can_kick = not context.is_kicked
142
-			can_ban = not context.is_banned
143
-			await message.add_reaction(
144
-				BotMessageReaction(
145
-					CONFIG['trash_emoji'],
146
-					can_delete,
147
-					'Delete messages' if can_delete else f'Deleted {deleted_count} messages'))
148
-			if can_ban:
149
-				# Only show kick info if they can also be banned. Otherwise we say
150
-				# dumb stuff like "user was kicked, user was banned".
151
-				await message.add_reaction(
152
-					BotMessageReaction(
153
-						CONFIG['kick_emoji'],
154
-						can_kick,
155
-						'Kick user' if can_kick else 'User kicked'))
156
-			else:
157
-				await message.remove_reaction(CONFIG['kick_emoji'])
158
-			await message.add_reaction(
159
-				BotMessageReaction(
160
-					CONFIG['ban_emoji'], 
161
-					can_ban,
162
-					'Ban user' if can_ban else 'User banned'))
141
+			await message.set_reactions(BotMessageReaction.standard_set(
142
+				did_delete = deleted_count >= spam_count,
143
+				message_count = spam_count,
144
+				did_kick = context.is_kicked,
145
+				did_ban = context.is_banned))
163 146
 		if context.bot_message is None:
164 147
 			await self.post_message(message)
165 148
 			context.bot_message = message
@@ -169,11 +152,13 @@ class CrossPostCog(BaseCog):
169 152
 			await message.delete()
170 153
 			context.deleted_messages.add(message)
171 154
 		await self.__update_from_context(context)
155
+		self.log(context.member.guild, f'Mod deleted messages from {context.member.name} ({context.member.id})')
172 156
 
173 157
 	async def __kick(self, context: SpamContext) -> None:
174 158
 		await context.member.kick(reason='Posting same message repeatedly')
175 159
 		context.is_kicked = True
176 160
 		await self.__update_from_context(context)
161
+		self.log(context.member.guild, f'Mod kicked user {context.member.name} ({context.member.id})')
177 162
 
178 163
 	async def __ban(self, context: SpamContext) -> None:
179 164
 		await context.member.ban(reason='Posting same message repeatedly', delete_message_days=1)
@@ -181,6 +166,7 @@ class CrossPostCog(BaseCog):
181 166
 		context.is_kicked = True
182 167
 		context.is_banned = True
183 168
 		await self.__update_from_context(context)
169
+		self.log(context.member.guild, f'Mod banned user {context.member.name} ({context.member.id})')
184 170
 
185 171
 	async def on_mod_react(self,
186 172
 			bot_message: BotMessage,
@@ -199,7 +185,12 @@ class CrossPostCog(BaseCog):
199 185
 
200 186
 	@commands.Cog.listener()
201 187
 	async def on_message(self, message: Message):
202
-		if message.author is None or message.channel is None or message.guild is None:
188
+		if message.author is None or \
189
+				message.author.bot or \
190
+				message.channel is None or \
191
+				message.guild is None or \
192
+				message.content is None or \
193
+				message.content == '':
203 194
 			return
204 195
 		await self.__record_message(message)
205 196
 

+ 11
- 1
cogs/generalcog.py ファイルの表示

@@ -32,8 +32,18 @@ class GeneralCog(BaseCog):
32 32
 			await self.warn(context.guild,
33 33
 				f'Test warning message (requested by {context.author.name})')
34 34
 
35
-	@commands.command()
35
+	@commands.command(
36
+		brief='Simple test reply',
37
+	)
36 38
 	async def hello(self, context):
37 39
 		await context.message.reply(
38 40
 			f'Hey, {context.author.name}!',
39 41
 		 	mention_author=False)
42
+
43
+	@commands.command(
44
+		brief='Shuts down the bot (admin only)',
45
+	)
46
+	@commands.has_permissions(administrator=True)
47
+	@commands.guild_only()
48
+	async def shutdown(self, context):
49
+		await self.bot.close()

+ 7
- 5
cogs/joinraidcog.py ファイルの表示

@@ -97,13 +97,10 @@ class JoinRaidRecord:
97 97
 			if self.phase == RaidPhase.NONE:
98 98
 				self.phase = RaidPhase.JUST_STARTED
99 99
 				self.raid_start_time = now
100
-				print('\u0007Join raid started!')
101 100
 			elif self.phase == RaidPhase.JUST_STARTED:
102 101
 				self.phase = RaidPhase.CONTINUING
103
-				print(f'\u0007Join raid up to {recent_count} people')
104 102
 		elif self.phase == self.phase in (RaidPhase.JUST_STARTED, RaidPhase.CONTINUING):
105 103
 			self.phase = RaidPhase.ENDED
106
-			print('Previous join raid ended')
107 104
 
108 105
 		# Undo join add if the raid is over
109 106
 		if self.phase == RaidPhase.ENDED and len(self.joins) > 0:
@@ -117,7 +114,9 @@ class JoinRaidRecord:
117 114
 		who were newly kicked.
118 115
 		"""
119 116
 		kicks = []
117
+		guild = None
120 118
 		for join in self.joins:
119
+			guild = join.member.guild
121 120
 			if join.is_kicked or join.is_banned:
122 121
 				continue
123 122
 			await join.member.kick(reason=reason)
@@ -125,7 +124,7 @@ class JoinRaidRecord:
125 124
 			kicks.append(join.member)
126 125
 		self.phase = RaidPhase.ENDED
127 126
 		if len(kicks) > 0:
128
-			print(f'Kicked {len(kicks)} people')
127
+			self.log(guild, f'Mod kicked {len(kicks)} people')
129 128
 		return kicks
130 129
 
131 130
 	async def ban_all(self,
@@ -137,7 +136,9 @@ class JoinRaidRecord:
137 136
 		still be banned. Returns a List of Members who were newly banned.
138 137
 		"""
139 138
 		bans = []
139
+		guild = None
140 140
 		for join in self.joins:
141
+			guild = join.member.guild
141 142
 			if join.is_banned:
142 143
 				continue
143 144
 			await join.member.ban(
@@ -147,7 +148,7 @@ class JoinRaidRecord:
147 148
 			bans.append(join.member)
148 149
 		self.phase = RaidPhase.ENDED
149 150
 		if len(bans) > 0:
150
-			print(f'Banned {len(bans)} people')
151
+			self.log(guild, f'Mod banned {len(bans)} people')
151 152
 		return bans
152 153
 
153 154
 class GuildContext:
@@ -452,6 +453,7 @@ class JoinRaidCog(BaseCog):
452 453
 			await raid.warning_message.add_reaction(CONFIG['kick_emoji'])
453 454
 		if can_ban:
454 455
 			await raid.warning_message.add_reaction(CONFIG['ban_emoji'])
456
+		self.log(guild, f'New join raid detected!')
455 457
 
456 458
 	async def __update_raid_warning(self, guild: Guild, raid: JoinRaidRecord) -> None:
457 459
 		"""

+ 14
- 9
cogs/patterncog.py ファイルの表示

@@ -72,10 +72,12 @@ class PatternCog(BaseCog):
72 72
 
73 73
 	@commands.Cog.listener()
74 74
 	async def on_message(self, message: Message) -> None:
75
-		if message.guild is None or message.content is None or message.channel is None:
76
-			return
77
-		if message.author.id == self.bot.user.id:
78
-			# Ignore self
75
+		if message.author is None or \
76
+				message.author.bot or \
77
+				message.channel is None or \
78
+				message.guild is None or \
79
+				message.content is None or \
80
+				message.content == '':
79 81
 			return
80 82
 		if message.author.permissions_in(message.channel).ban_members:
81 83
 			# Ignore mods
@@ -83,22 +85,25 @@ class PatternCog(BaseCog):
83 85
 		patterns = self.__patterns(message.guild)
84 86
 		for pattern in patterns:
85 87
 			if pattern.matches(message):
86
-				msg = None
88
+				text = None
87 89
 				if pattern.action == 'delete':
88 90
 					await message.delete()
89
-					msg = f'Message from {message.author.mention} matched ' + \
91
+					text = f'Message from {message.author.mention} matched ' + \
90 92
 						'banned pattern. Deleted.'
93
+					self.log(message.guild, 'Message matched pattern. Deleted.')
91 94
 				elif pattern.action == 'kick':
92 95
 					await message.delete()
93 96
 					await message.author.kick(reason='Rocketbot: Message matched banned pattern')
94
-					msg = f'Message from {message.author.mention} matched ' + \
97
+					text = f'Message from {message.author.mention} matched ' + \
95 98
 						'banned pattern. Message deleted and user kicked.'
99
+					self.log(message.guild, 'Message matched pattern. Kicked user.')
96 100
 				elif pattern.action == 'ban':
97 101
 					await message.delete()
98 102
 					await message.author.ban(reason='Rocketbot: Message matched banned pattern')
99
-					msg = f'Message from {message.author.mention} matched ' + \
103
+					text = f'Message from {message.author.mention} matched ' + \
100 104
 						'banned pattern. Message deleted and user banned.'
101
-				if msg:
105
+					self.log(message.guild, 'Message matched pattern. Banned user.')
106
+				if text:
102 107
 					m = BotMessage(message.guild,
103 108
 						text = msg,
104 109
 						type = BotMessage.TYPE_MOD_WARNING)

+ 100
- 15
cogs/urlspamcog.py ファイルの表示

@@ -1,12 +1,19 @@
1
-from discord import Guild, Message
1
+from discord import Guild, Member, Message
2 2
 from discord.ext import commands
3 3
 import re
4 4
 from datetime import timedelta
5 5
 
6
-from cogs.basecog import BaseCog
6
+from cogs.basecog import BaseCog, BotMessage, BotMessageReaction
7 7
 from config import CONFIG
8 8
 from storage import Storage
9 9
 
10
+class URLSpamContext:
11
+	def __init__(self, spam_message: Message):
12
+		self.spam_message = spam_message
13
+		self.is_deleted = False
14
+		self.is_kicked = False
15
+		self.is_banned = False
16
+
10 17
 class URLSpamCog(BaseCog):
11 18
 	CONFIG_KEY_EARLY_URL_TIMEOUT = "urlspam_early_url_timeout"
12 19
 	CONFIG_KEY_EARLY_URL_ACTION = "urlspam_early_url_action"
@@ -24,33 +31,111 @@ class URLSpamCog(BaseCog):
24 31
 
25 32
 	@commands.Cog.listener()
26 33
 	async def on_message(self, message: Message):
27
-		if message.guild is None or message.channel is None:
28
-			# DM or something
34
+		if message.author is None or \
35
+				message.author.bot or \
36
+				message.guild is None or \
37
+				message.channel is None or \
38
+				message.content is None:
29 39
 			return
40
+
30 41
 		action = self.__early_url_action(message.guild)
31 42
 		if action == 'nothing':
32 43
 			return
33
-		if message.author.permissions_in(message.channel).ban_members:
34
-			# Mods are exempt
35
-			return
36 44
 		if not self.__contains_url(message.content):
37 45
 			return
38 46
 		join_age = message.created_at - message.author.joined_at
39 47
 		join_age_str = self.__format_timedelta(join_age)
40 48
 		if join_age.total_seconds() < self.__early_url_timeout(message.guild):
41 49
 			if action == 'modwarn':
42
-				await self.warn(message.guild, f'User {message.author.mention} ' +
43
-					f'posted a URL {join_age_str} after joining.\n\n> {message.content}')
44
-				# TODO: Emoji actions
50
+				bm = BotMessage(
51
+					message.guild,
52
+					f'User {message.author.mention} posted a URL ' + \
53
+					f'{join_age_str} after joining.',
54
+					type = BotMessage.TYPE_MOD_WARNING,
55
+					context = URLSpamContext(message))
56
+				bm.quote = message.content
57
+				await bm.add_reaction(BotMessageReaction(CONFIG['trash_emoji'], True, 'Delete message'))
58
+				await bm.add_reaction(BotMessageReaction(CONFIG['kick_emoji'], True, 'Kick user'))
59
+				await bm.add_reaction(BotMessageReaction(CONFIG['ban_emoji'], True, 'Ban user'))
60
+				await self.post_message(bm)
61
+				self.log(message.guild, f'New user {message.author.name} ' + \
62
+					f'({message.author.id}) posted URL. Mods alerted.')
45 63
 			elif action == 'delete':
46 64
 				await message.delete()
47
-				# TODO: Info to mods
65
+				bm = BotMessage(
66
+					message.guild,
67
+					f'User {message.author.mention} posted a URL ' + \
68
+					f'{join_age_str} after joining. Message deleted.',
69
+					type = BotMessage.TYPE_INFO,
70
+					context = URLSpamContext(message))
71
+				bm.quote = message.content
72
+				await bm.add_reaction(BotMessageReaction(CONFIG['kick_emoji'], True, 'Kick user'))
73
+				await bm.add_reaction(BotMessageReaction(CONFIG['ban_emoji'], True, 'Ban user'))
74
+				await self.post_message(bm)
75
+				self.log(message.guild, f'New user {message.author.name} ' + \
76
+					f'({message.author.id}) posted URL. Message deleted.')
48 77
 			elif action == 'kick':
49
-				await message.author.kick(reason=f'User posted a link {join_age_str} after joining')
50
-				# TODO: Info to mods
78
+				await message.author.kick(reason='User posted a link ' + \
79
+					f'{join_age_str} after joining')
80
+				bm = BotMessage(
81
+					message.guild,
82
+					f'User {message.author.mention} posted a URL ' + \
83
+					f'{join_age_str} after joining. Kicked by bot.',
84
+					type = BotMessage.TYPE_INFO,
85
+					context = URLSpamContext(message))
86
+				bm.quote = message.content
87
+				await bm.add_reaction(BotMessageReaction(CONFIG['ban_emoji'], True, 'Ban user'))
88
+				await self.post_message(bm)
89
+				self.log(message.guild, f'New user {message.author.name} ' + \
90
+					f'({message.author.id}) posted URL. User kicked.')
51 91
 			elif action == 'ban':
52
-				await message.author.ban(reason=f'User posted a link {join_age_str} after joining', delete_message_days=1)
53
-				# TODO: Info to mods
92
+				await message.author.ban(reason='User posted a link ' + \
93
+					f'{join_age_str} after joining', delete_message_days=1)
94
+				bm = BotMessage(
95
+					message.guild,
96
+					f'User {message.author.mention} posted a URL ' + \
97
+					f'{join_age_str} after joining. Banned by bot.',
98
+					type = BotMessage.TYPE_INFO,
99
+					context = URLSpamContext(message))
100
+				bm.quote = message.content
101
+				await self.post_message(bm)
102
+				self.log(message.guild, f'New user {message.author.name} ' + \
103
+					f'({message.author.id}) posted URL. User banned.')
104
+
105
+	async def on_mod_react(self,
106
+			bot_message: BotMessage,
107
+			reaction: BotMessageReaction,
108
+			reacted_by: Member) -> None:
109
+		context: URLSpamContext = bot_message.context
110
+		if context is None:
111
+			return
112
+		sm: Message = context.spam_message
113
+		if reaction.emoji == CONFIG['trash_emoji']:
114
+			if not context.is_deleted:
115
+				await sm.delete()
116
+				context.is_deleted = True
117
+				self.log(sm.guild, f'URL spam by {sm.author.name} deleted by {reacted_by.name}')
118
+		elif reaction.emoji == CONFIG['kick_emoji']:
119
+			if not context.is_deleted:
120
+				await sm.delete()
121
+				context.is_deleted = True
122
+			if not context.is_kicked:
123
+				await sm.author.kick(reason=f'Rocketbot: Kicked for URL spam by {reacted_by.name}')
124
+				context.is_kicked = True
125
+				self.log(sm.guild, f'URL spammer {sm.author.name} kicked by {reacted_by.name}')
126
+		elif reaction.emoji == CONFIG['ban_emoji']:
127
+			if not context.is_banned:
128
+				await sm.author.ban(reason=f'Rocketbot: Banned for URL spam by {reacted_by.name}', delete_message_days=1)
129
+				context.is_deleted = True
130
+				context.is_kicked = True
131
+				context.is_banned = True
132
+				self.log(sm.guild, f'URL spammer {sm.author.name} banned by {reacted_by.name}')
133
+		else:
134
+			return
135
+		await bot_message.set_reactions(BotMessageReaction.standard_set(
136
+			did_delete=context.is_deleted,
137
+			did_kick=context.is_kicked,
138
+			did_ban=context.is_banned))
54 139
 
55 140
 	def __contains_url(self, text: str) -> bool:
56 141
 		p = re.compile(r'http(?:s)?://[^\s]+')

+ 2
- 2
rocketbot.py ファイルの表示

@@ -14,7 +14,7 @@ from cogs.crosspostcog import CrossPostCog
14 14
 from cogs.generalcog import GeneralCog
15 15
 from cogs.joinraidcog import JoinRaidCog
16 16
 from cogs.patterncog import PatternCog
17
-# from cogs.urlspamcog import URLSpamCog
17
+from cogs.urlspamcog import URLSpamCog
18 18
 
19 19
 CURRENT_CONFIG_VERSION = 1
20 20
 if (CONFIG.get('__config_version') or 0) < CURRENT_CONFIG_VERSION:
@@ -35,6 +35,6 @@ bot.add_cog(ConfigCog(bot))
35 35
 bot.add_cog(JoinRaidCog(bot))
36 36
 bot.add_cog(CrossPostCog(bot))
37 37
 bot.add_cog(PatternCog(bot))
38
-# bot.add_cog(URLSpamCog(bot))
38
+bot.add_cog(URLSpamCog(bot))
39 39
 bot.run(CONFIG['client_token'], bot=True, reconnect=True)
40 40
 print('\nBot aborted')

読み込み中…
キャンセル
保存