hooks/syncschema.py
changeset 3890 d7a270f50f54
parent 3889 8902b8745918
parent 3777 3ef8cdb5fb1c
child 4003 b9436fe77c9e
equal deleted inserted replaced
3810:5b75fd66c80e 3890:d7a270f50f54
   151             if not eschema.final:
   151             if not eschema.final:
   152                 clear_cache(eschema, 'ordered_relations')
   152                 clear_cache(eschema, 'ordered_relations')
   153 
   153 
   154     def commit_event(self):
   154     def commit_event(self):
   155         rebuildinfered = self.session.data.get('rebuild-infered', True)
   155         rebuildinfered = self.session.data.get('rebuild-infered', True)
   156         repo = self.session.repo
   156         self.repo.set_schema(self.repo.schema, rebuildinfered=rebuildinfered)
   157         repo.set_schema(repo.schema, rebuildinfered=rebuildinfered)
   157         # CWUser class might have changed, update current session users
       
   158         cwuser_cls = self.session.vreg['etypes'].etype_class('CWUser')
       
   159         for session in self.repo._sessions.values():
       
   160             session.user.__class__ = cwuser_cls
   158 
   161 
   159     def rollback_event(self):
   162     def rollback_event(self):
   160         self.precommit_event()
   163         self.precommit_event()
   161 
   164 
   162 
   165 
   184         i = -1
   187         i = -1
   185         for i, op in enumerate(self.session.pending_operations):
   188         for i, op in enumerate(self.session.pending_operations):
   186             if not isinstance(op, MemSchemaEarlyOperation):
   189             if not isinstance(op, MemSchemaEarlyOperation):
   187                 return i
   190                 return i
   188         return i + 1
   191         return i + 1
   189 
       
   190 
       
   191 class MemSchemaPermOperation(MemSchemaOperation):
       
   192     """base class to synchronize schema permission definitions"""
       
   193     def __init__(self, session, perm, etype_eid):
       
   194         self.perm = perm
       
   195         try:
       
   196             self.name = session.entity_from_eid(etype_eid).name
       
   197         except IndexError:
       
   198             self.error('changing permission of a no more existant type #%s',
       
   199                 etype_eid)
       
   200         else:
       
   201             hook.Operation.__init__(self, session)
       
   202 
   192 
   203 
   193 
   204 # operations for high-level source database alteration  ########################
   194 # operations for high-level source database alteration  ########################
   205 
   195 
   206 class SourceDbCWETypeRename(hook.Operation):
   196 class SourceDbCWETypeRename(hook.Operation):
   493         # so there is nothing to do here
   483         # so there is nothing to do here
   494         if session.added_in_transaction(rdef.eid):
   484         if session.added_in_transaction(rdef.eid):
   495             return
   485             return
   496         subjtype, rtype, objtype = session.vreg.schema.schema_by_eid(rdef.eid)
   486         subjtype, rtype, objtype = session.vreg.schema.schema_by_eid(rdef.eid)
   497         cstrtype = self.entity.type
   487         cstrtype = self.entity.type
   498         oldcstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
   488         oldcstr = rtype.rdef(subjtype, objtype).constraint_by_type(cstrtype)
   499         newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   489         newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   500         table = SQL_PREFIX + str(subjtype)
   490         table = SQL_PREFIX + str(subjtype)
   501         column = SQL_PREFIX + str(rtype)
   491         column = SQL_PREFIX + str(rtype)
   502         # alter the physical schema on size constraint changes
   492         # alter the physical schema on size constraint changes
   503         if newcstr.type() == 'SizeConstraint' and (
   493         if newcstr.type() == 'SizeConstraint' and (
   573 
   563 
   574 class MemSchemaCWRTypeAdd(MemSchemaEarlyOperation):
   564 class MemSchemaCWRTypeAdd(MemSchemaEarlyOperation):
   575     """actually add the relation type to the instance's schema"""
   565     """actually add the relation type to the instance's schema"""
   576     eid = None # make pylint happy
   566     eid = None # make pylint happy
   577     def commit_event(self):
   567     def commit_event(self):
   578         rschema = self.session.vreg.schema.add_relation_type(self.kobj)
   568         self.session.vreg.schema.add_relation_type(self.kobj)
   579         rschema.set_default_groups()
       
   580 
   569 
   581 
   570 
   582 class MemSchemaCWRTypeUpdate(MemSchemaOperation):
   571 class MemSchemaCWRTypeUpdate(MemSchemaOperation):
   583     """actually update some properties of a relation definition"""
   572     """actually update some properties of a relation definition"""
   584     rschema = values = None # make pylint happy
   573     rschema = values = None # make pylint happy
   612     rschema = values = None # make pylint happy
   601     rschema = values = None # make pylint happy
   613 
   602 
   614     def commit_event(self):
   603     def commit_event(self):
   615         # structure should be clean, not need to remove entity's relations
   604         # structure should be clean, not need to remove entity's relations
   616         # at this point
   605         # at this point
   617         self.rschema._rproperties[self.kobj].update(self.values)
   606         self.rschema.rdef[self.kobj].update(self.values)
   618 
   607 
   619 
   608 
   620 class MemSchemaRDefDel(MemSchemaOperation):
   609 class MemSchemaRDefDel(MemSchemaOperation):
   621     """actually remove the relation definition from the instance's schema"""
   610     """actually remove the relation definition from the instance's schema"""
   622     def commit_event(self):
   611     def commit_event(self):
   644             self.cancelled = True
   633             self.cancelled = True
   645             return
   634             return
   646         subjtype, rtype, objtype = self.session.vreg.schema.schema_by_eid(rdef.eid)
   635         subjtype, rtype, objtype = self.session.vreg.schema.schema_by_eid(rdef.eid)
   647         self.prepare_constraints(subjtype, rtype, objtype)
   636         self.prepare_constraints(subjtype, rtype, objtype)
   648         cstrtype = self.entity.type
   637         cstrtype = self.entity.type
   649         self.cstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
   638         self.cstr = rtype.rdef(subjtype, objtype).constraint_by_type(cstrtype)
   650         self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   639         self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
   651         self.newcstr.eid = self.entity.eid
   640         self.newcstr.eid = self.entity.eid
   652 
   641 
   653     def commit_event(self):
   642     def commit_event(self):
   654         if self.cancelled:
   643         if self.cancelled:
   670 
   659 
   671     def commit_event(self):
   660     def commit_event(self):
   672         self.constraints.remove(self.cstr)
   661         self.constraints.remove(self.cstr)
   673 
   662 
   674 
   663 
   675 class MemSchemaPermCWGroupAdd(MemSchemaPermOperation):
   664 class MemSchemaPermissionAdd(MemSchemaOperation):
   676     """synchronize schema when a *_permission relation has been added on a group
   665     """synchronize schema when a *_permission relation has been added on a group
   677     """
   666     """
   678     def __init__(self, session, perm, etype_eid, group_eid):
       
   679         self.group = session.entity_from_eid(group_eid).name
       
   680         super(MemSchemaPermCWGroupAdd, self).__init__(
       
   681             session, perm, etype_eid)
       
   682 
   667 
   683     def commit_event(self):
   668     def commit_event(self):
   684         """the observed connections pool has been commited"""
   669         """the observed connections pool has been commited"""
   685         try:
   670         try:
   686             erschema = self.session.vreg.schema[self.name]
   671             erschema = self.session.vreg.schema[self.name]
   687         except KeyError:
   672         except KeyError:
   688             # duh, schema not found, log error and skip operation
   673             # duh, schema not found, log error and skip operation
   689             self.error('no schema for %s', self.name)
   674             self.error('no schema for %s', self.name)
   690             return
   675             return
   691         groups = list(erschema.get_groups(self.perm))
   676         perms = list(erschema.action_permissions(self.action))
       
   677         if hasattr(self, group_eid):
       
   678             perm = self.session.entity_from_eid(self.group_eid).name
       
   679         else:
       
   680             perm = erschema.rql_expression(self.expr)
   692         try:
   681         try:
   693             groups.index(self.group)
   682             perms.index(perm)
   694             self.warning('group %s already have permission %s on %s',
   683             self.warning('%s already in permissions for %s on %s',
   695                          self.group, self.perm, erschema.type)
   684                          perm, self.action, erschema)
   696         except ValueError:
   685         except ValueError:
   697             groups.append(self.group)
   686             perms.append(perm)
   698             erschema.set_groups(self.perm, groups)
   687             erschema.set_action_permissions(self.action, perms)
   699 
   688 
   700 
   689 
   701 class MemSchemaPermCWGroupDel(MemSchemaPermCWGroupAdd):
   690 class MemSchemaPermissionDel(MemSchemaPermissionAdd):
   702     """synchronize schema when a *_permission relation has been deleted from a
   691     """synchronize schema when a *_permission relation has been deleted from a
   703     group
   692     group
   704     """
   693     """
   705 
   694 
   706     def commit_event(self):
   695     def commit_event(self):
   709             erschema = self.session.vreg.schema[self.name]
   698             erschema = self.session.vreg.schema[self.name]
   710         except KeyError:
   699         except KeyError:
   711             # duh, schema not found, log error and skip operation
   700             # duh, schema not found, log error and skip operation
   712             self.error('no schema for %s', self.name)
   701             self.error('no schema for %s', self.name)
   713             return
   702             return
   714         groups = list(erschema.get_groups(self.perm))
   703         perms = list(erschema.action_permissions(self.action))
       
   704         if hasattr(self, group_eid):
       
   705             perm = self.session.entity_from_eid(self.group_eid).name
       
   706         else:
       
   707             perm = erschema.rql_expression(self.expr)
   715         try:
   708         try:
   716             groups.remove(self.group)
   709             perms.remove(self.group)
   717             erschema.set_groups(self.perm, groups)
   710             erschema.set_action_permissions(self.action, perms)
   718         except ValueError:
   711         except ValueError:
   719             self.error('can\'t remove permission %s on %s to group %s',
   712             self.error('can\'t remove permission %s for %s on %s',
   720                 self.perm, erschema.type, self.group)
   713                        perm, self.action, erschema)
   721 
       
   722 
       
   723 class MemSchemaPermRQLExpressionAdd(MemSchemaPermOperation):
       
   724     """synchronize schema when a *_permission relation has been added on a rql
       
   725     expression
       
   726     """
       
   727     def __init__(self, session, perm, etype_eid, expression):
       
   728         self.expr = expression
       
   729         super(MemSchemaPermRQLExpressionAdd, self).__init__(
       
   730             session, perm, etype_eid)
       
   731 
       
   732     def commit_event(self):
       
   733         """the observed connections pool has been commited"""
       
   734         try:
       
   735             erschema = self.session.vreg.schema[self.name]
       
   736         except KeyError:
       
   737             # duh, schema not found, log error and skip operation
       
   738             self.error('no schema for %s', self.name)
       
   739             return
       
   740         exprs = list(erschema.get_rqlexprs(self.perm))
       
   741         exprs.append(erschema.rql_expression(self.expr))
       
   742         erschema.set_rqlexprs(self.perm, exprs)
       
   743 
       
   744 
       
   745 class MemSchemaPermRQLExpressionDel(MemSchemaPermRQLExpressionAdd):
       
   746     """synchronize schema when a *_permission relation has been deleted from an
       
   747     rql expression
       
   748     """
       
   749 
       
   750     def commit_event(self):
       
   751         """the observed connections pool has been commited"""
       
   752         try:
       
   753             erschema = self.session.vreg.schema[self.name]
       
   754         except KeyError:
       
   755             # duh, schema not found, log error and skip operation
       
   756             self.error('no schema for %s', self.name)
       
   757             return
       
   758         rqlexprs = list(erschema.get_rqlexprs(self.perm))
       
   759         for i, rqlexpr in enumerate(rqlexprs):
       
   760             if rqlexpr.expression == self.expr:
       
   761                 rqlexprs.pop(i)
       
   762                 break
       
   763         else:
       
   764             self.error('can\'t remove permission %s on %s for expression %s',
       
   765                 self.perm, erschema.type, self.expr)
       
   766             return
       
   767         erschema.set_rqlexprs(self.perm, rqlexprs)
       
   768 
   714 
   769 
   715 
   770 class MemSchemaSpecializesAdd(MemSchemaOperation):
   716 class MemSchemaSpecializesAdd(MemSchemaOperation):
   771 
   717 
   772     def commit_event(self):
   718     def commit_event(self):
   833       CWAttribute entities
   779       CWAttribute entities
   834     * add owned_by relation by creating the necessary CWRelation entity
   780     * add owned_by relation by creating the necessary CWRelation entity
   835     * register an operation to add the entity type to the instance's
   781     * register an operation to add the entity type to the instance's
   836       schema on commit
   782       schema on commit
   837     """
   783     """
       
   784 <<<<<<< /home/syt/src/fcubicweb/cubicweb/hooks/syncschema.py
   838     __regid__ = 'syncaddcwetype'
   785     __regid__ = 'syncaddcwetype'
   839     events = ('after_add_entity',)
   786     events = ('after_add_entity',)
   840 
   787 
   841     def __call__(self):
   788     def __call__(self):
   842         entity = self.entity
   789         entity = self.entity
   857         relrqls = []
   804         relrqls = []
   858         for rtype in (META_RTYPES - VIRTUAL_RTYPES):
   805         for rtype in (META_RTYPES - VIRTUAL_RTYPES):
   859             rschema = schema[rtype]
   806             rschema = schema[rtype]
   860             sampletype = rschema.subjects()[0]
   807             sampletype = rschema.subjects()[0]
   861             desttype = rschema.objects()[0]
   808             desttype = rschema.objects()[0]
   862             props = rschema.rproperties(sampletype, desttype)
   809             props = rschema.rdef(sampletype, desttype)
   863             relrqls += list(ss.rdef2rql(rschema, name, desttype, props))
   810             relrqls += list(ss.rdef2rql(rschema, name, desttype, props))
   864         # now remove it !
   811         # now remove it !
   865         schema.del_entity_type(name)
   812         schema.del_entity_type(name)
   866         # create the necessary table
   813         # create the necessary table
   867         for sql in tablesql.split(';'):
   814         for sql in tablesql.split(';'):
   963         if newvalues:
   910         if newvalues:
   964             MemSchemaCWRTypeUpdate(self._cw, rschema=rschema, values=newvalues)
   911             MemSchemaCWRTypeUpdate(self._cw, rschema=rschema, values=newvalues)
   965             SourceDbCWRTypeUpdate(self._cw, rschema=rschema, values=newvalues,
   912             SourceDbCWRTypeUpdate(self._cw, rschema=rschema, values=newvalues,
   966                                   entity=entity)
   913                                   entity=entity)
   967 
   914 
       
   915 def check_valid_changes(session, entity, ro_attrs=('name', 'final')):
       
   916     errors = {}
       
   917     # don't use getattr(entity, attr), we would get the modified value if any
       
   918     for attr in ro_attrs:
       
   919         if attr in entity.edited_attributes:
       
   920             origval, newval = entity_oldnewvalue(entity, attr)
       
   921             if newval != origval:
       
   922                 errors[attr] = session._("can't change the %s attribute") % \
       
   923                                display_name(session, attr)
       
   924     if errors:
       
   925         raise ValidationError(entity.eid, errors)
   968 
   926 
   969 # relation_type hooks ##########################################################
   927 # relation_type hooks ##########################################################
   970 
   928 
   971 class AfterDelRelationTypeHook(SyncSchemaHook):
   929 class AfterDelRelationTypeHook(SyncSchemaHook):
   972     """before deleting a CWAttribute or CWRelation entity:
   930     """before deleting a CWAttribute or CWRelation entity:
  1100             return
  1058             return
  1101         schema = self._cw.vreg.schema
  1059         schema = self._cw.vreg.schema
  1102         entity = self._cw.entity_from_eid(self.eidto)
  1060         entity = self._cw.entity_from_eid(self.eidto)
  1103         subjtype, rtype, objtype = schema.schema_by_eid(self.eidfrom)
  1061         subjtype, rtype, objtype = schema.schema_by_eid(self.eidfrom)
  1104         try:
  1062         try:
  1105             cstr = rtype.constraint_by_type(subjtype, objtype,
  1063             cstr = rtype.rdef(subjtype, objtype).constraint_by_type(
  1106                                             entity.cstrtype[0].name)
  1064                 entity.cstrtype[0].name)
  1107         except IndexError:
  1065         except IndexError:
  1108             self._cw.critical('constraint type no more accessible')
  1066             self._cw.critical('constraint type no more accessible')
  1109         else:
  1067         else:
  1110             SourceDbCWConstraintDel(self._cw, subjtype=subjtype, rtype=rtype,
  1068             SourceDbCWConstraintDel(self._cw, subjtype=subjtype, rtype=rtype,
  1111                                     objtype=objtype, cstr=cstr)
  1069                                     objtype=objtype, cstr=cstr)
  1122         'read_permission', 'add_permission', 'delete_permission',
  1080         'read_permission', 'add_permission', 'delete_permission',
  1123         'update_permission')
  1081         'update_permission')
  1124     events = ('after_add_relation',)
  1082     events = ('after_add_relation',)
  1125 
  1083 
  1126     def __call__(self):
  1084     def __call__(self):
  1127         perm = self.rtype.split('_', 1)[0]
  1085         action = self.rtype.split('_', 1)[0]
  1128         if self._cw.describe(self.eidto)[0] == 'CWGroup':
  1086         if self._cw.describe(self.eidto)[0] == 'CWGroup':
  1129             MemSchemaPermCWGroupAdd(self._cw, perm, self.eidfrom, self.eidto)
  1087             MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom,
       
  1088                                    group_eid=self.eidto)
  1130         else: # RQLExpression
  1089         else: # RQLExpression
  1131             expr = self._cw.entity_from_eid(self.eidto).expression
  1090             expr = self._cw.entity_from_eid(self.eidto).expression
  1132             MemSchemaPermRQLExpressionAdd(self._cw, perm, self.eidfrom, expr)
  1091             MemSchemaPermissionAdd(session, action=action, eid=self.eidfrom,
       
  1092                                    expr=expr)
  1133 
  1093 
  1134 
  1094 
  1135 class BeforeDelPermissionHook(AfterAddPermissionHook):
  1095 class BeforeDelPermissionHook(AfterAddPermissionHook):
  1136     """delete entity/relation *_permission, need to update schema
  1096     """delete entity/relation *_permission, need to update schema
  1137 
  1097 
  1141     events = ('before_delete_relation',)
  1101     events = ('before_delete_relation',)
  1142 
  1102 
  1143     def __call__(self):
  1103     def __call__(self):
  1144         if self._cw.deleted_in_transaction(self.eidfrom):
  1104         if self._cw.deleted_in_transaction(self.eidfrom):
  1145             return
  1105             return
  1146         perm = self.rtype.split('_', 1)[0]
  1106         action = self.rtype.split('_', 1)[0]
  1147         if self._cw.describe(self.eidto)[0] == 'CWGroup':
  1107         if self._cw.describe(self.eidto)[0] == 'CWGroup':
  1148             MemSchemaPermCWGroupDel(self._cw, perm, self.eidfrom, self.eidto)
  1108             MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom,
       
  1109                                    group_eid=self.eidto)
  1149         else: # RQLExpression
  1110         else: # RQLExpression
  1150             expr = self._cw.entity_from_eid(self.eidto).expression
  1111             expr = self._cw.entity_from_eid(self.eidto).expression
  1151             MemSchemaPermRQLExpressionDel(self._cw, perm, self.eidfrom, expr)
  1112             MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom,
       
  1113                                    expr=expr)
  1152 
  1114 
  1153 
  1115 
  1154 # specializes synchronization hooks ############################################
  1116 # specializes synchronization hooks ############################################
  1155 
  1117 
  1156 
  1118