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
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:
""":class:`bool`: Specifies if the client's internal cache is ready for use."""
return self._ready is not MISSING and self._ready.is_set()
@ -5054,3 +5062,58 @@ class Client:
experiments.append(GuildExperiment(state=state, data=exp))
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.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:
old_token, self.token = self.token, token
@ -1049,6 +1045,26 @@ class HTTPClient:
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
def start_group(self, recipients: SnowflakeList) -> Response[channel.GroupDMChannel]:
@ -1429,9 +1445,6 @@ class HTTPClient:
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
r = Route('PATCH', '/guilds/{guild_id}/voice-states/@me', guild_id=guild_id)
return self.request(r, json=payload)

4
discord/state.py

@ -614,6 +614,7 @@ class ConnectionState:
self.auth_session_id: Optional[str] = None
self.required_action: Optional[RequiredActionType] = None
self.friend_suggestion_count: int = 0
self.disclose: List[str] = []
self._emojis: Dict[int, Emoji] = {}
self._stickers: Dict[int, GuildSticker] = {}
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')]
self._add_private_channel(factory(me=user, data=pm, state=self)) # type: ignore
# Disloses
self.dislose = data.get('dislose', [])
# We're done
del self._ready_data
self.call_handlers('connect')

1
discord/types/gateway.py

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

8
discord/types/user.py

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

46
discord/user.py

@ -523,6 +523,13 @@ class BaseUser(_UserTag):
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
def relationship(self) -> Optional[Relationship]:
"""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,
bio: Optional[str] = MISSING,
date_of_birth: datetime = MISSING,
pomelo: bool = MISSING,
) -> ClientUser:
"""|coro|
@ -813,10 +821,10 @@ class ClientUser(BaseUser):
The hypesquad house you wish to change to.
Could be ``None`` to leave the current house.
username: :class:`str`
The new username you wish to change to.
The new username you wish to change to.
discriminator: :class:`int`
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`]
A :term:`py:bytes-like object` representing the image to upload.
Could be ``None`` to denote no avatar.
@ -841,12 +849,23 @@ class ClientUser(BaseUser):
Your date of birth. Can only ever be set once.
.. 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
------
HTTPException
Editing your profile failed.
You are not in the pomelo rollout.
ValueError
Username was not passed when migrating to pomelo.
Discriminator was passed when migrated to pomelo.
Password was not passed when it was required.
`house` field was not a :class:`HypeSquadHouse`.
`date_of_birth` field was not a :class:`datetime.datetime`.
@ -857,7 +876,17 @@ class ClientUser(BaseUser):
:class:`ClientUser`
The newly edited client user.
"""
state = self._state
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 password is MISSING:
@ -898,6 +927,8 @@ class ClientUser(BaseUser):
args['username'] = username
if discriminator is not MISSING:
if self.is_pomelo():
raise ValueError('Discriminator cannot be changed when migrated to pomelo')
args['discriminator'] = discriminator
if new_password is not MISSING:
@ -921,11 +952,12 @@ class ClientUser(BaseUser):
else:
await http.change_hypesquad_house(house.value)
data = await http.edit_profile(args)
try:
http._token(data['token'])
except KeyError:
pass
if args or data is None:
data = await http.edit_profile(args)
try:
http._token(data['token'])
except KeyError:
pass
return ClientUser(state=self._state, data=data)

Loading…
Cancel
Save