API - limit access to users for now

- only auth user can access his preference
- only admin can visualize users
This commit is contained in:
Sam 2022-03-13 09:30:50 +01:00
parent 6c42b9ffbd
commit ac6aceadfd
6 changed files with 180 additions and 104 deletions

View File

@ -14,7 +14,7 @@ from ..api_test_case import ApiTestCaseMixin
class TestGetUser(ApiTestCaseMixin): class TestGetUser(ApiTestCaseMixin):
def test_it_gets_single_user_without_workouts( def test_it_returns_error_if_user_has_no_admin_rights(
self, app: Flask, user_1: User, user_2: User self, app: Flask, user_1: User, user_2: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
@ -27,6 +27,21 @@ class TestGetUser(ApiTestCaseMixin):
headers=dict(Authorization=f'Bearer {auth_token}'), headers=dict(Authorization=f'Bearer {auth_token}'),
) )
self.assert_403(response)
def test_it_gets_single_user_without_workouts(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.get(
f'/api/users/{user_2.username}',
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
assert response.status_code == 200 assert response.status_code == 200
assert data['status'] == 'success' assert data['status'] == 'success'
@ -40,11 +55,7 @@ class TestGetUser(ApiTestCaseMixin):
assert user['last_name'] is None assert user['last_name'] is None
assert user['birth_date'] is None assert user['birth_date'] is None
assert user['bio'] is None assert user['bio'] is None
assert user['imperial_units'] is False
assert user['location'] is None assert user['location'] is None
assert user['timezone'] is None
assert user['weekm'] is False
assert user['language'] is None
assert user['nb_sports'] == 0 assert user['nb_sports'] == 0
assert user['nb_workouts'] == 0 assert user['nb_workouts'] == 0
assert user['records'] == [] assert user['records'] == []
@ -56,13 +67,14 @@ class TestGetUser(ApiTestCaseMixin):
self, self,
app: Flask, app: Flask,
user_1: User, user_1: User,
user_2_admin: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
sport_2_running: Sport, sport_2_running: Sport,
workout_cycling_user_1: Workout, workout_cycling_user_1: Workout,
workout_running_user_1: Workout, workout_running_user_1: Workout,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_2_admin.email
) )
response = client.get( response = client.get(
@ -84,11 +96,7 @@ class TestGetUser(ApiTestCaseMixin):
assert user['last_name'] is None assert user['last_name'] is None
assert user['birth_date'] is None assert user['birth_date'] is None
assert user['bio'] is None assert user['bio'] is None
assert user['imperial_units'] is False
assert user['location'] is None assert user['location'] is None
assert user['timezone'] is None
assert user['weekm'] is False
assert user['language'] is None
assert len(user['records']) == 8 assert len(user['records']) == 8
assert user['nb_sports'] == 2 assert user['nb_sports'] == 2
assert user['nb_workouts'] == 2 assert user['nb_workouts'] == 2
@ -97,10 +105,10 @@ class TestGetUser(ApiTestCaseMixin):
assert user['total_duration'] == '2:40:00' assert user['total_duration'] == '2:40:00'
def test_it_returns_error_if_user_does_not_exist( def test_it_returns_error_if_user_does_not_exist(
self, app: Flask, user_1: User self, app: Flask, user_1_admin: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -113,8 +121,8 @@ class TestGetUser(ApiTestCaseMixin):
class TestGetUsers(ApiTestCaseMixin): class TestGetUsers(ApiTestCaseMixin):
def test_it_get_users_list( def test_it_returns_error_if_user_has_no_admin_rights(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1: User, user_2: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -125,6 +133,20 @@ class TestGetUsers(ApiTestCaseMixin):
headers=dict(Authorization=f'Bearer {auth_token}'), headers=dict(Authorization=f'Bearer {auth_token}'),
) )
self.assert_403(response)
def test_it_get_users_list(
self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.get(
'/api/users',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
@ -132,10 +154,10 @@ class TestGetUsers(ApiTestCaseMixin):
assert 'created_at' in data['data']['users'][0] assert 'created_at' in data['data']['users'][0]
assert 'created_at' in data['data']['users'][1] assert 'created_at' in data['data']['users'][1]
assert 'created_at' in data['data']['users'][2] assert 'created_at' in data['data']['users'][2]
assert 'test' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert 'toto' in data['data']['users'][1]['username'] assert 'toto' in data['data']['users'][1]['username']
assert 'sam' in data['data']['users'][2]['username'] assert 'sam' in data['data']['users'][2]['username']
assert 'test@test.com' in data['data']['users'][0]['email'] assert 'admin@example.com' in data['data']['users'][0]['email']
assert 'toto@toto.com' in data['data']['users'][1]['email'] assert 'toto@toto.com' in data['data']['users'][1]['email']
assert 'sam@test.com' in data['data']['users'][2]['email'] assert 'sam@test.com' in data['data']['users'][2]['email']
assert data['data']['users'][0]['imperial_units'] is False assert data['data']['users'][0]['imperial_units'] is False
@ -148,20 +170,12 @@ class TestGetUsers(ApiTestCaseMixin):
assert data['data']['users'][0]['sports_list'] == [] assert data['data']['users'][0]['sports_list'] == []
assert data['data']['users'][0]['total_distance'] == 0 assert data['data']['users'][0]['total_distance'] == 0
assert data['data']['users'][0]['total_duration'] == '0:00:00' assert data['data']['users'][0]['total_duration'] == '0:00:00'
assert data['data']['users'][1]['imperial_units'] is False
assert data['data']['users'][1]['timezone'] is None
assert data['data']['users'][1]['weekm'] is False
assert data['data']['users'][1]['language'] is None
assert data['data']['users'][1]['nb_sports'] == 0 assert data['data']['users'][1]['nb_sports'] == 0
assert data['data']['users'][1]['nb_workouts'] == 0 assert data['data']['users'][1]['nb_workouts'] == 0
assert data['data']['users'][1]['records'] == [] assert data['data']['users'][1]['records'] == []
assert data['data']['users'][1]['sports_list'] == [] assert data['data']['users'][1]['sports_list'] == []
assert data['data']['users'][1]['total_distance'] == 0 assert data['data']['users'][1]['total_distance'] == 0
assert data['data']['users'][1]['total_duration'] == '0:00:00' assert data['data']['users'][1]['total_duration'] == '0:00:00'
assert data['data']['users'][2]['imperial_units'] is False
assert data['data']['users'][2]['timezone'] is None
assert data['data']['users'][2]['weekm'] is True
assert data['data']['users'][2]['language'] is None
assert data['data']['users'][2]['records'] == [] assert data['data']['users'][2]['records'] == []
assert data['data']['users'][2]['nb_sports'] == 0 assert data['data']['users'][2]['nb_sports'] == 0
assert data['data']['users'][2]['nb_workouts'] == 0 assert data['data']['users'][2]['nb_workouts'] == 0
@ -179,7 +193,7 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_users_list_with_workouts( def test_it_gets_users_list_with_workouts(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
@ -189,7 +203,7 @@ class TestGetUsers(ApiTestCaseMixin):
workout_cycling_user_2: Workout, workout_cycling_user_2: Workout,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -204,10 +218,10 @@ class TestGetUsers(ApiTestCaseMixin):
assert 'created_at' in data['data']['users'][0] assert 'created_at' in data['data']['users'][0]
assert 'created_at' in data['data']['users'][1] assert 'created_at' in data['data']['users'][1]
assert 'created_at' in data['data']['users'][2] assert 'created_at' in data['data']['users'][2]
assert 'test' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert 'toto' in data['data']['users'][1]['username'] assert 'toto' in data['data']['users'][1]['username']
assert 'sam' in data['data']['users'][2]['username'] assert 'sam' in data['data']['users'][2]['username']
assert 'test@test.com' in data['data']['users'][0]['email'] assert 'admin@example.com' in data['data']['users'][0]['email']
assert 'toto@toto.com' in data['data']['users'][1]['email'] assert 'toto@toto.com' in data['data']['users'][1]['email']
assert 'sam@test.com' in data['data']['users'][2]['email'] assert 'sam@test.com' in data['data']['users'][2]['email']
assert data['data']['users'][0]['imperial_units'] is False assert data['data']['users'][0]['imperial_units'] is False
@ -219,18 +233,12 @@ class TestGetUsers(ApiTestCaseMixin):
assert data['data']['users'][0]['sports_list'] == [1, 2] assert data['data']['users'][0]['sports_list'] == [1, 2]
assert data['data']['users'][0]['total_distance'] == 22.0 assert data['data']['users'][0]['total_distance'] == 22.0
assert data['data']['users'][0]['total_duration'] == '2:40:00' assert data['data']['users'][0]['total_duration'] == '2:40:00'
assert data['data']['users'][1]['imperial_units'] is False
assert data['data']['users'][1]['timezone'] is None
assert data['data']['users'][1]['weekm'] is False
assert data['data']['users'][1]['nb_sports'] == 1 assert data['data']['users'][1]['nb_sports'] == 1
assert data['data']['users'][1]['nb_workouts'] == 1 assert data['data']['users'][1]['nb_workouts'] == 1
assert len(data['data']['users'][1]['records']) == 4 assert len(data['data']['users'][1]['records']) == 4
assert data['data']['users'][1]['sports_list'] == [1] assert data['data']['users'][1]['sports_list'] == [1]
assert data['data']['users'][1]['total_distance'] == 15 assert data['data']['users'][1]['total_distance'] == 15
assert data['data']['users'][1]['total_duration'] == '1:00:00' assert data['data']['users'][1]['total_duration'] == '1:00:00'
assert data['data']['users'][2]['imperial_units'] is False
assert data['data']['users'][2]['timezone'] is None
assert data['data']['users'][2]['weekm'] is True
assert data['data']['users'][2]['nb_sports'] == 0 assert data['data']['users'][2]['nb_sports'] == 0
assert data['data']['users'][2]['nb_workouts'] == 0 assert data['data']['users'][2]['nb_workouts'] == 0
assert len(data['data']['users'][2]['records']) == 0 assert len(data['data']['users'][2]['records']) == 0
@ -249,12 +257,12 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_first_page_on_users_list( def test_it_gets_first_page_on_users_list(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -278,12 +286,12 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_next_page_on_users_list( def test_it_gets_next_page_on_users_list(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -306,12 +314,12 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_empty_next_page_on_users_list( def test_it_gets_empty_next_page_on_users_list(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -334,12 +342,12 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_user_list_with_2_per_page( def test_it_gets_user_list_with_2_per_page(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -362,12 +370,12 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_next_page_on_user_list_with_2_per_page( def test_it_gets_next_page_on_user_list_with_2_per_page(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -388,10 +396,10 @@ class TestGetUsers(ApiTestCaseMixin):
} }
def test_it_gets_users_list_ordered_by_username( def test_it_gets_users_list_ordered_by_username(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -403,8 +411,8 @@ class TestGetUsers(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'sam' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert 'test' in data['data']['users'][1]['username'] assert 'sam' in data['data']['users'][1]['username']
assert 'toto' in data['data']['users'][2]['username'] assert 'toto' in data['data']['users'][2]['username']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
@ -415,10 +423,10 @@ class TestGetUsers(ApiTestCaseMixin):
} }
def test_it_gets_users_list_ordered_by_username_ascending( def test_it_gets_users_list_ordered_by_username_ascending(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -430,8 +438,8 @@ class TestGetUsers(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'sam' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert 'test' in data['data']['users'][1]['username'] assert 'sam' in data['data']['users'][1]['username']
assert 'toto' in data['data']['users'][2]['username'] assert 'toto' in data['data']['users'][2]['username']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
@ -442,10 +450,10 @@ class TestGetUsers(ApiTestCaseMixin):
} }
def test_it_gets_users_list_ordered_by_username_descending( def test_it_gets_users_list_ordered_by_username_descending(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -458,8 +466,8 @@ class TestGetUsers(ApiTestCaseMixin):
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'toto' in data['data']['users'][0]['username'] assert 'toto' in data['data']['users'][0]['username']
assert 'test' in data['data']['users'][1]['username'] assert 'sam' in data['data']['users'][1]['username']
assert 'sam' in data['data']['users'][2]['username'] assert 'admin' in data['data']['users'][2]['username']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
'has_prev': False, 'has_prev': False,
@ -642,14 +650,14 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_users_list_ordered_by_workouts_count( def test_it_gets_users_list_ordered_by_workouts_count(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
workout_cycling_user_2: Workout, workout_cycling_user_2: Workout,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -661,7 +669,7 @@ class TestGetUsers(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'test' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert 0 == data['data']['users'][0]['nb_workouts'] assert 0 == data['data']['users'][0]['nb_workouts']
assert 'sam' in data['data']['users'][1]['username'] assert 'sam' in data['data']['users'][1]['username']
assert 0 == data['data']['users'][1]['nb_workouts'] assert 0 == data['data']['users'][1]['nb_workouts']
@ -678,14 +686,14 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_users_list_ordered_by_workouts_count_ascending( def test_it_gets_users_list_ordered_by_workouts_count_ascending(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
workout_cycling_user_2: Workout, workout_cycling_user_2: Workout,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -697,7 +705,7 @@ class TestGetUsers(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'test' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert 0 == data['data']['users'][0]['nb_workouts'] assert 0 == data['data']['users'][0]['nb_workouts']
assert 'sam' in data['data']['users'][1]['username'] assert 'sam' in data['data']['users'][1]['username']
assert 0 == data['data']['users'][1]['nb_workouts'] assert 0 == data['data']['users'][1]['nb_workouts']
@ -714,14 +722,14 @@ class TestGetUsers(ApiTestCaseMixin):
def test_it_gets_users_list_ordered_by_workouts_count_descending( def test_it_gets_users_list_ordered_by_workouts_count_descending(
self, self,
app: Flask, app: Flask,
user_1: User, user_1_admin: User,
user_2: User, user_2: User,
user_3: User, user_3: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
workout_cycling_user_2: Workout, workout_cycling_user_2: Workout,
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -735,7 +743,7 @@ class TestGetUsers(ApiTestCaseMixin):
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'toto' in data['data']['users'][0]['username'] assert 'toto' in data['data']['users'][0]['username']
assert 1 == data['data']['users'][0]['nb_workouts'] assert 1 == data['data']['users'][0]['nb_workouts']
assert 'test' in data['data']['users'][1]['username'] assert 'admin' in data['data']['users'][1]['username']
assert 0 == data['data']['users'][1]['nb_workouts'] assert 0 == data['data']['users'][1]['nb_workouts']
assert 'sam' in data['data']['users'][2]['username'] assert 'sam' in data['data']['users'][2]['username']
assert 0 == data['data']['users'][2]['nb_workouts'] assert 0 == data['data']['users'][2]['nb_workouts']
@ -748,10 +756,10 @@ class TestGetUsers(ApiTestCaseMixin):
} }
def test_it_gets_users_list_filtering_on_username( def test_it_gets_users_list_filtering_on_username(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -773,10 +781,10 @@ class TestGetUsers(ApiTestCaseMixin):
} }
def test_it_returns_empty_users_list_filtering_on_username( def test_it_returns_empty_users_list_filtering_on_username(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -797,10 +805,10 @@ class TestGetUsers(ApiTestCaseMixin):
} }
def test_it_users_list_with_complex_query( def test_it_users_list_with_complex_query(
self, app: Flask, user_1: User, user_2: User, user_3: User self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1_admin.email
) )
response = client.get( response = client.get(
@ -812,7 +820,7 @@ class TestGetUsers(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 1 assert len(data['data']['users']) == 1
assert 'sam' in data['data']['users'][0]['username'] assert 'admin' in data['data']['users'][0]['username']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
'has_prev': True, 'has_prev': True,

View File

@ -1,33 +1,71 @@
from typing import Dict
import pytest
from flask import Flask from flask import Flask
from fittrackee.users.exceptions import UserNotFoundException
from fittrackee.users.models import User, UserSportPreference from fittrackee.users.models import User, UserSportPreference
from fittrackee.workouts.models import Sport, Workout from fittrackee.workouts.models import Sport, Workout
class TestUserModel: class TestUserModel:
def test_user_model(self, app: Flask, user_1: User) -> None: @staticmethod
assert '<User \'test\'>' == str(user_1) def assert_serialized_used(serialized_user: Dict) -> None:
serialized_user = user_1.serialize()
assert 'test' == serialized_user['username']
assert 'created_at' in serialized_user assert 'created_at' in serialized_user
assert serialized_user['admin'] is False assert serialized_user['admin'] is False
assert serialized_user['first_name'] is None assert serialized_user['first_name'] is None
assert serialized_user['last_name'] is None assert serialized_user['last_name'] is None
assert serialized_user['imperial_units'] is False
assert serialized_user['bio'] is None assert serialized_user['bio'] is None
assert serialized_user['location'] is None assert serialized_user['location'] is None
assert serialized_user['birth_date'] is None assert serialized_user['birth_date'] is None
assert serialized_user['picture'] is False assert serialized_user['picture'] is False
assert serialized_user['timezone'] is None
assert serialized_user['weekm'] is False
assert serialized_user['language'] is None
assert serialized_user['nb_sports'] == 0
assert serialized_user['nb_workouts'] == 0 assert serialized_user['nb_workouts'] == 0
def test_user_model_as_auth_user(self, app: Flask, user_1: User) -> None:
assert '<User \'test\'>' == str(user_1)
serialized_user = user_1.serialize(user_1)
self.assert_serialized_used(serialized_user)
assert 'test' == serialized_user['username']
assert 'test@test.com' == serialized_user['email']
assert serialized_user['nb_sports'] == 0
assert serialized_user['records'] == [] assert serialized_user['records'] == []
assert serialized_user['sports_list'] == [] assert serialized_user['sports_list'] == []
assert serialized_user['total_distance'] == 0 assert serialized_user['total_distance'] == 0
assert serialized_user['total_duration'] == '0:00:00' assert serialized_user['total_duration'] == '0:00:00'
assert serialized_user['imperial_units'] is False
assert serialized_user['language'] is None
assert serialized_user['timezone'] is None
assert serialized_user['weekm'] is False
assert serialized_user['email_to_confirm'] is None
assert 'confirmation_token' not in serialized_user
def test_user_model_as_admin(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
serialized_user = user_2.serialize(user_1_admin)
self.assert_serialized_used(serialized_user)
assert 'toto' == serialized_user['username']
assert 'toto@toto.com' == serialized_user['email']
assert serialized_user['nb_sports'] == 0
assert serialized_user['records'] == []
assert serialized_user['sports_list'] == []
assert serialized_user['total_distance'] == 0
assert serialized_user['total_duration'] == '0:00:00'
assert serialized_user['email_to_confirm'] is None
assert 'imperial_units' not in serialized_user
assert 'language' not in serialized_user
assert 'timezone' not in serialized_user
assert 'weekm' not in serialized_user
assert 'confirmation_token' not in serialized_user
def test_user_model_as_regular_user(
self, app: Flask, user_1: User, user_2: User
) -> None:
with pytest.raises(UserNotFoundException):
user_2.serialize(user_1)
def test_encode_auth_token(self, app: Flask, user_1: User) -> None: def test_encode_auth_token(self, app: Flask, user_1: User) -> None:
auth_token = user_1.encode_auth_token(user_1.id) auth_token = user_1.encode_auth_token(user_1.id)
@ -49,7 +87,7 @@ class TestUserModel:
sport_1_cycling: Sport, sport_1_cycling: Sport,
workout_cycling_user_1: Workout, workout_cycling_user_1: Workout,
) -> None: ) -> None:
serialized_user = user_1.serialize() serialized_user = user_1.serialize(user_1)
assert len(serialized_user['records']) == 4 assert len(serialized_user['records']) == 4
assert serialized_user['records'][0]['record_type'] == 'AS' assert serialized_user['records'][0]['record_type'] == 'AS'
assert serialized_user['records'][0]['sport_id'] == sport_1_cycling.id assert serialized_user['records'][0]['sport_id'] == sport_1_cycling.id

View File

@ -386,7 +386,7 @@ def get_authenticated_user_profile(
- invalid token, please log in again - invalid token, please log in again
""" """
return {'status': 'success', 'data': auth_user.serialize()} return {'status': 'success', 'data': auth_user.serialize(auth_user)}
@auth_blueprint.route('/auth/profile/edit', methods=['POST']) @auth_blueprint.route('/auth/profile/edit', methods=['POST'])
@ -540,7 +540,7 @@ def edit_user(auth_user: User) -> Union[Dict, HttpResponse]:
return { return {
'status': 'success', 'status': 'success',
'message': 'user profile updated', 'message': 'user profile updated',
'data': auth_user.serialize(), 'data': auth_user.serialize(auth_user),
} }
# handler errors # handler errors
@ -734,7 +734,7 @@ def update_user_account(auth_user: User) -> Union[Dict, HttpResponse]:
return { return {
'status': 'success', 'status': 'success',
'message': 'user account updated', 'message': 'user account updated',
'data': auth_user.serialize(), 'data': auth_user.serialize(auth_user),
} }
except (exc.IntegrityError, exc.OperationalError, ValueError) as e: except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
@ -872,7 +872,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
return { return {
'status': 'success', 'status': 'success',
'message': 'user preferences updated', 'message': 'user preferences updated',
'data': auth_user.serialize(), 'data': auth_user.serialize(auth_user),
} }
# handler errors # handler errors

View File

@ -11,6 +11,8 @@ from sqlalchemy.sql.expression import select
from fittrackee import bcrypt, db from fittrackee import bcrypt, db
from fittrackee.workouts.models import Workout from fittrackee.workouts.models import Workout
from .exceptions import UserNotFoundException
from .roles import UserRole
from .utils.token import decode_user_token, get_user_token from .utils.token import decode_user_token, get_user_token
BaseModel: DeclarativeMeta = db.Model BaseModel: DeclarativeMeta = db.Model
@ -109,7 +111,18 @@ class User(BaseModel):
.label('workouts_count') .label('workouts_count')
) )
def serialize(self) -> Dict: def serialize(self, current_user: 'User') -> Dict:
role = (
UserRole.AUTH_USER
if current_user.id == self.id
else UserRole.ADMIN
if current_user.admin
else UserRole.USER
)
if role == UserRole.USER:
raise UserNotFoundException()
sports = [] sports = []
total = (0, '0:00:00') total = (0, '0:00:00')
if self.workouts_count > 0: # type: ignore if self.workouts_count > 0: # type: ignore
@ -127,30 +140,40 @@ class User(BaseModel):
.filter(Workout.user_id == self.id) .filter(Workout.user_id == self.id)
.first() .first()
) )
return {
'username': self.username, serialized_user = {
'email': self.email,
'created_at': self.created_at,
'admin': self.admin, 'admin': self.admin,
'bio': self.bio,
'birth_date': self.birth_date,
'created_at': self.created_at,
'email': self.email,
'email_to_confirm': self.email_to_confirm,
'first_name': self.first_name, 'first_name': self.first_name,
'last_name': self.last_name, 'last_name': self.last_name,
'bio': self.bio,
'location': self.location, 'location': self.location,
'birth_date': self.birth_date,
'picture': self.picture is not None,
'timezone': self.timezone,
'weekm': self.weekm,
'language': self.language,
'nb_sports': len(sports), 'nb_sports': len(sports),
'nb_workouts': self.workouts_count, 'nb_workouts': self.workouts_count,
'picture': self.picture is not None,
'records': [record.serialize() for record in self.records], 'records': [record.serialize() for record in self.records],
'sports_list': [ 'sports_list': [
sport for sportslist in sports for sport in sportslist sport for sportslist in sports for sport in sportslist
], ],
'total_distance': float(total[0]), 'total_distance': float(total[0]),
'total_duration': str(total[1]), 'total_duration': str(total[1]),
'imperial_units': self.imperial_units, 'username': self.username,
} }
if role == UserRole.AUTH_USER:
serialized_user = {
**serialized_user,
**{
'imperial_units': self.imperial_units,
'language': self.language,
'timezone': self.timezone,
'weekm': self.weekm,
},
}
return serialized_user
class UserSportPreference(BaseModel): class UserSportPreference(BaseModel):

View File

@ -0,0 +1,7 @@
from enum import Enum
class UserRole(Enum):
ADMIN = 'admin'
AUTH_USER = 'auth_user'
USER = 'user'

View File

@ -50,7 +50,7 @@ def set_admin(username: str) -> None:
@users_blueprint.route('/users', methods=['GET']) @users_blueprint.route('/users', methods=['GET'])
@authenticate @authenticate_as_admin
def get_users(auth_user: User) -> Dict: def get_users(auth_user: User) -> Dict:
""" """
Get all users Get all users
@ -227,7 +227,7 @@ def get_users(auth_user: User) -> Dict:
users = users_pagination.items users = users_pagination.items
return { return {
'status': 'success', 'status': 'success',
'data': {'users': [user.serialize() for user in users]}, 'data': {'users': [user.serialize(auth_user) for user in users]},
'pagination': { 'pagination': {
'has_next': users_pagination.has_next, 'has_next': users_pagination.has_next,
'has_prev': users_pagination.has_prev, 'has_prev': users_pagination.has_prev,
@ -239,7 +239,7 @@ def get_users(auth_user: User) -> Dict:
@users_blueprint.route('/users/<user_name>', methods=['GET']) @users_blueprint.route('/users/<user_name>', methods=['GET'])
@authenticate @authenticate_as_admin
def get_single_user( def get_single_user(
auth_user: User, user_name: str auth_user: User, user_name: str
) -> Union[Dict, HttpResponse]: ) -> Union[Dict, HttpResponse]:
@ -345,7 +345,7 @@ def get_single_user(
if user: if user:
return { return {
'status': 'success', 'status': 'success',
'data': {'users': [user.serialize()]}, 'data': {'users': [user.serialize(auth_user)]},
} }
except ValueError: except ValueError:
pass pass
@ -581,7 +581,7 @@ def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
return { return {
'status': 'success', 'status': 'success',
'data': {'users': [user.serialize()]}, 'data': {'users': [user.serialize(auth_user)]},
} }
except exc.StatementError as e: except exc.StatementError as e:
return handle_error_and_return_response(e, db=db) return handle_error_and_return_response(e, db=db)