API - init endpoint to update password for authenticated user
This commit is contained in:
parent
5831a70d4b
commit
a4d7dc24da
@ -12,6 +12,7 @@ from fittrackee.users.utils.token import get_user_token
|
|||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..api_test_case import ApiTestCaseMixin
|
||||||
|
from ..utils import random_string
|
||||||
|
|
||||||
|
|
||||||
class TestUserRegistration(ApiTestCaseMixin):
|
class TestUserRegistration(ApiTestCaseMixin):
|
||||||
@ -505,53 +506,6 @@ class TestUserProfileUpdate(ApiTestCaseMixin):
|
|||||||
app, user_1.email
|
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(
|
response = client.post(
|
||||||
'/api/auth/profile/edit',
|
'/api/auth/profile/edit',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
@ -624,6 +578,58 @@ class TestUserProfileUpdate(ApiTestCaseMixin):
|
|||||||
self.assert_400(response)
|
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):
|
class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
||||||
def test_it_updates_user_preferences(
|
def test_it_updates_user_preferences(
|
||||||
self, app: Flask, user_1: User
|
self, app: Flask, user_1: User
|
||||||
|
@ -542,6 +542,136 @@ def edit_user(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
return handle_error_and_return_response(e, db=db)
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
:<json string password: user password
|
||||||
|
|
||||||
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
|
:statuscode 200: user account updated
|
||||||
|
:statuscode 400:
|
||||||
|
- invalid payload
|
||||||
|
- password: 8 characters required
|
||||||
|
:statuscode 401:
|
||||||
|
- provide a valid auth token
|
||||||
|
- signature expired, please log in again
|
||||||
|
- invalid token, please log in again
|
||||||
|
:statuscode 500: error, please try again or contact the administrator
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = request.get_json()
|
||||||
|
if not data:
|
||||||
|
return InvalidPayloadErrorResponse()
|
||||||
|
|
||||||
|
password_data = data.get('password')
|
||||||
|
message = check_password(password_data)
|
||||||
|
if message != '':
|
||||||
|
return InvalidPayloadErrorResponse(message)
|
||||||
|
password = bcrypt.generate_password_hash(
|
||||||
|
password_data, current_app.config.get('BCRYPT_LOG_ROUNDS')
|
||||||
|
).decode()
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth_user.password = password
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'status': 'success',
|
||||||
|
'message': 'user account updated',
|
||||||
|
'data': auth_user.serialize(),
|
||||||
|
}
|
||||||
|
|
||||||
|
# handler errors
|
||||||
|
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
|
||||||
|
return handle_error_and_return_response(e, db=db)
|
||||||
|
|
||||||
|
|
||||||
@auth_blueprint.route('/auth/profile/edit/preferences', methods=['POST'])
|
@auth_blueprint.route('/auth/profile/edit/preferences', methods=['POST'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||||
|
Loading…
Reference in New Issue
Block a user