Skip to content

Commit

Permalink
membership-requests: [#855] 5) segregate invitations and membership r…
Browse files Browse the repository at this point in the history
…equests in search
  • Loading branch information
fenekku committed Jul 11, 2024
1 parent 97ec9d0 commit 6dcc6ae
Show file tree
Hide file tree
Showing 25 changed files with 526 additions and 392 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { parametrize, overrideStore } from "react-overridable";
import { createSearchAppInit } from "@js/invenio_search_ui";
import { DropdownSort } from "@js/invenio_search_ui/components";
import { i18next } from "@translations/invenio_communities/i18next";
import { RequestAcceptButton, RequestDeclineButton } from "@js/invenio_requests/components/Buttons";

Check failure on line 14 in invenio_communities/assets/semantic-ui/js/invenio_communities/members/membership_requests/index.js

View workflow job for this annotation

GitHub Actions / Tests (3.9, postgresql14, opensearch2)

Replace `·RequestAcceptButton,·RequestDeclineButton·` with `⏎··RequestAcceptButton,⏎··RequestDeclineButton,⏎`

Check failure on line 14 in invenio_communities/assets/semantic-ui/js/invenio_communities/members/membership_requests/index.js

View workflow job for this annotation

GitHub Actions / Tests (3.10, postgresql14, opensearch2)

Replace `·RequestAcceptButton,·RequestDeclineButton·` with `⏎··RequestAcceptButton,⏎··RequestDeclineButton,⏎`

Check failure on line 14 in invenio_communities/assets/semantic-ui/js/invenio_communities/members/membership_requests/index.js

View workflow job for this annotation

GitHub Actions / Tests (3.11, postgresql14, opensearch2)

Replace `·RequestAcceptButton,·RequestDeclineButton·` with `⏎··RequestAcceptButton,⏎··RequestDeclineButton,⏎`

Check failure on line 14 in invenio_communities/assets/semantic-ui/js/invenio_communities/members/membership_requests/index.js

View workflow job for this annotation

GitHub Actions / Tests (3.12, postgresql14, opensearch2)

Replace `·RequestAcceptButton,·RequestDeclineButton·` with `⏎··RequestAcceptButton,⏎··RequestDeclineButton,⏎`
import {
RequestAcceptModalTrigger,
RequestDeclineModalTrigger,
Expand Down Expand Up @@ -73,6 +74,8 @@ const defaultComponents = {
// The RequestModalTriggers are generic enough to be reused here
"RequestActionModalTrigger.accept": RequestAcceptModalTrigger,
"RequestActionModalTrigger.decline": RequestDeclineModalTrigger,
"RequestActionButton.accept": RequestAcceptButton,
"RequestActionButton.decline": RequestDeclineButton,
"RequestStatus.layout.submitted": SubmitStatus,
"RequestStatus.layout.deleted": DeleteStatus,
"RequestStatus.layout.accepted": AcceptStatus,
Expand Down
4 changes: 3 additions & 1 deletion invenio_communities/communities/services/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ class CommunityServiceConfig(RecordServiceConfig, ConfiguratorMixin):
"invitations": CommunityLink("{+api}/communities/{id}/invitations"),
"requests": CommunityLink("{+api}/communities/{id}/requests"),
"records": CommunityLink("{+api}/communities/{id}/records"),
"membership_requests": CommunityLink("{+api}/communities/{id}/membership-requests"), # noqa
"membership_requests": CommunityLink(
"{+api}/communities/{id}/membership-requests"
),
}

action_link = CommunityLink(
Expand Down
2 changes: 1 addition & 1 deletion invenio_communities/communities/services/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def search_community_requests(
dsl.Q("term", **{"receiver.community": community_id}),
~dsl.Q("term", **{"status": "created"}),
# Excluding explicitly for now
~dsl.Q("term", **{"type": "community-membership-request"})
~dsl.Q("term", **{"type": "community-membership-request"}),
],
),
**kwargs,
Expand Down
4 changes: 2 additions & 2 deletions invenio_communities/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"invitations": "/communities/<pid_value>/invitations",
"about": "/communities/<pid_value>/about",
"curation_policy": "/communities/<pid_value>/curation-policy",
"membership_requests": "/communities/<pid_value>/membership-requests"
"membership_requests": "/communities/<pid_value>/membership-requests",
}

"""Communities ui endpoints."""
Expand Down Expand Up @@ -341,5 +341,5 @@
COMMUNITIES_ALWAYS_SHOW_CREATE_LINK = False
"""Controls visibility of 'New Community' btn based on user's permission when set to True."""

COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS = False
COMMUNITIES_ALLOW_MEMBERSHIP_REQUESTS = True
"""Feature flag for membership request."""
7 changes: 7 additions & 0 deletions invenio_communities/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ def init_app(self, app):
self.init_hooks(app)
self.init_cache(app)

# TMP ADDITIONS
@app.context_processor
def inject_variables():
# Get all variables in the template context
# variables = {key: value for key, value in g.items()}
return {'template_variables': app.jinja_env}

def init_config(self, app):
"""Initialize configuration.
Expand Down
6 changes: 4 additions & 2 deletions invenio_communities/members/records/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2022 Northwestern University.
# Copyright (C) 2024 Northwestern University.
# Copyright (C) 2022 CERN.
# Copyright (C) 2022 Graz University of Technology.
#
Expand All @@ -22,11 +22,13 @@
from sqlalchemy import or_, select

from ..errors import InvalidMemberError
from .dumpers import RequestTypeDumperExt
from .models import ArchivedInvitationModel, MemberModel

relations_dumper = SearchDumper(
extensions=[
RelationDumperExt("relations"),
RequestTypeDumperExt(),
IndexedAtDumperExt(),
]
)
Expand Down Expand Up @@ -86,7 +88,7 @@ class MemberMixin:
Request,
"request_id",
"request",
attrs=["status", "expires_at", "is_open"],
attrs=["status", "expires_at", "is_open", "type"],
),
)

Expand Down
35 changes: 35 additions & 0 deletions invenio_communities/members/records/dumpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 Northwestern University.
#
# Invenio-Communities is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""Secondary storage (ES/OS) dumpers."""

from invenio_records.dictutils import dict_lookup, dict_set
from invenio_records.dumpers.search import SearchDumperExt


class RequestTypeDumperExt(SearchDumperExt):
"""Dumper for the relations.request.type field."""

def __init__(self):
"""Initialize the dumper."""
self.key = "relations.request.type"

def dump(self, record, data):
"""Dump relations."""
try: # In case no associated request type
request_type = dict_lookup(record, "request.type")
# Serialize back RequestType to its identifier only
dict_set(data, "request.type", request_type.type_id)
except KeyError:
return

def load(self, data, record_cls):
"""Load relations.request.type.
TODO: Works without it for now. Potentially revisit?
"""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"is_open": {
"type": "boolean"
},
"type": {
"type": "keyword"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"is_open": {
"type": "boolean"
},
"type": {
"type": "keyword"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"is_open": {
"type": "boolean"
},
"type": {
"type": "keyword"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"is_open": {
"type": "boolean"
},
"type": {
"type": "keyword"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"is_open": {
"type": "boolean"
},
"type": {
"type": "keyword"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"is_open": {
"type": "boolean"
},
"type": {
"type": "keyword"
}
}
},
Expand Down
5 changes: 3 additions & 2 deletions invenio_communities/members/resources/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ def create_url_rules(self):
route("PUT", routes["invitations"], self.update_invitations),
route("GET", routes["invitations"], self.search_invitations),
route("POST", routes["membership_requests"], self.request_membership),
route("GET", routes["membership_requests"],
self.search_membership_requests),
route(
"GET", routes["membership_requests"], self.search_membership_requests
),
]

@request_view_args
Expand Down
16 changes: 11 additions & 5 deletions invenio_communities/members/services/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
from ..records.api import ArchivedInvitation
from . import facets
from .components import CommunityMemberCachingComponent
from .schemas import MemberEntitySchema
from .links import LinksForActionsOfMember, LinksForRequestActionsOfMember
from .schemas import MemberEntitySchema


class PublicSearchOptions(SearchOptions):
Expand Down Expand Up @@ -184,13 +184,19 @@ class MemberServiceConfig(RecordServiceConfig, ConfiguratorMixin):
search_invitations = InvitationsSearchOptions

links_item = {
"actions": LinksForActionsOfMember([
LinksForRequestActionsOfMember("{+api}/requests/{request_id}/actions/{action}"), # noqa
])
"actions": LinksForActionsOfMember(
[
LinksForRequestActionsOfMember(
"{+api}/requests/{request_id}/actions/{action}"
),
]
)
}

# ResultList configurations
links_search = pagination_links("{+api}/communities/{community_id}/{endpoint}{?args*}") # noqa
links_search = pagination_links(
"{+api}/communities/{community_id}/{endpoint}{?args*}"
)

# Service components
components = [
Expand Down
16 changes: 6 additions & 10 deletions invenio_communities/members/services/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# Invenio-Communities is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""Links generation for the members service."""

from invenio_records_resources.services.base.links import Link, LinksTemplate
from invenio_requests.customizations import RequestActions
from invenio_requests.proxies import current_requests_service
Expand Down Expand Up @@ -110,7 +112,6 @@ def _get_created_by(self, obj):
creator_ref_type = self.type.allowed_creator_ref_types[0]
return self._get_proxy_by_ref_type(creator_ref_type, obj)


def _get_receiver(self, obj):
"""Set the receiver field.
Expand Down Expand Up @@ -143,9 +144,7 @@ def _get_proxy_by_ref_type(self, ref_type, obj):
)
elif ref_type == "user":
# This *creates* an entity proxy contrary to the name
return ResolverRegistry.resolve_entity_proxy(
{"user": obj.user_id}
)
return ResolverRegistry.resolve_entity_proxy({"user": obj.user_id})
else:
# again mostly for developers to be alerted
raise Exception("ref_type is unknown!")
Expand Down Expand Up @@ -206,12 +205,7 @@ def _vars_func(self, request, vars):
:param request: RequestLike
:param vars: dict of contextual values
"""
vars.update(
{
"action": self.action,
"request_id": request.id
}
)
vars.update({"action": self.action, "request_id": request.id})

def should_render(self, request, context):
"""Determine if the link should render."""
Expand All @@ -222,7 +216,9 @@ def should_render(self, request, context):
action_for_permission,
request=request,
)
# fmt: off
return (
RequestActions.can_execute(request, action_for_execute)
and permission.allows(identity)
)
# fmt: on
8 changes: 7 additions & 1 deletion invenio_communities/members/services/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def service():
"""Service."""
return current_communities.service.members


#
# CommunityInvitation: actions and request type
#
Expand Down Expand Up @@ -141,23 +142,28 @@ class CancelMembershipRequestAction(actions.CancelAction):
def execute(self, identity, uow):
"""Execute action."""
service().close_membership_request(system_identity, self.request.id, uow=uow)
# TODO: Investigate notifications
# TODO: Notification flow: Investigate notifications
super().execute(identity, uow)


class AcceptMembershipRequestAction(actions.AcceptAction):
"""Accept membership request action."""

def execute(self, identity, uow):
"""Execute action."""
# TODO: Decision flow: Implement me
pass


class DeclineMembershipRequestAction(actions.DeclineAction):
"""Decline membership request action."""

def execute(self, identity, uow):
"""Execute action."""
# TODO: Decision flow: Implement me
pass


class MembershipRequestRequestType(RequestType):
"""Request type for membership requests."""

Expand Down
10 changes: 10 additions & 0 deletions invenio_communities/members/services/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class RequestSchema(Schema):
# because the relations field doesn't properly load data from the index
# (it should have converted expires_at into a datetime object).
expires_at = fields.String()
type = fields.String()


#
Expand Down Expand Up @@ -225,3 +226,12 @@ def get_permissions(self, obj):
member=obj,
),
}


class MembershipRequestDumpSchema(MemberDumpSchema):
"""Schema for dumping membership requests.
TODO: Decision flow: Investigate if can be merged with InvitationDumpSchema
"""

request = fields.Nested(RequestSchema)
Loading

0 comments on commit 6dcc6ae

Please sign in to comment.