dataobject.py 13.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 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 <http://www.gnu.org/licenses/>.
"""cubicweb-seda views for data objects (BinaryDataObject / PhysicalDataObject)"""

18
19
import json

20
21
from logilab.mtconverter import xml_escape

Sylvain Thénault's avatar
Sylvain Thénault committed
22
from cubicweb import tags, view, _
23
from cubicweb.predicates import match_form_params, is_instance
24
from cubicweb.web.views import uicfg, tabs, ibreadcrumbs
25
26

from cubes.relationwidget import views as rwdg
27
from cubes.skos.views import widgets as skos
28

29
from cubes.seda.xsd2yams import RDEF_CONSTRAINTS
30
from cubes.seda.entities import parent_and_container, simplified_profile
31
from cubes.seda.views import rtags_from_xsd_element, add_subobject_link
32
from cubes.seda.views import viewlib, copy_rtag
33
from cubes.seda.views import uicfg as sedauicfg  # noqa - ensure those rules are defined first
34

35

36
pvs = uicfg.primaryview_section
37
pvdc = uicfg.primaryview_display_ctrl
38
39
rec = uicfg.reledit_ctrl
afs = uicfg.autoform_section
40
41
affk = uicfg.autoform_field_kwargs

42
43

class ContainedRelationFacetWidget(rwdg.RelationFacetWidget):
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    def _render_triggers(self, w, domid, form, field, rtype):
        parent, container = parent_and_container(form.edited_entity)
        req = form._cw
        if container is None:
            w(req._('you must validate first to select a possible value'))
        else:
            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_')]
                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)
69
70
71
72
73
74
75

    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
76
        _, container = parent_and_container(entity)
77
        # and put it as an extra url param
78
79
        if container is not None:
            url_params['container'] = unicode(container.eid)
80
81
82
        return super(ContainedRelationFacetWidget, self).trigger_search_url(entity, url_params)


83
class ContainedSearchForRelatedEntitiesView(skos.SearchForRelatedConceptsView):
84

85
    __select__ = skos.SearchForRelatedConceptsView.__select__ & match_form_params('container')
86

87
    def constrained_rql(self):
88
        container = int(self._cw.form['container'])
89
90
91
        constraints = self.schema_rdef.constraints
        assert len(constraints) == 1 and 'S container AT' in constraints[0].expression, constraints
        baserql = constraints[0].expression
92
        baserql = baserql.replace('S container AT', 'AT eid %(at)s')
93
        return baserql, {'at': container}
94
95


96
pvs.tag_object_of(('*', 'seda_data_object_reference_id', '*'),
97
                  'relations')
98
pvdc.tag_object_of(('*', 'seda_data_object_reference_id', '*'),
99
100
101
                   {'vid': 'autolimited',
                    'subvid': 'seda.object-ref.archive-unit',
                    'label': _('referenced by:')})
102

103
pvs.tag_subject_of(('*', 'seda_algorithm', '*'), 'attributes')
104
pvs.tag_object_of(('*', 'seda_target', '*'), 'hidden')  # in the relationship tab
105
106
107
108
109

simplified_pvs = copy_rtag(pvs, __name__,
                           is_instance('SEDABinaryDataObject') & simplified_profile())
simplified_pvs.tag_object_of(('*', 'seda_data_object_reference_id', '*'), 'hidden')

110
111
112
113
114
115
116
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': _('<unauthorized>')})
117
    simplified_pvs.tag_object_of(('*', rtype, '*'), 'hidden')
118
119
120
121
122
123

rec.tag_subject_of(('SEDABinaryDataObject', 'seda_alt_binary_data_object_attachment', '*'),
                   {'rvid': 'seda.reledit.alternative',
                    'novalue_label': _('<unauthorized>')})


124
125
def uri_cardinality_vocabulary(form, field):
    req = form._cw
126
127
128
129
130
131
132
133
134
135
    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]
136
137
138
139
140
141
142
143
    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})


144
145
146
147
148
149
150
for key, rql_expr in RDEF_CONSTRAINTS.items():
    if 'S container AT' in rql_expr:
        try:
            etype, rtype = key
        except ValueError:
            etype = '*'
            rtype = key
151
152
        if rtype == 'seda_rule':
            continue  # managed in mgmt_rules module
153
154
        affk.tag_subject_of((etype, rtype, '*'),
                            {'widget': ContainedRelationFacetWidget(dialog_options={'width': 800})})
155
156


157
158
159
160
161
162
163
164
165
166
167
168
169
bdo_ordered_fields = [
    ('id', 'subject'),
    ('user_cardinality', 'subject'),
    ('user_annotation', 'subject'),
    ('filename', 'subject'),
    ('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)


170
class BinaryDataObjectTabbedPrimaryView(tabs.TabbedPrimaryView):
171

172
173
174
    __select__ = tabs.TabbedPrimaryView.__select__ & is_instance('SEDABinaryDataObject')
    tabs = [
        'main_tab',
175
        _('seda_bdo_format_identification'),
176
        _('seda_bdo_file_information'),
177
        _('seda_do_relations'),
178
179
180
    ]


181
182
class BinaryDataObjectFormatIdentificationTab(tabs.PrimaryTab):
    """Display format identification information of a binary data object"""
183

184
185
186
187
188
189
    __regid__ = 'seda_bdo_format_identification'
    __select__ = tabs.PrimaryTab.__select__ & is_instance('SEDABinaryDataObject')

    rsection, display_ctrl = rtags_from_xsd_element('SEDABinaryDataObject', 'FormatIdentification')


190
191
192
193
194
195
196
197
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')


198
199
class BinaryDataObjectFileInfoTab(tabs.PrimaryTab):
    """Display file information of a binary data object"""
200

201
202
203
204
205
206
    __regid__ = 'seda_bdo_file_information'
    __select__ = tabs.PrimaryTab.__select__ & is_instance('SEDABinaryDataObject')

    rsection, display_ctrl = rtags_from_xsd_element('SEDABinaryDataObject', 'FileInfo')


207
class PhysicalDataObjectTabbedPrimaryView(tabs.TabbedPrimaryView):
208

209
210
211
    __select__ = tabs.TabbedPrimaryView.__select__ & is_instance('SEDAPhysicalDataObject')
    tabs = [
        'main_tab',
212
        _('seda_pdo_dimensions'),
213
        _('seda_do_relations'),
214
    ]
215
216


217
218
class PhysicalDataObjectDimensionsTab(tabs.PrimaryTab):
    """Display physical dimensions of a physical data object"""
219

220
221
222
223
224
225
    __regid__ = 'seda_pdo_dimensions'
    __select__ = tabs.PrimaryTab.__select__ & is_instance('SEDAPhysicalDataObject')

    rsection, display_ctrl = rtags_from_xsd_element('SEDAPhysicalDataObject', 'PhysicalDimensions')


Sylvain Thénault's avatar
Sylvain Thénault committed
226
class DataObjectRelationsTab(tabs.PrimaryTab):
227
    """Display relations of a binary or physical data object"""
228

229
230
231
232
    __regid__ = 'seda_do_relations'
    __select__ = tabs.PrimaryTab.__select__ & is_instance('SEDABinaryDataObject',
                                                          'SEDAPhysicalDataObject')

233
234
235
236
237
    _('creating SEDARelationship (SEDARelationship seda_relationship '
      'SEDABinaryDataObject %(linkto)s)')
    _('creating SEDARelationship (SEDARelationship seda_relationship '
      'SEDAPhysicalDataObject %(linkto)s)')

238
239
240
241
242
243
244
245
246
247
248
249
    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')
250
251
252
253
254
255
256
        rset = entity.related('seda_target', 'object')
        if rset:
            self.w(u'<h2>{0}</h2>'.format(self._cw._('Relationship target of')))
            self.w(u'<div>{0}</div>'.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)
257
258
259


class RelationshipBusinessValueLinkEntityView(viewlib.BusinessValueLinkEntityView):
260

261
    __select__ = is_instance('SEDARelationship')
262

263
264
265
266
267
268
    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._('<no data-object specified>'))
269
270
        if entity.seda_type_relationship:
            concept = entity.seda_type_relationship[0]
271
            msg = self._cw._(', of relationship type %s') % concept.label()
272
        else:
273
274
275
            msg = self._cw._(', no relationship type specified')
        value += xml_escape(msg)
        return value
276
277


278
class RelationshipReverseEntityView(view.EntityView):
279

280
281
282
283
284
285
286
287
288
289
290
291
292
293
    __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))


294
class ObjectReferencepArchiveUnitEntityView(view.EntityView):
295

296
297
298
299
300
301
302
303
304
305
    __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)


306
class UnitBusinessValueEntityView(viewlib.BusinessValueEntityView):
307

308
309
310
311
312
313
314
315
316
317
    __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._('<no unit specified>')
        self.w(u' (%s)' % xml_escape(unit))
318
319
320
321
322
323
324
325
326
327


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()