Skip to content

Commit

Permalink
feat: create user service to upgrade user to artist account and add p…
Browse files Browse the repository at this point in the history
…atch endpoint
  • Loading branch information
xiomaraR committed Aug 31, 2024
1 parent 3a74fb6 commit 9dfafe7
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 2 deletions.
36 changes: 36 additions & 0 deletions Backend/app/spotify_electron/user/artist/artist_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
)
from app.spotify_electron.user.user.user_schema import (
UserCreateException,
UserDAO,
UserNotFoundException,
UserRepositoryException,
)
Expand Down Expand Up @@ -90,6 +91,41 @@ def create_artist(name: str, photo: str, password: bytes, current_date: str) ->
artist_repository_logger.info(f"Artist added to repository: {artist}")


def create_artist_from_user(user_data: UserDAO) -> None:
"""Create artist based on existing user data
Args:
user_data: UserDao object
Raises:
UserRepositoryException: unexpected error while creating artist
"""
try:
artist_data = {
"name": user_data.name,
"photo": user_data.photo,
"register_date": user_data.register_date,
"password": user_data.password,
"saved_playlists": user_data.saved_playlists,
"playlists": user_data.playlists,
"playback_history": user_data.playback_history,
"uploaded_songs": [],
}
result = user_collection_provider.get_artist_collection().insert_one(artist_data)

validate_user_create(result)
except UserCreateException as exception:
artist_repository_logger.exception(f"Error inserting Artist {artist_data} in database")
raise UserRepositoryException from exception
except (UserRepositoryException, Exception) as exception:
artist_repository_logger.exception(
f"Unexpected error inserting artist {artist_data} in database"
)
raise UserRepositoryException from exception
else:
artist_repository_logger.info(f"Artist added to repository: {artist_data}")


def get_all_artists() -> list[ArtistDAO]:
"""Get all artists
Expand Down
31 changes: 30 additions & 1 deletion Backend/app/spotify_electron/user/user/user_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,36 @@ def create_user(name: str, photo: str, password: bytes, current_date: str) -> No
user_repository_logger.exception(f"Error inserting User {user} in database")
raise UserRepositoryException from exception
except (UserRepositoryException, Exception) as exception:
user_repository_logger.exception(f"Unexpected error inserting user {user} in database")
user_repository_logger.exception(
f"Unexpected error inserting user {user} in database"
)
raise UserRepositoryException from exception
else:
user_repository_logger.info(f"User added to repository: {user}")


def update_user_role(user_name: str, new_role: str) -> None:
"""Update user role
Args:
name (str): user name
new_role (str): user role
Raises:
UserNotFoundException: user was not found
UserRepositoryException: unexpected error while updating user role
"""
try:
user_collection = user_collection_provider.get_user_collection()
user = user_collection.find_one({"name": user_name})
validate_user_exists(user)
user_collection.update_one({"name": user_name}, {"$set": {"role": new_role}})
except UserNotFoundException as exception:
raise UserNotFoundException from exception
except Exception as exception:
user_repository_logger.exception(
f"Error updating User {user_name} role in database"
)
raise UserRepositoryException from exception
else:
user_repository_logger.info(f"User {user_name} role updated to {new_role}")
53 changes: 53 additions & 0 deletions Backend/app/spotify_electron/user/user/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
"""

import app.auth.auth_service as auth_service
import app.spotify_electron.user.artist.artist_repository as artist_repository
import app.spotify_electron.user.base_user_repository as base_user_repository
import app.spotify_electron.user.providers.user_collection_provider as user_collection_provider
import app.spotify_electron.user.user.user_repository as user_repository
import app.spotify_electron.user.validations.base_user_service_validations as base_user_service
from app.auth.auth_schema import TokenData
from app.logging.logging_constants import LOGGING_USER_SERVICE
from app.logging.logging_schema import SpotifyElectronLogger
from app.spotify_electron.user.user.user_schema import (
Expand All @@ -18,6 +20,9 @@
UserServiceException,
get_user_dto_from_dao,
)
from app.spotify_electron.user.validations.base_user_repository_validations import (
validate_user_exists,
)
from app.spotify_electron.utils.date.date_utils import get_current_iso8601_date

user_service_logger = SpotifyElectronLogger(LOGGING_USER_SERVICE).getLogger()
Expand Down Expand Up @@ -187,3 +192,51 @@ def search_by_name(name: str) -> list[UserDTO]:
f"Unexpected error in User Service getting items by name {name}"
)
raise UserServiceException from exception


# TODO wrap within DB transaction to be treated as atomic operation
def upgrade_user_to_artist(user_name: str, token: TokenData) -> None:
"""Upgrade user account to artist account
Args:
user_name (str): user name
token (TokenData): token data from user
Raises:
UserNotFoundException: if the user does not exist
UserServiceException: unexpected error while upgrading user to artist
UserBadNameException: if the user name is invalid
"""
try:
base_user_service.validate_user_name_parameter(user_name)
validate_user_exists(user_name)
auth_service.validate_jwt_user_matches_user(token, user_name)
user_data = user_repository.get_user(user_name)
artist_repository.create_artist_from_user(user_data)
user_repository.update_user_role(user_name, "artist")
new_token_data = {
"access_token": user_name,
"role": "artist",
"token_type": "bearer",
}
new_token = auth_service.create_access_token(new_token_data)

