677 * check session id validity |
679 * check session id validity |
678 * update user information on each user's request (i.e. groups and |
680 * update user information on each user's request (i.e. groups and |
679 custom properties) |
681 custom properties) |
680 """ |
682 """ |
681 session = self._get_session(sessionid, setpool=False) |
683 session = self._get_session(sessionid, setpool=False) |
682 # update session properties |
|
683 for prop, value in props.items(): |
684 for prop, value in props.items(): |
684 session.change_property(prop, value) |
685 session.change_property(prop, value) |
|
686 |
|
687 def undoable_transactions(self, sessionid, ueid=None, **actionfilters): |
|
688 """See :class:`cubicweb.dbapi.Connection.undoable_transactions`""" |
|
689 session = self._get_session(sessionid, setpool=True) |
|
690 try: |
|
691 return self.system_source.undoable_transactions(session, ueid, |
|
692 **actionfilters) |
|
693 finally: |
|
694 session.reset_pool() |
|
695 |
|
696 def transaction_info(self, sessionid, txuuid): |
|
697 """See :class:`cubicweb.dbapi.Connection.transaction_info`""" |
|
698 session = self._get_session(sessionid, setpool=True) |
|
699 try: |
|
700 return self.system_source.tx_info(session, txuuid) |
|
701 finally: |
|
702 session.reset_pool() |
|
703 |
|
704 def transaction_actions(self, sessionid, txuuid, public=True): |
|
705 """See :class:`cubicweb.dbapi.Connection.transaction_actions`""" |
|
706 session = self._get_session(sessionid, setpool=True) |
|
707 try: |
|
708 return self.system_source.tx_actions(session, txuuid, public) |
|
709 finally: |
|
710 session.reset_pool() |
|
711 |
|
712 def undo_transaction(self, sessionid, txuuid): |
|
713 """See :class:`cubicweb.dbapi.Connection.undo_transaction`""" |
|
714 session = self._get_session(sessionid, setpool=True) |
|
715 try: |
|
716 return self.system_source.undo_transaction(session, txuuid) |
|
717 finally: |
|
718 session.reset_pool() |
685 |
719 |
686 # public (inter-repository) interface ##################################### |
720 # public (inter-repository) interface ##################################### |
687 |
721 |
688 def entities_modified_since(self, etypes, mtime): |
722 def entities_modified_since(self, etypes, mtime): |
689 """function designed to be called from an external repository which |
723 """function designed to be called from an external repository which |
884 new = session.transaction_data.setdefault('neweids', set()) |
918 new = session.transaction_data.setdefault('neweids', set()) |
885 new.add(entity.eid) |
919 new.add(entity.eid) |
886 self.system_source.add_info(session, entity, source, extid, complete) |
920 self.system_source.add_info(session, entity, source, extid, complete) |
887 CleanupEidTypeCacheOp(session) |
921 CleanupEidTypeCacheOp(session) |
888 |
922 |
889 def delete_info(self, session, eid): |
923 def delete_info(self, session, entity, sourceuri, extid): |
890 self._prepare_delete_info(session, eid) |
924 """called by external source when some entity known by the system source |
891 self._delete_info(session, eid) |
925 has been deleted in the external source |
892 |
926 """ |
893 def _prepare_delete_info(self, session, eid): |
927 self._prepare_delete_info(session, entity, sourceuri) |
|
928 self._delete_info(session, entity, sourceuri, extid) |
|
929 |
|
930 def _prepare_delete_info(self, session, entity, sourceuri): |
894 """prepare the repository for deletion of an entity: |
931 """prepare the repository for deletion of an entity: |
895 * update the fti |
932 * update the fti |
896 * mark eid as being deleted in session info |
933 * mark eid as being deleted in session info |
897 * setup cache update operation |
934 * setup cache update operation |
898 """ |
935 * if undoable, get back all entity's attributes and relation |
|
936 """ |
|
937 eid = entity.eid |
899 self.system_source.fti_unindex_entity(session, eid) |
938 self.system_source.fti_unindex_entity(session, eid) |
900 pending = session.transaction_data.setdefault('pendingeids', set()) |
939 pending = session.transaction_data.setdefault('pendingeids', set()) |
901 pending.add(eid) |
940 pending.add(eid) |
902 CleanupEidTypeCacheOp(session) |
941 CleanupEidTypeCacheOp(session) |
903 |
942 |
904 def _delete_info(self, session, eid): |
943 def _delete_info(self, session, entity, sourceuri, extid): |
|
944 # attributes=None, relations=None): |
905 """delete system information on deletion of an entity: |
945 """delete system information on deletion of an entity: |
906 * delete all relations on this entity |
946 * delete all remaining relations from/to this entity |
907 * transfer record from the entities table to the deleted_entities table |
947 * call delete info on the system source which will transfer record from |
908 """ |
948 the entities table to the deleted_entities table |
909 etype, uri, extid = self.type_and_source_from_eid(eid, session) |
949 """ |
910 self._clear_eid_relations(session, etype, eid) |
|
911 self.system_source.delete_info(session, eid, etype, uri, extid) |
|
912 |
|
913 def _clear_eid_relations(self, session, etype, eid): |
|
914 """when a entity is deleted, build and execute rql query to delete all |
|
915 its relations |
|
916 """ |
|
917 rql = [] |
|
918 eschema = self.schema.eschema(etype) |
|
919 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
950 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
|
951 # delete remaining relations: if user can delete the entity, he can |
|
952 # delete all its relations without security checking |
920 with security_enabled(session, read=False, write=False): |
953 with security_enabled(session, read=False, write=False): |
921 for rschema, targetschemas, x in eschema.relation_definitions(): |
954 eid = entity.eid |
|
955 for rschema, _, role in entity.e_schema.relation_definitions(): |
922 rtype = rschema.type |
956 rtype = rschema.type |
923 if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes: |
957 if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes: |
924 continue |
958 continue |
925 var = '%s%s' % (rtype.upper(), x.upper()) |
959 if role == 'subject': |
926 if x == 'subject': |
|
927 # don't skip inlined relation so they are regularly |
960 # don't skip inlined relation so they are regularly |
928 # deleted and so hooks are correctly called |
961 # deleted and so hooks are correctly called |
929 selection = 'X %s %s' % (rtype, var) |
962 selection = 'X %s Y' % rtype |
930 else: |
963 else: |
931 selection = '%s %s X' % (var, rtype) |
964 selection = 'Y %s X' % rtype |
932 rql = 'DELETE %s WHERE X eid %%(x)s' % selection |
965 rql = 'DELETE %s WHERE X eid %%(x)s' % selection |
933 # if user can delete the entity, he can delete all its relations |
|
934 # without security checking |
|
935 session.execute(rql, {'x': eid}, 'x', build_descr=False) |
966 session.execute(rql, {'x': eid}, 'x', build_descr=False) |
|
967 self.system_source.delete_info(session, entity, sourceuri, extid) |
936 |
968 |
937 def locate_relation_source(self, session, subject, rtype, object): |
969 def locate_relation_source(self, session, subject, rtype, object): |
938 subjsource = self.source_from_eid(subject, session) |
970 subjsource = self.source_from_eid(subject, session) |
939 objsource = self.source_from_eid(object, session) |
971 objsource = self.source_from_eid(object, session) |
940 if not subjsource is objsource: |
972 if not subjsource is objsource: |
941 source = self.system_source |
973 source = self.system_source |
942 if not (subjsource.may_cross_relation(rtype) |
974 if not (subjsource.may_cross_relation(rtype) |
943 and objsource.may_cross_relation(rtype)): |
975 and objsource.may_cross_relation(rtype)): |
944 raise MultiSourcesError( |
976 raise MultiSourcesError( |
945 "relation %s can't be crossed among sources" |
977 "relation %s can't be crossed among sources" |
946 % rtype) |
978 % rtype) |
947 elif not subjsource.support_relation(rtype): |
979 elif not subjsource.support_relation(rtype): |
1092 self.hm.call_hooks('after_add_relation', session, |
1124 self.hm.call_hooks('after_add_relation', session, |
1093 eidfrom=entity.eid, rtype=attr, eidto=value) |
1125 eidfrom=entity.eid, rtype=attr, eidto=value) |
1094 |
1126 |
1095 def glob_delete_entity(self, session, eid): |
1127 def glob_delete_entity(self, session, eid): |
1096 """delete an entity and all related entities from the repository""" |
1128 """delete an entity and all related entities from the repository""" |
1097 # call delete_info before hooks |
1129 entity = session.entity_from_eid(eid) |
1098 self._prepare_delete_info(session, eid) |
1130 etype, sourceuri, extid = self.type_and_source_from_eid(eid, session) |
1099 etype, uri, extid = self.type_and_source_from_eid(eid, session) |
1131 self._prepare_delete_info(session, entity, sourceuri) |
1100 if server.DEBUG & server.DBG_REPO: |
1132 if server.DEBUG & server.DBG_REPO: |
1101 print 'DELETE entity', etype, eid |
1133 print 'DELETE entity', etype, eid |
1102 if eid == 937: |
1134 source = self.sources_by_uri[sourceuri] |
1103 server.DEBUG |= (server.DBG_SQL | server.DBG_RQL | server.DBG_MORE) |
|
1104 source = self.sources_by_uri[uri] |
|
1105 if source.should_call_hooks: |
1135 if source.should_call_hooks: |
1106 entity = session.entity_from_eid(eid) |
|
1107 self.hm.call_hooks('before_delete_entity', session, entity=entity) |
1136 self.hm.call_hooks('before_delete_entity', session, entity=entity) |
1108 self._delete_info(session, eid) |
1137 self._delete_info(session, entity, sourceuri, extid) |
1109 source.delete_entity(session, etype, eid) |
1138 source.delete_entity(session, entity) |
1110 if source.should_call_hooks: |
1139 if source.should_call_hooks: |
1111 self.hm.call_hooks('after_delete_entity', session, entity=entity) |
1140 self.hm.call_hooks('after_delete_entity', session, entity=entity) |
1112 # don't clear cache here this is done in a hook on commit |
1141 # don't clear cache here this is done in a hook on commit |
1113 |
1142 |
1114 def glob_add_relation(self, session, subject, rtype, object): |
1143 def glob_add_relation(self, session, subject, rtype, object): |