web/views/cwsources.py
changeset 6724 24bf6f181d0e
child 6944 0cf10429ad39
equal deleted inserted replaced
6723:a2ccbcbb08a6 6724:24bf6f181d0e
       
     1 # copyright 2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """Specific views for data sources"""
       
    19 
       
    20 __docformat__ = "restructuredtext en"
       
    21 _ = unicode
       
    22 
       
    23 from itertools import repeat, chain
       
    24 
       
    25 from cubicweb.selectors import is_instance, score_entity
       
    26 from cubicweb.view import EntityView
       
    27 from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
       
    28 from cubicweb.web import uicfg
       
    29 from cubicweb.web.views import tabs
       
    30 
       
    31 for rtype in ('cw_support', 'cw_may_cross', 'cw_dont_cross'):
       
    32     uicfg.primaryview_section.tag_subject_of(('CWSource', rtype, '*'),
       
    33                                              'hidden')
       
    34 
       
    35 class CWSourcePrimaryView(tabs.TabbedPrimaryView):
       
    36     __select__ = is_instance('CWSource')
       
    37     tabs = [_('cwsource-main'), _('cwsource-mapping')]
       
    38     default_tab = 'cwsource-main'
       
    39 
       
    40 
       
    41 class CWSourceMainTab(tabs.PrimaryTab):
       
    42     __regid__ = 'cwsource-main'
       
    43     __select__ = tabs.PrimaryTab.__select__ & is_instance('CWSource')
       
    44 
       
    45 
       
    46 class CWSourceMappingTab(EntityView):
       
    47     __regid__ = 'cwsource-mapping'
       
    48     __select__ = (tabs.PrimaryTab.__select__ & is_instance('CWSource')
       
    49                   & score_entity(lambda x:x.type == 'pyrorql'))
       
    50 
       
    51     def entity_call(self, entity):
       
    52         _ = self._cw._
       
    53         self.w('<h3>%s</h3>' % _('Entity and relation types supported by this source'))
       
    54         self.wview('list', entity.related('cw_support'), 'noresult')
       
    55         self.w('<h3>%s</h3>' % _('Relations that should not be crossed'))
       
    56         self.w('<p>%s</p>' % _(
       
    57             'By default, when a relation is not supported by a source, it is '
       
    58             'supposed that a local relation may point to an entity from the '
       
    59             'external source. Relations listed here won\'t have this '
       
    60             '"crossing" behaviour.'))
       
    61         self.wview('list', entity.related('cw_dont_cross'), 'noresult')
       
    62         self.w('<h3>%s</h3>' % _('Relations that can be crossed'))
       
    63         self.w('<p>%s</p>' % _(
       
    64             'By default, when a relation is supported by a source, it is '
       
    65             'supposed that a local relation can\'t point to an entity from the '
       
    66             'external source. Relations listed here may have this '
       
    67             '"crossing" behaviour anyway.'))
       
    68         self.wview('list', entity.related('cw_may_cross'), 'noresult')
       
    69         if self._cw.user.is_in_group('managers'):
       
    70             errors, warnings, infos = check_mapping(entity)
       
    71             if (errors or warnings or infos):
       
    72                 self.w('<h2>%s</h2>' % _('Detected problems'))
       
    73                 errors = zip(repeat(_('error'), errors))
       
    74                 warnings = zip(repeat(_('warning'), warnings))
       
    75                 infos = zip(repeat(_('warning'), infos))
       
    76                 self.wview('pyvaltable', pyvalue=chain(errors, warnings, infos))
       
    77 
       
    78 def check_mapping(cwsource):
       
    79     req = cwsource._cw
       
    80     _ = req._
       
    81     errors = []
       
    82     error = errors.append
       
    83     warnings = []
       
    84     warning = warnings.append
       
    85     infos = []
       
    86     info = infos.append
       
    87     srelations = set()
       
    88     sentities = set()
       
    89     maycross = set()
       
    90     dontcross = set()
       
    91     # first check supported stuff / meta & virtual types and get mapping as sets
       
    92     for cwertype in cwsource.cw_support:
       
    93         if cwertype.name in META_RTYPES:
       
    94             error(_('meta relation %s can not be supported') % cwertype.name)
       
    95         else:
       
    96             if cwertype.__regid__ == 'CWEType':
       
    97                 sentities.add(cwertype.name)
       
    98             else:
       
    99                 srelations.add(cwertype.name)
       
   100     for attr, attrset in (('cw_may_cross', maycross),
       
   101                           ('cw_dont_cross', dontcross)):
       
   102         for cwrtype in getattr(cwsource, attr):
       
   103             if cwrtype.name in VIRTUAL_RTYPES:
       
   104                 error(_('virtual relation %(rtype)s can not be referenced by '
       
   105                         'the "%(srel)s" relation') %
       
   106                       {'rtype': cwrtype.name,
       
   107                        'srel': display_name(req, attr, context='CWSource')})
       
   108             else:
       
   109                 attrset.add(cwrtype.name)
       
   110     # check relation in dont_cross_relations aren't in support_relations
       
   111     for rtype in dontcross & maycross:
       
   112         info(_('relation %(rtype)s is supported but in %(dontcross)s') %
       
   113              {'rtype': rtype,
       
   114               'dontcross': display_name(req, 'cw_dont_cross',
       
   115                                         context='CWSource')})
       
   116     # check relation in cross_relations are in support_relations
       
   117     for rtype in maycross & srelations:
       
   118         info(_('relation %(rtype)s isn\'t supported but in %(maycross)s') %
       
   119              {'rtype': rtype,
       
   120               'dontcross': display_name(req, 'cw_may_cross',
       
   121                                         context='CWSource')})
       
   122     # now check for more handy things
       
   123     seen = set()
       
   124     for etype in sentities:
       
   125         eschema = req.vreg.schema[etype]
       
   126         for rschema, ttypes, role in eschema.relation_definitions():
       
   127             if rschema in META_RTYPES:
       
   128                 continue
       
   129             ttypes = [ttype for ttype in ttypes if ttype in sentities]
       
   130             if not rschema in srelations:
       
   131                 somethingprinted = False
       
   132                 for ttype in ttypes:
       
   133                     rdef = rschema.role_rdef(etype, ttype, role)
       
   134                     seen.add(rdef)
       
   135                     if rdef.role_cardinality(role) in '1+':
       
   136                         error(_('relation %(type)s with %(etype)s as %(role)s '
       
   137                                 'and target type %(target)s is mandatory but '
       
   138                                 'not supported') %
       
   139                               {'rtype': rschema, 'etype': etype, 'role': role,
       
   140                                'target': ttype})
       
   141                         somethingprinted = True
       
   142                     elif ttype in sentities:
       
   143                         if rdef not in seen:
       
   144                             warning(_('%s could be supported') % rdef)
       
   145                         somethingprinted = True
       
   146                 if rschema not in dontcross:
       
   147                     if role == 'subject' and rschema.inlined:
       
   148                         error(_('inlined relation %(rtype)s of %(etype)s '
       
   149                                 'should be supported') %
       
   150                               {'rtype': rschema, 'etype': etype})
       
   151                     elif (not somethingprinted and rschema not in seen
       
   152                           and rschema not in maycross):
       
   153                         info(_('you may want to specify something for %s') %
       
   154                              rschema)
       
   155                         seen.add(rschema)
       
   156             else:
       
   157                 if not ttypes:
       
   158                     warning(_('relation %(rtype)s with %(etype)s as %(role)s '
       
   159                               'is supported but no target type supported') %
       
   160                             {'rtype': rschema, 'role': role, 'etype': etype})
       
   161                 if rschema in maycross and rschema.inlined:
       
   162                     error(_('you should un-inline relation %s which is '
       
   163                             'supported and may be crossed ') % rschema)
       
   164     for rschema in srelations:
       
   165         for subj, obj in rschema.rdefs:
       
   166             if subj in sentities and obj in sentities:
       
   167                 break
       
   168         else:
       
   169             error(_('relation %s is supported but none if its definitions '
       
   170                     'matches supported entities') % rschema)
       
   171     return errors, warnings, infos