Skip to content
Open
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
51 changes: 45 additions & 6 deletions fossology/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Groups:
"""Class dedicated to all "groups" related endpoints"""

def list_groups(self, deletable: bool = False) -> list[Group]:

"""Get the list of groups (accessible groups for user, all groups for admin)

If parameter deletable is True, the method will return only deletable groups.
Expand Down Expand Up @@ -63,7 +64,7 @@ def list_group_members(self, group_id: int) -> list[UserGroupMember]:
description = f"Unable to get a list of members for group {group_id}"
raise FossologyApiError(description, response)

def create_group(self, name: str):
def create_group(self, name: str) -> None:
"""Create a group

API Endpoint: POST /groups
Expand All @@ -81,8 +82,8 @@ def create_group(self, name: str):
description = f"Group {name} already exists, failed to create group or no group name provided"
raise FossologyApiError(description, response)

def delete_group(self, group_id: int):
"""Create a group
def delete_group(self, group_id: int) -> None:
"""Delete a group

API Endpoint: DELETE /groups/{group_id}

Expand All @@ -100,7 +101,7 @@ def delete_group(self, group_id: int):

def add_group_member(
self, group_id: int, user_id: int, perm: MemberPerm = MemberPerm.USER
):
) -> None:
"""Add a user to a group

API Endpoint: POST /groups/{group_id}/user/{user_id}
Expand Down Expand Up @@ -128,7 +129,45 @@ def add_group_member(
)
raise FossologyApiError(description, response)

def delete_group_member(self, group_id: int, user_id: int):
def change_group_member_permission(
self, group_id: int, user_id: int, perm: MemberPerm
) -> None:
"""Change the permission of a user in a group

API Endpoint: PATCH /groups/{group_id}/user/{user_id}

:param group_id: the id of the group
:param user_id: the id of the user
:param perm: the new permission level for the user
:type group_id: int
:type user_id: int
:type perm: MemberPerm
:raises FossologyApiError: if the REST call failed
"""
data = {"perm": perm.value}
response = self.session.patch(
f"{self.api}/groups/{group_id}/user/{user_id}", json=data
)
if response.status_code == 200:
logger.info(
f"Permission of user {user_id} in group {group_id} has been updated to {perm.name}."
)
elif response.status_code == 400:
description = f"Validation error while changing permission of user {user_id} in group {group_id}."
raise FossologyApiError(description, response)
elif response.status_code == 403:
description = f"Not authorized to change permission of user {user_id} in group {group_id}."
raise FossologyApiError(description, response)
elif response.status_code == 404:
description = f"User {user_id} or group {group_id} not found."
raise FossologyApiError(description, response)
else:
description = (
f"An error occurred while changing permission of user {user_id} in group {group_id}"
)
raise FossologyApiError(description, response)

def delete_group_member(self, group_id: int, user_id: int) -> None:
"""Delete a user from a group

API Endpoint: DELETE /groups/{group_id}/user/{user_id}
Expand All @@ -152,4 +191,4 @@ def delete_group_member(self, group_id: int, user_id: int):
description = (
f"An error occurred while deleting user {user_id} from group {group_id}"
)
raise FossologyApiError(description, response)
raise FossologyApiError(description, response)
10 changes: 5 additions & 5 deletions fossology/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class Users:
"""Class dedicated to all "users" related endpoints"""

def detail_user(self, user_id):
def detail_user(self, user_id: int) -> "User":
"""Get details of Fossology user.

API Endpoint: GET /users/{id}
Expand All @@ -38,7 +38,7 @@ def detail_user(self, user_id):
description = f"Error while getting details for user {user_id}"
raise FossologyApiError(description, response)

def list_users(self):
def list_users(self) -> list:
"""List all users from the Fossology instance

API Endpoint: GET /users
Expand All @@ -64,7 +64,7 @@ def list_users(self):
description = f"Unable to get a list of users from {self.host}" # type: ignore
raise FossologyApiError(description, response)

