Passed
Pull Request — main (#281)
by
unknown
02:10
created

pincer.objects.guild.webhook   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 440
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 23
eloc 181
dl 0
loc 440
rs 10
c 0
b 0
f 0

9 Methods

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