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

1454 notifications replace guest access request notification #1465

Merged
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
205 changes: 204 additions & 1 deletion invenio_rdm_records/notifications/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
from invenio_notifications.services.generators import EntityResolve, UserEmailBackend
from invenio_requests.notifications.filters import UserRecipientFilter
from invenio_users_resources.notifications.filters import UserPreferencesRecipientFilter
from invenio_users_resources.notifications.generators import UserRecipient
from invenio_users_resources.notifications.generators import (
EmailRecipient,
IfUserRecipient,
UserRecipient,
)


class CommunityInclusionNotificationBuilder(NotificationBuilder):
Expand Down Expand Up @@ -62,6 +66,197 @@ class CommunityInclusionSubmittedNotificationBuilder(
type = "community-submission.submit"


class GuestAccessRequestTokenCreateNotificationBuilder(NotificationBuilder):
"""Notification builder for user access requests."""

type = "guest-access-request-token.create"

@classmethod
def build(cls, record, email, verify_url):
"""Build notification with request context."""
return Notification(
type=cls.type,
context={
"record": EntityResolverRegistry.reference_entity(record),
"created_by": EntityResolverRegistry.reference_entity(email),
"verify_url": verify_url,
},
)

context = [
EntityResolve(key="record"),
EntityResolve(key="created_by"), # email
]

recipients = [
EmailRecipient(key="created_by"), # email only
]

recipient_filters = [] # assume guest is ok with mail being sent

recipient_backends = [
UserEmailBackend(),
]


class GuestAccessRequestSubmitNotificationBuilder(NotificationBuilder):
"""Notification builder for guest access requests."""

type = "guest-access-request.submit"

@classmethod
def build(cls, request):
"""Build notification with request context."""
return Notification(
type=cls.type,
context={
"request": EntityResolverRegistry.reference_entity(request),
"receiver_entity": request.receiver.reference_dict, # will not be resolved for easier lookup for recipients
},
)

context = [
EntityResolve(key="request"),
EntityResolve(key="request.created_by"),
EntityResolve(key="request.topic"),
EntityResolve(key="request.receiver"),
]

recipients = [
# Currently only these two are allowed. Adapt as needed.
IfUserRecipient(
key="receiver_entity",
then_=[UserRecipient(key="request.receiver")],
else_=[
CommunityMembersRecipient(
key="request.receiver", roles=["curator", "owner"]
)
],
)
]

recipient_filters = [
UserPreferencesRecipientFilter(),
]

recipient_backends = [
UserEmailBackend(),
]


class GuestAccessRequestAcceptNotificationBuilder(NotificationBuilder):
"""Notification builder for user access requests."""

type = "guest-access-request.accept"

@classmethod
def build(cls, request, access_url):
"""Build notification with request context."""
return Notification(
type=cls.type,
context={
"request": EntityResolverRegistry.reference_entity(request),
"access_url": access_url,
},
)

context = [
EntityResolve(key="request"),
EntityResolve(key="request.created_by"), # email
EntityResolve(key="request.topic"),
]

recipients = [
EmailRecipient(key="request.created_by"), # email only
]

recipient_filters = [] # assume guest is ok with mail being sent

recipient_backends = [
UserEmailBackend(),
]


class UserAccessRequestSubmitNotificationBuilder(NotificationBuilder):
"""Notification builder for user access requests."""

type = "user-access-request.submit"

@classmethod
def build(cls, request):
"""Build notification with request context."""
return Notification(
type=cls.type,
context={
"request": EntityResolverRegistry.reference_entity(request),
"receiver_entity": request.receiver.reference_dict, # will not be resolved for easier lookup for recipients
},
)

context = [
EntityResolve(key="request"),
EntityResolve(key="request.created_by"),
EntityResolve(key="request.topic"),
EntityResolve(key="request.receiver"),
]

recipients = [
# Currently only these two are allowed. Adapt as needed.
IfUserRecipient(
key="receiver_entity",
then_=[UserRecipient(key="request.receiver")],
else_=[
CommunityMembersRecipient(
key="request.receiver", roles=["curator", "owner"]
)
],
)
]

recipient_filters = [
UserPreferencesRecipientFilter(),
]

recipient_backends = [
UserEmailBackend(),
]


class UserAccessRequestAcceptNotificationBuilder(NotificationBuilder):
"""Notification builder for user access requests."""

type = "user-access-request.accept"

@classmethod
def build(cls, request):
"""Build notification with request context."""
return Notification(
type=cls.type,
context={
"request": EntityResolverRegistry.reference_entity(request),
},
)

context = [
EntityResolve(key="request"),
EntityResolve(key="request.created_by"),
EntityResolve(key="request.topic"),
EntityResolve(key="request.receiver"),
]

recipients = [
UserRecipient(key="request.created_by"),
]

recipient_filters = [
UserPreferencesRecipientFilter(),
]

recipient_backends = [
UserEmailBackend(),
]


class CommunityInclusionActionNotificationBuilder(NotificationBuilder):
"""Notification builder for inclusion actions."""

Expand Down Expand Up @@ -106,6 +301,14 @@ class CommunityInclusionAcceptNotificationBuilder(
type = f"{CommunityInclusionNotificationBuilder.type}.accept"


class CommunityInclusionAcceptNotificationBuilder(
CommunityInclusionActionNotificationBuilder
):
"""Notification builder for inclusion accept action."""

type = f"{CommunityInclusionNotificationBuilder.type}.accept"


class CommunityInclusionCancelNotificationBuilder(
CommunityInclusionActionNotificationBuilder
):
Expand Down
68 changes: 28 additions & 40 deletions invenio_rdm_records/requests/access/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,25 @@
from datetime import datetime, timedelta

import marshmallow as ma
from flask import current_app, g
from flask import g
from invenio_access.permissions import authenticated_user, system_identity
from invenio_drafts_resources.services.records.uow import ParentRecordCommitOp
from invenio_i18n import lazy_gettext as _
from invenio_mail.tasks import send_email
from invenio_records_resources.services.uow import Operation
from invenio_notifications.services.uow import NotificationOp
from invenio_requests import current_events_service
from invenio_requests.customizations import RequestType, actions
from invenio_requests.customizations.event_types import CommentEventType
from marshmallow import ValidationError, fields, validates
from marshmallow_utils.permissions import FieldPermissionsMixin

from ...proxies import current_rdm_records_service as service

from invenio_rdm_records.notifications.builders import (
GuestAccessRequestAcceptNotificationBuilder,
GuestAccessRequestSubmitNotificationBuilder,
UserAccessRequestAcceptNotificationBuilder,
UserAccessRequestSubmitNotificationBuilder,
)

class EmailOp(Operation):
"""A notification operation."""

def __init__(self, receiver, subject, html_body, body):
"""Initialize operation."""
self.receiver = receiver
self.subject = subject
self.html_body = html_body
self.body = body

def on_post_commit(self, uow):
"""Start task to send text via email."""
send_email(
{
"subject": self.subject,
"html_body": self.html_body,
"body": self.body,
"recipients": [self.receiver],
"sender": current_app.config["MAIL_DEFAULT_SENDER"],
}
)
from ...proxies import current_rdm_records_service as service


#
Expand All @@ -56,6 +39,11 @@ class UserSubmitAction(actions.SubmitAction):
def execute(self, identity, uow):
"""Execute the submit action."""
self.request["title"] = self.request.topic.resolve().metadata["title"]
uow.register(
NotificationOp(
UserAccessRequestSubmitNotificationBuilder.build(request=self.request)
)
)
super().execute(identity, uow)


Expand All @@ -66,7 +54,11 @@ def execute(self, identity, uow):
"""Execute the submit action."""
record = self.request.topic.resolve()
self.request["title"] = record.metadata["title"]

uow.register(
NotificationOp(
GuestAccessRequestSubmitNotificationBuilder.build(request=self.request)
)
)
super().execute(identity, uow)


Expand Down Expand Up @@ -98,27 +90,18 @@ def execute(self, identity, uow):
(datetime.utcnow() + timedelta(days=days)).date().isoformat()
)
link = service.access.create_secret_link(identity, record.id, data)

access_url = f"{record.links['self_html']}?token={link._link.token}"

plain_message = _("Access the record here: {url}".format(url=access_url))
message = _(
'Click <a href="{url}">here</a> to access the record.'.format(
url=access_url
)
)

uow.register(
ParentRecordCommitOp(
record._record.parent, indexer_context=dict(service=service)
)
)
uow.register(
EmailOp(
receiver=payload["email"],
subject="Request accepted",
body=plain_message,
html_body=message,
NotificationOp(
GuestAccessRequestAcceptNotificationBuilder.build(
self.request, access_url=access_url
)
)
)

Expand Down Expand Up @@ -165,6 +148,11 @@ def execute(self, identity, uow):
uow.register(
ParentRecordCommitOp(record.parent, indexer_context=dict(service=service))
)
uow.register(
NotificationOp(
UserAccessRequestAcceptNotificationBuilder.build(self.request)
)
)

super().execute(identity, uow)

Expand Down
5 changes: 5 additions & 0 deletions invenio_rdm_records/requests/entity_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ def __init__(self):
proxy_cls=RDMRecordServiceResultProxy,
)

def _reference_entity(self, entity):
"""Create a reference dict for the given result item."""
pid = entity.id if isinstance(entity, self.item_cls) else entity.pid.pid_value
return {self.type_key: str(pid)}


class EmailProxy(EntityProxy):
"""Entity proxy for email addresses."""
Expand Down
Loading