Skip to content

Commit

Permalink
membership-request [inveniosoftware#855]: implement expiration flow
Browse files Browse the repository at this point in the history
  • Loading branch information
fenekku committed Jul 30, 2024
1 parent 1550a91 commit a9a615a
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 20 deletions.
7 changes: 5 additions & 2 deletions invenio_communities/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,11 @@
}
"""Available membership requests sort options."""

COMMUNITIES_INVITATIONS_EXPIRES_IN = timedelta(days=30)
""""Default amount of time before an invitation expires."""
COMMUNITIES_MEMBER_REQUESTS_EXPIRE_IN = timedelta(days=30)
""""Default amount of time before a member request expires.
Replaces COMMUNITIES_INVITATIONS_EXPIRES_IN .
"""

COMMUNITIES_LOGO_MAX_FILE_SIZE = 10**6
"""Community logo size quota, in bytes."""
Expand Down
13 changes: 12 additions & 1 deletion invenio_communities/members/services/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,17 @@ def execute(self, identity, uow):
super().execute(identity, uow)


# TODO: Expiration flow: ExpireAction
class ExpireMembershipRequestAction(actions.ExpireAction):
"""Expire membership request action.
Triggered by task in invenio-requests.
"""

def execute(self, identity, uow):
"""Execute action."""
service().close_member_request(system_identity, self.request.id, uow=uow)
# TODO: Notification flow: Investigate notifications
super().execute(identity, uow)


class AcceptMembershipRequestAction(actions.AcceptAction):
Expand All @@ -181,6 +191,7 @@ class MembershipRequestRequestType(RequestType):
"cancel": CancelMembershipRequestAction,
"accept": AcceptMembershipRequestAction,
"decline": DeclineMembershipRequestAction,
"expire": ExpireMembershipRequestAction,
}

creator_can_be_none = False
Expand Down
4 changes: 1 addition & 3 deletions invenio_communities/members/services/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,4 @@ def get_permissions(self, obj):
community_id=obj.community_id,
member=obj,
)
return {
"can_update_role": is_open and can_update
}
return {"can_update_role": is_open and can_update}
25 changes: 15 additions & 10 deletions invenio_communities/members/services/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""Members service."""

from datetime import datetime, timezone
from warnings import warn

from flask import current_app
from invenio_access.permissions import system_identity
Expand Down Expand Up @@ -52,12 +53,18 @@
)


def invite_expires_at():
"""Get the invitation expiration date."""
return (
datetime.utcnow().replace(tzinfo=timezone.utc)
+ current_app.config["COMMUNITIES_INVITATIONS_EXPIRES_IN"]
)
def member_request_expires_at():
"""Get the request expiration date."""
expires_in_delta = current_app.config.get("COMMUNITIES_INVITATIONS_EXPIRES_IN")
if expires_in_delta:
# Deprecated
# TODO: Remove deprecation warning in v14
warn(
"COMMUNITIES_INVITATIONS_EXPIRES_IN is deprecated. Use COMMUNITIES_MEMBER_REQUESTS_EXPIRE_IN instead.", # noqa
DeprecationWarning,
)
expires_in_delta = current_app.config["COMMUNITIES_MEMBER_REQUESTS_EXPIRE_IN"]
return datetime.now(tz=timezone.utc) + expires_in_delta


class MemberService(RecordService):
Expand Down Expand Up @@ -712,7 +719,7 @@ def _invite_factory(self, identity, community, role, visible, member, message, u
# TODO: perhaps topic should be the actual membership record
# instead
topic=community,
expires_at=invite_expires_at(),
expires_at=member_request_expires_at(),
uow=uow,
)

Expand Down Expand Up @@ -811,14 +818,12 @@ def request_membership(self, identity, community_id, data, uow=None):
identity,
data={
"title": title,
# "description": description,
},
request_type=MembershipRequestRequestType,
receiver=community,
creator={"user": str(identity.user.id)},
topic=community, # user instead?
# TODO: Expiration flow: Consider expiration
# expires_at=invite_expires_at(),
expires_at=member_request_expires_at(),
uow=uow,
)

Expand Down
4 changes: 1 addition & 3 deletions tests/members/test_members_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ def test_get_membership_requests(
assert "id" in hit["request"]
assert "status" in hit["request"]
assert "expires_at" in hit["request"]
assert hit["request"]["expires_at"] is not None
# hits > hit > links
request_id = hit["request"]["id"]
expected_links = {
Expand All @@ -478,6 +479,3 @@ def test_get_membership_requests(
assert expected_links == hit["links"]
# hits > hit > permissions
assert hit["permissions"]["can_update_role"] is True

# TODO: Expiration flow : assess if expiration makes sense for membership requests.
# assert hit["request"]["expires_at"] is not None
44 changes: 43 additions & 1 deletion tests/members/test_members_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,7 @@ def test_request_membership_accept_flow(
request = requests_service.execute_action(
owner.identity, membership_request.id, "accept"
).to_dict()
ArchivedInvitation.index.refresh() # switch name?
ArchivedInvitation.index.refresh()
Member.index.refresh()

# Postconditions
Expand All @@ -1362,6 +1362,48 @@ def test_request_membership_accept_flow(
assert hit["request"]["is_open"] is False


def test_request_membership_expire_flow(
member_service,
community,
owner,
create_user,
requests_service,
db,
clean_index,
):
# Create membership request
user = create_user()
data = {
"message": "Can I join the club?",
}
community_uuid = community._record.id
membership_request = member_service.request_membership(
user.identity,
community_uuid,
data,
)

# Expire request
request = requests_service.execute_action(
system_identity, membership_request.id, "expire"
).to_dict()
ArchivedInvitation.index.refresh()
Member.index.refresh()

# Postconditions
# 1 member, the owner
res = member_service.search(owner.identity, community_uuid)
assert 1 == res.to_dict()["hits"]["total"]

# 1 "request", the expired membership request
res = member_service.search_membership_requests(owner.identity, community_uuid)
hits = res.to_dict()["hits"]
assert 1 == hits["total"]
hit = hits["hits"][0]
assert "expired" == hit["request"]["status"]
assert hit["request"]["is_open"] is False


#
# Change notifications
#
Expand Down

0 comments on commit a9a615a

Please sign in to comment.