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): |
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 |