diff --git a/src/c3nav/editor/models/changedobject.py b/src/c3nav/editor/models/changedobject.py index 01840440..1d384c68 100644 --- a/src/c3nav/editor/models/changedobject.py +++ b/src/c3nav/editor/models/changedobject.py @@ -253,6 +253,40 @@ class ChangedObject(models.Model): return False return True + def can_restore(self, force_query=False): + if not self.deleted: + return False + for field in self.model_class._meta.get_fields(): + if not field.many_to_one: + continue + if field.name not in self.updated_fields: + continue + related_model = field.related_model + if related_model._meta.app_label != 'mapdata': + continue + + pk = self.updated_fields[field.name] + + if force_query: + # query here to avoid a race condition + related_content_type = ContentType.objects.get_for_model(related_model) + qs = self.changeset.changed_objects_set.filter(content_type=related_content_type) + if is_created_pk(pk): + if not qs.filter(pk=int(pk[2:]), deleted=False).exists(): + return False + else: + if qs.filter(existing_object_pk=pk, deleted=True).exists(): + return False + else: + if is_created_pk(pk): + if pk not in self.changeset.created_objects.get(related_model, ()): + return False + else: + if pk in self.changeset.deleted_existing.get(related_model, ()): + return False + + return True + def mark_deleted(self): if not self.can_delete(): return False @@ -310,6 +344,10 @@ class ChangedObject(models.Model): self._m2m_added_cache.setdefault(name, set()).difference_update(pks) self.m2m_set(name) + def restore(self): + self.deleted = False + self.save(standalone=True) + @property def does_something(self): return (self.updated_fields or self._m2m_added_cache or self._m2m_removed_cache or self.is_created or diff --git a/src/c3nav/editor/templates/editor/changeset.html b/src/c3nav/editor/templates/editor/changeset.html index 28664ca8..e198bcbd 100644 --- a/src/c3nav/editor/templates/editor/changeset.html +++ b/src/c3nav/editor/templates/editor/changeset.html @@ -90,7 +90,7 @@ {% trans 'Edit' %} - {% elif obj.deleted and can_edit %} + {% elif obj.deleted and can_edit and obj.can_restore %} diff --git a/src/c3nav/editor/views/changes.py b/src/c3nav/editor/views/changes.py index 91bf4015..74511d86 100644 --- a/src/c3nav/editor/views/changes.py +++ b/src/c3nav/editor/views/changes.py @@ -43,10 +43,12 @@ def changeset_detail(request, pk): except: pass else: - if changed_object.deleted: - changed_object.deleted = False - changed_object.save(standalone=True) - messages.success(request, _('Object has been successfully restored.')) + if changed_object.can_restore(force_query=True): + changed_object.restore() + messages.success(request, _('Object has been successfully restored.')) + else: + messages.error(request, _('You cannot restore this object, because ' + 'it depends on a deleted object.')) else: messages.error(request, _('You can not edit changes on this change set.')) @@ -235,6 +237,7 @@ def changeset_detail(request, pk): 'changes': changes, 'edit_url': edit_url, 'deleted': changed_object.deleted, + 'can_restore': changed_object.can_restore(), 'order': (changed_object.deleted and changed_object.is_created, not changed_object.is_created), } changed_objects_data.append(changed_object_data)