Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions tests/time_tracker_api/users/users_namespace_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,45 @@ def test_if_user_is_in_group(
)
assert HTTPStatus.OK == response.status_code
assert 'value' in json.loads(response.data)


@patch('utils.azure_users.AzureConnection.get_msal_client', Mock())
@patch('utils.azure_users.AzureConnection.get_token', Mock())
@patch('utils.azure_users.AzureConnection.add_user_to_group')
def test_add_to_group(
add_user_to_group_mock,
client: FlaskClient,
valid_header: dict,
user_id: str,
):

add_user_to_group_mock.return_value = {}
valid_data = {'group_name': 'dummy_group'}

response = client.post(
f'/users/{user_id}/groups/add', headers=valid_header, json=valid_data
)
assert HTTPStatus.OK == response.status_code
add_user_to_group_mock.assert_called_once()


@patch('utils.azure_users.AzureConnection.get_msal_client', Mock())
@patch('utils.azure_users.AzureConnection.get_token', Mock())
@patch('utils.azure_users.AzureConnection.remove_user_from_group')
def test_remove_from_group(
remove_user_from_group_mock,
client: FlaskClient,
valid_header: dict,
user_id: str,
):

remove_user_from_group_mock.return_value = {}
valid_data = {'group_name': 'dummy_group'}

response = client.post(
f'/users/{user_id}/groups/remove',
headers=valid_header,
json=valid_data,
)
assert HTTPStatus.OK == response.status_code
remove_user_from_group_mock.assert_called_once()
52 changes: 52 additions & 0 deletions tests/utils/azure_users_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,55 @@ def test_get_groups_and_users_called_once_by_instance(
azure_connection.get_groups_by_user_id(user_id)

get_groups_and_users_mock.assert_called_once()


@patch('utils.azure_users.AzureConnection.get_msal_client', Mock())
@patch('utils.azure_users.AzureConnection.get_token', Mock())
@patch('utils.azure_users.AzureConnection.get_user')
@patch('utils.azure_users.AzureConnection.get_group_id_by_group_name')
@patch('requests.post')
def test_add_user_to_group(
post_mock, get_group_id_by_group_name_mock, get_user_mock
):
get_group_id_by_group_name_mock.return_value = 'dummy_group'
test_user = AzureUser('ID1', None, None, [], [])
get_user_mock.return_value = test_user

response_mock = Mock()
response_mock.status_code = 204
post_mock.return_value = response_mock

azure_connection = AzureConnection()
expected_value = azure_connection.add_user_to_group(
'dummy_user_id', 'dummy_group'
)

get_group_id_by_group_name_mock.assert_called_once()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think you can send an assert with the mock of a user in the test that is changing the group? It is optional because I see that if you are testing the methods.

get_user_mock.assert_called_once()
assert expected_value == test_user


@patch('utils.azure_users.AzureConnection.get_msal_client', Mock())
@patch('utils.azure_users.AzureConnection.get_token', Mock())
@patch('utils.azure_users.AzureConnection.get_user')
@patch('utils.azure_users.AzureConnection.get_group_id_by_group_name')
@patch('requests.delete')
def test_remove_user_from_group(
delete_mock, get_group_id_by_group_name_mock, get_user_mock
):
get_group_id_by_group_name_mock.return_value = 'dummy_group'
test_user = AzureUser('ID1', None, None, [], [])
get_user_mock.return_value = test_user

response_mock = Mock()
response_mock.status_code = 204
delete_mock.return_value = response_mock

azure_connection = AzureConnection()
expected_value = azure_connection.remove_user_from_group(
'dummy_user_id', 'dummy_group'
)

get_group_id_by_group_name_mock.assert_called_once()
get_user_mock.assert_called_once()
assert expected_value == test_user
64 changes: 53 additions & 11 deletions time_tracker_api/users/users_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,16 @@
},
)

group_name_field = fields.String(
title='group_name',
max_length=50,
description='Name of the Group',
example=Faker().word(['time-tracker-admin', 'time-tracker-tester']),
)

# Data to check if a user is in the group
user_in_group_input = ns.model(
'UserInGroupInput',
{
'group_name': fields.String(
title='group_name',
max_length=50,
description='Name of the Group to verify',
example=Faker().word(
['time-tracker-admin', 'time-tracker-tester']
),
),
},
'UserInGroupInput', {'group_name': group_name_field},
)

user_in_group_response = ns.model(
Expand Down Expand Up @@ -146,3 +143,48 @@ class UserInGroup(Resource):
def post(self, user_id):
"""Check if user belongs to group"""
return AzureConnection().is_user_in_group(user_id, ns.payload)


add_user_to_group_input = ns.model(
'AddUserToGroupInput', {'group_name': group_name_field},
)


@ns.route('/<string:user_id>/groups/add')
@ns.param('user_id', 'The user identifier')
class AddToGroup(Resource):
@ns.doc('add_to_group')
@ns.expect(add_user_to_group_input)
@ns.marshal_with(user_response_fields)
def post(self, user_id):
"""
Add user to an EXISTING group in the Azure Tenant directory.
Available options for `group_name`:
```
- time-tracker-admin
- time-tracker-tester
```
"""
return AzureConnection().add_user_to_group(
user_id, ns.payload['group_name']
)


remove_user_from_group_input = ns.model(
'RemoveUserFromGroupInput', {'group_name': group_name_field},
)


@ns.route('/<string:user_id>/groups/remove')
@ns.param('user_id', 'The user identifier')
class RemoveFromGroup(Resource):
@ns.doc('remove_from_group')
@ns.expect(remove_user_from_group_input)
@ns.marshal_with(user_response_fields)
def post(self, user_id):
"""
Remove user from an EXISTING group in the Azure Tenant directory.
"""
return AzureConnection().remove_user_from_group(
user_id, ns.payload['group_name']
)
30 changes: 30 additions & 0 deletions utils/azure_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,36 @@ def update_role(self, user_id, role_id, is_grant):

return self.to_azure_user(response.json())

def add_user_to_group(self, user_id, group_name):
group_id = self.get_group_id_by_group_name(group_name)
endpoint = "{endpoint}/groups/{group_id}/$links/members?api-version=1.6".format(
endpoint=self.config.ENDPOINT, group_id=group_id,
)
data = {'url': f'{self.config.ENDPOINT}/directoryObjects/{user_id}'}
response = requests.post(
endpoint,
auth=BearerAuth(self.access_token),
data=json.dumps(data),
headers=HTTP_PATCH_HEADERS,
)
assert 204 == response.status_code

return self.get_user(user_id)

def remove_user_from_group(self, user_id, group_name):
group_id = self.get_group_id_by_group_name(group_name)
endpoint = "{endpoint}/groups/{group_id}/$links/members/{user_id}?api-version=1.6".format(
endpoint=self.config.ENDPOINT, group_id=group_id, user_id=user_id
)
response = requests.delete(
endpoint,
auth=BearerAuth(self.access_token),
headers=HTTP_PATCH_HEADERS,
)
assert 204 == response.status_code

return self.get_user(user_id)

def get_non_test_users(self) -> List[AzureUser]:
test_user_ids = self.get_test_user_ids()
return [user for user in self.users() if user.id not in test_user_ids]
Expand Down