diff --git a/tests/conftest.py b/tests/conftest.py index e03221b9..3c55d3e1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -140,11 +140,6 @@ def owner_id() -> str: return fake.uuid4() -@pytest.fixture(scope="session") -def user_id() -> str: - return fake.uuid4() - - @pytest.fixture(scope="function") def sample_item( cosmos_db_repository: CosmosDBRepository, diff --git a/tests/time_tracker_api/users/users_namespace_test.py b/tests/time_tracker_api/users/users_namespace_test.py index 46ff68fa..dfca1e93 100644 --- a/tests/time_tracker_api/users/users_namespace_test.py +++ b/tests/time_tracker_api/users/users_namespace_test.py @@ -1,4 +1,4 @@ -from unittest.mock import Mock, patch +from unittest.mock import Mock from flask import json from flask.testing import FlaskClient from flask_restplus._http import HTTPStatus @@ -6,73 +6,20 @@ def test_users_response_contains_expected_props( - client: FlaskClient, valid_header: dict, + client: FlaskClient, + valid_header: dict, ): AzureConnection.users = Mock( return_value=[{'name': 'dummy', 'email': 'dummy', 'role': 'dummy'}] ) - response = client.get('/users', headers=valid_header,) + response = client.get( + '/users', + headers=valid_header, + ) assert HTTPStatus.OK == response.status_code assert 'name' in json.loads(response.data)[0] assert 'email' in json.loads(response.data)[0] assert 'role' in json.loads(response.data)[0] - - -def test_update_user_role_response_contains_expected_props( - client: FlaskClient, valid_header: dict, user_id: str, -): - valid_user_role_data = {'role': 'admin'} - AzureConnection.update_user_role = Mock( - return_value={'name': 'dummy', 'email': 'dummy', 'role': 'dummy'} - ) - - response = client.post( - f'/users/{user_id}/roles', - headers=valid_header, - json=valid_user_role_data, - ) - - assert HTTPStatus.OK == response.status_code - assert 'name' in json.loads(response.data) - assert 'email' in json.loads(response.data) - assert 'role' in json.loads(response.data) - - -@patch('utils.azure_users.AzureConnection.update_user_role', new_callable=Mock) -def test_on_post_update_user_role_is_being_called_with_valid_arguments( - update_user_role_mock, - client: FlaskClient, - valid_header: dict, - user_id: str, -): - - valid_user_role_data = {'role': 'admin'} - response = client.post( - f'/users/{user_id}/roles', - headers=valid_header, - json=valid_user_role_data, - ) - - assert HTTPStatus.OK == response.status_code - update_user_role_mock.assert_called_once_with( - user_id, valid_user_role_data['role'] - ) - - -@patch('utils.azure_users.AzureConnection.update_user_role', new_callable=Mock) -def test_on_delete_update_user_role_is_being_called_with_valid_arguments( - update_user_role_mock, - client: FlaskClient, - valid_header: dict, - user_id: str, -): - - response = client.delete( - f'/users/{user_id}/roles/time-tracker-admin', headers=valid_header, - ) - - assert HTTPStatus.OK == response.status_code - update_user_role_mock.assert_called_once_with(user_id, role=None) diff --git a/time_tracker_api/users/users_namespace.py b/time_tracker_api/users/users_namespace.py index fea40834..80d40139 100644 --- a/time_tracker_api/users/users_namespace.py +++ b/time_tracker_api/users/users_namespace.py @@ -2,12 +2,9 @@ from flask_restplus import fields, Resource from flask_restplus._http import HTTPStatus -from time_tracker_api.api import common_fields, api, NullableString +from time_tracker_api.api import common_fields, api -from utils.azure_users import AzureConnection - - -azure_connection = AzureConnection() +faker = Faker() ns = api.namespace('users', description='Namespace of the API for users') @@ -20,38 +17,25 @@ title='Name', max_length=50, description='Name of the user', - example=Faker().word(['Marcelo', 'Sandro']), + example=faker.word(['Marcelo', 'Sandro']), ), 'email': fields.String( title="User's Email", max_length=50, description='Email of the user that belongs to the tenant', - example=Faker().email(), + example=faker.email(), ), - 'role': NullableString( + 'role': fields.String( title="User's Role", max_length=50, description='Role assigned to the user by the tenant', - example=Faker().word(['time-tracker-admin']), + example=faker.word(['admin']), ), }, ) user_response_fields.update(common_fields) -user_role_input_fields = ns.model( - 'UserRoleInput', - { - 'role': NullableString( - title="User's Role", - required=True, - max_length=50, - description='Role assigned to the user by the tenant', - example=Faker().word(['time-tracker-admin']), - ), - }, -) - @ns.route('') class Users(Resource): @@ -59,33 +43,19 @@ class Users(Resource): @ns.marshal_list_with(user_response_fields) def get(self): """List all users""" + from utils.azure_users import AzureConnection + + azure_connection = AzureConnection() return azure_connection.users() -@ns.route('//roles') +@ns.route('/') @ns.response(HTTPStatus.NOT_FOUND, 'User not found') @ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The id has an invalid format') @ns.param('id', 'The user identifier') -class UserRoles(Resource): - @ns.doc('create_user_role') - @ns.expect(user_role_input_fields) - @ns.response( - HTTPStatus.BAD_REQUEST, 'Invalid format or structure of the user' - ) - @ns.marshal_with(user_response_fields) - def post(self, id): - """Create user's role""" - return azure_connection.update_user_role(id, ns.payload['role']) - - -@ns.route('//roles/') -@ns.response(HTTPStatus.NOT_FOUND, 'User not found') -@ns.response(HTTPStatus.UNPROCESSABLE_ENTITY, 'The id has an invalid format') -@ns.param('user_id', 'The user identifier') -@ns.param('role_id', 'The role name identifier') -class UserRole(Resource): - @ns.doc('delete_user_role') +class User(Resource): + @ns.doc('get_user') @ns.marshal_with(user_response_fields) - def delete(self, user_id, role_id): - """Delete user's role""" - return azure_connection.update_user_role(user_id, role=None) + def get(self, id): + """Get an user""" + return {} diff --git a/utils/azure_users.py b/utils/azure_users.py index 15ec85b6..700b654f 100644 --- a/utils/azure_users.py +++ b/utils/azure_users.py @@ -1,7 +1,6 @@ import msal import os import requests -import json from typing import List @@ -55,8 +54,6 @@ def __init__(self, config=MSConfig): self.config = config self.access_token = self.get_token() - self.role_field = 'extension_1d76efa96f604499acc0c0ee116a1453_role' - def get_token(self): response = self.client.acquire_token_for_client( scopes=self.config.SCOPE @@ -68,43 +65,28 @@ def get_token(self): raise ValueError(error_info) def users(self) -> List[AzureUser]: + def to_azure_user(item) -> AzureUser: + there_is_email = len(item['otherMails']) > 0 + there_is_role = ( + 'extension_1d76efa96f604499acc0c0ee116a1453_role' in item + ) + + id = item['objectId'] + name = item['displayName'] + email = item['otherMails'][0] if there_is_email else '' + role = ( + item['extension_1d76efa96f604499acc0c0ee116a1453_role'] + if there_is_role + else None + ) + return AzureUser(id, name, email, role) + endpoint = "{endpoint}/users?api-version=1.6&$select=displayName,otherMails,objectId,{role_field}".format( - endpoint=self.config.ENDPOINT, role_field=self.role_field, + endpoint=self.config.ENDPOINT, + role_field='extension_1d76efa96f604499acc0c0ee116a1453_role', ) response = requests.get(endpoint, auth=BearerAuth(self.access_token)) assert 200 == response.status_code assert 'value' in response.json() - return [self.to_azure_user(item) for item in response.json()['value']] - - def update_user_role(self, id, role): - headers = { - 'Content-type': 'application/json', - 'Accept': 'application/json', - } - endpoint = "{endpoint}/users/{user_id}?api-version=1.6".format( - endpoint=self.config.ENDPOINT, user_id=id - ) - data = {self.role_field: role} - response = requests.patch( - endpoint, - auth=BearerAuth(self.access_token), - data=json.dumps(data), - headers=headers, - ) - assert 204 == response.status_code - - response = requests.get(endpoint, auth=BearerAuth(self.access_token)) - assert 200 == response.status_code - - return self.to_azure_user(response.json()) - - def to_azure_user(self, item) -> AzureUser: - there_is_email = len(item['otherMails']) > 0 - there_is_role = self.role_field in item - - id = item['objectId'] - name = item['displayName'] - email = item['otherMails'][0] if there_is_email else '' - role = item[self.role_field] if there_is_role else None - return AzureUser(id, name, email, role) + return [to_azure_user(item) for item in response.json()['value']]