Commit 8eede03f authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

Find a suitable concept scheme for encoding/mime type/algorithm relations of a...

Find a suitable concept scheme for encoding/mime type/algorithm relations of a component archive unit

Former constraint was relying on a 'code list version' relation which was setup
on the archive transfer, which a component archive unit doesn't have. To find a
suitable scheme, we may still find the one that is linked to the correct entity
and relation type in the schema (at least until we've several of those, which is
not the case for now).

To do so, add a new `SCHEME_FROM_CONTAINER` structure in xsd2yams (close to
where constraints are defined) so one may easily get the correct query depending
on the container type (ie. wether we are in an archive transfer or an archive
unit).

Also, extend tests to check both case for the 3 aforementionned relations, since
the rql constraint deserves to be tested...
parent 1a14a179d0fc
sync_schema_props_perms('seda_mime_type_to')
sync_schema_props_perms('seda_encoding_to')
sync_schema_props_perms('seda_algorithm')
......@@ -740,7 +740,7 @@ class binary_data_object_algorithm(RelationDefinition):
cardinality = '?*'
composite = fulltext_container = None
inlined = True
constraints = [RQLConstraint('O in_scheme CS, AT seda_message_digest_algorithm_code_list_version CS, S container AT')]
constraints = [RQLConstraint('O in_scheme CS, EXISTS(S container AT, AT seda_message_digest_algorithm_code_list_version CS) OR EXISTS(S container AU, AU is SEDAArchiveUnit, CS scheme_relation_type RT, RT name "seda_algorithm", CS scheme_entity_type ET, ET name "SEDABinaryDataObject")')]
class compressed_algorithm(RelationDefinition):
name = 'seda_algorithm'
......@@ -789,7 +789,7 @@ class mime_type_mime_type_to(RelationDefinition):
cardinality = '?*'
composite = fulltext_container = None
inlined = True
constraints = [RQLConstraint('O in_scheme CS, CACLV seda_mime_type_code_list_version_from AT, CACLV seda_mime_type_code_list_version_to CS,S container AT')]
constraints = [RQLConstraint('O in_scheme CS, EXISTS(CACLV seda_mime_type_code_list_version_from AT, CACLV seda_mime_type_code_list_version_to CS, S container AT) OR EXISTS(S container AU, AU is SEDAArchiveUnit, CS scheme_relation_type RT, RT name "seda_mime_type_to")')]
@seda_profile_element(cardinalities=['0..1', '1'], default_cardinality='0..1',
annotable=True)
......@@ -837,7 +837,7 @@ class encoding_encoding_to(RelationDefinition):
cardinality = '?*'
composite = fulltext_container = None
inlined = True
constraints = [RQLConstraint('O in_scheme CS, CACLV seda_encoding_code_list_version_from AT, CACLV seda_encoding_code_list_version_to CS,S container AT')]
constraints = [RQLConstraint('O in_scheme CS, EXISTS(CACLV seda_encoding_code_list_version_from AT, CACLV seda_encoding_code_list_version_to CS, S container AT) OR EXISTS(S container AU, AU is SEDAArchiveUnit, CS scheme_relation_type RT, RT name "seda_encoding_to")')]
@seda_profile_element(cardinalities=['0..1', '1'], default_cardinality='0..1',
annotable=True)
......
......@@ -52,29 +52,91 @@ class SchemaConceptConstraintsTC(CubicWebTC):
bdo.cw_set(seda_algorithm=self.enc_concept)
cnx.commit()
def test_code_lists_constraints_complex(self):
def assertMimeTypeConcept(self, bdo):
cnx = bdo._cw
cnx.create_entity('SEDAMimeType',
seda_mime_type_from=bdo,
seda_mime_type_to=self.enc_concept)
with self.assertRaises(ValidationError) as cm:
cnx.commit()
self.assertIn('seda_mime_type_to-subject', cm.exception.errors)
cnx.create_entity('SEDAMimeType',
seda_mime_type_from=bdo,
seda_mime_type_to=self.mt_concept)
cnx.commit()
def test_archive_transfer_mime_type_constraint(self):
with self.admin_access.client_cnx() as cnx:
create = cnx.create_entity
bdo = testutils.create_transfer_to_bdo(cnx)
cnx.commit() # will setup code list version
self.assertMimeTypeConcept(bdo)
mt_scheme = create('ConceptScheme', title=u'mime types')
mt_concept = mt_scheme.add_concept(label=u'text/plain')
other_scheme = create('ConceptScheme', title=u'Reply code algorithms')
other_concept = other_scheme.add_concept(label=u'ok')
def test_component_archive_unit_mime_type_constraint(self):
with self.admin_access.client_cnx() as cnx:
unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(None, cnx=cnx)
bdo = testutils.create_data_object(unit_alt_seq)
cnx.commit()
self.assertMimeTypeConcept(bdo)
def assertEncodingConcept(self, bdo):
cnx = bdo._cw
cnx.create_entity('SEDAEncoding',
seda_encoding_from=bdo,
seda_encoding_to=self.mt_concept)
with self.assertRaises(ValidationError) as cm:
cnx.commit()
self.assertIn('seda_encoding_to-subject', cm.exception.errors)
cnx.create_entity('SEDAEncoding',
seda_encoding_from=bdo,
seda_encoding_to=self.enc_concept)
cnx.commit()
def test_archive_transfer_encoding_constraint(self):
with self.admin_access.client_cnx() as cnx:
bdo = testutils.create_transfer_to_bdo(cnx)
create('SEDAMimeTypeCodeListVersion',
seda_mime_type_code_list_version_from=bdo.container,
seda_mime_type_code_list_version_to=mt_scheme)
cnx.commit() # will setup code list version
self.assertEncodingConcept(bdo)
def test_component_archive_unit_encoding_constraint(self):
with self.admin_access.client_cnx() as cnx:
unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(None, cnx=cnx)
bdo = testutils.create_data_object(unit_alt_seq)
cnx.commit()
self.assertEncodingConcept(bdo)
create('SEDAMimeType', seda_mime_type_from=bdo, seda_mime_type_to=other_concept)
with self.assertRaises(ValidationError) as cm:
cnx.commit()
self.assertIn('seda_mime_type_to-subject', cm.exception.errors)
def assertDigestAlgorithmConcept(self, bdo):
cnx = bdo._cw
with self.assertRaises(ValidationError) as cm:
bdo.cw_set(seda_algorithm=self.mt_concept)
cnx.commit()
self.assertIn('seda_algorithm-subject', cm.exception.errors)
create('SEDAMimeType', seda_mime_type_from=bdo, seda_mime_type_to=mt_concept)
bdo.cw_set(seda_algorithm=self.enc_concept)
cnx.commit()
def test_archive_transfer_digest_algorithm_constraint(self):
with self.admin_access.client_cnx() as cnx:
bdo = testutils.create_transfer_to_bdo(cnx)
cnx.commit() # commit first to get the container
bdo.container[0].cw_set(seda_message_digest_algorithm_code_list_version=self.enc_scheme)
cnx.commit()
self.assertDigestAlgorithmConcept(bdo)
def test_component_archive_unit_digest_algorithm_constraint(self):
with self.admin_access.client_cnx() as cnx:
unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(None, cnx=cnx)
bdo = testutils.create_data_object(unit_alt_seq)
bdo_type = cnx.find('CWEType', name=u'SEDABinaryDataObject').one()
alg_type = cnx.find('CWRType', name=u'seda_algorithm').one()
cnx.entity_from_eid(self.enc_scheme).cw_set(scheme_entity_type=bdo_type,
scheme_relation_type=alg_type)
cnx.commit()
self.assertDigestAlgorithmConcept(bdo)
class SchemaTC(CubicWebTC):
......
......@@ -28,7 +28,7 @@ from cubicweb.web.views import uicfg, tabs, ibreadcrumbs
from cubes.relationwidget import views as rwdg
from cubes.skos.views import widgets as skos
from cubes.seda.xsd2yams import RDEF_CONSTRAINTS
from cubes.seda.xsd2yams import SCHEME_FROM_CONTAINER
from cubes.seda.entities import parent_and_container, simplified_profile, full_seda2_profile
from cubes.seda.views import rtags_from_xsd_element, add_subobject_link
from cubes.seda.views import viewlib
......@@ -42,24 +42,27 @@ afs = uicfg.autoform_section
affk = uicfg.autoform_field_kwargs
def scheme_rql_expr(container, etype, rtype):
"""Return RQL expression (right part of the WHERE) to retrieve the scheme (mapped as 'CS'
variable) for some (entity type / relation type) couple, in the context of the given
`container`.
"""
try:
scheme_from_container = SCHEME_FROM_CONTAINER[(etype, rtype)]
except KeyError:
scheme_from_container = SCHEME_FROM_CONTAINER[rtype]
return scheme_from_container[container.cw_etype]
class ContainedRelationFacetWidget(rwdg.RelationFacetWidget):
def _render_triggers(self, w, domid, form, field, rtype):
req = form._cw
parent, container = parent_and_container(form.edited_entity)
assert container is not None
if container.cw_etype != 'SEDAArchiveTransfer':
w('XXX FIXME')
return
req = form._cw
try:
constraint = RDEF_CONSTRAINTS[(form.edited_entity.cw_etype, field.name)]
except KeyError:
constraint = RDEF_CONSTRAINTS[field.name]
rql = 'Any CS WHERE ' + (
constraint.replace('O in_scheme CS, ', '').replace(', S container AT', ''))
rql += ', AT eid %(at)s'
if not req.execute(rql, {'at': container.eid}):
scheme_relations = [x for x in rql.split() if x.startswith('seda_')]
rql_expr = scheme_rql_expr(container, form.edited_entity.cw_etype, field.name)
if not req.execute('Any CS WHERE ' + rql_expr, {'container': container.eid}):
scheme_relations = [x for x in rql_expr.split() if x.startswith('seda_')]
if len(scheme_relations) == 1:
scheme_relation = req._(scheme_relations[0])
else:
......@@ -83,17 +86,24 @@ class ContainedRelationFacetWidget(rwdg.RelationFacetWidget):
return super(ContainedRelationFacetWidget, self).trigger_search_url(entity, url_params)
for key in SCHEME_FROM_CONTAINER:
try:
etype, rtype = key
except ValueError:
etype = '*'
rtype = key
affk.tag_subject_of((etype, rtype, '*'),
{'widget': ContainedRelationFacetWidget(dialog_options={'width': 800})})
class ContainedSearchForRelatedEntitiesView(skos.SearchForRelatedConceptsView):
__select__ = skos.SearchForRelatedConceptsView.__select__ & match_form_params('container')
def constrained_rql(self):
container = int(self._cw.form['container'])
constraints = self.schema_rdef.constraints
assert len(constraints) == 1 and 'S container AT' in constraints[0].expression, constraints
baserql = constraints[0].expression
baserql = baserql.replace('S container AT', 'AT eid %(at)s')
return baserql, {'at': container}
container = self._cw.entity_from_eid(int(self._cw.form['container']))
rql_expr = scheme_rql_expr(container, self.schema_rdef.subject, self.schema_rdef.rtype)
return rql_expr + ', O in_scheme CS', {'container': container.eid}
pvs.tag_object_of(('*', 'seda_data_object_reference_id', '*'),
......@@ -140,19 +150,6 @@ affk.tag_attribute(('SEDAUri', 'user_cardinality'),
{'choices': uri_cardinality_vocabulary})
for key, rql_expr in RDEF_CONSTRAINTS.items():
if 'S container AT' in rql_expr:
try:
etype, rtype = key
except ValueError:
etype = '*'
rtype = key
if rtype == 'seda_rule':
continue # managed in mgmt_rules module
affk.tag_subject_of((etype, rtype, '*'),
{'widget': ContainedRelationFacetWidget(dialog_options={'width': 800})})
bdo_ordered_fields = [
('id', 'subject'),
('user_cardinality', 'subject'),
......
......@@ -114,17 +114,25 @@ RDEF_CONSTRAINTS = {
'O in_scheme CS, CS scheme_relation_type CR, CR name "seda_final_action", '
'CS scheme_entity_type ET, ET name "{subjtype}"'),
# - scheme defined as code list
# if you modify one of those, keep synchronized the SCHEME_FROM_CONTAINER map below
# and run "python -m tox -e make" to update the schema"
'seda_mime_type_to': (
'O in_scheme CS, CACLV seda_mime_type_code_list_version_from AT, '
'CACLV seda_mime_type_code_list_version_to CS,'
'S container AT'),
'O in_scheme CS, '
'EXISTS(CACLV seda_mime_type_code_list_version_from AT, '
' CACLV seda_mime_type_code_list_version_to CS,'
' S container AT)'
' OR EXISTS(S container AU, AU is SEDAArchiveUnit, CS scheme_relation_type RT, '
' RT name "seda_mime_type_to")'),
'seda_encoding_to': (
'O in_scheme CS, '
'EXISTS(CACLV seda_encoding_code_list_version_from AT, '
' CACLV seda_encoding_code_list_version_to CS,'
' S container AT)'
' OR EXISTS(S container AU, AU is SEDAArchiveUnit, CS scheme_relation_type RT, '
' RT name "seda_encoding_to")'),
'seda_format_id_to': (
'O in_scheme CS, AT seda_file_format_code_list_version CS, '
'S container AT'),
'seda_encoding_to': (
'O in_scheme CS, CACLV seda_encoding_code_list_version_from AT, '
'CACLV seda_encoding_code_list_version_to CS,'
'S container AT'),
'seda_data_object_version_to': (
'O in_scheme CS, CACLV seda_data_object_version_code_list_version_from AT, '
'CACLV seda_data_object_version_code_list_version_to CS,'
......@@ -134,8 +142,11 @@ RDEF_CONSTRAINTS = {
'CACLV seda_relationship_code_list_version_to CS,'
'S container AT'),
('SEDABinaryDataObject', 'seda_algorithm'): (
'O in_scheme CS, AT seda_message_digest_algorithm_code_list_version CS, '
'S container AT'),
'O in_scheme CS, '
'EXISTS(S container AT, AT seda_message_digest_algorithm_code_list_version CS) '
'OR EXISTS(S container AU, AU is SEDAArchiveUnit, '
' CS scheme_relation_type RT, RT name "seda_algorithm", '
' CS scheme_entity_type ET, ET name "SEDABinaryDataObject")'),
('SEDACompressed', 'seda_algorithm'): (
'O in_scheme CS, CACLV seda_compression_algorithm_code_list_version_from AT, '
'CACLV seda_compression_algorithm_code_list_version_to CS,'
......@@ -198,6 +209,48 @@ _CARD_TO_CARDS = {
'*': ['0..1', '0..n', '1', '1..n'],
}
# Map RQL expression to retrieve matching concept scheme depending on the container type.
# Client code (e.g. in `views/dataobject`) expect scheme to be mapped to the "CS" variable
# and container's eid will be specified using a "container" query argument.
SCHEME_FROM_CONTAINER = {
'seda_mime_type_to': {
'SEDAArchiveTransfer': ('CACLV seda_mime_type_code_list_version_from AT, '
'CACLV seda_mime_type_code_list_version_to CS, '
'AT eid %(container)s'),
'SEDAArchiveUnit': 'CS scheme_relation_type RT, RT name "seda_mime_type_to"',
},
'seda_encoding_to': {
'SEDAArchiveTransfer': ('CACLV seda_encoding_code_list_version_from AT, '
'CACLV seda_encoding_code_list_version_to CS, '
'AT eid %(container)s'),
'SEDAArchiveUnit': 'CS scheme_relation_type RT, RT name "seda_encoding_to"',
},
'seda_format_id_to': {
'SEDAArchiveTransfer': ('AT seda_file_format_code_list_version CS, '
'AT eid %(container)s'),
},
'seda_data_object_version_to': {
'SEDAArchiveTransfer': ('CACLV seda_data_object_version_code_list_version_from AT, '
'CACLV seda_data_object_version_code_list_version_to CS, '
'AT eid %(container)s'),
},
'seda_type_relationship': {
'SEDAArchiveTransfer': ('CACLV seda_relationship_code_list_version_to CS,'
'AT eid %(container)s'),
},
('SEDABinaryDataObject', 'seda_algorithm'): {
'SEDAArchiveTransfer': ('AT seda_message_digest_algorithm_code_list_version CS, '
'AT eid %(container)s'),
'SEDAArchiveUnit': ('CS scheme_relation_type RT, RT name "seda_algorithm", '
'CS scheme_entity_type ET, ET name "SEDABinaryDataObject"'),
},
('SEDACompressed', 'seda_algorithm'): {
'SEDAArchiveTransfer': ('CACLV seda_compression_algorithm_code_list_version_from AT, '
'CACLV seda_compression_algorithm_code_list_version_to CS,'
'AT eid %(container)s'),
},
}
def xsy_mapping(tagname='ArchiveTransfer'):
mapping = XSYMapping()
......
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