schema.py
branchstable
changeset 8124 acc23c284432
parent 8027 9ac82788f67b
child 8125 7070250bf50d
child 8160 e53c003e3d37
equal deleted inserted replaced
8118:7b2c7f3d3703 8124:acc23c284432
    57                            'initial_state', 'default_workflow',
    57                            'initial_state', 'default_workflow',
    58                            'allowed_transition', 'destination_state',
    58                            'allowed_transition', 'destination_state',
    59                            'from_state', 'to_state', 'condition',
    59                            'from_state', 'to_state', 'condition',
    60                            'subworkflow', 'subworkflow_state', 'subworkflow_exit',
    60                            'subworkflow', 'subworkflow_state', 'subworkflow_exit',
    61                            ))
    61                            ))
    62 SYSTEM_RTYPES = set(('in_group', 'require_group', 'require_permission',
    62 SYSTEM_RTYPES = set(('in_group', 'require_group',
    63                      # cwproperty
    63                      # cwproperty
    64                      'for_user',
    64                      'for_user',
    65                      )) | WORKFLOW_RTYPES
    65                      )) | WORKFLOW_RTYPES
    66 NO_I18NCONTEXT = META_RTYPES | WORKFLOW_RTYPES
    66 NO_I18NCONTEXT = META_RTYPES | WORKFLOW_RTYPES
    67 NO_I18NCONTEXT.add('require_permission')
       
    68 
    67 
    69 SKIP_COMPOSITE_RELS = [('cw_source', 'subject')]
    68 SKIP_COMPOSITE_RELS = [('cw_source', 'subject')]
    70 
    69 
    71 # set of entity and relation types used to build the schema
    70 # set of entity and relation types used to build the schema
    72 SCHEMA_TYPES = set((
    71 SCHEMA_TYPES = set((
    83 
    82 
    84 WORKFLOW_TYPES = set(('Transition', 'State', 'TrInfo', 'Workflow',
    83 WORKFLOW_TYPES = set(('Transition', 'State', 'TrInfo', 'Workflow',
    85                       'WorkflowTransition', 'BaseTransition',
    84                       'WorkflowTransition', 'BaseTransition',
    86                       'SubWorkflowExitPoint'))
    85                       'SubWorkflowExitPoint'))
    87 
    86 
    88 INTERNAL_TYPES = set(('CWProperty', 'CWPermission', 'CWCache', 'ExternalUri',
    87 INTERNAL_TYPES = set(('CWProperty', 'CWCache', 'ExternalUri',
    89                       'CWSource', 'CWSourceHostConfig', 'CWSourceSchemaConfig'))
    88                       'CWSource', 'CWSourceHostConfig', 'CWSourceSchemaConfig'))
    90 
    89 
    91 
    90 
    92 _LOGGER = getLogger('cubicweb.schemaloader')
    91 _LOGGER = getLogger('cubicweb.schemaloader')
    93 
    92 
   169     if form == 'subject':
   168     if form == 'subject':
   170         form = ''
   169         form = ''
   171     if form:
   170     if form:
   172         key = key + '_' + form
   171         key = key + '_' + form
   173     # ensure unicode
   172     # ensure unicode
   174     # .lower() in case no translation are available XXX done whatever a translation is there or not!
       
   175     if context is not None:
   173     if context is not None:
   176         return unicode(req.pgettext(context, key)).lower()
   174         return unicode(req.pgettext(context, key))
   177     else:
   175     else:
   178         return unicode(req._(key)).lower()
   176         return unicode(req._(key))
   179 
       
   180 __builtins__['display_name'] = deprecated('[3.4] display_name should be imported from cubicweb.schema')(display_name)
       
   181 
   177 
   182 
   178 
   183 # Schema objects definition ###################################################
   179 # Schema objects definition ###################################################
   184 
   180 
   185 def ERSchema_display_name(self, req, form='', context=None):
   181 def ERSchema_display_name(self, req, form='', context=None):
   850             assert creating == False
   846             assert creating == False
   851             return self._check(session, x=eid, **kwargs)
   847             return self._check(session, x=eid, **kwargs)
   852         return self._check(session, **kwargs)
   848         return self._check(session, **kwargs)
   853 
   849 
   854 
   850 
       
   851 def vargraph(rqlst):
       
   852     """ builds an adjacency graph of variables from the rql syntax tree, e.g:
       
   853     Any O,S WHERE T subworkflow_exit S, T subworkflow WF, O state_of WF
       
   854     => {'WF': ['O', 'T'], 'S': ['T'], 'T': ['WF', 'S'], 'O': ['WF']}
       
   855     """
       
   856     vargraph = {}
       
   857     for relation in rqlst.get_nodes(nodes.Relation):
       
   858         try:
       
   859             rhsvarname = relation.children[1].children[0].variable.name
       
   860             lhsvarname = relation.children[0].name
       
   861         except AttributeError:
       
   862             pass
       
   863         else:
       
   864             vargraph.setdefault(lhsvarname, []).append(rhsvarname)
       
   865             vargraph.setdefault(rhsvarname, []).append(lhsvarname)
       
   866             #vargraph[(lhsvarname, rhsvarname)] = relation.r_type
       
   867     return vargraph
       
   868 
       
   869 
       
   870 class GeneratedConstraint(object):
       
   871     def __init__(self, rqlst, mainvars):
       
   872         self.snippet_rqlst = rqlst
       
   873         self.mainvars = mainvars
       
   874         self.vargraph = vargraph(rqlst)
       
   875 
       
   876 
   855 class RRQLExpression(RQLExpression):
   877 class RRQLExpression(RQLExpression):
   856     def __init__(self, expression, mainvars=None, eid=None):
   878     def __init__(self, expression, mainvars=None, eid=None):
   857         if mainvars is None:
   879         if mainvars is None:
   858             mainvars = guess_rrqlexpr_mainvars(expression)
   880             mainvars = guess_rrqlexpr_mainvars(expression)
   859         RQLExpression.__init__(self, expression, mainvars, eid)
   881         RQLExpression.__init__(self, expression, mainvars, eid)
   860         # graph of links between variable, used by rql rewriter
   882         # graph of links between variable, used by rql rewriter
   861         self.vargraph = {}
   883         self.vargraph = vargraph(self.rqlst)
   862         for relation in self.rqlst.get_nodes(nodes.Relation):
       
   863             try:
       
   864                 rhsvarname = relation.children[1].children[0].variable.name
       
   865                 lhsvarname = relation.children[0].name
       
   866             except AttributeError:
       
   867                 pass
       
   868             else:
       
   869                 self.vargraph.setdefault(lhsvarname, []).append(rhsvarname)
       
   870                 self.vargraph.setdefault(rhsvarname, []).append(lhsvarname)
       
   871                 #self.vargraph[(lhsvarname, rhsvarname)] = relation.r_type
       
   872 
   884 
   873     @property
   885     @property
   874     def full_rql(self):
   886     def full_rql(self):
   875         rql = self.minimal_rql
   887         rql = self.minimal_rql
   876         rqlst = getattr(self, 'rqlst', None) # may be not set yet
   888         rqlst = getattr(self, 'rqlst', None) # may be not set yet
   957     """
   969     """
   958 
   970 
   959     def repo_check(self, session, eidfrom, rtype, eidto):
   971     def repo_check(self, session, eidfrom, rtype, eidto):
   960         """raise ValidationError if the relation doesn't satisfy the constraint
   972         """raise ValidationError if the relation doesn't satisfy the constraint
   961         """
   973         """
   962         pass # this is a vocabulary constraint, not enforce 
   974         pass # this is a vocabulary constraint, not enforced
   963 
   975 
   964 
   976 
   965 class RepoEnforcedRQLConstraintMixIn(object):
   977 class RepoEnforcedRQLConstraintMixIn(object):
   966 
   978 
   967     def __init__(self, expression, mainvars=None, msg=None):
   979     def __init__(self, expression, mainvars=None, msg=None):
  1174 set_log_methods(BootstrapSchemaLoader, getLogger('cubicweb.bootstrapschemaloader'))
  1186 set_log_methods(BootstrapSchemaLoader, getLogger('cubicweb.bootstrapschemaloader'))
  1175 set_log_methods(RQLExpression, getLogger('cubicweb.schema'))
  1187 set_log_methods(RQLExpression, getLogger('cubicweb.schema'))
  1176 
  1188 
  1177 # _() is just there to add messages to the catalog, don't care about actual
  1189 # _() is just there to add messages to the catalog, don't care about actual
  1178 # translation
  1190 # translation
  1179 PERM_USE_TEMPLATE_FORMAT = _('use_template_format')
  1191 MAY_USE_TEMPLATE_FORMAT = set(('managers',))
  1180 NEED_PERM_FORMATS = [_('text/cubicweb-page-template')]
  1192 NEED_PERM_FORMATS = [_('text/cubicweb-page-template')]
  1181 
  1193 
  1182 @monkeypatch(FormatConstraint)
  1194 @monkeypatch(FormatConstraint)
  1183 def vocabulary(self, entity=None, form=None):
  1195 def vocabulary(self, entity=None, form=None):
  1184     cw = None
  1196     cw = None
  1189     if cw is not None:
  1201     if cw is not None:
  1190         if hasattr(cw, 'write_security'): # test it's a session and not a request
  1202         if hasattr(cw, 'write_security'): # test it's a session and not a request
  1191             # cw is a server session
  1203             # cw is a server session
  1192             hasperm = not cw.write_security or \
  1204             hasperm = not cw.write_security or \
  1193                       not cw.is_hook_category_activated('integrity') or \
  1205                       not cw.is_hook_category_activated('integrity') or \
  1194                       cw.user.has_permission(PERM_USE_TEMPLATE_FORMAT)
  1206                       cw.user.matching_groups(MAY_USE_TEMPLATE_FORMAT)
  1195         else:
  1207         else:
  1196             hasperm = cw.user.has_permission(PERM_USE_TEMPLATE_FORMAT)
  1208             hasperm = cw.user.matching_groups(MAY_USE_TEMPLATE_FORMAT)
  1197         if hasperm:
  1209         if hasperm:
  1198             return self.regular_formats + tuple(NEED_PERM_FORMATS)
  1210             return self.regular_formats + tuple(NEED_PERM_FORMATS)
  1199     return self.regular_formats
  1211     return self.regular_formats
  1200 
  1212 
  1201 # XXX monkey patch PyFileReader.import_erschema until bw_normalize_etype is
  1213 # XXX monkey patch PyFileReader.import_erschema until bw_normalize_etype is