Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subcommunities: add invitation request #1067

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
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
4 changes: 4 additions & 0 deletions invenio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ from zenodo_rdm.queryparser import word_communities, word_doi
from zenodo_rdm.subcommunities import (
ZenodoSubCommunityRequest,
ZenodoSubcommunityRequestSchema,
ZenodoSubCommunityInvitationRequest
)
from zenodo_rdm.tokens import RATSubjectSchema
from zenodo_rdm.views import frontpage_view_function
Expand Down Expand Up @@ -1035,6 +1036,9 @@ COMMUNITIES_SUB_SERVICE_SCHEMA = ZenodoSubcommunityRequestSchema
COMMUNITIES_SUB_REQUEST_CLS = ZenodoSubCommunityRequest
"""Request type for subcommunities."""

COMMUNITIES_SUB_INVITATION_REQUEST_CLS = ZenodoSubCommunityInvitationRequest
"""Request type for subcommunity invitations."""

ANNOSTOR_COMMUNITIES = {}
"""Annostor communities configuration.

Expand Down
3 changes: 2 additions & 1 deletion site/zenodo_rdm/legacy/requests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from invenio_access.permissions import system_identity
from invenio_records.dictutils import dict_lookup
from invenio_records_resources.services.uow import unit_of_work
from invenio_requests import current_request_type_registry, current_requests_service
from invenio_requests import (current_request_type_registry,
current_requests_service)
from invenio_requests.resolvers.registry import ResolverRegistry
from invenio_search.engine import dsl

Expand Down
2 changes: 2 additions & 0 deletions site/zenodo_rdm/subcommunities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
"""Subcommunities implementation."""

from .request import ZenodoSubCommunityRequest
from .request import ZenodoSubCommunityInvitationRequest
from .schema import ZenodoSubcommunityRequestSchema

__all__ = (
"ZenodoSubcommunityRequestSchema",
"ZenodoSubCommunityRequest",
"ZenodoSubCommunityInvitationRequest",
)
147 changes: 127 additions & 20 deletions site/zenodo_rdm/subcommunities/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@
# it under the terms of the MIT License; see LICENSE file for more details.
"""Subcommunities request implementation for ZenodoRDM."""

import invenio_communities.notifications.builders as notifications
from invenio_access.permissions import system_identity
from invenio_communities.proxies import current_communities
from invenio_communities.subcommunities.services.request import (
AcceptSubcommunity,
DeclineSubcommunity,
SubCommunityRequest,
)
from invenio_rdm_records.proxies import (
current_community_records_service,
current_rdm_records,
)
AcceptSubcommunity, AcceptSubcommunityInvitation,
CreateSubcommunityInvitation, DeclineSubcommunity,
DeclineSubcommunityInvitation, SubCommunityInvitationRequest,
SubCommunityRequest)
from invenio_notifications.services.uow import NotificationOp
from invenio_rdm_records.proxies import (current_community_records_service,
current_rdm_records)
from invenio_records_resources.services.uow import RecordCommitOp
from invenio_requests.customizations import actions
from invenio_requests.customizations.event_types import CommentEventType
from invenio_requests.proxies import current_events_service
from marshmallow import fields
from werkzeug.local import LocalProxy

community_service = LocalProxy(lambda: current_communities.service)
carlinmack marked this conversation as resolved.
Show resolved Hide resolved


def _add_community_records(child, parent, uow):
"""Add records from child to parent."""
records = current_community_records_service.search(
system_identity, community_id=child
)
current_rdm_records.record_communities_service.bulk_add(
system_identity, parent, (x["id"] for x in records), uow=uow
)


class SubcommunityAcceptAction(AcceptSubcommunity):
Expand All @@ -29,22 +43,12 @@ class SubcommunityAcceptAction(AcceptSubcommunity):
Zenodo re-implementation of the accept action, to also move the records.
"""

def _get_community_records(self, community_id):
"""Get the records of a community."""
return current_community_records_service.search(
system_identity, community_id=community_id
)

def execute(self, identity, uow):
"""Execute approve action."""
to_be_moved = self.request.topic.resolve().id
move_to = self.request.receiver.resolve().id

# Move records
records = self._get_community_records(to_be_moved)
current_rdm_records.record_communities_service.bulk_add(
system_identity, move_to, (x["id"] for x in records), uow=uow
)
_add_community_records(to_be_moved, move_to, uow)
super().execute(identity, uow)


Expand Down Expand Up @@ -113,8 +117,111 @@ class ZenodoSubCommunityRequest(SubCommunityRequest):

available_actions = {
"delete": actions.DeleteAction,
"create": SubcommunityCreateAction,
"cancel": actions.CancelAction,
# Custom implemented actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean by "custom implemented actions"? custom = only present in zenodo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom meaning that they aren't using the default actions.Action. Comment was added to match invenio-communities
https://github.com/inveniosoftware/invenio-communities/blob/master/invenio_communities/subcommunities/services/request.py#L70

"create": SubcommunityCreateAction,
"accept": SubcommunityAcceptAction,
"decline": DeclineSubcommunity,
}