except UserBadNameException as exception:
user_service_logger.exception(f"Bad User Name Parameter: {user_name}")
raise UserBadNameException from exception
except UserNotFoundException as exception:
user_service_logger.exception(f"User not found: {user_name}")
raise UserNotFoundException from exception
except UserRepositoryException as exception:
user_service_logger.exception(
f"Unexpected error in User Repository upgrading user to artist: {user_name}"
)
raise UserServiceException from exception
except Exception as exception:
user_service_logger.exception(
f"Unexpected error in User Service upgrading user to artist: {user_name}"
)
raise UserServiceException from exception
else:
user_service_logger.info(f"Account {user_name} upgraded to artist successfully")
return new_token
47 changes: 47 additions & 0 deletions Backend/app/spotify_electron/user/user_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,53 @@ def delete_user(name: str) -> Response:
)


@router.patch("/{name}/upgrade_to_artist")
def upgrade_to_artist(
name: str, token: Annotated[TokenData, Depends(JWTBearer())]
) -> Response:
"""Upgrade user account to artist account
Args:
name (str): user name
token (TokenData): the jwt token. Defaults to None.
"""
try:
new_token = user_service.upgrade_user_to_artist(name, token)
response_data = {"token": new_token}
response_json = json_converter_utils.get_json_from_model(response_data)
return Response(
content=response_json,
media_type="application/json",
status_code=HTTP_200_OK,
)
except UserBadNameException:
return Response(
status_code=HTTP_400_BAD_REQUEST,
content=PropertiesMessagesManager.userBadName,
)
except UserNotFoundException:
return Response(
status_code=HTTP_404_NOT_FOUND,
content=PropertiesMessagesManager.userNotFound,
)
except UserUnauthorizedException:
return Response(
status_code=HTTP_403_FORBIDDEN,
content=PropertiesMessagesManager.userUnauthorized,
)
except BadJWTTokenProvidedException:
return Response(
status_code=HTTP_403_FORBIDDEN,
content=PropertiesMessagesManager.tokenInvalidCredentials,
headers={"WWW-Authenticate": "Bearer"},
)
except (Exception, UserServiceException):
return Response(
status_code=HTTP_500_INTERNAL_SERVER_ERROR,
content=PropertiesMessagesManager.commonInternalServerError,
)


@router.patch("/{name}/playback_history")
def patch_playback_history(
name: str, song_name: str, token: Annotated[TokenData, Depends(JWTBearer())]
Expand Down
4 changes: 4 additions & 0 deletions Backend/tests/test_API/api_test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ def delete_user(name: str) -> Response:

def patch_history_playback(user_name: str, song_name: str) -> Response:
return client.patch(f"/users/{user_name}/playback_history/?song_name={song_name}")


def upgrade_to_artist(user_name: str, headers=dict[str, str]) -> Response:
return client.patch(f"/users/{user_name}/upgrade_to_artist", headers=headers)
61 changes: 60 additions & 1 deletion Backend/tests/test__user.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
import app.spotify_electron.user.base_user_service as base_user_service
import app.spotify_electron.user.user.user_service as user_service
from app.auth.auth_schema import VerifyPasswordException
from tests.test_API.api_test_user import create_user, delete_user, get_user
from tests.test_API.api_test_artist import get_artist
from tests.test_API.api_test_user import (
create_user,
delete_user,
get_user,
upgrade_to_artist,
)
from tests.test_API.api_token import get_user_jwt_header


Expand Down Expand Up @@ -124,6 +130,59 @@ def test_check_encrypted_password_different():
base_user_service.delete_user(name)


def test_upgrade_user_to_artist_correct(clear_test_data_db):
name = "8232392323623823723"
photo = "https://photo"
password = "hola"

res_create_user = create_user(name=name, password=password, photo=photo)
assert res_create_user.status_code == HTTP_201_CREATED

jwt_headers = get_user_jwt_header(username=name, password=password)

res_get_user = get_user(name=name, headers=jwt_headers)
assert res_get_user.status_code == HTTP_200_OK
assert res_get_user.json()["name"] == name
assert res_get_user.json()["photo"] == photo

res_upgrade_user = upgrade_to_artist(user_name=name, headers=jwt_headers)
assert res_upgrade_user.status_code == HTTP_200_OK

new_token_data = res_upgrade_user.json()
assert "token" in new_token_data
new_token = new_token_data["token"]

decoded_token = auth_service.get_jwt_token_data(new_token)
assert decoded_token.role == "artist"

res_get_artist = get_artist(name=name, headers=jwt_headers)
assert res_get_artist.status_code == HTTP_200_OK
artist_data = res_get_artist.json()
assert artist_data["name"] == name
assert artist_data["photo"] == photo

base_user_service.delete_user(name)


def test_upgrade_to_artist_user_not_found():
name = "8232392323623823723"
photo = "https://photo"
password = "hola"

res_create_user = create_user(name=name, password=password, photo=photo)
assert res_create_user.status_code == HTTP_201_CREATED

jwt_headers = get_user_jwt_header(username=name, password=password)
res_get_user = get_user(name=name, headers=jwt_headers)
assert res_get_user.status_code == HTTP_200_OK
assert res_get_user.json()["name"] == name
assert res_get_user.json()["photo"] == photo
base_user_service.delete_user(name)

res_upgrade_user = upgrade_to_artist(user_name=name, headers=jwt_headers)
assert res_upgrade_user.status_code == HTTP_404_NOT_FOUND


# executes after all tests
@pytest.fixture()
def clear_test_data_db():
Expand Down

0 comments on commit 9dfafe7

Please sign in to comment.