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)