2020-06-30 16:38:06 +01:00
|
|
|
from dataclasses import dataclass
|
2019-08-26 18:31:21 +01:00
|
|
|
import logging
|
2019-09-27 10:32:42 +01:00
|
|
|
from datetime import timedelta, datetime, timezone
|
2021-03-24 10:06:54 +00:00
|
|
|
from typing import Optional
|
2019-08-26 18:31:21 +01:00
|
|
|
|
2020-06-22 20:21:54 +01:00
|
|
|
from spotframework.net.network import Network as SpotifyNetwork, SpotifyNetworkException
|
2020-06-30 16:38:06 +01:00
|
|
|
from spotframework.net.user import NetworkUser
|
2019-10-07 12:21:26 +01:00
|
|
|
from fmframework.net.network import Network as FmNetwork
|
2019-10-23 14:44:17 +01:00
|
|
|
from music.model.user import User
|
2022-11-29 21:13:26 +00:00
|
|
|
|
2022-11-29 22:46:53 +00:00
|
|
|
from music.magic_strings import SPOT_CLIENT_URI, SPOT_SECRET_URI, LASTFM_CLIENT_URI
|
2022-11-29 21:13:26 +00:00
|
|
|
|
|
|
|
from google.cloud import secretmanager
|
2019-08-26 18:31:21 +01:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2022-11-29 21:13:26 +00:00
|
|
|
secret_client = secretmanager.SecretManagerServiceClient()
|
2019-08-26 18:31:21 +01:00
|
|
|
|
|
|
|
|
2021-03-24 10:06:54 +00:00
|
|
|
def refresh_token_database_callback(user: User) -> None:
|
|
|
|
"""Callback for handling when a spotframework network updates user credemtials
|
|
|
|
|
|
|
|
Used to store newly authenticated credentials
|
|
|
|
|
|
|
|
Args:
|
|
|
|
user (User): Subject user
|
|
|
|
"""
|
|
|
|
|
2019-09-27 10:32:42 +01:00
|
|
|
if isinstance(user, DatabaseUser):
|
2020-04-30 14:54:05 +01:00
|
|
|
user_obj = User.collection.filter('username', '==', user.user_id.strip().lower()).get()
|
|
|
|
if user_obj is None:
|
|
|
|
logger.error(f'user {user} not found')
|
|
|
|
|
|
|
|
user_obj.access_token = user.access_token
|
|
|
|
user_obj.refresh_token = user.refresh_token
|
|
|
|
user_obj.last_refreshed = user.last_refreshed
|
|
|
|
user_obj.token_expiry = user.token_expiry
|
|
|
|
|
|
|
|
user_obj.update()
|
2019-09-27 10:32:42 +01:00
|
|
|
|
|
|
|
logger.debug(f'{user.user_id} database entry updated')
|
|
|
|
else:
|
|
|
|
logger.error('user has no attached id')
|
|
|
|
|
|
|
|
|
2021-03-24 10:06:54 +00:00
|
|
|
def get_authed_spotify_network(user: User) -> Optional[SpotifyNetwork]:
|
|
|
|
"""Get an authenticated spotframework network for a given user
|
|
|
|
|
|
|
|
Args:
|
|
|
|
user (User): Subject user to retrieve a network for
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Optional[SpotifyNetwork]: Authenticated spotframework network
|
|
|
|
"""
|
|
|
|
|
2019-10-27 19:05:50 +00:00
|
|
|
if user is not None:
|
|
|
|
if user.spotify_linked:
|
2022-11-29 21:13:26 +00:00
|
|
|
spot_client = secret_client.access_secret_version(request={"name": SPOT_CLIENT_URI})
|
|
|
|
spot_secret = secret_client.access_secret_version(request={"name": SPOT_SECRET_URI})
|
2019-09-27 10:32:42 +01:00
|
|
|
|
2022-11-29 21:13:26 +00:00
|
|
|
user_obj = DatabaseUser(client_id=spot_client.payload.data.decode("UTF-8"),
|
|
|
|
client_secret=spot_secret.payload.data.decode("UTF-8"),
|
2019-10-27 19:05:50 +00:00
|
|
|
refresh_token=user.refresh_token,
|
2020-04-30 14:54:05 +01:00
|
|
|
user_id=user.username,
|
2019-10-27 19:05:50 +00:00
|
|
|
access_token=user.access_token)
|
2019-09-27 10:32:42 +01:00
|
|
|
user_obj.on_refresh.append(refresh_token_database_callback)
|
|
|
|
|
2020-06-22 20:21:54 +01:00
|
|
|
net = SpotifyNetwork(user_obj)
|
|
|
|
|
2020-05-16 10:58:35 +01:00
|
|
|
if user.last_refreshed is not None and user.token_expiry is not None:
|
|
|
|
if user.last_refreshed + timedelta(seconds=user.token_expiry - 1) \
|
|
|
|
< datetime.now(timezone.utc):
|
2020-06-22 20:21:54 +01:00
|
|
|
net.refresh_access_token()
|
2020-05-16 10:58:35 +01:00
|
|
|
else:
|
2020-06-22 20:21:54 +01:00
|
|
|
net.refresh_access_token()
|
|
|
|
|
|
|
|
try:
|
|
|
|
net.refresh_user_info()
|
2020-07-01 11:03:43 +01:00
|
|
|
except SpotifyNetworkException:
|
|
|
|
logger.exception(f'error refreshing user info for {user.username}')
|
2019-09-27 10:32:42 +01:00
|
|
|
|
2020-06-22 20:21:54 +01:00
|
|
|
return net
|
2019-09-27 10:32:42 +01:00
|
|
|
else:
|
|
|
|
logger.error('user spotify not linked')
|
|
|
|
else:
|
2020-05-16 10:58:35 +01:00
|
|
|
logger.error(f'no user provided')
|
2019-09-27 10:32:42 +01:00
|
|
|
|
|
|
|
|
2021-03-24 10:06:54 +00:00
|
|
|
def get_authed_lastfm_network(user: User) -> Optional[FmNetwork]:
|
|
|
|
"""Get an authenticated fmframework network for a given user
|
|
|
|
|
|
|
|
Args:
|
|
|
|
user (User): Subject user to retrieve a network for
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Optional[FmNetwork]: Authenticated fmframework network
|
|
|
|
"""
|
|
|
|
|
2020-05-16 10:58:35 +01:00
|
|
|
if user is not None:
|
2019-10-27 19:05:50 +00:00
|
|
|
if user.lastfm_username:
|
2022-11-29 21:13:26 +00:00
|
|
|
lastfm_client = secret_client.access_secret_version(request={"name": LASTFM_CLIENT_URI})
|
|
|
|
|
|
|
|
return FmNetwork(username=user.lastfm_username, api_key=lastfm_client.payload.data.decode("UTF-8"))
|
2019-10-07 12:21:26 +01:00
|
|
|
else:
|
2020-04-30 14:54:05 +01:00
|
|
|
logger.error(f'{user.username} has no last.fm username')
|
2019-10-23 14:44:17 +01:00
|
|
|
else:
|
2020-05-16 10:58:35 +01:00
|
|
|
logger.error(f'no user provided')
|
2020-06-30 16:38:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class DatabaseUser(NetworkUser):
|
2022-08-07 13:27:59 +01:00
|
|
|
"""Adding Mixonomer username to spotframework network user"""
|
2020-06-30 16:38:06 +01:00
|
|
|
user_id: str = None
|