# 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
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see .
"""cubicweb-seda views for data objects (BinaryDataObject / PhysicalDataObject)"""
import json
from six import text_type
from logilab.mtconverter import xml_escape
from cubicweb import tags, view, _
from cubicweb.predicates import match_form_params, is_instance
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 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
from cubes.seda.views import uicfg as sedauicfg # noqa - ensure those rules are defined first
pvs = uicfg.primaryview_section
pvdc = uicfg.primaryview_display_ctrl
rec = uicfg.reledit_ctrl
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
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 not scheme_relations:
w(req._('there is no scheme available for this relation. '
'Contact the site administrator.'))
return
if len(scheme_relations) == 1:
scheme_relation = req._(scheme_relations[0])
else:
scheme_relation = req.__(scheme_relations[0] + '_object')
w(req._('you must specify a scheme for {0} to select a value').format(
scheme_relation))
else:
return super(ContainedRelationFacetWidget, self)._render_triggers(
w, domid, form, field, rtype)
def trigger_search_url(self, entity, url_params):
"""Overriden to add information about who is the container
This information will be used later for proper vocabulary computation.
"""
# first retrieve the container entity
_, container = parent_and_container(entity)
assert container is not None
# and put it as an extra url param
url_params['container'] = text_type(container.eid)
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 = 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', '*'),
'relations')
pvdc.tag_object_of(('*', 'seda_data_object_reference_id', '*'),
{'vid': 'autolimited',
'subvid': 'seda.object-ref.archive-unit',
'label': _('referenced by:')})
pvs.tag_subject_of(('*', 'seda_algorithm', '*'), 'attributes')
pvs.tag_object_of(('*', 'seda_target', '*'), 'hidden') # in the relationship tab
for rtype in ('seda_compressed', 'seda_data_object_version_from'):
# hide relation from autoform because of limitation of _container_eid
afs.tag_object_of(('*', rtype, '*'), 'main', 'hidden')
pvs.tag_object_of(('*', rtype, '*'), 'attributes')
rec.tag_object_of(('*', rtype, '*'),
{'rvid': 'seda.reledit.complexlink',
'novalue_label': _('')})
rec.tag_subject_of(('SEDABinaryDataObject', 'seda_alt_binary_data_object_attachment', '*'),
{'rvid': 'seda.reledit.alternative',
'novalue_label': _('')})
def uri_cardinality_vocabulary(form, field):
req = form._cw
if form.edited_entity.has_eid():
parent_type = form.edited_entity.cw_adapt_to('IContained').parent.cw_etype
else:
try:
# inlined creation form
parent_type = json.loads(req.form['arg'][1])
except KeyError:
# edition through reledit
parent_eid = req.form['eid']
parent_type = req.describe(int(parent_eid))[0]
if parent_type in ('SEDABinaryDataObject', 'SEDAAltBinaryDataObjectAttachment'):
return [u'1']
return [u'0..1', u'1']
affk.tag_attribute(('SEDAUri', 'user_cardinality'),
{'choices': uri_cardinality_vocabulary})
bdo_ordered_fields = [
('id', 'subject'),
('user_cardinality', 'subject'),
('user_annotation', 'subject'),
('filename', 'subject'),
('seda_date_created_by_application', 'object'),
('seda_compressed', 'object'),
('seda_data_object_version_from', 'object'),
('seda_algorithm', 'object'),
]
affk.set_fields_order('SEDABinaryDataObject', bdo_ordered_fields)
pvdc.set_fields_order('SEDABinaryDataObject', bdo_ordered_fields)
class BinaryDataObjectTabbedPrimaryView(tabs.TabbedPrimaryView):
__select__ = is_instance('SEDABinaryDataObject')
tabs = [
'main_tab',
_('seda_bdo_format_identification'),
_('seda_bdo_file_information'),
_('seda_do_relations'),
]
class BinaryDataObjectFormatIdentificationTab(viewlib.PrimaryTabWithoutBoxes):
"""Display format identification information of a binary data object"""
__regid__ = 'seda_bdo_format_identification'
__select__ = is_instance('SEDABinaryDataObject')
rsection, display_ctrl = rtags_from_xsd_element('SEDABinaryDataObject', 'FormatIdentification')
class SimplifiedBinaryDataObjectFormatIdentificationTab(BinaryDataObjectFormatIdentificationTab):
__select__ = BinaryDataObjectFormatIdentificationTab.__select__ & simplified_profile()
rsection, display_ctrl = rtags_from_xsd_element('SEDABinaryDataObject', 'FormatIdentification')
rsection.tag_object_of(('*', 'seda_format_id_from', 'SEDABinaryDataObject'), 'hidden')
class BinaryDataObjectFileInfoTab(viewlib.PrimaryTabWithoutBoxes):
"""Display file information of a binary data object"""
__regid__ = 'seda_bdo_file_information'
__select__ = is_instance('SEDABinaryDataObject') & full_seda2_profile()
rsection, display_ctrl = rtags_from_xsd_element('SEDABinaryDataObject', 'FileInfo')
class PhysicalDataObjectTabbedPrimaryView(tabs.TabbedPrimaryView):
__select__ = is_instance('SEDAPhysicalDataObject')
tabs = [
'main_tab',
_('seda_pdo_dimensions'),
_('seda_do_relations'),
]
class PhysicalDataObjectDimensionsTab(viewlib.PrimaryTabWithoutBoxes):
"""Display physical dimensions of a physical data object"""
__regid__ = 'seda_pdo_dimensions'
__select__ = is_instance('SEDAPhysicalDataObject')
rsection, display_ctrl = rtags_from_xsd_element('SEDAPhysicalDataObject', 'PhysicalDimensions')
class DataObjectRelationsTab(viewlib.PrimaryTabWithoutBoxes):
"""Display relations of a binary or physical data object"""
__regid__ = 'seda_do_relations'
__select__ = (is_instance('SEDABinaryDataObject', 'SEDAPhysicalDataObject')
& full_seda2_profile())
_('creating SEDARelationship (SEDARelationship seda_relationship '
'SEDABinaryDataObject %(linkto)s)')
_('creating SEDARelationship (SEDARelationship seda_relationship '
'SEDAPhysicalDataObject %(linkto)s)')
def entity_call(self, entity):
rschema = self._cw.vreg.schema.rschema('seda_relationship')
if rschema.has_perm(self._cw, 'add', toeid=entity.eid):
urlparams = {'__redirectparams': 'tab=' + self.__regid__}
self.w(add_subobject_link(entity, 'seda_relationship', 'object', urlparams,
msg=self._cw._('add a SEDARelationship'),
klass='btn btn-success pull-right'))
self.w(tags.div(klass='clearfix'))
rset = entity.related('seda_relationship', 'object')
if rset:
self._cw.view('list', rset=rset, parent=entity, w=self.w, tabid=self.__regid__,
subvid='seda.listitem')
rset = entity.related('seda_target', 'object')
if rset:
self.w(u'{0}
'.format(self._cw._('Relationship target of')))
self.w(u'{0}
'.format(
self._cw._('This object is used as a relationship target of the following '
'entities')))
self._cw.view('list', rset=rset, subvid='seda.relationship.reverse', w=self.w)
class RelationshipBusinessValueLinkEntityView(viewlib.BusinessValueLinkEntityView):
__select__ = is_instance('SEDARelationship')
def entity_value(self, entity):
target = entity.seda_target[0] if entity.seda_target else None
if target:
value = tags.a(target.dc_title(), href=target.absolute_url())
else:
value = xml_escape(self._cw._(''))
if entity.seda_type_relationship:
concept = entity.seda_type_relationship[0]
msg = self._cw._(', of relationship type %s') % concept.label()
else:
msg = self._cw._(', no relationship type specified')
value += xml_escape(msg)
return value
class RelationshipReverseEntityView(view.EntityView):
__regid__ = 'seda.relationship.reverse'
__select__ = is_instance('SEDARelationship')
def entity_call(self, entity):
target = entity.seda_relationship[0]
self.w(tags.a(target.dc_title(), href=target.absolute_url()))
if entity.seda_type_relationship:
concept = entity.seda_type_relationship[0]
msg = self._cw._(', of relationship type %s') % concept.label()
else:
msg = self._cw._(', no relationship type specified')
self.w(xml_escape(msg))
class ObjectReferencepArchiveUnitEntityView(view.EntityView):
__regid__ = 'seda.object-ref.archive-unit'
__select__ = is_instance('SEDADataObjectReference')
def entity_call(self, entity):
au_seq = entity.seda_data_object_reference[0]
au_choice = au_seq.reverse_seda_seq_alt_archive_unit_archive_unit_ref_id_management[0]
archive_unit = au_choice.reverse_seda_alt_archive_unit_archive_unit_ref_id[0]
self._cw.view('listitem', rset=archive_unit.as_rset(), w=self.w)
class UnitBusinessValueEntityView(viewlib.BusinessValueEntityView):
__select__ = is_instance('SEDAWidth', 'SEDAHeight', 'SEDADepth', 'SEDAShape',
'SEDADiameter', 'SEDALength', 'SEDAThickness', 'SEDAWeight')
def entity_call(self, entity):
super(UnitBusinessValueEntityView, self).entity_call(entity)
if entity.seda_unit:
unit = self._cw._('unit: {0}').format(entity.seda_unit[0].label())
else:
unit = self._cw._('')
self.w(u' (%s)' % xml_escape(unit))
class IBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter):
"""Override adapter from compound when BDO is within a simplified profile to display the archive
unit as parent.
"""
__select__ = is_instance('SEDABinaryDataObject') & simplified_profile()
def parent_entity(self):
return self.entity.cw_adapt_to('ITreeBase').parent()