Skip to content

Commit

Permalink
Add actions to group membership APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
seanh committed Nov 23, 2024
1 parent 702c89e commit cd86e36
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 16 deletions.
41 changes: 39 additions & 2 deletions h/presenters/group_membership_json.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
from h.models import GroupMembershipRoles
from h.security import Permission
from h.traversal.group_membership import (
EditGroupMembershipContext,
GroupMembershipContext,
)


class GroupMembershipJSONPresenter:
def __init__(self, membership):
def __init__(self, request, membership, authenticated_roles=None):
self.request = request
self.membership = membership
self.authenticated_roles = authenticated_roles

def asdict(self):
return {
membership_dict = {
"authority": self.membership.group.authority,
"userid": self.membership.user.userid,
"username": self.membership.user.username,
"display_name": self.membership.user.display_name,
"roles": self.membership.roles,
"actions": [],
}

if self.request.has_permission(
Permission.Group.MEMBER_REMOVE,
GroupMembershipContext(
self.membership.group,
self.membership.user,
self.membership,
self.authenticated_roles,
),
):
membership_dict["actions"].append("delete")

for role in GroupMembershipRoles:
if self.request.has_permission(
Permission.Group.MEMBER_EDIT,
EditGroupMembershipContext(
self.membership.group,
self.membership.user,
self.membership,
role,
self.authenticated_roles,
),
):
membership_dict["actions"].append(f"updates.roles.{role}")

return membership_dict
28 changes: 17 additions & 11 deletions h/security/predicates.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,17 +185,19 @@ def group_matches_authenticated_client_authority(identity, context):

@requires(authenticated_user, group_found)
def group_member_remove(identity, context: GroupMembershipContext):
def get_authenticated_users_membership():
"""Return the authenticated users membership in the target group."""
def get_authenticated_users_roles():
"""Return the authenticated users roles in the target group."""
for membership in identity.user.memberships:
if membership.group.id == context.group.id:
return membership
return membership.roles

return None

membership = get_authenticated_users_membership()
authenticated_users_roles = (
context.authenticated_roles or get_authenticated_users_roles()
)

if not membership:
if not authenticated_users_roles:
# You can't remove anyone from a group you're not a member of.
return False

Expand All @@ -205,17 +207,19 @@ def get_authenticated_users_membership():

if "owner" in context.membership.roles or "admin" in context.membership.roles:
# Only owners can remove other owners.
return "owner" in membership.roles
return "owner" in authenticated_users_roles

if "moderator" in context.membership.roles:
# Owners and admins can remove moderators.
return "owner" in membership.roles or "admin" in membership.roles
return (
"owner" in authenticated_users_roles or "admin" in authenticated_users_roles
)

# Owners, admins and moderators can remove plain members.
return (
"owner" in membership.roles
or "admin" in membership.roles
or "moderator" in membership.roles
"owner" in authenticated_users_roles
or "admin" in authenticated_users_roles
or "moderator" in authenticated_users_roles
)


Expand All @@ -234,7 +238,9 @@ def get_authenticated_users_roles():

return None

authenticated_users_roles = get_authenticated_users_roles()
authenticated_users_roles = (
context.authenticated_roles or get_authenticated_users_roles()
)

if not authenticated_users_roles:
return False
Expand Down
2 changes: 2 additions & 0 deletions h/traversal/group_membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class GroupMembershipContext:
group: Group
user: User
membership: GroupMembership | None
authenticated_roles: list[GroupMembershipRoles] | None = None


@dataclass
Expand All @@ -19,6 +20,7 @@ class EditGroupMembershipContext:
user: User
membership: GroupMembership
new_roles: list[GroupMembershipRoles]
authenticated_roles: list[GroupMembershipRoles] | None = None


def group_membership_api_factory(request) -> GroupMembershipContext:
Expand Down
6 changes: 3 additions & 3 deletions h/views/api/group_members.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
description="Fetch a list of all members of a group",
permission=Permission.Group.READ,
)
def list_members(context: GroupContext, _request):
def list_members(context: GroupContext, request):
return [
GroupMembershipJSONPresenter(membership).asdict()
GroupMembershipJSONPresenter(request, membership).asdict()
for membership in context.group.memberships
]

Expand Down Expand Up @@ -90,4 +90,4 @@ def edit_member(context: GroupMembershipContext, request):
old_roles,
)

return GroupMembershipJSONPresenter(context.membership).asdict()
return GroupMembershipJSONPresenter(request, context.membership, new_roles).asdict()

0 comments on commit cd86e36

Please sign in to comment.