def create_user(self, user_spec):
def create_user(self, user_spec: dict) -> None:
"""Create a new Fossology user

API Endpoint: POST /users
Expand Down Expand Up @@ -114,7 +114,7 @@ def create_user(self, user_spec):
description = f"Error while creating user {user_spec['name']}"
raise FossologyApiError(description, response)

def delete_user(self, user):
def delete_user(self, user: "User") -> None:
"""Delete a Fossology user.

API Endpoint: DELETE /users/{id}
Expand All @@ -129,4 +129,4 @@ def delete_user(self, user):
return
else:
description = f"Error while deleting user {user.name} ({user.id})"
raise FossologyApiError(description, response)
raise FossologyApiError(description, response)
90 changes: 90 additions & 0 deletions tests/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,93 @@ def test_delete_group_member_if_group_does_not_exists_raises_fossology_api_error
with pytest.raises(FossologyApiError) as excinfo:
foss.delete_group_member(42, created_foss_user.id)
assert f"Member {created_foss_user.id} or group 42 not found." in str(excinfo.value)


@responses.activate
def test_change_group_member_permission_validation_error(
foss_server: str, foss: fossology.Fossology
):
responses.add(
responses.PATCH, f"{foss_server}/api/v1/groups/42/user/42", status=400
)
with pytest.raises(FossologyApiError) as excinfo:
foss.change_group_member_permission(42, 42, MemberPerm.ADMIN)
assert "Validation error while changing permission of user 42 in group 42." in str(
excinfo.value
)


@responses.activate
def test_change_group_member_permission_not_authorized(
foss_server: str, foss: fossology.Fossology
):
responses.add(
responses.PATCH, f"{foss_server}/api/v1/groups/42/user/42", status=403
)
with pytest.raises(FossologyApiError) as excinfo:
foss.change_group_member_permission(42, 42, MemberPerm.ADMIN)
assert "Not authorized to change permission of user 42 in group 42." in str(
excinfo.value
)


@responses.activate
def test_change_group_member_permission_not_found(
foss_server: str, foss: fossology.Fossology
):
responses.add(
responses.PATCH, f"{foss_server}/api/v1/groups/42/user/42", status=404
)
with pytest.raises(FossologyApiError) as excinfo:
foss.change_group_member_permission(42, 42, MemberPerm.ADMIN)
assert "User 42 or group 42 not found." in str(excinfo.value)


@responses.activate
def test_change_group_member_permission_server_error(
foss_server: str, foss: fossology.Fossology
):
responses.add(
responses.PATCH, f"{foss_server}/api/v1/groups/42/user/42", status=500
)
with pytest.raises(FossologyApiError) as excinfo:
foss.change_group_member_permission(42, 42, MemberPerm.ADMIN)
assert "An error occurred while changing permission of user 42 in group 42" in str(
excinfo.value
)


@pytest.mark.xfail(
reason="PATCH /groups/{id}/user/{id} is not yet available in FOSSology API v1 server",
raises=FossologyApiError,
strict=True,
)
def test_change_group_member_permission(
foss: fossology.Fossology,
created_foss_user: User,
monkeypatch: pytest.MonkeyPatch,
):
mocked_logger = Mock()
monkeypatch.setattr("fossology.groups.logger", mocked_logger)
name = secrets.token_urlsafe(8)
foss.create_group(name)
group = get_group(foss, name)
foss.add_group_member(group.id, created_foss_user.id, MemberPerm.USER)

# Change permission from USER to ADMIN
foss.change_group_member_permission(group.id, created_foss_user.id, MemberPerm.ADMIN)
assert (
call(
f"Permission of user {created_foss_user.id} in group {group.id} has been updated to ADMIN."
)
in mocked_logger.info.mock_calls
)

# Verify the new permission is reflected
members = foss.list_group_members(group.id)
for member in members:
if member.user.id == created_foss_user.id:
assert member.group_perm == MemberPerm.ADMIN.value

# Cleanup
foss.delete_group(group.id)
Loading