server/migractions.py
branchreldefsecurity
changeset 3877 7ca53fc72a0a
parent 3836 58c09f21f503
child 3889 8902b8745918
equal deleted inserted replaced
3876:1169d3154be6 3877:7ca53fc72a0a
   303                                                'after_add_entity', '')
   303                                                'after_add_entity', '')
   304                     self.reactivate_verification_hooks()
   304                     self.reactivate_verification_hooks()
   305 
   305 
   306     # schema synchronization internals ########################################
   306     # schema synchronization internals ########################################
   307 
   307 
   308     def _synchronize_permissions(self, ertype):
   308     def _synchronize_permissions(self, erschema, teid):
   309         """permission synchronization for an entity or relation type"""
   309         """permission synchronization for an entity or relation type"""
   310         if ertype in VIRTUAL_RTYPES:
   310         if erschema in VIRTUAL_RTYPES:
   311             return
   311             return
   312         newrschema = self.fs_schema[ertype]
   312         assert teid, erschema
   313         teid = self.repo.schema[ertype].eid
   313         if 'update' in erschema.ACTIONS or erschema.final:
   314         if 'update' in newrschema.ACTIONS or newrschema.final:
       
   315             # entity type
   314             # entity type
   316             exprtype = u'ERQLExpression'
   315             exprtype = u'ERQLExpression'
   317         else:
   316         else:
   318             # relation type
   317             # relation type
   319             exprtype = u'RRQLExpression'
   318             exprtype = u'RRQLExpression'
   320         assert teid, ertype
       
   321         gm = self.group_mapping()
   319         gm = self.group_mapping()
   322         confirm = self.verbosity >= 2
   320         confirm = self.verbosity >= 2
   323         # * remove possibly deprecated permission (eg in the persistent schema
   321         # * remove possibly deprecated permission (eg in the persistent schema
   324         #   but not in the new schema)
   322         #   but not in the new schema)
   325         # * synchronize existing expressions
   323         # * synchronize existing expressions
   326         # * add new groups/expressions
   324         # * add new groups/expressions
   327         for action in newrschema.ACTIONS:
   325         for action in erschema.ACTIONS:
   328             perm = '%s_permission' % action
   326             perm = '%s_permission' % action
   329             # handle groups
   327             # handle groups
   330             newgroups = list(newrschema.get_groups(action))
   328             newgroups = list(erschema.get_groups(action))
   331             for geid, gname in self.rqlexec('Any G, GN WHERE T %s G, G name GN, '
   329             for geid, gname in self.rqlexec('Any G, GN WHERE T %s G, G name GN, '
   332                                             'T eid %%(x)s' % perm, {'x': teid}, 'x',
   330                                             'T eid %%(x)s' % perm, {'x': teid}, 'x',
   333                                             ask_confirm=False):
   331                                             ask_confirm=False):
   334                 if not gname in newgroups:
   332                 if not gname in newgroups:
   335                     if not confirm or self.confirm('remove %s permission of %s to %s?'
   333                     if not confirm or self.confirm('remove %s permission of %s to %s?'
   336                                                    % (action, ertype, gname)):
   334                                                    % (action, erschema, gname)):
   337                         self.rqlexec('DELETE T %s G WHERE G eid %%(x)s, T eid %s'
   335                         self.rqlexec('DELETE T %s G WHERE G eid %%(x)s, T eid %s'
   338                                      % (perm, teid),
   336                                      % (perm, teid),
   339                                      {'x': geid}, 'x', ask_confirm=False)
   337                                      {'x': geid}, 'x', ask_confirm=False)
   340                 else:
   338                 else:
   341                     newgroups.remove(gname)
   339                     newgroups.remove(gname)
   342             for gname in newgroups:
   340             for gname in newgroups:
   343                 if not confirm or self.confirm('grant %s permission of %s to %s?'
   341                 if not confirm or self.confirm('grant %s permission of %s to %s?'
   344                                                % (action, ertype, gname)):
   342                                                % (action, erschema, gname)):
   345                     self.rqlexec('SET T %s G WHERE G eid %%(x)s, T eid %s'
   343                     self.rqlexec('SET T %s G WHERE G eid %%(x)s, T eid %s'
   346                                  % (perm, teid),
   344                                  % (perm, teid),
   347                                  {'x': gm[gname]}, 'x', ask_confirm=False)
   345                                  {'x': gm[gname]}, 'x', ask_confirm=False)
   348             # handle rql expressions
   346             # handle rql expressions
   349             newexprs = dict((expr.expression, expr) for expr in newrschema.get_rqlexprs(action))
   347             newexprs = dict((expr.expression, expr) for expr in erschema.get_rqlexprs(action))
   350             for expreid, expression in self.rqlexec('Any E, EX WHERE T %s E, E expression EX, '
   348             for expreid, expression in self.rqlexec('Any E, EX WHERE T %s E, E expression EX, '
   351                                                     'T eid %s' % (perm, teid),
   349                                                     'T eid %s' % (perm, teid),
   352                                                     ask_confirm=False):
   350                                                     ask_confirm=False):
   353                 if not expression in newexprs:
   351                 if not expression in newexprs:
   354                     if not confirm or self.confirm('remove %s expression for %s permission of %s?'
   352                     if not confirm or self.confirm('remove %s expression for %s permission of %s?'
   355                                                    % (expression, action, ertype)):
   353                                                    % (expression, action, erschema)):
   356                         # deleting the relation will delete the expression entity
   354                         # deleting the relation will delete the expression entity
   357                         self.rqlexec('DELETE T %s E WHERE E eid %%(x)s, T eid %s'
   355                         self.rqlexec('DELETE T %s E WHERE E eid %%(x)s, T eid %s'
   358                                      % (perm, teid),
   356                                      % (perm, teid),
   359                                      {'x': expreid}, 'x', ask_confirm=False)
   357                                      {'x': expreid}, 'x', ask_confirm=False)
   360                 else:
   358                 else:
   361                     newexprs.pop(expression)
   359                     newexprs.pop(expression)
   362             for expression in newexprs.values():
   360             for expression in newexprs.values():
   363                 expr = expression.expression
   361                 expr = expression.expression
   364                 if not confirm or self.confirm('add %s expression for %s permission of %s?'
   362                 if not confirm or self.confirm('add %s expression for %s permission of %s?'
   365                                                % (expr, action, ertype)):
   363                                                % (expr, action, erschema)):
   366                     self.rqlexec('INSERT RQLExpression X: X exprtype %%(exprtype)s, '
   364                     self.rqlexec('INSERT RQLExpression X: X exprtype %%(exprtype)s, '
   367                                  'X expression %%(expr)s, X mainvars %%(vars)s, T %s X '
   365                                  'X expression %%(expr)s, X mainvars %%(vars)s, T %s X '
   368                                  'WHERE T eid %%(x)s' % perm,
   366                                  'WHERE T eid %%(x)s' % perm,
   369                                  {'expr': expr, 'exprtype': exprtype,
   367                                  {'expr': expr, 'exprtype': exprtype,
   370                                   'vars': expression.mainvars, 'x': teid}, 'x',
   368                                   'vars': expression.mainvars, 'x': teid}, 'x',
   392         reporschema = self.repo.schema.rschema(rtype)
   390         reporschema = self.repo.schema.rschema(rtype)
   393         if syncrdefs:
   391         if syncrdefs:
   394             for subj, obj in rschema.iter_rdefs():
   392             for subj, obj in rschema.iter_rdefs():
   395                 if not reporschema.has_rdef(subj, obj):
   393                 if not reporschema.has_rdef(subj, obj):
   396                     continue
   394                     continue
   397                 self._synchronize_rdef_schema(subj, rschema, obj)
   395                 self._synchronize_rdef_schema(subj, rschema, obj, syncperms=syncperms)
   398         if syncperms:
       
   399             self._synchronize_permissions(rtype)
       
   400 
   396 
   401     def _synchronize_eschema(self, etype, syncperms=True):
   397     def _synchronize_eschema(self, etype, syncperms=True):
   402         """synchronize properties of the persistent entity schema against
   398         """synchronize properties of the persistent entity schema against
   403         its current definition:
   399         its current definition:
   404 
   400 
   444                 for obj in objtypes:
   440                 for obj in objtypes:
   445                     if not reporschema.has_rdef(subj, obj):
   441                     if not reporschema.has_rdef(subj, obj):
   446                         continue
   442                         continue
   447                     self._synchronize_rdef_schema(subj, rschema, obj)
   443                     self._synchronize_rdef_schema(subj, rschema, obj)
   448         if syncperms:
   444         if syncperms:
   449             self._synchronize_permissions(etype)
   445             self._synchronize_permissions(eschema, repoeschema.eid)
   450 
   446 
   451     def _synchronize_rdef_schema(self, subjtype, rtype, objtype):
   447     def _synchronize_rdef_schema(self, subjtype, rtype, objtype, syncperms=True):
   452         """synchronize properties of the persistent relation definition schema
   448         """synchronize properties of the persistent relation definition schema
   453         against its current definition:
   449         against its current definition:
   454         * order and other properties
   450         * order and other properties
   455         * constraints
   451         * constraints
   456         """
   452         """
   465         confirm = self.verbosity >= 2
   461         confirm = self.verbosity >= 2
   466         # properties
   462         # properties
   467         self.rqlexecall(ss.updaterdef2rql(rschema, subjtype, objtype),
   463         self.rqlexecall(ss.updaterdef2rql(rschema, subjtype, objtype),
   468                         ask_confirm=confirm)
   464                         ask_confirm=confirm)
   469         # constraints
   465         # constraints
   470         newconstraints = list(rschema.rproperty(subjtype, objtype, 'constraints'))
   466         rdef = rschema.rdef(subjtype, objtype)
       
   467         repordef = reporschema.rdef(subjtype, objtype)
       
   468         newconstraints = list(rdef.constraints)
   471         # 1. remove old constraints and update constraints of the same type
   469         # 1. remove old constraints and update constraints of the same type
   472         # NOTE: don't use rschema.constraint_by_type because it may be
   470         # NOTE: don't use rschema.constraint_by_type because it may be
   473         #       out of sync with newconstraints when multiple
   471         #       out of sync with newconstraints when multiple
   474         #       constraints of the same type are used
   472         #       constraints of the same type are used
   475         for cstr in reporschema.rproperty(subjtype, objtype, 'constraints'):
   473         for cstr in repordef.constraints:
   476             for newcstr in newconstraints:
   474             for newcstr in newconstraints:
   477                 if newcstr.type() == cstr.type():
   475                 if newcstr.type() == cstr.type():
   478                     break
   476                     break
   479             else:
   477             else:
   480                 newcstr = None
   478                 newcstr = None
   494         # 2. add new constraints
   492         # 2. add new constraints
   495         for newcstr in newconstraints:
   493         for newcstr in newconstraints:
   496             self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype,
   494             self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype,
   497                                               newcstr),
   495                                               newcstr),
   498                             ask_confirm=confirm)
   496                             ask_confirm=confirm)
       
   497         if syncperms:
       
   498             self._synchronize_permissions(rdef, repordef.eid)
   499 
   499 
   500     # base actions ############################################################
   500     # base actions ############################################################
   501 
   501 
   502     def checkpoint(self):
   502     def checkpoint(self):
   503         """checkpoint action"""
   503         """checkpoint action"""
   886         assert syncperms or syncprops, 'nothing to do'
   886         assert syncperms or syncprops, 'nothing to do'
   887         if ertype is not None:
   887         if ertype is not None:
   888             if isinstance(ertype, (tuple, list)):
   888             if isinstance(ertype, (tuple, list)):
   889                 assert len(ertype) == 3, 'not a relation definition'
   889                 assert len(ertype) == 3, 'not a relation definition'
   890                 assert syncprops, 'can\'t update permission for a relation definition'
   890                 assert syncprops, 'can\'t update permission for a relation definition'
   891                 self._synchronize_rdef_schema(*ertype)
   891                 self._synchronize_rdef_schema(ertype[0], ertype[1], ertype[2],
       
   892                                               syncperms=syncperms)
   892             elif syncprops:
   893             elif syncprops:
   893                 erschema = self.repo.schema[ertype]
   894                 erschema = self.repo.schema[ertype]
   894                 if isinstance(erschema, CubicWebRelationSchema):
   895                 if isinstance(erschema, CubicWebRelationSchema):
   895                     self._synchronize_rschema(erschema, syncperms=syncperms,
   896                     self._synchronize_rschema(erschema, syncperms=syncperms,
   896                                               syncrdefs=syncrdefs)
   897                                               syncrdefs=syncrdefs)
   897                 else:
   898                 else:
   898                     self._synchronize_eschema(erschema, syncperms=syncperms)
   899                     self._synchronize_eschema(erschema, syncperms=syncperms)
   899             else:
   900             else:
   900                 self._synchronize_permissions(ertype)
   901                 erschema = self.repo.schema[ertype]
       
   902                 self._synchronize_permissions(self.fs_schema[ertype], erschema.eid)
   901         else:
   903         else:
   902             for etype in self.repo.schema.entities():
   904             for etype in self.repo.schema.entities():
   903                 if syncprops:
   905                 if syncprops:
   904                     self._synchronize_eschema(etype, syncperms=syncperms)
   906                     self._synchronize_eschema(etype, syncperms=syncperms)
   905                 else:
   907                 else:
   906                     self._synchronize_permissions(etype)
   908                     self._synchronize_permissions(self.fs_schema[etype], erschema.eid)
   907         if commit:
   909         if commit:
   908             self.commit()
   910             self.commit()
   909 
   911 
   910     def cmd_change_relation_props(self, subjtype, rtype, objtype,
   912     def cmd_change_relation_props(self, subjtype, rtype, objtype,
   911                                   commit=True, **kwargs):
   913                                   commit=True, **kwargs):