inveniosoftware / invenio-app-rdm

Turn-key research data management platform.
https://inveniordm.docs.cern.ch
MIT License
100 stars 144 forks source link

Notifications support #2065

Closed zzacharo closed 1 year ago

zzacharo commented 1 year ago
### Tasks
- [ ] https://github.com/inveniosoftware/cookiecutter-invenio-module/pull/147
- [ ] https://github.com/inveniosoftware/invenio-notifications/issues/1
- [ ] https://github.com/inveniosoftware/invenio-notifications/issues/2
- [ ] https://github.com/inveniosoftware/invenio-records-resources/issues/440
- [ ] https://github.com/inveniosoftware/invenio-records-resources/issues/450
- [ ] https://github.com/inveniosoftware/invenio-notifications/issues/3
- [ ] https://github.com/inveniosoftware/invenio-rdm-records/issues/1179
- [ ] https://github.com/inveniosoftware/invenio-notifications/issues/5
- [ ] https://github.com/inveniosoftware/invenio-app-rdm/issues/2204
- [ ] https://github.com/inveniosoftware/invenio-requests/issues/304
- [ ] https://github.com/inveniosoftware/invenio-communities/issues/889
- [ ] https://github.com/inveniosoftware/invenio-app-rdm/issues/2069
- [ ] https://github.com/inveniosoftware/invenio-communities/issues/864
- [ ] https://github.com/inveniosoftware/invenio-notifications/issues/4

New repository at https://github.com/inveniosoftware/invenio-notifications

Previous RFC

https://codimd.web.cern.ch/RH_steApSGOk4Yaoex782A#notifications

Issues/comments

Open PRs

Next steps

Image

Decisions

Image

slint commented 1 year ago

[
    {target: <Jim>, template:  }
    # Anna (curator)
    Bob (curator)

]

#
# Notification builder interface
#

# Invenio-Records-Resources/Invenio-Notifications
class PayloadGeneratorABC:

    def run(context: dict) -> dict:
        pass

class NotificationBuilderBase:

    def build(context: dict) -> Notification:
        pass

    payload_generator: List[PayloadGeneratorABC]
    recipients_generator: List[RecipientGeneratorABC]
    recipients_filters: List[PayloadGeneratorABC]
    recipient_backend_transform: List[PayloadGeneratorABC]

#
# Notification builder implementation for community record inclusion request
#

# invenio_rdm_records/communities/notifications.py
class CommunityRecordInclusionNotificationBuilder(NotificationBuilderBase):

    payload_generator = [
        RequestPayloadGenerator,
        CommunityPayloadGenerator,
        RecordPayloadGenerator,
    ]

    recipients_generator = [
        RequestRecipientsGenerator,
        CommunityRecipientsGenerator,
    ]

    recipients_filters = [
        UserRecipientFilter,
        CommunityMemberRecipientFilter,
    ]

    recipient_backend_transform = [
        UserPreferencesBackend,
    ]

# invenio_requests/notifications.py
class RequestPayloadGenerator:

    def run(**kwargs):
        return { "request": request_item.to_dict(), }

# invenio_rdm_records/notifications.py
class RecordPayloadGenerator:
    def run():
        return {"record": record.dumps()},

# invenio_communities/notifications.py
class CommunityPayloadGenerator:
    def run():
        return {"community": current_communities.service.read(identity=system_identity, id_=community.id).to_dict()}

# invenio_requests/notifications.py
class RequestRecipientsGenerator:

    def run():
        return [
            request.created_by,
            # {"community": "biosyslit"}
            request.receiver,
        ]

# invenio_communities/notifications.py
class CommunityRecipientsGenerator:

    def run(request_item):

        if type in [CommunitySubmissionCreatedEvent, CommunitySubmissionSubmittedEvent]:
            members = Member.get_members(community.id)
            # get owner, managers and curators. There should be an easier way
            return [
                m.relations.user.dereference() for m in members
                if m.user_id
                and m.role in ["owner", "manager", "curator"] #
            ]

# invenio_users_resources/notifications.py
class UserRecipientFilter:

    def run(user):
        return user.preferences["notifications"]["enabled"]

# invenio_communities/notifications.py
class CommunityMemberRecipientFilter:

    def run(user, community, request):
        community_member = community.members[user.id]
        comm_pref = community_member.preferences.notifications
        PREF_MAP = {
            "all": ["inclusion requests", "accepted/rejected", "comments"],
            "all_but_no_comments": ["inclusion requests", "accepted/rejected"],
            "none": [],
        }
        return request.type in PREF_MAP[comm_pref]

#
# Example fully-resolved user payload
#
user = {
    "id": 1234,
    "email": "jim@example.com",
    "username": "jim",
    "profile": {
        "full_name": "Jim Doe",
        "affiliation": "ACME Inc.",
    },
    "preferences": {
        "visibility": "public",
        "email_visibility": "public",
        "notifications": {
            "enabled": True,
            # E.g. in the future we could have:
            # "prefferd_backend": "email",
        }
    }
}

#
# Example backend payloads
#
email_backend_payload = {
    "backend": "email",
    "template": "member_invitation_receiver.html",
    # "template": "member_invitation_curators.html",
    "to": "Jim Doe <jim@example.com",
    # or could be:
    # "cc": "Jim Doe <jim@example.com",
}
chat_backend_payload = {
    "backend": "chat",
    "target": "@jim",
}

recipients = [
    {"user": user, "backends": [email_backend_payload, chat_backend_payload]},
]

#
# Example UoW notification sending
#
# in the service
uow.register(NotificationOp(CommunityRecordInclusionNotificationBuilder.build(
    {
        "request": request,
        "community": community,
        "record": record,
    }
)))

def on_post_commit():
    curent_notifications.broadcast(self._payload)

#
# User preferences marshmallow schema
#
# invenio_users_resources/schemas.py
class NotificationPreferencesSchema(BaseUserPreferencesSchema):

    notifications = fields.Nested({
        "enabled": fields.Bool(),
    })

class NotificationPreferencesMixin:

    notifications = fields.Nested({
        "enabled": fields.Bool(),
    })

# invenio_app_rdm/config.py
from invenio_users_resources.schema import NotificationPreferencesSchema
ACCOUNTS_USER_PREFERENCES_SCHEMA = NotificationPreferencesSchema

from invenio_users_resources.schema import NotificationPreferencesMixin

class UserPreferencesSchema(BaseUserPreferencesSchema, NotificationPreferencesMixin):
    pass
ACCOUNTS_USER_PREFERENCES_SCHEMA = UserPreferencesSchema
github-actions[bot] commented 1 year ago

This issue was automatically marked as stale.