Skip to content

Commit fe80915

Browse files
authored
Merge branch 'Pycord-Development:master' into master
2 parents 2fa60be + 87d2331 commit fe80915

File tree

16 files changed

+230
-4
lines changed

16 files changed

+230
-4
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ possible (see our [Version Guarantees] for more info).
1010

1111
These changes are available on the `master` branch, but have not yet been released.
1212

13+
## [2.5.0] - 2024-03-02
14+
1315
### Added
1416

1517
- Added method to start bot via async context manager.
@@ -93,6 +95,12 @@ These changes are available on the `master` branch, but have not yet been releas
9395
([#2342](https://github.com/Pycord-Development/pycord/pull/2342))
9496
- Added `invitable` and `slowmode_delay` to `Thread` creation methods.
9597
([#2350](https://github.com/Pycord-Development/pycord/pull/2350))
98+
- Added support for voice channel statuses.
99+
([#2368](https://github.com/Pycord-Development/pycord/pull/2368))
100+
- Added `enforce_nonce` parameter for message sending.
101+
([#2370](https://github.com/Pycord-Development/pycord/pull/2370))
102+
- Added audit log support for voice channel status.
103+
([#2373](https://github.com/Pycord-Development/pycord/pull/2373))
96104

97105
### Changed
98106

@@ -772,7 +780,8 @@ These changes are available on the `master` branch, but have not yet been releas
772780
- Fix py3.10 UnionType checks issue.
773781
([#1240](https://github.com/Pycord-Development/pycord/pull/1240))
774782

775-
[unreleased]: https://github.com/Pycord-Development/pycord/compare/v2.4.1...HEAD
783+
[unreleased]: https://github.com/Pycord-Development/pycord/compare/v2.5.0...HEAD
784+
[2.5.0]: https://github.com/Pycord-Development/pycord/compare/v2.4.1...v2.5.0
776785
[2.4.1]: https://github.com/Pycord-Development/pycord/compare/v2.4.0...v2.4.1
777786
[2.4.0]: https://github.com/Pycord-Development/pycord/compare/v2.3.3...v2.4.0
778787
[2.3.3]: https://github.com/Pycord-Development/pycord/compare/v2.3.2...v2.3.3

discord/abc.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,7 @@ async def send(
13461346
stickers: Sequence[GuildSticker | StickerItem] = ...,
13471347
delete_after: float = ...,
13481348
nonce: str | int = ...,
1349+
enforce_nonce: bool = ...,
13491350
allowed_mentions: AllowedMentions = ...,
13501351
reference: Message | MessageReference | PartialMessage = ...,
13511352
mention_author: bool = ...,
@@ -1365,6 +1366,7 @@ async def send(
13651366
stickers: Sequence[GuildSticker | StickerItem] = ...,
13661367
delete_after: float = ...,
13671368
nonce: str | int = ...,
1369+
enforce_nonce: bool = ...,
13681370
allowed_mentions: AllowedMentions = ...,
13691371
reference: Message | MessageReference | PartialMessage = ...,
13701372
mention_author: bool = ...,
@@ -1384,6 +1386,7 @@ async def send(
13841386
stickers: Sequence[GuildSticker | StickerItem] = ...,
13851387
delete_after: float = ...,
13861388
nonce: str | int = ...,
1389+
enforce_nonce: bool = ...,
13871390
allowed_mentions: AllowedMentions = ...,
13881391
reference: Message | MessageReference | PartialMessage = ...,
13891392
mention_author: bool = ...,
@@ -1403,6 +1406,7 @@ async def send(
14031406
stickers: Sequence[GuildSticker | StickerItem] = ...,
14041407
delete_after: float = ...,
14051408
nonce: str | int = ...,
1409+
enforce_nonce: bool = ...,
14061410
allowed_mentions: AllowedMentions = ...,
14071411
reference: Message | MessageReference | PartialMessage = ...,
14081412
mention_author: bool = ...,
@@ -1423,6 +1427,7 @@ async def send(
14231427
stickers=None,
14241428
delete_after=None,
14251429
nonce=None,
1430+
enforce_nonce=None,
14261431
allowed_mentions=None,
14271432
reference=None,
14281433
mention_author=None,
@@ -1463,6 +1468,10 @@ async def send(
14631468
nonce: :class:`int`
14641469
The nonce to use for sending this message. If the message was successfully sent,
14651470
then the message will have a nonce with this value.
1471+
enforce_nonce: Optional[:class:`bool`]
1472+
Whether :attr:`nonce` is enforced to be validated.
1473+
1474+
.. versionadded:: 2.5
14661475
delete_after: :class:`float`
14671476
If provided, the number of seconds to wait in the background
14681477
before deleting the message we just sent. If the deletion fails,
@@ -1602,6 +1611,7 @@ async def send(
16021611
embed=embed,
16031612
embeds=embeds,
16041613
nonce=nonce,
1614+
enforce_nonce=enforce_nonce,
16051615
message_reference=reference,
16061616
stickers=stickers,
16071617
components=components,
@@ -1627,6 +1637,7 @@ async def send(
16271637
embed=embed,
16281638
embeds=embeds,
16291639
nonce=nonce,
1640+
enforce_nonce=enforce_nonce,
16301641
allowed_mentions=allowed_mentions,
16311642
message_reference=reference,
16321643
stickers=stickers,
@@ -1644,6 +1655,7 @@ async def send(
16441655
embed=embed,
16451656
embeds=embeds,
16461657
nonce=nonce,
1658+
enforce_nonce=enforce_nonce,
16471659
allowed_mentions=allowed_mentions,
16481660
message_reference=reference,
16491661
stickers=stickers,

discord/channel.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,20 +1519,37 @@ class VoiceChannel(discord.abc.Messageable, VocalGuildChannel):
15191519
Bots and users with :attr:`~Permissions.manage_channels` or
15201520
:attr:`~Permissions.manage_messages` bypass slowmode.
15211521
1522+
.. versionadded:: 2.5
1523+
status: Optional[:class:`str`]
1524+
The channel's status, if set.
1525+
15221526
.. versionadded:: 2.5
15231527
flags: :class:`ChannelFlags`
15241528
Extra features of the channel.
15251529
15261530
.. versionadded:: 2.0
15271531
"""
15281532

1533+
def __init__(
1534+
self,
1535+
*,
1536+
state: ConnectionState,
1537+
guild: Guild,
1538+
data: VoiceChannelPayload,
1539+
):
1540+
self.status: str | None = None
1541+
super().__init__(state=state, guild=guild, data=data)
1542+
15291543
def _update(self, guild: Guild, data: VoiceChannelPayload):
15301544
super()._update(guild, data)
1545+
if data.get("status"):
1546+
self.status = data.get("status")
15311547

15321548
def __repr__(self) -> str:
15331549
attrs = [
15341550
("id", self.id),
15351551
("name", self.name),
1552+
("status", self.status),
15361553
("rtc_region", self.rtc_region),
15371554
("position", self.position),
15381555
("bitrate", self.bitrate),
@@ -1955,6 +1972,31 @@ async def create_activity_invite(
19551972
**kwargs,
19561973
)
19571974

1975+
async def set_status(
1976+
self, status: str | None, *, reason: str | None = None
1977+
) -> None:
1978+
"""|coro|
1979+
1980+
Sets the status of the voice channel.
1981+
1982+
You must have the :attr:`~Permissions.set_voice_channel_status` permission to use this.
1983+
1984+
Parameters
1985+
----------
1986+
status: Union[:class:`str`, None]
1987+
The new status.
1988+
reason: Optional[:class:`str`]
1989+
The reason for setting the status. Shows up on the audit log.
1990+
1991+
Raises
1992+
------
1993+
Forbidden
1994+
You do not have proper permissions to set the status.
1995+
HTTPException
1996+
Setting the status failed.
1997+
"""
1998+
await self._state.http.set_voice_channel_status(self.id, status, reason=reason)
1999+
19582000

19592001
class StageChannel(discord.abc.Messageable, VocalGuildChannel):
19602002
"""Represents a Discord guild stage channel.

discord/enums.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ class AuditLogAction(Enum):
439439
onboarding_update = 167
440440
server_guide_create = 190
441441
server_guide_update = 191
442+
voice_channel_status_update = 192
443+
voice_channel_status_delete = 193
442444

443445
@property
444446
def category(self) -> AuditLogActionCategory | None:
@@ -506,6 +508,8 @@ def category(self) -> AuditLogActionCategory | None:
506508
AuditLogAction.onboarding_update: AuditLogActionCategory.update,
507509
AuditLogAction.server_guide_create: AuditLogActionCategory.create,
508510
AuditLogAction.server_guide_update: AuditLogActionCategory.update,
511+
AuditLogAction.voice_channel_status_update: AuditLogActionCategory.update,
512+
AuditLogAction.voice_channel_status_delete: AuditLogActionCategory.delete,
509513
}
510514
return lookup[self]
511515

@@ -552,6 +556,8 @@ def target_type(self) -> str | None:
552556
return "onboarding"
553557
elif v < 192:
554558
return "server_guide"
559+
elif v < 194:
560+
return "voice_channel_status"
555561

556562

557563
class UserFlags(Enum):

discord/http.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ def send_message(
465465
embed: embed.Embed | None = None,
466466
embeds: list[embed.Embed] | None = None,
467467
nonce: str | None = None,
468+
enforce_nonce: bool | None = None,
468469
allowed_mentions: message.AllowedMentions | None = None,
469470
message_reference: message.MessageReference | None = None,
470471
stickers: list[sticker.StickerItem] | None = None,
@@ -489,6 +490,9 @@ def send_message(
489490
if nonce:
490491
payload["nonce"] = nonce
491492

493+
if enforce_nonce:
494+
payload["enforce_nonce"] = enforce_nonce
495+
492496
if allowed_mentions:
493497
payload["allowed_mentions"] = allowed_mentions
494498

@@ -521,6 +525,7 @@ def send_multipart_helper(
521525
embed: embed.Embed | None = None,
522526
embeds: Iterable[embed.Embed | None] | None = None,
523527
nonce: str | None = None,
528+
enforce_nonce: bool | None = None,
524529
allowed_mentions: message.AllowedMentions | None = None,
525530
message_reference: message.MessageReference | None = None,
526531
stickers: list[sticker.StickerItem] | None = None,
@@ -538,6 +543,8 @@ def send_multipart_helper(
538543
payload["embeds"] = embeds
539544
if nonce:
540545
payload["nonce"] = nonce
546+
if enforce_nonce:
547+
payload["enforce_nonce"] = enforce_nonce
541548
if allowed_mentions:
542549
payload["allowed_mentions"] = allowed_mentions
543550
if message_reference:
@@ -581,6 +588,7 @@ def send_files(
581588
embed: embed.Embed | None = None,
582589
embeds: list[embed.Embed] | None = None,
583590
nonce: str | None = None,
591+
enforce_nonce: bool | None = None,
584592
allowed_mentions: message.AllowedMentions | None = None,
585593
message_reference: message.MessageReference | None = None,
586594
stickers: list[sticker.StickerItem] | None = None,
@@ -596,6 +604,7 @@ def send_files(
596604
embed=embed,
597605
embeds=embeds,
598606
nonce=nonce,
607+
enforce_nonce=enforce_nonce,
599608
allowed_mentions=allowed_mentions,
600609
message_reference=message_reference,
601610
stickers=stickers,
@@ -2185,6 +2194,13 @@ def move_member(
21852194
guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason
21862195
)
21872196

2197+
def set_voice_channel_status(
2198+
self, channel_id: Snowflake, status: str | None, *, reason: str | None = None
2199+
) -> Response[None]:
2200+
payload = {"status": status}
2201+
r = Route("PUT", "/channels/{channel_id}/voice-status", channel_id=channel_id)
2202+
return self.request(r, json=payload, reason=reason)
2203+
21882204
# Stage instance management
21892205

21902206
def get_stage_instance(

discord/permissions.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def all(cls: type[P]) -> P:
180180
"""A factory method that creates a :class:`Permissions` with all
181181
permissions set to ``True``.
182182
"""
183-
return cls(0b11111111111111111111111111111111111111111)
183+
return cls(0b1111111111111111111111111111111111111111111111111)
184184

185185
@classmethod
186186
def all_channel(cls: type[P]) -> P:
@@ -250,7 +250,7 @@ def voice(cls: type[P]) -> P:
250250
"""A factory method that creates a :class:`Permissions` with all
251251
"Voice" permissions from the official Discord UI set to ``True``.
252252
"""
253-
return cls(0b00000011111100000000001100000000)
253+
return cls(0b1000000001000000000000011111100000000001100000000)
254254

255255
@classmethod
256256
def stage(cls: type[P]) -> P:
@@ -618,6 +618,14 @@ def send_voice_messages(self) -> int:
618618
"""
619619
return 1 << 46
620620

621+
@flag_value
622+
def set_voice_channel_status(self) -> int:
623+
""":class:`bool`: Returns ``True`` if a member can set voice channel status.
624+
625+
.. versionadded:: 2.5
626+
"""
627+
return 1 << 48
628+
621629

622630
PO = TypeVar("PO", bound="PermissionOverwrite")
623631

@@ -736,6 +744,7 @@ class PermissionOverwrite:
736744
start_embedded_activities: bool | None
737745
moderate_members: bool | None
738746
send_voice_messages: bool | None
747+
set_voice_channel_status: bool | None
739748

740749
def __init__(self, **kwargs: bool | None):
741750
self._values: dict[str, bool | None] = {}

discord/raw_models.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
ThreadMembersUpdateEvent,
5757
ThreadUpdateEvent,
5858
TypingEvent,
59+
VoiceChannelStatusUpdateEvent,
5960
)
6061

6162

@@ -75,6 +76,7 @@
7576
"AutoModActionExecutionEvent",
7677
"RawThreadMembersUpdateEvent",
7778
"RawAuditLogEntryEvent",
79+
"RawVoiceChannelStatusUpdateEvent",
7880
)
7981

8082

@@ -441,6 +443,36 @@ def __init__(self, data: ThreadDeleteEvent) -> None:
441443
self.data: ThreadDeleteEvent = data
442444

443445

446+
class RawVoiceChannelStatusUpdateEvent(_RawReprMixin):
447+
"""Represents the payload for an :func:`on_raw_voice_channel_status_update` event.
448+
449+
.. versionadded:: 2.5
450+
451+
Attributes
452+
----------
453+
id: :class:`int`
454+
The channel ID where the voice channel status update originated from.
455+
guild_id: :class:`int`
456+
The guild ID where the voice channel status update originated from.
457+
status: Optional[:class:`str`]
458+
The new new voice channel status.
459+
data: :class:`dict`
460+
The raw data sent by the `gateway <https://discord.com/developers/docs/topics/gateway-events#voice-channel-status-update>`_.
461+
"""
462+
463+
__slots__ = ("id", "guild_id", "status", "data")
464+
465+
def __init__(self, data: VoiceChannelStatusUpdateEvent) -> None:
466+
self.id: int = int(data["id"])
467+
self.guild_id: int = int(data["guild_id"])
468+
469+
try:
470+
self.status: str | None = data["status"]
471+
except KeyError:
472+
self.status: str | None = None
473+
self.data: VoiceChannelStatusUpdateEvent = data
474+
475+
444476
class RawTypingEvent(_RawReprMixin):
445477
"""Represents the payload for a :func:`on_raw_typing` event.
446478

discord/state.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,30 @@ def parse_voice_server_update(self, data) -> None:
17851785
)
17861786
)
17871787

1788+
def parse_voice_channel_status_update(self, data) -> None:
1789+
raw = RawVoiceChannelStatusUpdateEvent(data)
1790+
self.dispatch("raw_voice_channel_status_update", raw)
1791+
guild = self._get_guild(int(data["guild_id"]))
1792+
channel_id = int(data["id"])
1793+
if guild is not None:
1794+
channel = guild.get_channel(channel_id)
1795+
if channel is not None:
1796+
old_status = channel.status
1797+
channel.status = data.get("status", None)
1798+
self.dispatch(
1799+
"voice_channel_status_update", channel, old_status, channel.status
1800+
)
1801+
else:
1802+
_log.debug(
1803+
"VOICE_CHANNEL_STATUS_UPDATE referencing an unknown channel ID: %s. Discarding.",
1804+
channel_id,
1805+
)
1806+
else:
1807+
_log.debug(
1808+
"VOICE_CHANNEL_STATUS_UPDATE referencing unknown guild ID: %s. Discarding.",
1809+
data["guild_id"],
1810+
)
1811+
17881812
def parse_typing_start(self, data) -> None:
17891813
raw = RawTypingEvent(data)
17901814

0 commit comments

Comments
 (0)