|
|
@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE. |
|
|
|
""" |
|
|
|
from __future__ import annotations |
|
|
|
|
|
|
|
from typing import TYPE_CHECKING, List, Optional |
|
|
|
from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple |
|
|
|
|
|
|
|
from .enums import ConnectionType, try_enum |
|
|
|
from .integrations import Integration |
|
|
@ -38,6 +38,7 @@ if TYPE_CHECKING: |
|
|
|
__all__ = ( |
|
|
|
'PartialConnection', |
|
|
|
'Connection', |
|
|
|
'ConnectionMetadata', |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
@ -46,6 +47,8 @@ class PartialConnection: |
|
|
|
|
|
|
|
This is the info you get for other users' connections. |
|
|
|
|
|
|
|
.. versionadded:: 2.0 |
|
|
|
|
|
|
|
.. container:: operations |
|
|
|
|
|
|
|
.. describe:: x == y |
|
|
@ -64,8 +67,6 @@ class PartialConnection: |
|
|
|
|
|
|
|
Returns the connection's name. |
|
|
|
|
|
|
|
.. versionadded:: 2.0 |
|
|
|
|
|
|
|
Attributes |
|
|
|
---------- |
|
|
|
id: :class:`str` |
|
|
@ -73,16 +74,14 @@ class PartialConnection: |
|
|
|
name: :class:`str` |
|
|
|
The connection's account name. |
|
|
|
type: :class:`ConnectionType` |
|
|
|
The connection service (e.g. youtube, twitch, etc.). |
|
|
|
The connection service type (e.g. youtube, twitch, etc.). |
|
|
|
verified: :class:`bool` |
|
|
|
Whether the connection is verified. |
|
|
|
revoked: :class:`bool` |
|
|
|
Whether the connection is revoked. |
|
|
|
visible: :class:`bool` |
|
|
|
Whether the connection is visible on the user's profile. |
|
|
|
""" |
|
|
|
|
|
|
|
__slots__ = ('id', 'name', 'type', 'verified', 'revoked', 'visible') |
|
|
|
__slots__ = ('id', 'name', 'type', 'verified', 'visible') |
|
|
|
|
|
|
|
def __init__(self, data: PartialConnectionPayload): |
|
|
|
self._update(data) |
|
|
@ -94,7 +93,7 @@ class PartialConnection: |
|
|
|
return f'<{self.__class__.__name__} id={self.id!r} name={self.name!r} type={self.type!r} visible={self.visible}>' |
|
|
|
|
|
|
|
def __hash__(self) -> int: |
|
|
|
return hash((self.name, self.id)) |
|
|
|
return hash((self.type.value, self.id)) |
|
|
|
|
|
|
|
def __eq__(self, other: object) -> bool: |
|
|
|
if isinstance(other, PartialConnection): |
|
|
@ -110,15 +109,15 @@ class PartialConnection: |
|
|
|
self.id: str = data['id'] |
|
|
|
self.name: str = data['name'] |
|
|
|
self.type: ConnectionType = try_enum(ConnectionType, data['type']) |
|
|
|
|
|
|
|
self.verified: bool = data['verified'] |
|
|
|
self.revoked: bool = data.get('revoked', False) |
|
|
|
self.visible: bool = True |
|
|
|
self.visible: bool = True # If we have a partial connection, it's visible |
|
|
|
|
|
|
|
|
|
|
|
class Connection(PartialConnection): |
|
|
|
"""Represents a Discord profile connection. |
|
|
|
|
|
|
|
.. versionadded:: 2.0 |
|
|
|
|
|
|
|
.. container:: operations |
|
|
|
|
|
|
|
.. describe:: x == y |
|
|
@ -137,32 +136,54 @@ class Connection(PartialConnection): |
|
|
|
|
|
|
|
Returns the connection's name. |
|
|
|
|
|
|
|
.. versionadded:: 2.0 |
|
|
|
|
|
|
|
Attributes |
|
|
|
---------- |
|
|
|
revoked: :class:`bool` |
|
|
|
Whether the connection is revoked. |
|
|
|
friend_sync: :class:`bool` |
|
|
|
Whether friends are synced over the connection. |
|
|
|
show_activity: :class:`bool` |
|
|
|
Whether activities from this connection will be shown in presences. |
|
|
|
access_token: :class:`str` |
|
|
|
two_way_link: :class:`bool` |
|
|
|
Whether the connection is authorized both ways (i.e. it's both a connection and an authorization). |
|
|
|
metadata_visible: :class:`bool` |
|
|
|
Whether the connection's metadata is visible. |
|
|
|
metadata: Optional[:class:`ConnectionMetadata`] |
|
|
|
Various metadata about the connection. |
|
|
|
|
|
|
|
The contents of this are always subject to change. |
|
|
|
access_token: Optional[:class:`str`] |
|
|
|
The OAuth2 access token for the account, if applicable. |
|
|
|
integrations: List[:class:`Integration`] |
|
|
|
The integrations attached to the connection. |
|
|
|
""" |
|
|
|
|
|
|
|
__slots__ = ('_state', 'visible', 'friend_sync', 'show_activity', 'access_token', 'integrations') |
|
|
|
__slots__ = ( |
|
|
|
'_state', |
|
|
|
'revoked', |
|
|
|
'friend_sync', |
|
|
|
'show_activity', |
|
|
|
'two_way_link', |
|
|
|
'metadata_visible', |
|
|
|
'metadata', |
|
|
|
'access_token', |
|
|
|
'integrations', |
|
|
|
) |
|
|
|
|
|
|
|
def __init__(self, *, data: ConnectionPayload, state: ConnectionState): |
|
|
|
super().__init__(data) |
|
|
|
self._update(data) |
|
|
|
self._state = state |
|
|
|
self.access_token: Optional[str] = None |
|
|
|
|
|
|
|
def _update(self, data: ConnectionPayload): |
|
|
|
super()._update(data) |
|
|
|
self.visible: bool = bool(data.get('visibility', True)) |
|
|
|
self.revoked: bool = data.get('revoked', False) |
|
|
|
self.visible: bool = bool(data.get('visibility', False)) |
|
|
|
self.friend_sync: bool = data.get('friend_sync', False) |
|
|
|
self.show_activity: bool = data.get('show_activity', True) |
|
|
|
self.two_way_link: bool = data.get('two_way_link', False) |
|
|
|
self.metadata_visible: bool = bool(data.get('metadata_visibility', False)) |
|
|
|
self.metadata: Optional[ConnectionMetadata] = ConnectionMetadata(data['metadata']) if 'metadata' in data else None |
|
|
|
|
|
|
|
# Only sometimes in the payload |
|
|
|
try: |
|
|
@ -171,14 +192,16 @@ class Connection(PartialConnection): |
|
|
|
pass |
|
|
|
|
|
|
|
self.integrations: List[Integration] = [ |
|
|
|
Integration(data=i, guild=self._resolve_guild(i)) for i in data.get('integrations', []) |
|
|
|
Integration(data=i, guild=self._resolve_guild(i)) for i in data.get('integrations') or [] |
|
|
|
] |
|
|
|
|
|
|
|
def _resolve_guild(self, data: IntegrationPayload) -> Guild: |
|
|
|
from .guild import Guild |
|
|
|
|
|
|
|
state = self._state |
|
|
|
guild_data = data['guild'] |
|
|
|
guild_data = data.get('guild') |
|
|
|
if not guild_data: |
|
|
|
return None # type: ignore |
|
|
|
|
|
|
|
guild_id = int(guild_data['id']) |
|
|
|
guild = state._get_guild(guild_id) |
|
|
@ -187,8 +210,14 @@ class Connection(PartialConnection): |
|
|
|
return guild |
|
|
|
|
|
|
|
async def edit( |
|
|
|
self, *, name: str = MISSING, visible: bool = MISSING, show_activity: bool = MISSING, friend_sync: bool = MISSING |
|
|
|
) -> None: |
|
|
|
self, |
|
|
|
*, |
|
|
|
name: str = MISSING, |
|
|
|
visible: bool = MISSING, |
|
|
|
friend_sync: bool = MISSING, |
|
|
|
show_activity: bool = MISSING, |
|
|
|
metadata_visible: bool = MISSING, |
|
|
|
) -> Connection: |
|
|
|
"""|coro| |
|
|
|
|
|
|
|
Edit the connection. |
|
|
@ -201,27 +230,48 @@ class Connection(PartialConnection): |
|
|
|
The new name of the connection. Only editable for certain connection types. |
|
|
|
visible: :class:`bool` |
|
|
|
Whether the connection is visible on your profile. |
|
|
|
friend_sync: :class:`bool` |
|
|
|
Whether friends are synced over the connection. |
|
|
|
show_activity: :class:`bool` |
|
|
|
Whether activities from this connection will be shown in presences. |
|
|
|
friend_sync: :class:`bool` |
|
|
|
Whether friends are synced over the connection. |
|
|
|
metadata_visible: :class:`bool` |
|
|
|
Whether the connection's metadata is visible. |
|
|
|
|
|
|
|
Raises |
|
|
|
------ |
|
|
|
HTTPException |
|
|
|
Editing the connection failed. |
|
|
|
|
|
|
|
Returns |
|
|
|
------- |
|
|
|
:class:`Connection` |
|
|
|
The edited connection. |
|
|
|
""" |
|
|
|
payload = {} |
|
|
|
if name is not MISSING: |
|
|
|
payload['name'] = name |
|
|
|
if visible is not MISSING: |
|
|
|
payload['visibility'] = visible |
|
|
|
if friend_sync is not MISSING: |
|
|
|
payload['friend_sync'] = friend_sync |
|
|
|
if show_activity is not MISSING: |
|
|
|
payload['show_activity'] = show_activity |
|
|
|
if friend_sync is not MISSING: |
|
|
|
payload['friend_sync'] = friend_sync |
|
|
|
if metadata_visible is not MISSING: |
|
|
|
payload['metadata_visibility'] = metadata_visible |
|
|
|
data = await self._state.http.edit_connection(self.type.value, self.id, **payload) |
|
|
|
self._update(data) |
|
|
|
return Connection(data=data, state=self._state) |
|
|
|
|
|
|
|
async def refresh(self) -> None: |
|
|
|
"""|coro| |
|
|
|
|
|
|
|
Refreshes the connection. This updates the connection's :attr:`metadata`. |
|
|
|
|
|
|
|
Raises |
|
|
|
------ |
|
|
|
HTTPException |
|
|
|
Refreshing the connection failed. |
|
|
|
""" |
|
|
|
await self._state.http.refresh_connection(self.type.value, self.id) |
|
|
|
|
|
|
|
async def delete(self) -> None: |
|
|
|
"""|coro| |
|
|
@ -251,5 +301,67 @@ class Connection(PartialConnection): |
|
|
|
The new access token. |
|
|
|
""" |
|
|
|
data = await self._state.http.get_connection_token(self.type.value, self.id) |
|
|
|
self.access_token = token = data['access_token'] |
|
|
|
return token |
|
|
|
return data['access_token'] |
|
|
|
|
|
|
|
|
|
|
|
class ConnectionMetadata: |
|
|
|
"""Represents a connection's metadata. |
|
|
|
|
|
|
|
Because of how unstable and wildly varying this metadata can be, this is a simple class that just |
|
|
|
provides access ro the raw data using dot notation. This means if an attribute is not present, |
|
|
|
``None`` will be returned instead of raising an AttributeError. |
|
|
|
|
|
|
|
.. versionadded:: 2.0 |
|
|
|
|
|
|
|
.. container:: operations |
|
|
|
|
|
|
|
.. describe:: x == y |
|
|
|
|
|
|
|
Checks if two metadata objects are equal. |
|
|
|
|
|
|
|
.. describe:: x != y |
|
|
|
|
|
|
|
Checks if two metadata objects are not equal. |
|
|
|
|
|
|
|
.. describe:: x[key] |
|
|
|
|
|
|
|
Returns a metadata value if it is found, otherwise raises a :exc:`KeyError`. |
|
|
|
|
|
|
|
.. describe:: key in x |
|
|
|
|
|
|
|
Checks if a metadata value is present. |
|
|
|
|
|
|
|
.. describe:: iter(x) |
|
|
|
Returns an iterator of ``(field, value)`` pairs. This allows this class |
|
|
|
to be used as an iterable in list/dict/etc constructions. |
|
|
|
""" |
|
|
|
|
|
|
|
__slots__ = () |
|
|
|
|
|
|
|
def __init__(self, data: Optional[dict]) -> None: |
|
|
|
self.__dict__.update(data or {}) |
|
|
|
|
|
|
|
def __repr__(self) -> str: |
|
|
|
return f'<ConnectionMetadata {" ".join(f"{k}={v!r}" for k, v in self.__dict__.items())}>' |
|
|
|
|
|
|
|
def __eq__(self, other: object) -> bool: |
|
|
|
if not isinstance(other, ConnectionMetadata): |
|
|
|
return False |
|
|
|
return self.__dict__ == other.__dict__ |
|
|
|
|
|
|
|
def __ne__(self, other: object) -> bool: |
|
|
|
if not isinstance(other, ConnectionMetadata): |
|
|
|
return True |
|
|
|
return self.__dict__ != other.__dict__ |
|
|
|
|
|
|
|
def __iter__(self) -> Iterator[Tuple[str, Any]]: |
|
|
|
yield from self.__dict__.items() |
|
|
|
|
|
|
|
def __getitem__(self, key: str) -> Any: |
|
|
|
return self.__dict__[key] |
|
|
|
|
|
|
|
def __getattr__(self, attr: str) -> Any: |
|
|
|
return None |
|
|
|
|
|
|
|
def __contains__(self, key: str) -> bool: |
|
|
|
return key in self.__dict__ |
|
|
|