Commit 6fad73f6 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

[hooks] Add hook to synchronize file_category with mime_type / format_id

Upon modification of file_category relation, synchronize mime_type / format_id
values for the binary data-object, through intermediary SEDAMimeType /
SEDAFormatId entities which are kept for now but could be removed if the
automatic user cardinality system is validated by business people.

Synchronization is implemented to consider textual values of concept in the
category vocabulary, and to keep only those which have a match in the
vocabularies that are set on the transfer (code list version).

Because of that, don't attempt to synchronize values on archive unit component,
that should be done when it is imported into a transfer.

Related to #36331831
parent f5069136d86d
......@@ -5,7 +5,7 @@ recursive-include doc *.rst *.py
recursive-include test *.py
include cubicweb_seda/migration/data/*.csv
include cubicweb_seda/i18n/*.po cubicweb_seda/i18n/*.pot
include test/data/bootstrap_cubes test/data/*.xml test/data/*.xsd test/data/*.rng
include test/data/bootstrap_cubes test/data/*.xml test/data/*.xsd test/data/*.rng test/data/*.csv
include tox.ini dev-requirements.txt cubicweb_seda/makefile
prune __pkginfo__.py
......
......@@ -486,6 +486,76 @@ class InitBDO(hook.Hook):
seda_format_id_from=self.entity)
class SyncFileCategoryOp(hook.DataOperationMixIn, hook.LateOperation):
"""On file category change, synchronize associated mime types and format ids
to the data object.
This is a late operation because we have to go back to the container to know
if it's a component archive unit or a transfer, so it has to be executed
once the 'container' relation is set.
"""
# set possible mime types / format ids by joining related transfer's
# vocabularies to file category vocabulary using the concept's label
set_mime_type_rql = (
'SET X seda_mime_type_to MT WHERE X eid %(x)s, '
'MT in_scheme CS, CACLV seda_mime_type_code_list_version_from AT, '
'CACLV seda_mime_type_code_list_version_to CS, AT eid %(c)s, '
'MTL label_of MT, MTL label MTLL, '
'FCMTL label_of FCMT , FCMTL label MTLL, '
'EXISTS(FCMT broader_concept EXT1, EXT1 eid IN ({eids})) '
'OR EXISTS(FCMT broader_concept EXT2, EXT2 broader_concept CAT, '
' CAT eid IN ({eids}))'
)
set_format_id_rql = (
'SET X seda_format_id_to FI WHERE X eid %(x)s, '
'FI in_scheme CS, CACLV seda_file_format_code_list_version_from AT, '
'CACLV seda_file_format_code_list_version_to CS, AT eid %(c)s, '
'FIL label_of FI, FIL label FILL, '
'FCFIL label_of FCFI , FCFIL label FILL, '
'EXISTS(FCFI broader_concept MT, MT broader_concept EXT1, EXT1 eid IN ({eids})) '
'OR EXISTS(FCFI broader_concept MT2, MT2 broader_concept EXT2, EXT2 broader_concept CAT, '
' CAT eid IN ({eids}))'
)
def precommit_event(self):
for bdo_eid in self.get_data():
bdo = self.cnx.entity_from_eid(bdo_eid)
container = bdo.cw_adapt_to('IContained').container
if container.cw_etype != 'SEDAArchiveTransfer':
# don't afford doing this in components which are not bound to
# vocabularies, it will be done upon import in a transfer
continue
if not bdo.file_category:
# no related category
card = u'0..1'
eids = None
else:
card = u'1'
eids = ','.join(str(x.eid) for x in bdo.file_category)
bdo.mime_type.cw_set(user_cardinality=card,
seda_mime_type_to=None)
bdo.format_id.cw_set(user_cardinality=card,
seda_format_id_to=None)
if eids is not None:
self.cnx.execute(self.set_mime_type_rql.format(eids=eids),
{'x': bdo.mime_type.eid, 'c': container.eid})
self.cnx.execute(self.set_format_id_rql.format(eids=eids),
{'x': bdo.format_id.eid, 'c': container.eid})
class SyncFileCategoryHook(hook.Hook):
"""On file category change, instantiate an operation to synchronize
associated mime types and format ids to the data object.
"""
__regid__ = 'seda.ux.filecategory'
__select__ = hook.Hook.__select__ & hook.match_rtype('file_category')
events = ('after_add_relation', 'after_delete_relation')
def __call__(self):
SyncFileCategoryOp.get_instance(self._cw).add_data(self.eidfrom)
def registration_callback(vreg):
from cubicweb.server import ON_COMMIT_ADD_RELATIONS
from cubicweb_seda import seda_profile_container_def, iter_all_rdefs
......
#;$id;broader_concept;libellé;Description du titre du niveau;libellé alternatif;libellé alternatif
lang;;;seda;fr;fr;fr
url;skos:Concept;skos:broader;skos:prefLabel;skos:definition;skos:altLabel;skos:note
type;;url;string;string;string;string
;#3;;document;catégorie;;
;#3-1;#3;doc;extension;;
;#3-1-1;#3-1;application/msword;type_mime;;
;#3-1-1-1;#3-1-1;fmt/37;format;version 1.0;
;#3-1-1-2;#3-1-1;fmt/38;format;version 2.0;
;#3-13;#3;pdf;extension;;
;#3-13-1;#3-13;application/pdf;type_mime;;
;#3-13-1-1;#3-13-1;fmt/14;format;version 1.0;
......@@ -25,7 +25,7 @@ class ConcepSchemeImportTC(CubicWebTC):
def test_import_seda_schemes(self):
with self.admin_access.cnx() as cnx:
dataimport.import_seda_schemes(cnx, lcsv_import=dataimport.lcsv_check)
self.assertEqual(len(cnx.find('ConceptScheme')), 18)
self.assertEqual(len(cnx.find('ConceptScheme')), 19)
if __name__ == '__main__':
......
......@@ -15,11 +15,12 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb-seda unit tests for hooks"""
from os.path import dirname, join
from itertools import chain, repeat
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb_seda import testutils
from cubicweb_seda import testutils, dataimport
class ValidationHooksTC(CubicWebTC):
......@@ -265,6 +266,57 @@ class CheckProfileTC(CubicWebTC):
access_rule_seq.cw_delete()
class DispatchFileCategoryTC(CubicWebTC):
def test(self):
with self.admin_access.cnx() as cnx:
testutils.scheme_for_type(cnx, 'seda_format_id_to', None,
u'fmt/37', u'fmt/38', u'fmt/14')
testutils.scheme_for_type(cnx, 'seda_mime_type_to', None,
u'application/msword', u'application/pdf')
concepts = dict(cnx.execute('Any LL, C WHERE L label_of C, L label LL'))
dataimport.import_seda_schemes(cnx, lcsv_files=[
(u'Categories de fichier',
'file_category', (),
join(dirname(__file__), 'data', 'file_categories.csv'))])
categories = dict(cnx.execute('Any LL, C WHERE L label_of C, L label LL, '
'C in_scheme CS, CS title "Categories de fichier"'))
transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile',
simplified_profile=True)
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()
bdo.cw_set(file_category=categories['document'])
cnx.commit()
self.assertFormatEqual(bdo, u'1',
[concepts['application/msword'], concepts['application/pdf']],
[concepts['fmt/37'], concepts['fmt/38'], concepts['fmt/14']])
bdo.cw_set(file_category=None)
cnx.commit()
self.assertFormatEqual(bdo, u'0..1', [], [])
bdo.cw_set(file_category=categories['doc'])
cnx.commit()
self.assertFormatEqual(bdo, u'1',
[concepts['application/msword']],
[concepts['fmt/37'], concepts['fmt/38']])
def assertFormatEqual(self, bdo, cardinality, mime_types, format_ids):
bdo.cw_clear_all_caches()
bdo.reverse_seda_mime_type_from[0].cw_clear_all_caches()
bdo.reverse_seda_format_id_from[0].cw_clear_all_caches()
self.assertEqual(bdo.reverse_seda_mime_type_from[0].user_cardinality, cardinality)
self.assertEqual(set(x.eid for x in bdo.reverse_seda_mime_type_from[0].seda_mime_type_to),
set(mime_types))
self.assertEqual(bdo.reverse_seda_format_id_from[0].user_cardinality, cardinality)
self.assertEqual(set(x.eid for x in bdo.reverse_seda_format_id_from[0].seda_format_id_to),
set(format_ids))
if __name__ == '__main__':
import unittest
unittest.main()
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