Browse Source

Implement pomelo migrating

pull/10109/head
dolfies 2 years ago
parent
commit
26280fd24d
  1. 63
      discord/client.py
  2. 27
      discord/http.py
  3. 4
      discord/state.py
  4. 1
      discord/types/gateway.py
  5. 8
      discord/types/user.py
  6. 46
      discord/user.py

63
discord/client.py

@ -571,6 +571,14 @@ class Client:
exp.name = name exp.name = name
return exp return exp
@property
def disclose(self) -> Sequence[str]:
"""Sequence[:class:`str`]: Upcoming changes to the user's account.
.. versionadded:: 2.1
"""
return utils.SequenceProxy(self._connection.disclose)
def is_ready(self) -> bool: def is_ready(self) -> bool:
""":class:`bool`: Specifies if the client's internal cache is ready for use.""" """:class:`bool`: Specifies if the client's internal cache is ready for use."""
return self._ready is not MISSING and self._ready.is_set() return self._ready is not MISSING and self._ready.is_set()
@ -5054,3 +5062,58 @@ class Client:
experiments.append(GuildExperiment(state=state, data=exp)) experiments.append(GuildExperiment(state=state, data=exp))
return experiments return experiments
async def pomelo_suggestion(self) -> str:
"""|coro|
Gets the suggested pomelo username for your account.
This username can be used with :meth:`edit` to migrate your account
to Discord's `new unique username system <https://discord.com/blog/usernames>`_
.. note::
This method requires you to be in the pomelo rollout.
.. versionadded:: 2.1
Raises
-------
HTTPException
You are not in the pomelo rollout.
Returns
--------
:class:`str`
The suggested username.
"""
data = await self.http.pomelo_suggestion()
return data['username']
async def check_pomelo_username(self, username: str) -> bool:
"""|coro|
Checks if a pomelo username is taken.
.. note::
This method requires you to be in the pomelo rollout.
.. versionadded:: 2.1
Parameters
-----------
username: :class:`str`
The username to check.
Raises
-------
HTTPException
You are not in the pomelo rollout.
Returns
--------
:class:`bool`
Whether the username is taken.
"""
data = await self.http.pomelo_attempt(username)
return data['taken']

27
discord/http.py

@ -1032,10 +1032,6 @@ class HTTPClient:
self.token = token self.token = token
self.ack_token = None self.ack_token = None
def get_me(self, with_analytics_token: bool = True) -> Response[user.User]:
params = {'with_analytics_token': str(with_analytics_token).lower()}
return self.request(Route('GET', '/users/@me'), params=params)
async def static_login(self, token: str) -> user.User: async def static_login(self, token: str) -> user.User:
old_token, self.token = self.token, token old_token, self.token = self.token, token
@ -1049,6 +1045,26 @@ class HTTPClient:
return data return data
# Self user
def get_me(self, with_analytics_token: bool = True) -> Response[user.User]:
params = {'with_analytics_token': str(with_analytics_token).lower()}
return self.request(Route('GET', '/users/@me'), params=params)
def edit_profile(self, payload: Dict[str, Any]) -> Response[user.User]:
return self.request(Route('PATCH', '/users/@me'), json=payload)
def pomelo(self, username: str) -> Response[user.User]:
payload = {'username': username}
return self.request(Route('POST', '/users/@me/pomelo'), json=payload)
def pomelo_suggestion(self) -> Response[user.PomeloSuggestion]:
return self.request(Route('GET', '/users/@me/pomelo-suggestions'))
def pomelo_attempt(self, username: str) -> Response[user.PomeloAttempt]:
payload = {'username': username}
return self.request(Route('POST', '/users/@me/pomelo-attempt'), json=payload)
# PM functionality # PM functionality
def start_group(self, recipients: SnowflakeList) -> Response[channel.GroupDMChannel]: def start_group(self, recipients: SnowflakeList) -> Response[channel.GroupDMChannel]:
@ -1429,9 +1445,6 @@ class HTTPClient:
return self.request(r, json=payload, reason=reason) return self.request(r, json=payload, reason=reason)
def edit_profile(self, payload: Dict[str, Any]) -> Response[user.User]:
return self.request(Route('PATCH', '/users/@me'), json=payload)
def edit_my_voice_state(self, guild_id: Snowflake, payload: Dict[str, Any]) -> Response[None]: # TODO: remove payload def edit_my_voice_state(self, guild_id: Snowflake, payload: Dict[str, Any]) -> Response[None]: # TODO: remove payload
r = Route('PATCH', '/guilds/{guild_id}/voice-states/@me', guild_id=guild_id) r = Route('PATCH', '/guilds/{guild_id}/voice-states/@me', guild_id=guild_id)
return self.request(r, json=payload) return self.request(r, json=payload)

