Skip to content

Commit

Permalink
permissions: add can_request_membership
Browse files Browse the repository at this point in the history
  • Loading branch information
fenekku committed Jul 9, 2024
1 parent 51255d1 commit 824760b
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 4 deletions.
22 changes: 21 additions & 1 deletion invenio_communities/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from itertools import chain

from flask_principal import UserNeed
from invenio_access.permissions import any_user, system_process
from invenio_access.permissions import any_user, authenticated_user, system_process
from invenio_records_permissions.generators import Generator
from invenio_search.engine import dsl

Expand Down Expand Up @@ -199,6 +199,26 @@ def query_filter(self, **kwargs):
#
# Community membership generators
#

class AuthenticatedButNotCommunityMembers(Generator):
"""Authenticated user not part of community."""

def needs(self, record=None, **kwargs):
"""Required needs."""
return [authenticated_user]

def excludes(self, record=None, **kwargs):
"""Exluding needs.
Excludes identities with a role in the community. This assumes all roles at
this point mean valid memberships. This is the same assumption as
`CommunityMembers` below.
"""
if not record:
return []
community_id = str(record.id)
return [CommunityRoleNeed(community_id, r.name) for r in current_roles]

class CommunityRoles(Generator):
"""Base class for community roles generators."""

Expand Down
19 changes: 18 additions & 1 deletion invenio_communities/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from .generators import (
AllowedMemberTypes,
AuthenticatedButNotCommunityMembers,
CommunityCurators,
CommunityManagers,
CommunityManagersForRole,
Expand Down Expand Up @@ -179,9 +180,25 @@ class CommunityPermissionPolicy(BasePermissionPolicy):
# Permissions to set if communities can have children
can_manage_children = [SystemProcess()]

# Permission for assinging a parent community
# Permission for assigning a parent community
can_manage_parent = [Administration(), SystemProcess()]

# request_membership permission is based on configuration, community settings and
# identity. Other factors (e.g., previous membership requests) are not under
# its purview and are dealt with elsewhere.
can_request_membership = [
IfConfig(
"COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS",
then_=[
IfPolicyClosed(
"member_policy",
then_=[Disable()],
else_=[AuthenticatedButNotCommunityMembers()]
)
],
else_=[Disable()]
),
]

def can_perform_action(community, context):
"""Check if the given action is available on the request."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
{%- from "invenio_communities/details/macros/access-status-label.html" import access_status_label -%}

{% macro button_to_request_membership(community) %}
{# TODO: replace by permission check when permissions implemented #}
{% if config.COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS %}
{% if permissions.can_request_membership %}
{# TODO: Add relation_to_community for other flows #}
<div
id="request-membership-app"
data-community='{{ community | tojson }}'
Expand Down
1 change: 1 addition & 0 deletions invenio_communities/views/communities.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
"search_requests",
"members_search_public",
"moderate",
"request_membership",
}

PRIVATE_PERMISSIONS = HEADER_PERMISSIONS | {
Expand Down
63 changes: 63 additions & 0 deletions tests/communities/test_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 Northwestern University.
#
# Invenio-RDM-Records is free software; you can redistribute it
# and/or modify it under the terms of the MIT License; see LICENSE file for
# more details.

"""Test permissions."""

from invenio_communities.permissions import CommunityPermissionPolicy


def test_can_request_membership(
app, community, owner, anon_identity, any_user, superuser_identity
):

policy = CommunityPermissionPolicy
community_record = community._record
authenticated_identity = any_user.identity

allow_membership_requests_orig = app.config["COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS"]

# Case - feature disabled
app.config["COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS"] = False
assert not (
policy(action="request_membership", record=community_record).allows(
superuser_identity
)
)

app.config["COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS"] = True

# Case - setting disabled
community_record.access.member_policy = "closed"
assert not (
policy(action="request_membership", record=community_record).allows(
superuser_identity
)
)

community_record.access.member_policy = "open"

# Case - unlogged user
assert not (
policy(action="request_membership", record=community_record).allows(
anon_identity
)
)

# Case - logged user not part of community
assert policy(action="request_membership", record=community_record).allows(
authenticated_identity
)

# Case - member of community
assert not (
policy(action="request_membership", record=community_record).allows(
owner.identity
)
)

app.config["COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS"] = allow_membership_requests_orig

0 comments on commit 824760b

Please sign in to comment.