Passed
Pull Request — main (#157)
by
unknown
01:26
created

AllowedMentions.get_str_id()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nop 1
1
# Copyright Pincer 2021-Present
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# Full MIT License can be found in `LICENSE` at the project root.
3
4
from __future__ import annotations
5
6
from dataclasses import dataclass
7
from enum import IntEnum, Enum
8
from typing import Any, Generator, List, Optional, Union, TYPE_CHECKING
9
10
from ..app.application import Application
11
from ..app.interaction_base import MessageInteraction
12
from ..guild.channel import Channel, ChannelMention
13
from ..guild.member import GuildMember, PartialGuildMember
14
from ..guild.role import Role
15
from ..message.attachment import Attachment
16
from ..message.component import MessageComponent
17
from ..message.embed import Embed
18
from ..message.reaction import Reaction
19
from ..message.reference import MessageReference
20
from ..message.sticker import StickerItem
21
from ..user import User
22
from ..._config import GatewayConfig
23
from ...utils.api_object import APIObject
24
from ...utils.conversion import construct_client_dict, convert
25
from ...utils.snowflake import Snowflake
26
from ...utils.timestamp import Timestamp
0 ignored issues
show
introduced by
Cannot import 'utils.timestamp' due to syntax error 'invalid syntax (<unknown>, line 70)'
Loading history...
Bug introduced by
The name timestamp does not seem to exist in module pincer.utils.
Loading history...
27
from ...utils.types import MISSING
28
29
if TYPE_CHECKING:
30
    from ...utils import APINullable
31
32
33
class MessageActivityType(IntEnum):
34
    """
35
    The activity people can perform on a rich presence activity.
36
37
    Such an activity could for example be a spotify listen.
38
    """
39
    JOIN = 1
40
    SPECTATE = 2
41
    LISTEN = 3
42
    JOIN_REQUEST = 5
43
44
45
class MessageFlags(IntEnum):
46
    """
47
    Special message properties.
48
49
    :param CROSSPOSTED:
50
        the message has been published to subscribed
51
        channels (via Channel Following)
52
53
    :param IS_CROSSPOST:
54
        this message originated from a message
55
        in another channel (via Channel Following)
56
57
    :param SUPPRESS_EMBEDS:
58
        do not include any embeds when serializing this message
59
60
    :param SOURCE_MESSAGE_DELETED:
61
        the source message for this crosspost
62
        has been deleted (via Channel Following)
63
64
    :param URGENT:
65
        this message came from the urgent message system
66
67
    :param HAS_THREAD:
68
        this message has an associated thread,
69
        with the same id as the message
70
71
    :param EPHEMERAL:
72
        this message is only visible to the user
73
        who invoked the Interaction
74
75
    :param LOADING:
76
        this message is an Interaction
77
        Response and the bot is "thinking"
78
    """
79
    CROSSPOSTED = 1 << 0
80
    IS_CROSSPOST = 1 << 1
81
    SUPPRESS_EMBEDS = 1 << 2
82
    SOURCE_MESSAGE_DELETED = 1 << 3
83
    URGENT = 1 << 4
84
    HAS_THREAD = 1 << 5
85
    EPHEMERAL = 1 << 6
86
    LOADING = 1 << 7
87
88
89
class MessageType(IntEnum):
90
    """
91
    Represents the type of the message.
92
    """
93
    DEFAULT = 0
94
    RECIPIENT_ADD = 1
95
    RECIPIENT_REMOVE = 2
96
    CALL = 3
97
    CHANNEL_NAME_CHANGE = 4
98
    CHANNEL_ICON_CHANGE = 5
99
    CHANNEL_PINNED_MESSAGE = 6
100
    GUILD_MEMBER_JOIN = 7
101
    USER_PREMIUM_GUILD_SUBSCRIPTION = 8
102
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9
103
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10
104
    USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11
105
    CHANNEL_FOLLOW_ADD = 12
106
    GUILD_DISCOVERY_DISQUALIFIED = 14
107
    GUILD_DISCOVERY_REQUALIFIED = 15
108
    GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16
109
    GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17
110
    THREAD_CREATED = 18
111
    REPLY = 19
112
    APPLICATION_COMMAND = 20
113
114
    if GatewayConfig.version < 8:
115
        REPLY = 0
116
        APPLICATION_COMMAND = 0
117
118
    if GatewayConfig.version >= 9:
119
        THREAD_STARTER_MESSAGE = 21
120
121
    GUILD_INVITE_REMINDER = 22
122
123
124
@dataclass
125
class MessageActivity(APIObject):
126
    """
127
    Represents a Discord Message Activity object
128
129
    :param type:
130
        type of message activity
131
132
    :param party_id:
133
        party_id from a Rich Presence event
134
    """
135
    type: MessageActivityType
136
    party_id: APINullable[str] = MISSING
137
138
139
class AllowedMentionTypes(str, Enum):
140
    """
141
    The allowed mentions.
142
143
    :param ROLES:
144
        Controls role mentions
145
146
    :param USERS:
147
        Controls user mentions
148
149
    :param EVERYONE:
150
        Controls @everyone and @here mentions
151
    """
152
    ROLES = "roles"
153
    USERS = "users"
154
    EVERYONE = "everyone"
155
156
157
@dataclass
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
158
class AllowedMentions(APIObject):
159
    parse: List[AllowedMentionTypes]
160
    roles: List[Union[Role, Snowflake]]
161
    users: List[Union[User, Snowflake]]
162
    reply: bool = True
163
164
    @staticmethod
165
    def get_str_id(obj: Union[Snowflake, User, Role]) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
166
        if hasattr(obj, "id"):
167
            obj = obj.id
168
169
        return str(obj)
170
171
    def to_dict(self):
172
        return {
173
            "parse": self.parse,
174
            "roles": list(map(self.get_str_id, self.roles)),
175
            "users": list(map(self.get_str_id, self.users)),
176
            "replied_user": self.reply
177
        }
178
179
180
@dataclass
0 ignored issues
show
best-practice introduced by
Too many instance attributes (30/7)
Loading history...
181
class UserMessage(APIObject):
182
    """
183
    Represents a message sent in a channel within Discord.
184
185
    :param id:
186
        id of the message
187
188
    :param channel_id:
189
        id of the channel the message was sent in
190
191
    :param guild_id:
192
        id of the guild the message was sent in
193
194
    :param author:
195
        the author of this message (not guaranteed to be a valid user)
196
197
    :param member:
198
        member properties for this message's author
199
200
    :param content:
201
        contents of the message
202
203
    :param timestamp:
204
        when this message was sent
205
206
    :param edited_timestamp:
207
        when this message was edited (or null if never)
208
209
    :param tts:
210
        whether this was a TTS message
211
212
    :param mention_everyone:
213
        whether this message mentions everyone
214
215
    :param mentions:
216
        users specifically mentioned in the message
217
218
    :param mention_roles:
219
        roles specifically mentioned in this message
220
221
    :param mention_channels:
222
        channels specifically mentioned in this message
223
224
    :param attachments:
225
        any attached files
226
227
    :param embeds:
228
        any embedded content
229
230
    :param reactions:
231
        reactions to the message
232
233
    :param nonce:
234
        user for validating a message was sent
235
236
    :param pinned:
237
        whether this message is pinned
238
239
    :param webhook_id:
240
        if the message is generated by a webhook,
241
        this is the webhook's id
242
243
    :param type:
244
        type of message
245
246
    :param activity:
247
        sent with Rich Presence-related chat embeds
248
249
    :param application:
250
        sent with Rich Presence-related chat embeds
251
252
    :param application_id:
253
        if the message is a response to an Interaction,
254
        this is the id of the interaction's application
255
256
    :param message_reference:
257
        data showing the source of a crosspost,
258
        channel follow add, pin, or reply message
259
260
    :param flags:
261
        message flags combined as a bitfield
262
263
    :param referenced_message:
264
        the message associated with the message_reference
265
266
    :param interaction:
267
        sent if the message is a response to an Interaction
268
269
    :param thread:
270
        the thread that was started from this message,
271
        includes thread member object
272
273
    :param components:
274
        sent if the message contains components like buttons,
275
        action rows, or other interactive components
276
277
    :param sticker_items:
278
        sent if the message contains stickers
279
    """
280
    id: Snowflake
281
    channel_id: Snowflake
282
    author: User
283
    content: str
284
    timestamp: Timestamp
285
    tts: bool
286
    mention_everyone: bool
287
    mentions: List[GuildMember]
288
    mention_roles: List[Role]
289
    attachments: List[Attachment]
290
    embeds: List[Embed]
291
    pinned: bool
292
    type: MessageType
293
294
    edited_timestamp: APINullable[Timestamp] = MISSING
295
    mention_channels: APINullable[List[ChannelMention]] = MISSING
296
    guild_id: APINullable[Snowflake] = MISSING
297
    member: APINullable[PartialGuildMember] = MISSING
298
    reactions: APINullable[List[Reaction]] = MISSING
299
    nonce: APINullable[Union[int, str]] = MISSING
300
    webhook_id: APINullable[Snowflake] = MISSING
301
    activity: APINullable[MessageActivity] = MISSING
302
    application: APINullable[Application] = MISSING
303
    application_id: APINullable[Snowflake] = MISSING
304
    message_reference: APINullable[MessageReference] = MISSING
305
    flags: APINullable[MessageFlags] = MISSING
306
    referenced_message: APINullable[Optional[UserMessage]] = MISSING
307
    interaction: APINullable[MessageInteraction] = MISSING
308
    thread: APINullable[Channel] = MISSING
309
    components: APINullable[List[MessageComponent]] = MISSING
310
    sticker_items: APINullable[List[StickerItem]] = MISSING
311
312
    def __post_init__(self):
313
        self.id = convert(self.id, Snowflake.from_string)
314
        self.channel_id = convert(self.channel_id, Snowflake.from_string)
315
        self.author = convert(self.author, User.from_dict, client=self._client)
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _client.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
316
        self.timestamp = convert(self.timestamp, Timestamp)
317
        self.edited_timestamp = convert(self.edited_timestamp, Timestamp)
318
        self.mentions = convert(self.mentions, PartialGuildMember.from_dict,
319
                                client=self._client)
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _client.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
320
        self.mention_roles = convert(self.mention_roles, Role.from_dict)
321
        self.attachments = convert(self.attachments, Attachment.from_dict)
322
        self.embeds = convert(self.embeds, Embed.from_dict)
323
        self.mention_channels = convert(
324
            self.mention_channels,
325
            ChannelMention.from_dict
326
        )
327
        self.guild_id = convert(self.guild_id, Snowflake.from_string)
328
        self.member = convert(self.member, GuildMember.from_dict,
329
                              client=self._client)
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _client.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
330
        self.reactions = convert(self.reactions, Reaction.from_dict)
331
        self.webhook_id = convert(self.webhook_id, Snowflake.from_string)
332
        self.activity = convert(self.activity, MessageActivity.from_dict)
333
        self.application = convert(self.application, Application.from_dict)
334
        self.application_id = convert(
335
            self.application_id,
336
            Snowflake.from_string
337
        )
338
        self.message_reference = convert(
339
            self.message_reference,
340
            MessageReference.from_dict
341
        )
342
        # self.flags = convert(self.flags, MessageFlags.from_bytes)
343
        # self.referenced_message = convert(
344
        #     self.referenced_message,
345
        #     Message.from_dict
346
        # )
347
        self.interaction = convert(
348
            self.interaction,
349
            MessageInteraction.from_dict
350
        )
351
        self.thread = convert(self.thread, Channel.from_dict,
352
                              client=self._client)
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _client.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
353
        self.components = convert(self.components, MessageComponent.from_dict)
354
        self.sticker_items = convert(self.sticker_items, StickerItem.from_dict)
355
356
    async def get_most_recent(self):
357
        """
358
        Certain Discord methods don't return the message object data after its
359
        updated. This function can be run to get the most recent version of the
360
        message object.
361
        """
362
363
        return self.from_dict(
364
            construct_client_dict(
365
                self._client,
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _client.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
366
                await self._http.get(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
367
                    f"/channels/{self.channel_id}/messages/{self.id}"
368
                )
369
            )
370
        )
371
372
    async def react(self, emoji: str):
373
        """
374
        Create a reaction for the message. Requires the
375
        ``READ_MESSAGE_HISTORY` itent. ``ADD_REACTIONS`` intent is required if
376
        nobody else has reacted using the emoji.
377
378
        :param emoji:
379
            Character for emoji. Does not need to be URL encoded.
380
        """
381
382
        await self._http.put(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
383
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}/@me"
384
        )
