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

Fire notifications when UID references are created/destroyed #2061

Merged
merged 3 commits into from
Jul 18, 2022
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
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog
2.3.0 (unreleased)
------------------

- #2061 Fire notifications when UID references are created/destroyed
- #2058 Filter 'Interpretation templates' in sample view by template and type
- #2048 Fix catalog logging counter duplicates
- #2047 Make resultsinterpretation.pt to retrieve departments from viewlet
Expand Down
52 changes: 52 additions & 0 deletions src/senaite/core/events/uidreference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-

from zope.interface import implementer
from zope.interface.interfaces import IObjectEvent


class IUIDReferenceCreatedEvent(IObjectEvent):
"""An event fired after a reference between two objects was cretated
"""


class IUIDReferenceDestroyedEvent(IObjectEvent):
"""An event fired after a reference between two objects was destroyed
"""


@implementer(IUIDReferenceCreatedEvent)
class UIDReferenceCreated(object):

def __init__(self, field, source, target):
"""Reference Created Event

:param field: The field on the source object
:param source: The context object holding the UID reference field
:param target: The context object being referenced
"""
self.field = field
self.source = source
self.target = target

# See IObjectEvent
# -> Allow to define an event subscriber for a custom type
self.object = source


@implementer(IUIDReferenceDestroyedEvent)
class UIDReferenceDestroyed(object):

def __init__(self, field, source, target):
"""Reference Destroyed Event

:param field: The field on the source object
:param source: The context object holding the UID reference field
:param target: The context object being referenced
"""
self.field = field
self.source = source
self.target = target

# See IObjectEvent
# -> Allow to define an event subscriber for a custom type
self.object = source
5 changes: 4 additions & 1 deletion src/senaite/core/schema/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
i18n_domain="senaite.core">

<!-- Event subscribers -->
<subscriber handler=".uidreferencefield.on_object_created" />
<subscriber
for="senaite.core.interfaces.IHaveUIDReferences
zope.lifecycleevent.interfaces.IObjectCreatedEvent"
handler=".uidreferencefield.on_object_created" />

</configure>
30 changes: 23 additions & 7 deletions src/senaite/core/schema/uidreferencefield.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,33 @@
from plone.behavior.interfaces import IBehavior
from plone.uuid.interfaces import ATTRIBUTE_NAME
from senaite.core import logger
from senaite.core.events.uidreference import UIDReferenceCreated
from senaite.core.events.uidreference import UIDReferenceDestroyed
from senaite.core.interfaces import IHaveUIDReferences
from senaite.core.schema.fields import BaseField
from senaite.core.schema.interfaces import IUIDReferenceField
from zope.annotation.interfaces import IAnnotations
from zope.component import adapter
from zope.event import notify
from zope.interface import alsoProvides
from zope.interface import implementer
from zope.lifecycleevent.interfaces import IObjectCreatedEvent
from zope.schema import ASCIILine
from zope.schema import List

BACKREFS_STORAGE = "senaite.core.schema.uidreferencefield.backreferences"


@adapter(IHaveUIDReferences, IObjectCreatedEvent)
def notify_reference_created(field, source, target):
"""Notify that a reference between two objects was created
"""
notify(UIDReferenceCreated(field, source, target))


def notify_reference_destroyed(field, source, target):
"""Notify that a reference between two objects was destroyed
"""
notify(UIDReferenceDestroyed(field, source, target))


def on_object_created(object, event):
"""Link backreferences after the object was created

Expand All @@ -41,17 +53,19 @@ def on_object_created(object, event):
value = field.get(object)
# handle single valued reference fields
if api.is_object(value):
field.link_backref(value, object)
logger.info(
"Adding back reference from %s -> %s" % (
value, object))
if field.link_backref(value, object):
notify_reference_created(field, object, value)
# handle multi valued reference fields
elif isinstance(value, list):
for ref in value:
logger.info(
"Adding back reference from %s -> %s" % (
ref, object))
field.link_backref(ref, object)
if field.link_backref(ref, object):
notify_reference_created(field, object, ref)


def get_backrefs(context, relationship, as_objects=False):
Expand Down Expand Up @@ -208,11 +222,13 @@ def set(self, object, value):

# link backreferences of new uids
for added_obj in added_objs:
self.link_backref(added_obj, object)
if self.link_backref(added_obj, object):
notify_reference_created(self, object, added_obj)

# unlink backreferences of removed UIDs
for removed_obj in removed_objs:
self.unlink_backref(removed_obj, object)
if self.unlink_backref(removed_obj, object):
notify_reference_destroyed(self, object, removed_obj)

super(UIDReferenceField, self).set(object, uids)

Expand Down