diff --git a/tests/time_tracker_api/users/users_namespace_test.py b/tests/time_tracker_api/users/users_namespace_test.py index a7f7a985..35a1b6e9 100644 --- a/tests/time_tracker_api/users/users_namespace_test.py +++ b/tests/time_tracker_api/users/users_namespace_test.py @@ -10,7 +10,9 @@ @patch('utils.azure_users.AzureConnection.get_token', Mock()) @patch('utils.azure_users.AzureConnection.get_user') def test_get_user_response_contains_expected_props( - get_user_mock, client: FlaskClient, valid_header: dict, + get_user_mock, + client: FlaskClient, + valid_header: dict, ): get_user_mock.return_value = { 'name': 'dummy', @@ -35,7 +37,9 @@ def test_get_user_response_contains_expected_props( ) @patch('utils.azure_users.AzureConnection.users') def test_users_response_contains_expected_props( - users_mock, client: FlaskClient, valid_header: dict, + users_mock, + client: FlaskClient, + valid_header: dict, ): users_mock.return_value = [ {'name': 'dummy', 'email': 'dummy', 'roles': ['dummy-role']} @@ -54,7 +58,8 @@ def test_users_response_contains_expected_props( @patch('utils.azure_users.AzureConnection.get_token', Mock()) @patch('utils.azure_users.AzureConnection.update_role') @mark.parametrize( - 'role_id,action', [('test', 'grant'), ('admin', 'revoke')], + 'role_id,action', + [('test', 'grant'), ('admin', 'revoke')], ) def test_update_role_response_contains_expected_props( update_role_mock, @@ -70,7 +75,8 @@ def test_update_role_response_contains_expected_props( 'roles': [], } response = client.post( - f'/users/{user_id}/roles/{role_id}/{action}', headers=valid_header, + f'/users/{user_id}/roles/{role_id}/{action}', + headers=valid_header, ) assert HTTPStatus.OK == response.status_code assert 'name' in json.loads(response.data) @@ -101,10 +107,34 @@ def test_update_role_is_called_properly_on_each_action( ): update_role_mock.return_value = {} response = client.post( - f'/users/{user_id}/roles/{role_id}/{action}', headers=valid_header, + f'/users/{user_id}/roles/{role_id}/{action}', + headers=valid_header, ) assert HTTPStatus.OK == response.status_code update_role_mock.assert_called_once_with( user_id, role_id, is_grant=is_grant ) + + +@patch('utils.azure_users.AzureConnection.get_msal_client', Mock()) +@patch('utils.azure_users.AzureConnection.get_token', Mock()) +@patch('utils.azure_users.AzureConnection.is_user_in_group') +@mark.parametrize( + 'group_name, expected_value', [('admin', True), ('admin', False)] +) +def test_if_user_is_in_group( + is_user_in_group_mock, + client: FlaskClient, + valid_header: dict, + user_id: str, + group_name, + expected_value, +): + is_user_in_group_mock.return_value = {'value': expected_value} + response = client.get( + f'/users/{user_id}/groups/{group_name}/is-member-of', + headers=valid_header, + ) + assert HTTPStatus.OK == response.status_code + assert 'value' in json.loads(response.data) diff --git a/tests/utils/azure_users_test.py b/tests/utils/azure_users_test.py index 07ed0191..ca07d51f 100644 --- a/tests/utils/azure_users_test.py +++ b/tests/utils/azure_users_test.py @@ -14,7 +14,10 @@ ], ) def test_azure_connection_is_test_user( - get_mock, field_name, field_value, is_test_user_expected_value, + get_mock, + field_name, + field_value, + is_test_user_expected_value, ): response_mock = Mock() response_mock.status_code = 200 @@ -33,7 +36,12 @@ def test_azure_connection_get_test_user_ids(get_mock): response_mock = Mock() response_mock.status_code = 200 response_mock.json = Mock( - return_value={'value': [{'objectId': 'ID1'}, {'objectId': 'ID2'},]} + return_value={ + 'value': [ + {'objectId': 'ID1'}, + {'objectId': 'ID2'}, + ] + } ) get_mock.return_value = response_mock @@ -56,3 +64,42 @@ def test_azure_connection_get_non_test_users( non_test_users = [non_test_user] az_conn = AzureConnection() assert az_conn.get_non_test_users() == non_test_users + + +@patch('utils.azure_users.AzureConnection.get_msal_client', Mock()) +@patch('utils.azure_users.AzureConnection.get_token', Mock()) +@patch('requests.get') +def test_azure_connection_get_group_id_by_group_name(get_mock): + response_mock = Mock() + response_mock.status_code = 200 + response_mock.json = Mock(return_value={'value': [{'objectId': 'ID1'}]}) + get_mock.return_value = response_mock + + group_id = 'ID1' + azure_connection = AzureConnection() + assert ( + azure_connection.get_group_id_by_group_name('group_name') == group_id + ) + + +@patch('utils.azure_users.AzureConnection.get_msal_client', Mock()) +@patch('utils.azure_users.AzureConnection.get_token', Mock()) +@patch('utils.azure_users.AzureConnection.get_group_id_by_group_name') +@patch('requests.post') +@mark.parametrize('expected_value', [True, False]) +def test_is_user_in_group( + post_mock, get_group_id_by_group_name_mock, expected_value +): + response_expected = {'value': expected_value} + response_mock = Mock() + response_mock.status_code = 200 + response_mock.json = Mock(return_value=response_expected) + post_mock.return_value = response_mock + + get_group_id_by_group_name_mock.return_value = 'group_id' + + azure_connection = AzureConnection() + assert ( + azure_connection.is_user_in_group('user_id', 'group_name') + == response_expected + ) diff --git a/time_tracker_api/users/users_namespace.py b/time_tracker_api/users/users_namespace.py index e822c7e1..9dfe60f7 100644 --- a/time_tracker_api/users/users_namespace.py +++ b/time_tracker_api/users/users_namespace.py @@ -31,7 +31,12 @@ description='List of the roles assigned to the user by the tenant', ), example=Faker().words( - 3, ['time-tracker-admin', 'test-user', 'guest',], + 3, + [ + 'time-tracker-admin', + 'test-user', + 'guest', + ], ), ), }, @@ -94,3 +99,13 @@ class RevokeRole(Resource): def post(self, user_id, role_id): """Revoke role to user""" return AzureConnection().update_role(user_id, role_id, is_grant=False) + + +@ns.route('//groups//is-member-of') +@ns.param('user_id', 'The user identifier') +@ns.param('group_id', 'The group name identifier') +class UserInGroup(Resource): + @ns.doc('user_in_group') + def get(self, user_id, group_id): + """Is User in the Group""" + return AzureConnection().is_user_in_group(user_id, group_id) diff --git a/utils/azure_users.py b/utils/azure_users.py index 1ae7f0c3..02d8692e 100644 --- a/utils/azure_users.py +++ b/utils/azure_users.py @@ -169,3 +169,35 @@ def get_test_user_ids(self): assert 200 == response.status_code assert 'value' in response.json() return [item['objectId'] for item in response.json()['value']] + + def get_group_id_by_group_name(self, group_name): + endpoint = "{endpoint}/groups?api-version=1.6&$select=objectId&$filter=displayName eq '{group_name}'".format( + endpoint=self.config.ENDPOINT, group_name=group_name + ) + + response = requests.get(endpoint, auth=BearerAuth(self.access_token)) + + assert 200 == response.status_code + + return response.json()['value'][0]['objectId'] + + def is_user_in_group(self, user_id, group_name): + group_id = self.get_group_id_by_group_name(group_name=group_name) + + endpoint = "{endpoint}/isMemberOf?api-version=1.6".format( + endpoint=self.config.ENDPOINT + ) + + data = {"groupId": group_id, "memberId": user_id} + + response = requests.post( + endpoint, + auth=BearerAuth(self.access_token), + data=json.dumps(data), + headers=HTTP_PATCH_HEADERS, + ) + + assert 200 == response.status_code + + item = response.json()['value'] + return {'value': item}