diff --git a/fittrackee/tests/users/test_auth_api.py b/fittrackee/tests/users/test_auth_api.py index 5c9a4f5c..53158fb8 100644 --- a/fittrackee/tests/users/test_auth_api.py +++ b/fittrackee/tests/users/test_auth_api.py @@ -12,6 +12,7 @@ from fittrackee.users.utils.token import get_user_token from fittrackee.workouts.models import Sport, Workout from ..api_test_case import ApiTestCaseMixin +from ..utils import random_string class TestUserRegistration(ApiTestCaseMixin): @@ -505,53 +506,6 @@ class TestUserProfileUpdate(ApiTestCaseMixin): app, user_1.email ) - response = client.post( - '/api/auth/profile/edit', - content_type='application/json', - data=json.dumps( - dict( - first_name='John', - last_name='Doe', - location='Somewhere', - bio='Nothing to tell', - birth_date='1980-01-01', - password='87654321', - ) - ), - headers=dict(Authorization=f'Bearer {auth_token}'), - ) - - data = json.loads(response.data.decode()) - assert data['status'] == 'success' - assert data['message'] == 'user profile updated' - assert response.status_code == 200 - assert data['data']['username'] == 'test' - assert data['data']['email'] == 'test@test.com' - assert not data['data']['admin'] - assert data['data']['created_at'] - assert data['data']['first_name'] == 'John' - assert data['data']['last_name'] == 'Doe' - assert data['data']['birth_date'] - assert data['data']['bio'] == 'Nothing to tell' - assert data['data']['imperial_units'] is False - assert data['data']['location'] == 'Somewhere' - assert data['data']['timezone'] is None - assert data['data']['weekm'] is False - assert data['data']['language'] is None - assert data['data']['nb_sports'] == 0 - assert data['data']['nb_workouts'] == 0 - assert data['data']['records'] == [] - assert data['data']['sports_list'] == [] - assert data['data']['total_distance'] == 0 - assert data['data']['total_duration'] == '0:00:00' - - def test_it_updates_user_profile_without_password( - self, app: Flask, user_1: User - ) -> None: - client, auth_token = self.get_test_client_and_auth_token( - app, user_1.email - ) - response = client.post( '/api/auth/profile/edit', content_type='application/json', @@ -624,6 +578,58 @@ class TestUserProfileUpdate(ApiTestCaseMixin): self.assert_400(response) +class TestUserAccountUpdate(ApiTestCaseMixin): + def test_it_returns_error_if_payload_is_empty( + self, app: Flask, user_1: User + ) -> None: + client, auth_token = self.get_test_client_and_auth_token( + app, user_1.email + ) + + response = client.patch( + '/api/auth/profile/edit/account', + content_type='application/json', + data=json.dumps(dict()), + headers=dict(Authorization=f'Bearer {auth_token}'), + ) + + self.assert_400(response) + + def test_it_updates_user_profile(self, app: Flask, user_1: User) -> None: + client, auth_token = self.get_test_client_and_auth_token( + app, user_1.email + ) + + response = client.patch( + '/api/auth/profile/edit/account', + content_type='application/json', + data=json.dumps(dict(password=random_string())), + headers=dict(Authorization=f'Bearer {auth_token}'), + ) + assert response.status_code == 200 + data = json.loads(response.data.decode()) + assert data['status'] == 'success' + assert data['message'] == 'user account updated' + + def test_it_returns_error_if_controls_fail( + self, app: Flask, user_1: User + ) -> None: + client, auth_token = self.get_test_client_and_auth_token( + app, user_1.email + ) + + response = client.patch( + '/api/auth/profile/edit/account', + content_type='application/json', + data=json.dumps(dict(password=random_string(length=5))), + headers=dict(Authorization=f'Bearer {auth_token}'), + ) + + self.assert_400( + response, error_message='password: 8 characters required' + ) + + class TestUserPreferencesUpdate(ApiTestCaseMixin): def test_it_updates_user_preferences( self, app: Flask, user_1: User diff --git a/fittrackee/users/auth.py b/fittrackee/users/auth.py index b99f8656..3106ddcf 100644 --- a/fittrackee/users/auth.py +++ b/fittrackee/users/auth.py @@ -542,6 +542,136 @@ def edit_user(auth_user: User) -> Union[Dict, HttpResponse]: return handle_error_and_return_response(e, db=db) +@auth_blueprint.route('/auth/profile/edit/account', methods=['PATCH']) +@authenticate +def update_user_account(auth_user: User) -> Union[Dict, HttpResponse]: + """ + update authenticated user password + + **Example request**: + + .. sourcecode:: http + + PATCH /api/auth/profile/edit/account HTTP/1.1 + Content-Type: application/json + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "admin": false, + "bio": null, + "birth_date": null, + "created_at": "Sun, 14 Jul 2019 14:09:58 GMT", + "email": "sam@example.com", + "first_name": null, + "imperial_units": false, + "language": "en", + "last_name": null, + "location": null, + "nb_sports": 3, + "nb_workouts": 6, + "picture": false, + "records": [ + { + "id": 9, + "record_type": "AS", + "sport_id": 1, + "user": "sam", + "value": 18, + "workout_date": "Sun, 07 Jul 2019 08:00:00 GMT", + "workout_id": "hvYBqYBRa7wwXpaStWR4V2" + }, + { + "id": 10, + "record_type": "FD", + "sport_id": 1, + "user": "sam", + "value": 18, + "workout_date": "Sun, 07 Jul 2019 08:00:00 GMT", + "workout_id": "hvYBqYBRa7wwXpaStWR4V2" + }, + { + "id": 11, + "record_type": "LD", + "sport_id": 1, + "user": "sam", + "value": "1:01:00", + "workout_date": "Sun, 07 Jul 2019 08:00:00 GMT", + "workout_id": "hvYBqYBRa7wwXpaStWR4V2" + }, + { + "id": 12, + "record_type": "MS", + "sport_id": 1, + "user": "sam", + "value": 18, + "workout_date": "Sun, 07 Jul 2019 08:00:00 GMT", + "workout_id": "hvYBqYBRa7wwXpaStWR4V2" + } + ], + "sports_list": [ + 1, + 4, + 6 + ], + "timezone": "Europe/Paris", + "total_distance": 67.895, + "total_duration": "6:50:27", + "username": "sam" + "weekm": true, + }, + "message": "user profile updated", + "status": "success" + } + + : Union[Dict, HttpResponse]: