1121 """ |
1121 """ |
1122 # begin by inserting eid/type/source/extid into the entities table |
1122 # begin by inserting eid/type/source/extid into the entities table |
1123 hook.CleanupNewEidsCacheOp.get_instance(session).add_data(entity.eid) |
1123 hook.CleanupNewEidsCacheOp.get_instance(session).add_data(entity.eid) |
1124 self.system_source.add_info(session, entity, source, extid, complete) |
1124 self.system_source.add_info(session, entity, source, extid, complete) |
1125 |
1125 |
1126 def delete_info(self, session, entity, sourceuri, scleanup=None): |
1126 def delete_info(self, session, entity, sourceuri): |
1127 """called by external source when some entity known by the system source |
1127 """called by external source when some entity known by the system source |
1128 has been deleted in the external source |
1128 has been deleted in the external source |
1129 """ |
1129 """ |
1130 # mark eid as being deleted in session info and setup cache update |
1130 # mark eid as being deleted in session info and setup cache update |
1131 # operation |
1131 # operation |
1132 hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) |
1132 hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) |
1133 self._delete_info(session, entity, sourceuri, scleanup) |
1133 self._delete_info(session, entity, sourceuri) |
1134 |
1134 |
1135 def _delete_info(self, session, entity, sourceuri, scleanup=None): |
1135 def _delete_info(self, session, entity, sourceuri): |
1136 """delete system information on deletion of an entity: |
1136 """delete system information on deletion of an entity: |
1137 |
1137 |
1138 * delete all remaining relations from/to this entity |
1138 * delete all remaining relations from/to this entity |
1139 * call delete info on the system source |
1139 * call delete info on the system source |
1140 |
|
1141 When scleanup is specified, it's expected to be the source's eid, in |
|
1142 which case we'll specify the target's relation source so that this |
|
1143 source is ignored. E.g. we want to delete relations stored locally, as |
|
1144 the deletion information comes from the external source, it's its |
|
1145 responsability to have cleaned-up its own relations. |
|
1146 """ |
1140 """ |
1147 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
1141 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
1148 if scleanup is not None: |
|
1149 source = self.sources_by_eid[scleanup] |
|
1150 # delete remaining relations: if user can delete the entity, he can |
1142 # delete remaining relations: if user can delete the entity, he can |
1151 # delete all its relations without security checking |
1143 # delete all its relations without security checking |
1152 with session.security_enabled(read=False, write=False): |
1144 with session.security_enabled(read=False, write=False): |
1153 eid = entity.eid |
1145 eid = entity.eid |
1154 for rschema, _, role in entity.e_schema.relation_definitions(): |
1146 for rschema, _, role in entity.e_schema.relation_definitions(): |
1159 # don't skip inlined relation so they are regularly |
1151 # don't skip inlined relation so they are regularly |
1160 # deleted and so hooks are correctly called |
1152 # deleted and so hooks are correctly called |
1161 rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype |
1153 rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype |
1162 else: |
1154 else: |
1163 rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype |
1155 rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype |
1164 if scleanup is not None: |
|
1165 # source cleaning: only delete relations stored locally |
|
1166 # (here, scleanup |
|
1167 rql += ', NOT (Y cw_source S, S eid %(seid)s)' |
|
1168 try: |
1156 try: |
1169 session.execute(rql, {'x': eid, 'seid': scleanup}, |
1157 session.execute(rql, {'x': eid}, build_descr=False) |
1170 build_descr=False) |
|
1171 except Exception: |
1158 except Exception: |
1172 if self.config.mode == 'test': |
1159 if self.config.mode == 'test': |
1173 raise |
1160 raise |
1174 self.exception('error while cascading delete for entity %s ' |
1161 self.exception('error while cascading delete for entity %s ' |
1175 'from %s. RQL: %s', entity, sourceuri, rql) |
1162 'from %s. RQL: %s', entity, sourceuri, rql) |
1176 self.system_source.delete_info_multi(session, [entity]) |
1163 self.system_source.delete_info_multi(session, [entity]) |
1177 |
1164 |
1178 def _delete_info_multi(self, session, entities, scleanup=None): |
1165 def _delete_info_multi(self, session, entities): |
1179 """same as _delete_info but accepts a list of entities with |
1166 """same as _delete_info but accepts a list of entities with |
1180 the same etype and belinging to the same source. |
1167 the same etype and belinging to the same source. |
1181 """ |
1168 """ |
1182 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
1169 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
1183 if scleanup is not None: |
|
1184 source = self.sources_by_eid[scleanup] |
|
1185 # delete remaining relations: if user can delete the entity, he can |
1170 # delete remaining relations: if user can delete the entity, he can |
1186 # delete all its relations without security checking |
1171 # delete all its relations without security checking |
1187 with session.security_enabled(read=False, write=False): |
1172 with session.security_enabled(read=False, write=False): |
1188 in_eids = ','.join([str(_e.eid) for _e in entities]) |
1173 in_eids = ','.join([str(_e.eid) for _e in entities]) |
1189 for rschema, _, role in entities[0].e_schema.relation_definitions(): |
1174 for rschema, _, role in entities[0].e_schema.relation_definitions(): |
1194 # don't skip inlined relation so they are regularly |
1179 # don't skip inlined relation so they are regularly |
1195 # deleted and so hooks are correctly called |
1180 # deleted and so hooks are correctly called |
1196 rql = 'DELETE X %s Y WHERE X eid IN (%s)' % (rtype, in_eids) |
1181 rql = 'DELETE X %s Y WHERE X eid IN (%s)' % (rtype, in_eids) |
1197 else: |
1182 else: |
1198 rql = 'DELETE Y %s X WHERE X eid IN (%s)' % (rtype, in_eids) |
1183 rql = 'DELETE Y %s X WHERE X eid IN (%s)' % (rtype, in_eids) |
1199 if scleanup is not None: |
|
1200 # source cleaning: only delete relations stored locally |
|
1201 rql += ', NOT (Y cw_source S, S eid %(seid)s)' |
|
1202 try: |
1184 try: |
1203 session.execute(rql, {'seid': scleanup}, build_descr=False) |
1185 session.execute(rql, build_descr=False) |
1204 except ValidationError: |
1186 except ValidationError: |
1205 raise |
1187 raise |
1206 except Unauthorized: |
1188 except Unauthorized: |
1207 self.exception('Unauthorized exception while cascading delete for entity %s. ' |
1189 self.exception('Unauthorized exception while cascading delete for entity %s. ' |
1208 'RQL: %s.\nThis should not happen since security is disabled here.', |
1190 'RQL: %s.\nThis should not happen since security is disabled here.', |