385
386
    async def unreact(self, emoji: str):
387
        """
388
        Delete a reaction the current user has made for the message.
389
390
        :param emoji:
391
            Character for emoji. Does not need to be URL encoded.
392
        """
393
394
        await self._http.delete(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
395
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}/@me"
396
        )
397
398
    async def remove_user_reaction(self, emoji: str, user_id: Snowflake):
399
        """
400
        Deletes another user's reaction. Requires the ``MANAGE_MESSAGES``
401
        intent.
402
403
        :param emoji:
404
            Character for emoji. Does not need to be URL encoded.
405
406
        :param user_id:
407
            User ID
408
        """
409
410
        await self._http.delete(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
411
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}"
412
            f"/{user_id}"
413
        )
414
415
    async def get_reactions(
416
        self, emoji: str, after: Snowflake = 0, limit=25
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
417
    ) -> Generator[User, None, None]:
418
        # TODO: HTTP Client will need to refactored to allow parameters using aiohttp's system.
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
419
        """
420
        Returns the users that reacted with this emoji.
421
422
        :param after:
423
            Get users after this user ID. Returns all users if not provided.
424
425
        :param limit:
426
            Max number of users to return (1-100). 25 is not provided.
427
        """
428
429
        for user in await self._http.get(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
430
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}"
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
431
            f"?after={after}&limit={limit}"
