Commit 3099aab1 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

[schema] Use hook instead of adding composite=True on seda_data_object_reference_id

Because when this is not a simplified profile, we don't want the "auto-deletion"
behaviour, ie deleting the data object when its reference is deleted.

But since we still want this for simplified profiles, reimplement this behaviour
using hook+op.

Removing composite marker also implies to add/change some setup in various
places controlled by the SEDA compound graph, which only consider composite
relation. Add individual explanation as comment for posterity. At some point it
would probably be desirable to allow *additional relations to follow* in the
compound graph (we can only specify relations to filter out for now).

Closes #17113413
parent 9a71e061a886
# copyright 2016-2017 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr -- mailto:contact@logilab.fr
#
# This program is free software: you can redistribute it and/or modify it under
......@@ -172,6 +172,9 @@ class SEDAArchiveUnitIClonableAdapter(IClonableAdapter):
__select__ = is_instance('SEDAArchiveUnit')
rtype = 'clone_of'
skiprtypes = ('container',)
# this relation isn't composite but it should be followed for cloning since
# it's an intra-container relation
follow_relations = [('seda_data_object_reference_id', 'subject')]
def clone_into(self, clone):
"""Recursivily clone the container graph of this entity into `clone`."""
......@@ -208,7 +211,7 @@ def registration_callback(vreg):
assert cls
vreg.register(cls)
if etype in ('SEDABinaryDataObject', 'SEDAPhysicalDataObject'):
# control parent relation order
# insert seda_data_object_reference_id as potential parent,
# necessary in case of data object in a component archive unit
cls.parent_relations = list(cls.parent_relations)
if cls.parent_relations[0][0] == 'seda_data_object_reference_id':
cls.parent_relations = cls.parent_relations[::-1]
cls.parent_relations.append(('seda_data_object_reference_id', 'object'))
......@@ -279,6 +279,34 @@ class SimplifiedProfileSyncDORefCardOp(hook.Operation):
self.do_ref.cw_set(user_cardinality=self.do.user_cardinality)
class SimplifiedProfileDelRefROHook(hook.Hook):
"""Hook triggering an operation to delete the data object associated to a
reference when the later is deleted from a simplified profile.
"""
__regid__ = 'seda.doref.del'
__select__ = hook.Hook.__select__ & hook.match_rtype('seda_data_object_reference_id')
events = ('after_delete_relation',)
def __call__(self):
ref = self._cw.entity_from_eid(self.eidfrom)
bdo = self._cw.entity_from_eid(self.eidto)
if ref.cw_etype == 'SEDADataObjectReference' and bdo.cw_etype == 'SEDABinaryDataObject':
container = bdo.seda_binary_data_object[0] if bdo.seda_binary_data_object else None
if container and container.simplified_profile:
SimplifiedProfileDelRefROOp(self._cw, do_ref=ref, do=bdo)
class SimplifiedProfileDelRefROOp(hook.Operation):
"""Delete data object whose former reference has been deleted in the
transaction. Expected to be run only if the profile is a simplified
profile.
"""
def precommit_event(self):
if self.cnx.deleted_in_transaction(self.do_ref.eid):
self.do.cw_delete()
class CheckProfileSEDACompatiblityOp(hook.DataOperationMixIn, hook.LateOperation):
"""Data operation that will check compatibility of a SEDA profile upon modification.
......@@ -488,5 +516,10 @@ def registration_callback(vreg):
for rtype, role in parent_rdefs:
if SEDA_PARENT_RTYPES.setdefault(rtype, role) != role:
raise Exception('inconsistent relation', rtype, role)
# manually add seda_data_object_reference_id since it's not composite and as
# such not considered as part of the graph, but it has to be watched by hook
# triggering the operation to set the container for the case of component
# archive unit
SEDA_PARENT_RTYPES['seda_data_object_reference_id'] = 'object'
for rdef, role in iter_all_rdefs(vreg.schema, 'SEDAArchiveTransfer'):
ON_COMMIT_ADD_RELATIONS.add(str(rdef.rtype))
......@@ -10,3 +10,4 @@ commit()
sync_schema_props_perms('seda_mime_type_to')
sync_schema_props_perms('seda_format_id_to')
sync_schema_props_perms('seda_data_object_reference_id')
......@@ -162,11 +162,6 @@ language_code = skos.Label.get_relation('language_code')
language_code.constraints[0].max = 7
from cubicweb_seda.schema.seda2 import data_object_reference_data_object_reference_id # noqa
data_object_reference_data_object_reference_id.composite = 'subject'
def post_build_callback(schema):
from cubicweb_seda import seda_profile_container_def, iter_all_rdefs
......
......@@ -258,6 +258,27 @@ class SchemaTC(CubicWebTC):
'delete': (),
'read': ('managers', 'users', 'guests')})
def test_reference_to_data_object_is_not_composite(self):
self._test_reference_to_data_object_composite(False)
def test_simplified_reference_to_data_object_is_composite(self):
self._test_reference_to_data_object_composite(True)
def _test_reference_to_data_object_composite(self, simplified):
with self.admin_access.cnx() as cnx:
transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile',
simplified_profile=simplified)
unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(transfer)
bdo = testutils.create_data_object(unit_alt_seq,
seda_binary_data_object=transfer)
cnx.commit()
reference = bdo.reverse_seda_data_object_reference_id[0]
reference.cw_delete()
cnx.commit()
self.assertEqual(
len(cnx.execute('Any X WHERE X eid %(x)s', {'x': bdo.eid})),
0 if simplified else 1)
class SecurityTC(CubicWebTC):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment