diff -r a2ccbcbb08a6 -r 24bf6f181d0e web/views/cwsources.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/cwsources.py Wed Dec 01 17:11:35 2010 +0100 @@ -0,0 +1,171 @@ +# copyright 2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of CubicWeb. +# +# CubicWeb 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. +# +# CubicWeb 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 CubicWeb. If not, see . +"""Specific views for data sources""" + +__docformat__ = "restructuredtext en" +_ = unicode + +from itertools import repeat, chain + +from cubicweb.selectors import is_instance, score_entity +from cubicweb.view import EntityView +from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name +from cubicweb.web import uicfg +from cubicweb.web.views import tabs + +for rtype in ('cw_support', 'cw_may_cross', 'cw_dont_cross'): + uicfg.primaryview_section.tag_subject_of(('CWSource', rtype, '*'), + 'hidden') + +class CWSourcePrimaryView(tabs.TabbedPrimaryView): + __select__ = is_instance('CWSource') + tabs = [_('cwsource-main'), _('cwsource-mapping')] + default_tab = 'cwsource-main' + + +class CWSourceMainTab(tabs.PrimaryTab): + __regid__ = 'cwsource-main' + __select__ = tabs.PrimaryTab.__select__ & is_instance('CWSource') + + +class CWSourceMappingTab(EntityView): + __regid__ = 'cwsource-mapping' + __select__ = (tabs.PrimaryTab.__select__ & is_instance('CWSource') + & score_entity(lambda x:x.type == 'pyrorql')) + + def entity_call(self, entity): + _ = self._cw._ + self.w('

%s

' % _('Entity and relation types supported by this source')) + self.wview('list', entity.related('cw_support'), 'noresult') + self.w('

%s

' % _('Relations that should not be crossed')) + self.w('

%s

' % _( + 'By default, when a relation is not supported by a source, it is ' + 'supposed that a local relation may point to an entity from the ' + 'external source. Relations listed here won\'t have this ' + '"crossing" behaviour.')) + self.wview('list', entity.related('cw_dont_cross'), 'noresult') + self.w('

%s

' % _('Relations that can be crossed')) + self.w('

%s

' % _( + 'By default, when a relation is supported by a source, it is ' + 'supposed that a local relation can\'t point to an entity from the ' + 'external source. Relations listed here may have this ' + '"crossing" behaviour anyway.')) + self.wview('list', entity.related('cw_may_cross'), 'noresult') + if self._cw.user.is_in_group('managers'): + errors, warnings, infos = check_mapping(entity) + if (errors or warnings or infos): + self.w('

%s

' % _('Detected problems')) + errors = zip(repeat(_('error'), errors)) + warnings = zip(repeat(_('warning'), warnings)) + infos = zip(repeat(_('warning'), infos)) + self.wview('pyvaltable', pyvalue=chain(errors, warnings, infos)) + +def check_mapping(cwsource): + req = cwsource._cw + _ = req._ + errors = [] + error = errors.append + warnings = [] + warning = warnings.append + infos = [] + info = infos.append + srelations = set() + sentities = set() + maycross = set() + dontcross = set() + # first check supported stuff / meta & virtual types and get mapping as sets + for cwertype in cwsource.cw_support: + if cwertype.name in META_RTYPES: + error(_('meta relation %s can not be supported') % cwertype.name) + else: + if cwertype.__regid__ == 'CWEType': + sentities.add(cwertype.name) + else: + srelations.add(cwertype.name) + for attr, attrset in (('cw_may_cross', maycross), + ('cw_dont_cross', dontcross)): + for cwrtype in getattr(cwsource, attr): + if cwrtype.name in VIRTUAL_RTYPES: + error(_('virtual relation %(rtype)s can not be referenced by ' + 'the "%(srel)s" relation') % + {'rtype': cwrtype.name, + 'srel': display_name(req, attr, context='CWSource')}) + else: + attrset.add(cwrtype.name) + # check relation in dont_cross_relations aren't in support_relations + for rtype in dontcross & maycross: + info(_('relation %(rtype)s is supported but in %(dontcross)s') % + {'rtype': rtype, + 'dontcross': display_name(req, 'cw_dont_cross', + context='CWSource')}) + # check relation in cross_relations are in support_relations + for rtype in maycross & srelations: + info(_('relation %(rtype)s isn\'t supported but in %(maycross)s') % + {'rtype': rtype, + 'dontcross': display_name(req, 'cw_may_cross', + context='CWSource')}) + # now check for more handy things + seen = set() + for etype in sentities: + eschema = req.vreg.schema[etype] + for rschema, ttypes, role in eschema.relation_definitions(): + if rschema in META_RTYPES: + continue + ttypes = [ttype for ttype in ttypes if ttype in sentities] + if not rschema in srelations: + somethingprinted = False + for ttype in ttypes: + rdef = rschema.role_rdef(etype, ttype, role) + seen.add(rdef) + if rdef.role_cardinality(role) in '1+': + error(_('relation %(type)s with %(etype)s as %(role)s ' + 'and target type %(target)s is mandatory but ' + 'not supported') % + {'rtype': rschema, 'etype': etype, 'role': role, + 'target': ttype}) + somethingprinted = True + elif ttype in sentities: + if rdef not in seen: + warning(_('%s could be supported') % rdef) + somethingprinted = True + if rschema not in dontcross: + if role == 'subject' and rschema.inlined: + error(_('inlined relation %(rtype)s of %(etype)s ' + 'should be supported') % + {'rtype': rschema, 'etype': etype}) + elif (not somethingprinted and rschema not in seen + and rschema not in maycross): + info(_('you may want to specify something for %s') % + rschema) + seen.add(rschema) + else: + if not ttypes: + warning(_('relation %(rtype)s with %(etype)s as %(role)s ' + 'is supported but no target type supported') % + {'rtype': rschema, 'role': role, 'etype': etype}) + if rschema in maycross and rschema.inlined: + error(_('you should un-inline relation %s which is ' + 'supported and may be crossed ') % rschema) + for rschema in srelations: + for subj, obj in rschema.rdefs: + if subj in sentities and obj in sentities: + break + else: + error(_('relation %s is supported but none if its definitions ' + 'matches supported entities') % rschema) + return errors, warnings, infos