432
        ):
433
            yield User.from_dict(user)
434
435
    async def remove_all_reactions(self):
436
        """
437
        Delete all reactions on a message. Requires the ``MANAGE_MESSAGES``
438
        intent.
439
        """
440
441
        await self._http.delete(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
442
            f"/channels/{self.channel_id}/messages/{self.id}/reactions"
443
        )
444
445
    async def remove_emoji(self, emoji):
446
        """
447
        Deletes all the reactions for a given emoji on a message. Requires the
448
        ``MANAGE_MESSAGES`` intent.
449
450
        :param emoji:
451
            Character for emoji. Does not need to be URL encoded.
452
        """
453
454
        await self._http.delete(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
455
            f"/channels/{self.channel_id}/messages/{self.id}/reactions/{emoji}"
456
        )
457
458
    # TODO: Implement file (https://discord.com/developers/docs/resources/channel#edit-message)
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
459
    async def edit(
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
460
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
461
        content: str = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
462
        embeds: List[Embed] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
463
        flags: int = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
464
        allowed_mentions: AllowedMentions = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
465
        attachments: List[Attachment] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
466
        components: List[MessageComponent] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
467
    ):
468
        """
469
        Edit a previously sent message. The fields content, embeds, and flags
470
        can be edited by the original message author. Other users can only
471
        edit flags and only if they have the ``MANAGE_MESSAGES`` permission in
472
        the corresponding channel. When specifying flags, ensure to include
473
        all previously set flags/bits in addition to ones that you are
474
        modifying.
475
476
        :param content:
477
            The message contents (up to 2000 characters)
478
479
        :param embeds:
480
            Embedded rich content (up to 6000 characters)
481
482
        :param flags:
483
            Edit the flags of a message (only ``SUPPRESS_EMBEDS`` can
484
            currently be set/unset)
485
486
        :param allowed_mentions:
487
            allowed mentions for the message
488
489
        :param attachments:
490
            attached files to keep
491
492
        :param components:
493
            the components to include with the message
494
        """
495
496
        data = {}
497
498
        def set_if_not_none(value: Any, name: str):
499
            if isinstance(value, APIObject):
500
                data[name] = value.to_dict()
501
            elif value is not None:
502
                data[name] = value
503
504
        set_if_not_none(content, "content")
505
        set_if_not_none(embeds, "embeds")
506
        set_if_not_none(flags, "flags")
507
        set_if_not_none(allowed_mentions, "allowed_mentions")
508
        set_if_not_none(attachments, "attachments")
509
        set_if_not_none(components, "components")
510
511
        await self._http.patch(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
512
            f"/channels/{self.channel_id}/messages/{self.id}",
513
            data=data
514
        )
515
516
    async def delete(self):
517
        """
518
        Delete a message. Requires the ``MANAGE_MESSAGES`` intent if the
519
        message was not sent by the current user.
520
        """
521
522
        await self._http.delete(
0 ignored issues
show
Bug introduced by
The Instance of UserMessage does not seem to have a member named _http.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
523
            f"/channels/{self.channel_id}/messages/{self.id}"
524
        )
525