Passed
Pull Request — main (#281)
by
unknown
01:48
created

pincer.objects.guild.webhook   A

Complexity

Total Complexity 0

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 0
eloc 32
dl 0
loc 93
rs 10
c 0
b 0
f 0
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 Enum, IntEnum
8
from typing import TYPE_CHECKING, overload
9
10
from ...utils.api_object import APIObject
11
from ...utils.conversion import construct_client_dict
12
from ...utils.types import MISSING
13
14
if TYPE_CHECKING:
15
    from typing import List, Optional
16
17
    from ..message.attachment import Attachment
18
    from ..message.component import MessageComponent
19
    from ..message.embed import Embed
20
    from ..message.user_message import UserMessage
21
    from ..message.user_message import AllowedMentions
22
    from ..user.user import User
23
    from ..guild.guild import Guild
24
    from ..guild.channel import Channel
25
    from ...utils.types import APINullable
26
    from ...utils.snowflake import Snowflake
27
    from ...client import Client
28
29
class WebhookCompatibility(Enum):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
30
    GitHub = "/github"
31
    Slack = "/slack"
32
    Default = ""
33
34
class WebhookType(IntEnum):
35
    """Represents the type of a webhook.
36
37
    Attributes
38
    ----------
39
    INCOMING:
40
        Incoming Webhooks can post messages to channels with a
41
        generated token.
42
    CHANNEL_FOLLOWER:
43
        Channel Follower Webhooks are internal webhooks used with
44
        Channel Following to post new messages into channels.
45
    APPLICATION:
46
        Application webhooks are webhooks used with Interactions
47
    """
48
    INCOMING = 1
49
    CHANNEL_FOLLOWER = 2
50
    APPLICATION = 3
51
52
53
@dataclass
54
class Webhook(APIObject):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (12/7)
Loading history...
55
    """Represents a Discord channel webhook.
56
57
    Attributes
58
    ----------
59
    id: :class:`~pincer.utils.snowflake.Snowflake`
60
        The id of the webhook
61
    type: :class:`~pincer.objects.guild.webhook.WebhookType`
62
        The type of the webhook
63
    channel_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
64
        The channel id this webhook is for, if any
65
    name: Optional[:class:`str`]
66
        The default name of the webhook
67
    avatar: Optional[:class:`str`]
68
        The default user avatar hash of the webhook
69
    application_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
70
        The bot/OAuth2 application that created this webhook
71
    user: APINullable[:class:`~pincer.objects.user.user.User`]
72
        The user this webhook was created by
73
        (not returned when getting a webhook with its token)
74
    token: APINullable[:class:`str`]
75
        The secure token of the webhook
76
        (returned for Incoming Webhooks)
77
    source_guild: APINullable[:class:`~pincer.objects.guild.guild.Guild`]
78
        The guild of the channel that this webhook is following
79
        (returned for Channel Follower Webhooks)
80
    source_channel: APINullable[:class:`~pincer.objects.guild.channel.Channel`]
81
        The channel that this webhook is following
82
        (returned for Channel Follower Webhooks)
83
    url: APINullable[:class:`str`]
84
        The url used for executing the webhook
85
        (returned by the webhooks OAuth2 flow)
86
    guild_id: APINullable[Optional[:class:`~pincer.objects.guild.guild.Guild`]]
87
        The guild id this webhook is for, if any
88
    """
89
    id: Snowflake
90
    type: WebhookType
91
92
    channel_id: Optional[Snowflake] = None
93
    name: Optional[str] = None
94
    avatar: Optional[str] = None
95
    application_id: Optional[Snowflake] = None
96
97
    user: APINullable[User] = MISSING
98
    token: APINullable[str] = MISSING
99
    source_guild: APINullable[Guild] = MISSING
100
    source_channel: APINullable[Channel] = MISSING
101
    url: APINullable[str] = MISSING
102
103
    guild_id: APINullable[Optional[Snowflake]] = MISSING
104
105
    async def edit(
106
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
107
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
108
        name: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
109
        avatar: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
110
        channel_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
111
        token: Optional[str] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
112
    ) -> None:
113
        """
114
        Modifies a webhook and returns it.
115
        Requires the ``MANAGE_WEBHOOKS`` permission.
116
117
        Parameters
118
        ----------
119
        name: Optional[:class:`str`]
120
            The new name of the webhook
121
        avatar: Optional[:class:`str`]
122
            The new avatar hash of the webhook
123
        channel_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
124
            The new channel id this webhook is for
125
        token: Optional[:class:`str`]
126
            The new token of the webhook
127
        """
128
        request_route = (
129
            f"webhooks/{self.id}"
130
            + (f"/{token}" if token else "")
131
        )
132
        request_data = {
133
            "name": name,
134
            "avatar": avatar,
135
            "channel_id": channel_id
136
        }
137
138
        if token:
139
            del request_data["channel_id"]
140
141
        data = await self._http.patch(
142
            request_route,
143
            data=request_data
144
        )
145
        return Webhook.from_dict(
146
            construct_client_dict(self._client, data)
147
        )
148
149
    async def delete(self, token: Optional[str] = None) -> None:
150
        """
151
        Deletes a webhook.
152
        Requires the ``MANAGE_WEBHOOKS`` permission.
153
154
        Parameters
155
        ----------
156
        token: Optional[:class:`str`]
157
            The token of the webhook
158
        """
159
        await self._http.delete(
160
            f"webhooks/{self.id}"
161
            + (f"/{token}" if token else "")
162
        )
163
164
    @overload
165
    async def execute(
166
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
167
        webhook_compatibility: WebhookCompatibility = WebhookCompatibility.Default, # noqa: E501
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
168
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
169
        thread_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
170
        wait: Optional[bool] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
171
        content: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
172
        username: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
173
        avatar_url: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
174
        tts: Optional[bool] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
175
        embeds: Optional[List[Embed]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
176
        allowed_mentions: Optional[AllowedMentions] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
177
        components: Optional[List[MessageComponent]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
178
        files: Optional[str] = None,  # TODO: Add support for files
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
179
        payload_json: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
180
        attachments: Optional[List[Attachment]] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
181
    ):
182
        """|coro|
183
        Executes a webhook.
184
185
        Note that when sending a message, you must provide a value
186
        for at least one of ``content``, ``embeds``, or ``file``.
187
188
        Parameters
189
        ----------
190
        webhook_compatibility: :class:`~pincer.objects.guild.webhook.WebhookCompatibility`
191
            The compatibility of the webhook
192
        thread_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
193
            ID of the thread to send message in
194
        wait: Optional[:class:`bool`]
195
            Waits for server confirmation of message send before
196
            response (defaults to ``true``, when ``false`` a message
197
            that is not saved does not return an error)
198
        content: Optional[:class:`str`]
199
            The message contents (up to 2000 characters)
200
        username: Optional[:class:`str`]
201
            Override the default username of the webhook
202
        avatar_url: Optional[:class:`str`]
203
            Override the default avatar of the webhook
204
        tts: Optional[:class:`bool`]
205
            True if this is a TTS message
206
        embeds: Optional[List[:class:`~pincer.objects.message.embed.Embed`]]
207
            Embedded ``rich`` content, up to 10 embeds
208
        allowed_mentions: Optional[:class:`~pincer.objects.message.user_message.AllowedMentions`]
209
            Allowed mentions for the message
210
        components: Optional[List[:class:`~pincer.objects.message.component.MessageComponent`]]
211
            The components to include in the message
212
        files: Optional[:class:`str`]
213
            The contents of the file being sent
214
        payload_json: Optional[:class:`str`]
215
            JSON encoded body of non-file params
216
        attachments: Optional[List[:class:`~pincer.objects.message.attachment.Attachment`]]
217
            Attachment objects with filename and description
218
        """
219
        ...
220
221
    async def execute(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
222
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
223
        webhook_compatibility: WebhookCompatibility = WebhookCompatibility.Default, # noqa: E501
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
224
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
225
        thread_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
226
        wait: Optional[bool] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
227
        **kwargs
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
228
    ):
229
        if embeds := kwargs.get("embeds"):
230
            assert len(embeds) <= 10, "You can only include up to 10 embeds"
231
        request_route = f"webhooks/{self.id}/{self.token}"
232
233
        # Adding the subdirectory
234
        request_route += webhook_compatibility.value
235
236
        # Adding query params
237
        request_route += f"?{wait=}" if wait else ""
238
        request_route += (
239
            ("&?"[wait is None]
240
            + f"{thread_id=}")
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (add 1 space).
Loading history...
241
            if thread_id else ""
242
        )
243
244
245
        if webhook_compatibility == WebhookCompatibility.Default:
246
            request_data = kwargs
247
        else:
248
            request_data = None
249
250
        await self._http.post(request_route, data=request_data)
251
252
    async def execute_github(
253
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
254
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
255
        thread_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
256
        wait: Optional[bool] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
257
    ):
258
        """|coro|
259
        Executes a GitHub compatible webhook.
260
261
        Parameters
262
        ----------
263
        thread_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
264
            ID of the thread to send message in
265
        wait: Optional[:class:`bool`]
266
            Waits for server confirmation of message send before
267
            response (defaults to ``true``, when ``false`` a message
268
            that is not saved does not return an error)
269
        """
270
        await self.execute(
271
            WebhookCompatibility.GitHub,
272
            thread_id=thread_id,
273
            wait=wait
274
        )
275
276
    async def execute_slack(
277
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
278
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
279
        thread_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
280
        wait: Optional[bool] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
281
    ):
282
        """|coro|
283
        Executes a Slack compatible webhook.
284
285
        Parameters
286
        ----------
287
        thread_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
288
            ID of the thread to send message in
289
        wait: Optional[:class:`bool`]
290
            Waits for server confirmation of message send before
291
            response (defaults to ``true``, when ``false`` a message
292
            that is not saved does not return an error)
293
        """
294
        await self.execute(
295
            WebhookCompatibility.Slack,
296
            thread_id=thread_id,
297
            wait=wait
298
        )
299
300
    async def get_message(
301
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
302
        message_id: Snowflake,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
303
        thread_id: Snowflake
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
304
    ) -> UserMessage:
305
        """|coro|
306
        Returns a previously-sent webhook message from the same token.
307
308
        Parameters
309
        ----------
310
        message_id: :class:`~pincer.utils.snowflake.Snowflake`
311
            The ID of the message to get
312
        thread_id: :class:`~pincer.utils.snowflake.Snowflake`
313
            The ID of the thread to get the message from
314
315
        Returns
316
        -------
317
        :class:`~pincer.objects.message.message.Message`
318
            The message
319
        """
320
        return UserMessage.from_dict(
321
            construct_client_dict(
322
                self._client,
323
                await self._http.get(
324
                    f"webhooks/{self.id}/{self.token}/messages/{message_id}"
325
                    + (f"?{thread_id=}" if thread_id else "")
326
                )
327
            )
328
        )
329
330
    async def delete_message(
331
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
332
        message_id: Snowflake,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
333
        thread_id: Snowflake
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
334
    ) -> None:
335
        """|coro|
336
        Deletes a message created by a webhook.
337
338
        Parameters
339
        ----------
340
        message_id: :class:`~pincer.utils.snowflake.Snowflake`
341
            The ID of the message to delete
342
        thread_id: :class:`~pincer.utils.snowflake.Snowflake`
343
            The ID of the thread to delete the message from
344
        """
345
        await self._http.delete(
346
            f"webhooks/{self.id}/{self.token}/messages/{message_id}"
347
            + (f"?{thread_id=}" if thread_id else "")
348
        )
349
350
    @overload
351
    async def edit_message(
352
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
353
        message_id: Snowflake,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
354
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
355
        thread_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
356
        content: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
357
        embeds: Optional[List[Embed]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
358
        allowed_mentions: Optional[AllowedMentions] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
359
        components: Optional[List[MessageComponent]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
360
        files: Optional[str] = None,  # TODO: Add support for files
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
361
        payload_json: Optional[str] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
362
        attachments: Optional[List[Attachment]] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
363
    ) -> UserMessage:
364
        """|coro|
365
        Edits a previously-sent webhook message from the same token.
366
367
        Parameters
368
        ----------
369
        message_id: :class:`~pincer.utils.snowflake.Snowflake`
370
            The ID of the message to edit
371
        thread_id: Optional[:class:`~pincer.utils.snowflake.Snowflake`]
372
            ID of the thread the message is in
373
        content: Optional[:class:`str`]
374
            The new content of the message (up to 2000 characters)
375
        embeds: Optional[List[:class:`~pincer.objects.message.embed.Embed`]]
376
            Embedded ``rich`` content, up to 10 embeds
377
        allowed_mentions: Optional[:class:`~pincer.objects.message.user_message.AllowedMentions`]
378
            Allowed mentions for the message
379
        components: Optional[List[:class:`~pincer.objects.message.component.MessageComponent`]]
380
            The components to include in the message
381
        files: Optional[:class:`str`]
382
            The contents of the file being sent/edited
383
        payload_json: Optional[:class:`str`]
384
            JSON encoded body of non-file params
385
            (multipart/form-data only)
386
        attachments: Optional[List[:class:`~pincer.objects.message.attachment.Attachment`]]
387
            Attached files to keep and
388
            possible descriptions for new files
389
        """
390
        ...
391
392
    async def edit_message(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
393
        self,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
394
        message_id: Snowflake,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
395
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
396
        thread_id: Optional[Snowflake] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
397
        **kwargs
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
398
    ) -> UserMessage:
399
        if embeds := kwargs.get("embeds"):
400
            assert len(embeds) <= 10, "You can only include up to 10 embeds"
401
        data = await self._http.patch(
402
            f"webhooks/{self.id}/{self.token}/messages/{message_id}"
403
            + (f"?{thread_id=}" if thread_id else ""),
404
            data=kwargs
405
        )
406
        return UserMessage.from_dict(
407
            construct_client_dict(self._client, data)
408
        )
409
410
    @classmethod
411
    async def from_id(
412
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
413
        client: Client,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
414
        id: Snowflake,
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
415
        token: Optional[str] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
416
    ) -> Webhook:
417
        """|coro|
418
        Gets a webhook by its ID.
419
420
        Parameters
421
        ----------
422
        client: `~pincer.client.Client`
423
            The client to use to make the request.
424
        id: `~pincer.utils.snowflake.Snowflake`
425
            The ID of the webhook to get.
426
        token: Optional[:class:`str`]
427
            The token of the webhook to get.
428
429
        Returns
430
        -------
431
        `~pincer.objects.guild.webhook.Webhook`
432
            The webhook with the given ID.
433
        """
434
        return cls.from_dict(
435
            construct_client_dict(
436
                client,
437
                await client.http.get(
438
                    f"webhooks/{id}"
439
                    + (f"/{token}" if token else "")
440
                )
441
            )
442
        )
0 ignored issues
show
Coding Style introduced by
Final newline missing
Loading history...