4
discord/state.py

@ -614,6 +614,7 @@ class ConnectionState:
self.auth_session_id: Optional[str] = None self.auth_session_id: Optional[str] = None
self.required_action: Optional[RequiredActionType] = None self.required_action: Optional[RequiredActionType] = None
self.friend_suggestion_count: int = 0 self.friend_suggestion_count: int = 0
self.disclose: List[str] = []
self._emojis: Dict[int, Emoji] = {} self._emojis: Dict[int, Emoji] = {}
self._stickers: Dict[int, GuildSticker] = {} self._stickers: Dict[int, GuildSticker] = {}
self._guilds: Dict[int, Guild] = {} self._guilds: Dict[int, Guild] = {}
@ -1080,6 +1081,9 @@ class ConnectionState:
pm['recipients'] = [temp_users[int(u_id)] for u_id in pm.pop('recipient_ids')] pm['recipients'] = [temp_users[int(u_id)] for u_id in pm.pop('recipient_ids')]
self._add_private_channel(factory(me=user, data=pm, state=self)) # type: ignore self._add_private_channel(factory(me=user, data=pm, state=self)) # type: ignore
# Disloses
self.dislose = data.get('dislose', [])
# We're done # We're done
del self._ready_data del self._ready_data
self.call_handlers('connect') self.call_handlers('connect')

1
discord/types/gateway.py

@ -135,6 +135,7 @@ class ReadySupplementalEvent(TypedDict):
merged_members: List[List[MemberWithUser]] merged_members: List[List[MemberWithUser]]
merged_presences: MergedPresences merged_presences: MergedPresences
lazy_private_channels: List[Union[DMChannel, GroupDMChannel]] lazy_private_channels: List[Union[DMChannel, GroupDMChannel]]
disclose: List[str]
class VersionedReadState(TypedDict): class VersionedReadState(TypedDict):

8
discord/types/user.py

@ -90,6 +90,14 @@ class User(APIUser, total=False):
nsfw_allowed: Optional[bool] nsfw_allowed: Optional[bool]
class PomeloAttempt(TypedDict):
taken: bool
class PomeloSuggestion(TypedDict):
username: str
class PartialConnection(TypedDict): class PartialConnection(TypedDict):
id: str id: str
type: ConnectionType type: ConnectionType

46
discord/user.py

