diff --git a/discord/abc.py b/discord/abc.py index c59a6276be..11d2a2be82 100644 --- a/discord/abc.py +++ b/discord/abc.py @@ -501,6 +501,13 @@ async def _edit(self, options: dict[str, Any], reason: str | None) -> ChannelPay default_reaction_emoji._to_forum_reaction_payload() if default_reaction_emoji else None ) + try: + icon = options["icon"] + except KeyError: + pass + else: + options["icon"] = icon and utils._bytes_to_base64_data(icon) + if options: return await self._state.http.edit_channel(self.id, reason=reason, **options) diff --git a/discord/channel.py b/discord/channel.py index cff03c1614..cd20a8a703 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -3215,6 +3215,48 @@ async def leave(self) -> None: await self._state.http.leave_group(self.id) + @overload + async def edit( + self, + *, + name: str = ..., + icon: bytes | None = ..., + ) -> GroupChannel: ... + + @overload + async def edit(self) -> GroupChannel: ... + + async def edit(self, *, reason=None, **options): + """|coro| + + Edits this group DM channel. + + .. versionadded:: 3.0 + + Parameters + ---------- + name: :class:`str` + The new channel name. + icon: :class:`bytes` + A :term:`py:bytes-like object` representing the icon. Only PNG/JPEG is supported. + Could be ``None`` to denote removal of the icon. + + Returns + ------- + :class:`.GroupChannel` + The newly edited text channel. + + Raises + ------ + Forbidden + You do not have permissions to edit the channel. + HTTPException + Editing the channel failed. + """ + payload = await self._edit(options, reason=reason) + if payload is not None: + return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore + class PartialMessageable(discord.abc.Messageable, Hashable): """Represents a partial messageable to aid with working messageable channels when diff --git a/discord/client.py b/discord/client.py index 4180182ace..1516322931 100644 --- a/discord/client.py +++ b/discord/client.py @@ -1587,55 +1587,6 @@ async def fetch_guild(self, guild_id: int, /, *, with_counts=True) -> Guild: data = await self.http.get_guild(guild_id, with_counts=with_counts) return Guild(data=data, state=self._connection) - async def create_guild( - self, - *, - name: str, - icon: bytes | utils.Undefined = MISSING, - code: str | utils.Undefined = MISSING, - ) -> Guild: - """|coro| - - Creates a :class:`.Guild`. - - Bot accounts in more than 10 guilds are not allowed to create guilds. - - Parameters - ---------- - name: :class:`str` - The name of the guild. - icon: Optional[:class:`bytes`] - The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit` - for more details on what is expected. - code: :class:`str` - The code for a template to create the guild with. - - .. versionadded:: 1.4 - - Returns - ------- - :class:`.Guild` - The guild created. This is not the same guild that is - added to cache. - - Raises - ------ - :exc:`HTTPException` - Guild creation failed. - :exc:`InvalidArgument` - Invalid icon image format given. Must be PNG or JPG. - """ - if icon is not MISSING: - icon_base64 = utils._bytes_to_base64_data(icon) - else: - icon_base64 = None - - if code: - data = await self.http.create_from_template(code, name, icon_base64) - else: - data = await self.http.create_guild(name, icon_base64) - return Guild(data=data, state=self._connection) - async def fetch_stage_instance(self, channel_id: int, /) -> StageInstance: """|coro| diff --git a/discord/gateway.py b/discord/gateway.py index 05f1277f7d..d5c83e50a1 100644 --- a/discord/gateway.py +++ b/discord/gateway.py @@ -42,6 +42,7 @@ from .activity import BaseActivity from .enums import SpeakingState from .errors import ConnectionClosed, InvalidArgument +from .http import API_VERSION _log = logging.getLogger(__name__) @@ -327,7 +328,9 @@ async def from_client( This is for internal use only. """ - gateway = gateway or await client.http.get_gateway() + if not gateway: + data = await client.http.get_gateway() + gateway = f"{data['url']}?encoding=json&v={API_VERSION}" socket = await client.http.ws_connect(gateway) ws = cls(socket, loop=client.loop) diff --git a/discord/guild.py b/discord/guild.py index 3b8ffcad37..07dd62bba3 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -1538,21 +1538,6 @@ async def leave(self) -> None: """ await self._state.http.leave_guild(self.id) - async def delete(self) -> None: - """|coro| - - Deletes the guild. You must be the guild owner to delete the - guild. - - Raises - ------ - HTTPException - Deleting the guild failed. - Forbidden - You do not have permissions to delete the guild. - """ - await self._state.http.delete_guild(self.id) - async def set_mfa_required(self, required: bool, *, reason: str = None) -> None: """|coro| @@ -2348,32 +2333,6 @@ async def create_template(self, *, name: str, description: str | utils.Undefined return Template(state=self._state, data=data) - async def create_integration(self, *, type: str, id: int) -> None: - """|coro| - - Attaches an integration to the guild. - - You must have the :attr:`~Permissions.manage_guild` permission to - do this. - - .. versionadded:: 1.4 - - Parameters - ---------- - type: :class:`str` - The integration type (e.g. Twitch). - id: :class:`int` - The integration ID. - - Raises - ------ - Forbidden - You do not have permission to create the integration. - HTTPException - The account could not be found. - """ - await self._state.http.create_integration(self.id, type, id) - async def integrations(self) -> list[Integration]: """|coro| diff --git a/discord/http.py b/discord/http.py index 4600c045c6..68e71471b7 100644 --- a/discord/http.py +++ b/discord/http.py @@ -64,6 +64,7 @@ components, embed, emoji, + gateway, guild, integration, interactions, @@ -420,13 +421,6 @@ def logout(self) -> Response[None]: # Group functionality - def start_group(self, user_id: Snowflake, recipients: list[int]) -> Response[channel.GroupDMChannel]: - payload = { - "recipients": recipients, - } - - return self.request(Route("POST", "/users/{user_id}/channels", user_id=user_id), json=payload) - def leave_group(self, channel_id) -> Response[None]: return self.request(Route("DELETE", "/channels/{channel_id}", channel_id=channel_id)) @@ -952,19 +946,6 @@ def guild_voice_state( def edit_profile(self, payload: dict[str, Any]) -> Response[user.User]: return self.request(Route("PATCH", "/users/@me"), json=payload) - def change_my_nickname( - self, - guild_id: Snowflake, - nickname: str, - *, - reason: str | None = None, - ) -> Response[member.Nickname]: - r = Route("PATCH", "/guilds/{guild_id}/members/@me", guild_id=guild_id) - payload = { - "nick": nickname, - } - return self.request(r, json=payload, reason=reason) - def change_nickname( self, guild_id: Snowflake, @@ -997,6 +978,16 @@ def edit_voice_state(self, guild_id: Snowflake, user_id: Snowflake, payload: dic ) return self.request(r, json=payload) + def edit_current_member( + self, + guild_id: Snowflake, + *, + reason: str | None = None, + **fields: Any, + ) -> Response[member.Member]: + r = Route("PATCH", "/guilds/{guild_id}/members/@me", guild_id=guild_id) + return self.request(r, json=fields, reason=reason) + def edit_member( self, guild_id: Snowflake, @@ -1025,6 +1016,7 @@ def edit_channel( r = Route("PATCH", "/channels/{channel_id}", channel_id=channel_id) valid_keys = ( "name", + "icon", "parent_id", "topic", "bitrate", @@ -1405,18 +1397,6 @@ def get_guild(self, guild_id: Snowflake, *, with_counts=True) -> Response[guild. params = {"with_counts": int(with_counts)} return self.request(Route("GET", "/guilds/{guild_id}", guild_id=guild_id), params=params) - def delete_guild(self, guild_id: Snowflake) -> Response[None]: - return self.request(Route("DELETE", "/guilds/{guild_id}", guild_id=guild_id)) - - def create_guild(self, name: str, icon: str | None) -> Response[guild.Guild]: - payload = { - "name": name, - } - if icon: - payload["icon"] = icon - - return self.request(Route("POST", "/guilds"), json=payload) - def edit_guild(self, guild_id: Snowflake, *, reason: str | None = None, **fields: Any) -> Response[guild.Guild]: valid_keys = ( "name", @@ -1505,15 +1485,6 @@ def delete_template(self, guild_id: Snowflake, code: str) -> Response[None]: ) ) - def create_from_template(self, code: str, name: str, icon: str | None) -> Response[guild.Guild]: - payload = { - "name": name, - } - if icon: - payload["icon"] = icon - - return self.request(Route("POST", "/guilds/templates/{code}", code=code), json=payload) - def get_bans( self, guild_id: Snowflake, @@ -1843,15 +1814,6 @@ def get_all_integrations(self, guild_id: Snowflake) -> Response[list[integration return self.request(r) - def create_integration(self, guild_id: Snowflake, type: integration.IntegrationType, id: int) -> Response[None]: - payload = { - "type": type, - "id": id, - } - - r = Route("POST", "/guilds/{guild_id}/integrations", guild_id=guild_id) - return self.request(r, json=payload) - def edit_integration(self, guild_id: Snowflake, integration_id: Snowflake, **payload: Any) -> Response[None]: r = Route( "PATCH", @@ -2027,16 +1989,6 @@ def delete_role(self, guild_id: Snowflake, role_id: Snowflake, *, reason: str | ) return self.request(r, reason=reason) - def replace_roles( - self, - user_id: Snowflake, - guild_id: Snowflake, - role_ids: list[int], - *, - reason: str | None = None, - ) -> Response[member.MemberWithUser]: - return self.edit_member(guild_id=guild_id, user_id=user_id, roles=role_ids, reason=reason) - def create_role(self, guild_id: Snowflake, *, reason: str | None = None, **fields: Any) -> Response[role.Role]: r = Route("POST", "/guilds/{guild_id}/roles", guild_id=guild_id) return self.request(r, json=fields, reason=reason) @@ -2141,16 +2093,6 @@ def edit_welcome_screen( # Voice management - def move_member( - self, - user_id: Snowflake, - guild_id: Snowflake, - channel_id: Snowflake, - *, - reason: str | None = None, - ) -> Response[member.MemberWithUser]: - return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason) - def set_voice_channel_status( self, channel_id: Snowflake, status: str | None, *, reason: str | None = None ) -> Response[None]: @@ -2777,20 +2719,6 @@ def edit_application_command_permissions( ) return self.request(r, json=payload) - def bulk_edit_guild_application_command_permissions( - self, - application_id: Snowflake, - guild_id: Snowflake, - payload: list[interactions.PartialGuildApplicationCommandPermissions], - ) -> Response[None]: - r = Route( - "PUT", - "/applications/{application_id}/guilds/{guild_id}/commands/permissions", - application_id=application_id, - guild_id=guild_id, - ) - return self.request(r, json=payload) - # Application Role Connections def get_application_role_connection_metadata_records( @@ -3009,28 +2937,19 @@ def get_application(self, application_id: Snowflake, /) -> Response[appinfo.Part ) ) - async def get_gateway(self, *, encoding: str = "json", zlib: bool = True) -> str: + async def get_gateway(self) -> Response[gateway.Gateway]: try: data = await self.request(Route("GET", "/gateway")) except HTTPException as exc: raise GatewayNotFound() from exc - if zlib: - value = "{0}?encoding={1}&v={2}&compress=zlib-stream" - else: - value = "{0}?encoding={1}&v={2}" - return value.format(data["url"], encoding, API_VERSION) + return data - async def get_bot_gateway(self, *, encoding: str = "json", zlib: bool = True) -> tuple[int, str]: + async def get_gateway_bot(self) -> Response[gateway.GatewayBot]: try: data = await self.request(Route("GET", "/gateway/bot")) except HTTPException as exc: raise GatewayNotFound() from exc - - if zlib: - value = "{0}?encoding={1}&v={2}&compress=zlib-stream" - else: - value = "{0}?encoding={1}&v={2}" - return data["shards"], value.format(data["url"], encoding, API_VERSION) + return data def get_user(self, user_id: Snowflake) -> Response[user.User]: return self.request(Route("GET", "/users/{user_id}", user_id=user_id)) diff --git a/discord/member.py b/discord/member.py index 0775f2670f..d7853a4d79 100644 --- a/discord/member.py +++ b/discord/member.py @@ -843,7 +843,7 @@ async def edit( if nick is not MISSING: nick = nick or "" if me: - await http.change_my_nickname(guild_id, nick, reason=reason) + await http.edit_current_member(guild_id, reason=reason, nick=nick) else: payload["nick"] = nick diff --git a/discord/shard.py b/discord/shard.py index 2e59baa198..f1b99af79a 100644 --- a/discord/shard.py +++ b/discord/shard.py @@ -42,6 +42,7 @@ PrivilegedIntentsRequired, ) from .gateway import * +from .http import API_VERSION from .state import AutoShardedConnectionState if TYPE_CHECKING: @@ -423,9 +424,11 @@ async def launch_shard(self, gateway: str, shard_id: int, *, initial: bool = Fal async def launch_shards(self) -> None: if self.shard_count is None: - self.shard_count, gateway = await self.http.get_bot_gateway() + data = await self.http.get_gateway_bot() + self.shard_count = data["shards"] else: - gateway = await self.http.get_gateway() + data = await self.http.get_gateway() + gateway = f"{data['url']}?encoding=json&v={API_VERSION}" self._connection.shard_count = self.shard_count diff --git a/discord/template.py b/discord/template.py index 4eaa71e9b7..0dd786e902 100644 --- a/discord/template.py +++ b/discord/template.py @@ -166,40 +166,6 @@ def __repr__(self) -> str: f" creator={self.creator!r} source_guild={self.source_guild!r} is_dirty={self.is_dirty}>" ) - async def create_guild(self, name: str, icon: Any = None) -> Guild: - """|coro| - - Creates a :class:`.Guild` using the template. - - Bot accounts in more than 10 guilds are not allowed to create guilds. - - Parameters - ---------- - name: :class:`str` - The name of the guild. - icon: :class:`bytes` - The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit` - for more details on what is expected. - - Returns - ------- - :class:`.Guild` - The guild created. This is not the same guild that is - added to cache. - - Raises - ------ - HTTPException - Guild creation failed. - InvalidArgument - Invalid icon image format given. Must be PNG or JPG. - """ - if icon is not None: - icon = _bytes_to_base64_data(icon) - - data = await self._state.http.create_from_template(self.code, name, icon) - return Guild(data=data, state=self._state) - async def sync(self) -> Template: """|coro|