|
|
@@ -2,6 +2,8 @@
|
|
2
|
2
|
Classes for crafting messages from the bot. Content can change as information
|
|
3
|
3
|
changes, and mods can perform actions on the message via emoji reactions.
|
|
4
|
4
|
"""
|
|
|
5
|
+from typing import Any, Optional, Union
|
|
|
6
|
+
|
|
5
|
7
|
from datetime import datetime
|
|
6
|
8
|
from discord import Guild, Message, PartialEmoji, TextChannel
|
|
7
|
9
|
|
|
|
@@ -20,9 +22,16 @@ class BotMessageReaction:
|
|
20
|
22
|
to explain why an action is no longer available.
|
|
21
|
23
|
"""
|
|
22
|
24
|
def __init__(self, emoji: str, is_enabled: bool, description: str):
|
|
23
|
|
- self.emoji = emoji
|
|
24
|
|
- self.is_enabled = is_enabled
|
|
25
|
|
- self.description = description
|
|
|
25
|
+ """
|
|
|
26
|
+ Creates a bot message reaction.
|
|
|
27
|
+ - emoji: The emoji string
|
|
|
28
|
+ - is_enabled: Whether the emoji can be used
|
|
|
29
|
+ - description: What reacting with this emoji does (or an explanation of
|
|
|
30
|
+ why it's disabled)
|
|
|
31
|
+ """
|
|
|
32
|
+ self.emoji: str = emoji
|
|
|
33
|
+ self.is_enabled: bool = is_enabled
|
|
|
34
|
+ self.description: str = description
|
|
26
|
35
|
|
|
27
|
36
|
def __eq__(self, other):
|
|
28
|
37
|
return other is not None and \
|
|
|
@@ -36,7 +45,7 @@ class BotMessageReaction:
|
|
36
|
45
|
message_count: int = 1,
|
|
37
|
46
|
did_kick: bool = None,
|
|
38
|
47
|
did_ban: bool = None,
|
|
39
|
|
- user_count: int = 1) -> list:
|
|
|
48
|
+ user_count: int = 1) -> list[BotMessageReaction]:
|
|
40
|
49
|
"""
|
|
41
|
50
|
Convenience factory for generating any of the three most common
|
|
42
|
51
|
commands: delete message(s), kick user(s), and ban user(s). All
|
|
|
@@ -55,7 +64,7 @@ class BotMessageReaction:
|
|
55
|
64
|
- user_count How many users there are. Used for pluralizing
|
|
56
|
65
|
description. Defaults to 1. Omit if n/a.
|
|
57
|
66
|
"""
|
|
58
|
|
- reactions = []
|
|
|
67
|
+ reactions: list[BotMessageReaction] = []
|
|
59
|
68
|
if did_delete is not None:
|
|
60
|
69
|
if did_delete:
|
|
61
|
70
|
reactions.append(BotMessageReaction(
|
|
|
@@ -104,29 +113,38 @@ class BotMessage:
|
|
104
|
113
|
actions that can be taken via a mod reacting to the message.
|
|
105
|
114
|
"""
|
|
106
|
115
|
|
|
107
|
|
- TYPE_DEFAULT = 0
|
|
108
|
|
- TYPE_INFO = 1
|
|
109
|
|
- TYPE_MOD_WARNING = 2
|
|
110
|
|
- TYPE_SUCCESS = 3
|
|
111
|
|
- TYPE_FAILURE = 4
|
|
|
116
|
+ TYPE_DEFAULT: int = 0
|
|
|
117
|
+ TYPE_INFO: int = 1
|
|
|
118
|
+ TYPE_MOD_WARNING: int = 2
|
|
|
119
|
+ TYPE_SUCCESS: int = 3
|
|
|
120
|
+ TYPE_FAILURE: int = 4
|
|
112
|
121
|
|
|
113
|
122
|
def __init__(self,
|
|
114
|
123
|
guild: Guild,
|
|
115
|
124
|
text: str,
|
|
116
|
125
|
type: int = TYPE_DEFAULT, # pylint: disable=redefined-builtin
|
|
117
|
|
- context = None,
|
|
118
|
|
- reply_to: Message = None):
|
|
119
|
|
- self.guild = guild
|
|
120
|
|
- self.text = text
|
|
121
|
|
- self.type = type
|
|
122
|
|
- self.context = context
|
|
123
|
|
- self.quote = None
|
|
|
126
|
+ context: Optional[Any] = None,
|
|
|
127
|
+ reply_to: Optional[Message] = None):
|
|
|
128
|
+ """
|
|
|
129
|
+ Creates a bot message.
|
|
|
130
|
+ - guild: The Discord guild to send the message to.
|
|
|
131
|
+ - text: Main text of the message.
|
|
|
132
|
+ - type: One of the TYPE_ constants.
|
|
|
133
|
+ - context: Arbitrary value that will be passed in the callback. Can be
|
|
|
134
|
+ associated data for performing some action. (optional)
|
|
|
135
|
+ - reply_to: Existing message this message is in reply to. (optional)
|
|
|
136
|
+ """
|
|
|
137
|
+ self.guild: Guild = guild
|
|
|
138
|
+ self.text: str = text
|
|
|
139
|
+ self.type: int = type
|
|
|
140
|
+ self.context: Optional[Any] = context
|
|
|
141
|
+ self.quote: Optional[str] = None
|
|
124
|
142
|
self.source_cog = None # Set by `BaseCog.post_message()`
|
|
125
|
|
- self.__posted_text = None # last text posted, to test for changes
|
|
126
|
|
- self.__posted_emoji = set()
|
|
127
|
|
- self.__message = None # Message
|
|
128
|
|
- self.__reply_to = reply_to
|
|
129
|
|
- self.__reactions = [] # BotMessageReaction[]
|
|
|
143
|
+ self.__posted_text: str = None # last text posted, to test for changes
|
|
|
144
|
+ self.__posted_emoji: set[str] = set() # last emoji list posted
|
|
|
145
|
+ self.__message: Optional[Message] = None # set once the message has been posted
|
|
|
146
|
+ self.__reply_to: Optional[Message] = reply_to
|
|
|
147
|
+ self.__reactions: list[BotMessageReaction] = []
|
|
130
|
148
|
|
|
131
|
149
|
def is_sent(self) -> bool:
|
|
132
|
150
|
"""
|
|
|
@@ -136,11 +154,11 @@ class BotMessage:
|
|
136
|
154
|
"""
|
|
137
|
155
|
return self.__message is not None
|
|
138
|
156
|
|
|
139
|
|
- def message_id(self):
|
|
|
157
|
+ def message_id(self) -> Optional[int]:
|
|
140
|
158
|
'Returns the Message id or None if not sent.'
|
|
141
|
159
|
return self.__message.id if self.__message else None
|
|
142
|
160
|
|
|
143
|
|
- def message_sent_at(self) -> datetime:
|
|
|
161
|
+ def message_sent_at(self) -> Optional[datetime]:
|
|
144
|
162
|
'Returns when the message was sent or None if not sent.'
|
|
145
|
163
|
return self.__message.created_at if self.__message else None
|
|
146
|
164
|
|
|
|
@@ -156,7 +174,7 @@ class BotMessage:
|
|
156
|
174
|
self.text = new_text
|
|
157
|
175
|
await self.update_if_sent()
|
|
158
|
176
|
|
|
159
|
|
- async def set_reactions(self, reactions: list) -> None:
|
|
|
177
|
+ async def set_reactions(self, reactions: list[BotMessageReaction]) -> None:
|
|
160
|
178
|
"""
|
|
161
|
179
|
Replaces all BotMessageReactions with a new list. If the message has
|
|
162
|
180
|
been sent, it will be updated.
|
|
|
@@ -194,7 +212,7 @@ class BotMessage:
|
|
194
|
212
|
self.__reactions.append(reaction)
|
|
195
|
213
|
await self.update_if_sent()
|
|
196
|
214
|
|
|
197
|
|
- async def remove_reaction(self, reaction_or_emoji) -> None:
|
|
|
215
|
+ async def remove_reaction(self, reaction_or_emoji: Union[BotMessageReaction, str]) -> None:
|
|
198
|
216
|
"""
|
|
199
|
217
|
Removes a reaction. Can pass either a BotMessageReaction or just the
|
|
200
|
218
|
emoji string. If the message has been sent, it will be updated.
|
|
|
@@ -207,7 +225,7 @@ class BotMessage:
|
|
207
|
225
|
await self.update_if_sent()
|
|
208
|
226
|
return
|
|
209
|
227
|
|
|
210
|
|
- def reaction_for_emoji(self, emoji) -> BotMessageReaction:
|
|
|
228
|
+ def reaction_for_emoji(self, emoji) -> Optional[BotMessageReaction]:
|
|
211
|
229
|
"""
|
|
212
|
230
|
Finds the BotMessageReaction for the given emoji or None if not found.
|
|
213
|
231
|
Accepts either a PartialEmoji or str.
|
|
|
@@ -245,11 +263,15 @@ class BotMessage:
|
|
245
|
263
|
else:
|
|
246
|
264
|
channel_id = Storage.get_config_value(self.guild, ConfigKey.WARNING_CHANNEL_ID)
|
|
247
|
265
|
if channel_id is None:
|
|
248
|
|
- bot_log(self.guild, None, '\u0007No warning channel set! No warning issued.')
|
|
|
266
|
+ bot_log(self.guild, \
|
|
|
267
|
+ type(self.source_cog) if self.source_cog else None, \
|
|
|
268
|
+ '\u0007No warning channel set! No warning issued.')
|
|
249
|
269
|
return
|
|
250
|
270
|
channel: TextChannel = self.guild.get_channel(channel_id)
|
|
251
|
271
|
if channel is None:
|
|
252
|
|
- bot_log(self.guild, None, '\u0007Configured warning channel does not exist!')
|
|
|
272
|
+ bot_log(self.guild, \
|
|
|
273
|
+ type(self.source_cog) if self.source_cog else None, \
|
|
|
274
|
+ '\u0007Configured warning channel does not exist!')
|
|
253
|
275
|
return
|
|
254
|
276
|
self.__message = await channel.send(content=content)
|
|
255
|
277
|
self.__posted_text = content
|
|
|
@@ -267,6 +289,10 @@ class BotMessage:
|
|
267
|
289
|
self.__posted_emoji.remove(emoji)
|
|
268
|
290
|
|
|
269
|
291
|
def __formatted_message(self) -> str:
|
|
|
292
|
+ """
|
|
|
293
|
+ Composes the entire message markdown from components. Includes the main
|
|
|
294
|
+ message, quoted text, summary of available reactions, etc.
|
|
|
295
|
+ """
|
|
270
|
296
|
s: str = ''
|
|
271
|
297
|
|
|
272
|
298
|
if self.type == self.TYPE_INFO:
|