@ -523,6 +523,13 @@ class BaseUser(_UserTag):
return any(user.id == self.id for user in message.mentions) return any(user.id == self.id for user in message.mentions)
def is_pomelo(self) -> bool:
""":class:`bool`: Checks if the user has migrated to Discord's `new unique username system <https://discord.com/blog/usernames>`_
.. versionadded:: 2.1
"""
return self.discriminator == '0'
@property @property
def relationship(self) -> Optional[Relationship]: def relationship(self) -> Optional[Relationship]:
"""Optional[:class:`Relationship`]: Returns the :class:`Relationship` with this user if applicable, ``None`` otherwise.""" """Optional[:class:`Relationship`]: Returns the :class:`Relationship` with this user if applicable, ``None`` otherwise."""
@ -781,6 +788,7 @@ class ClientUser(BaseUser):
accent_color: Colour = MISSING, accent_color: Colour = MISSING,
bio: Optional[str] = MISSING, bio: Optional[str] = MISSING,
date_of_birth: datetime = MISSING, date_of_birth: datetime = MISSING,
pomelo: bool = MISSING,
) -> ClientUser: ) -> ClientUser:
"""|coro| """|coro|
@ -813,10 +821,10 @@ class ClientUser(BaseUser):
The hypesquad house you wish to change to. The hypesquad house you wish to change to.
Could be ``None`` to leave the current house. Could be ``None`` to leave the current house.
username: :class:`str` username: :class:`str`
The new username you wish to change to. The new username you wish to change to.
discriminator: :class:`int` discriminator: :class:`int`
The new discriminator you wish to change to. The new discriminator you wish to change to.
Can only be used if you have Nitro. This is a legacy concept that is no longer used. Can only be used if you have Nitro.
avatar: Optional[:class:`bytes`] avatar: Optional[:class:`bytes`]
A :term:`py:bytes-like object` representing the image to upload. A :term:`py:bytes-like object` representing the image to upload.
Could be ``None`` to denote no avatar. Could be ``None`` to denote no avatar.
@ -841,12 +849,23 @@ class ClientUser(BaseUser):
Your date of birth. Can only ever be set once. Your date of birth. Can only ever be set once.
.. versionadded:: 2.0 .. versionadded:: 2.0
pomelo: :class:`bool`
Whether to migrate your account to Discord's `new unique username system <https://discord.com/blog/usernames>`_.
.. note::
This change cannot be undone and requires you to be in the pomelo rollout.
.. versionadded:: 2.1
Raises Raises
------ ------
HTTPException HTTPException
Editing your profile failed. Editing your profile failed.
You are not in the pomelo rollout.
ValueError ValueError
Username was not passed when migrating to pomelo.
Discriminator was passed when migrated to pomelo.
Password was not passed when it was required. Password was not passed when it was required.
`house` field was not a :class:`HypeSquadHouse`. `house` field was not a :class:`HypeSquadHouse`.
`date_of_birth` field was not a :class:`datetime.datetime`. `date_of_birth` field was not a :class:`datetime.datetime`.
@ -857,7 +876,17 @@ class ClientUser(BaseUser):
:class:`ClientUser` :class:`ClientUser`
The newly edited client user. The newly edited client user.
""" """
state = self._state
args: Dict[str, Any] = {} args: Dict[str, Any] = {}
data = None
if pomelo:
if not username:
raise ValueError('Username is required for pomelo migration')
if discriminator:
raise ValueError('Discriminator cannot be changed when migrated to pomelo')
data = await state.http.pomelo(username)
username = MISSING
if any(x is not MISSING for x in (new_password, email, username, discriminator)): if any(x is not MISSING for x in (new_password, email, username, discriminator)):
if password is MISSING: if password is MISSING:
@ -898,6 +927,8 @@ class ClientUser(BaseUser):
args['username'] = username args['username'] = username
if discriminator is not MISSING: if discriminator is not MISSING:
if self.is_pomelo():
raise ValueError('Discriminator cannot be changed when migrated to pomelo')
args['discriminator'] = discriminator args['discriminator'] = discriminator
if new_password is not MISSING: if new_password is not MISSING:
@ -921,11 +952,12 @@ class ClientUser(BaseUser):
else: else:
await http.change_hypesquad_house(house.value) await http.change_hypesquad_house(house.value)
data = await http.edit_profile(args) if args or data is None:
try: data = await http.edit_profile(args)
http._token(data['token']) try:
except KeyError: http._token(data['token'])
pass except KeyError:
pass
return ClientUser(state=self._state, data=data) return ClientUser(state=self._state, data=data)

Loading…
Cancel
Save