class SubcommunityInvitationCreateAction(CreateSubcommunityInvitation):
"""Represents an action to create and submit a subcommunity invitation."""

def execute(self, identity, uow):
"""Execute approve action."""
self.request["title"] = "Invitation to join the EU Open Research Repository"

# example: "May 11, 2024"
expires_at = self.request.expires_at.strftime("%B %d, %Y")
NAME = "TODO"
ACRONYMS = "TODO"
Comment on lines +137 to +138
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor/shelve: these will probably be part of the data/payload of the request, so we can easily pass them as parameters when bulk creating the requests.

self.request["description"] = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be in a template?

"<p>We would like to invite you to join the <a href='https://zenodo.org/communities/eu/'>"
"EU Open Research Repository</a> because we have detected that your Zenodo community "
"is likely related to an EU-funded project:</br><ul><li>Zenodo community: "
f"{NAME}</li><li>EU-funded project(s): {ACRONYMS}</li></ul>The EU Open "
"Research Repository is a Zenodo community dedicated to fostering open science "
"and enhancing the visibility and accessibility of research outputs funded by "
"the European Union. The community is managed by CERN on behalf of the European "
"Commission.</br></br><b>What does it mean to join?</b></br><ul><li><b>Indexing:</b> "
"All current and future records in your community will be automatically indexed "
"in the EU Open Research Repository increasing their visibility</li><li><b>Curation:</b> "
"All records will be subject to the EU Open Research Repository "
"<a href='https://zenodo.org/communities/eu/curation-policy'>curation policy</a>. "
"For instance, you can only deposit records in the community related to the EU-funded "
"project</li><li><b>Verified:</b> All EU project communities are marked with a "
"Verified community badge</li></ul></b></br>The EU Open Research Repository is gradually "
"being improved and by mid-2025 new submissions will automatically be checked "
"for compliance with the related open science requirements in the Horizon Europe "
"grant agreement. For more information see <a href='https://zenodo.org/communities/eu/pages/join'>"
"https://zenodo.org/communities/eu/pages/join</a>.</br></br><b>Which EU-funded projects "
"have already joined?</b></br>You can browse the "
"<a href='https://zenodo.org/communities/eu/browse/subcommunities'>EU-funded projects</a> "
"which have already already joined.</br></br><b>When should I decline the invitation "
"to join?</b></br>You should <b>decline</b> this invitation if your Zenodo community "
"is not related to the above mentioned EU-funded project, or if the community is used "
"for multiple purposes (e.g both an organisation and a project).</br></br><b>"
"Further questions?</b></br>Don't hesitate to get in <a href='https://zenodo.org/support'>"
"touch with us</a> if you have any questions.</br></br>The request will be automatically "
f"accepted on <b>{expires_at}</b> in case you do not accept or decline the request by then."
"</br></br>Your sincerely,</br>The Zenodo team"
)

super().execute(identity, uow)


class SubCommunityInvitationAcceptAction(AcceptSubcommunityInvitation):
"""Represents an accept action used to accept a subcommunity.

Zenodo re-implementation of the accept action, to also move the records.
"""

def execute(self, identity, uow):
"""Execute approve action."""
child = self.request.receiver.resolve().id
parent = self.request.created_by.resolve().id

_add_community_records(child, parent, uow)
# moving the community is handled by super()

super().execute(identity, uow)


class SubcommunityInvitationExpireAction(actions.ExpireAction):
"""Expire action."""

def execute(self, identity, uow):
"""Execute expire action."""
child = self.request.receiver.resolve().id
parent = self.request.created_by.resolve().id

_add_community_records(child, parent, uow)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it mean you add records to parent community when invitation expires? Since I don't know the requirements it seems a bit counter intuitive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, by default they will be included if the request expires. The thinking is that this is mutually beneficial and the request would only be declined if there has been a mistake


current_communities.service.bulk_update_parent(
system_identity, [child], parent_id=parent, uow=uow
)

super().execute(identity, uow)

uow.register(
NotificationOp(
notifications.SubComInvitationExpire.build(
identity=identity, request=self.request
)
)
)


class ZenodoSubCommunityInvitationRequest(SubCommunityInvitationRequest):
"""Request from a Zenodo community to add a child community."""

available_actions = {
"delete": actions.DeleteAction,
"cancel": actions.CancelAction,
# Custom implemented actions
"create": SubcommunityInvitationCreateAction,
"accept": SubCommunityInvitationAcceptAction,
"decline": DeclineSubcommunityInvitation,
"expire": SubcommunityInvitationExpireAction,
}
Loading