From faa22cb6377e2a2b2c02a773c5a839b04d896764 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Sat, 15 Feb 2020 22:39:08 +0000 Subject: [PATCH] Fixes #2511: Compare object change to the previous change --- netbox/extras/views.py | 24 +++++++++++++++++++ netbox/templates/extras/objectchange.html | 29 +++++++++++++++++++++++ netbox/utilities/utils.py | 16 +++++++++++++ 3 files changed, 69 insertions(+) diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 3912c602f..b625cf7b1 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -12,6 +12,7 @@ from django_tables2 import RequestConfig from utilities.forms import ConfirmationForm from utilities.paginator import EnhancedPaginator +from utilities.utils import shallow_compare_dict from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView from . import filters, forms from .models import ConfigContext, ImageAttachment, ObjectChange, ReportResult, Tag, TaggedItem @@ -207,8 +208,31 @@ class ObjectChangeView(PermissionRequiredMixin, View): orderable=False ) + objectchanges = ObjectChange.objects.filter( + changed_object_type=objectchange.changed_object_type, + changed_object_id=objectchange.changed_object_id, + ) + + next_change = objectchanges.filter(time__gt=objectchange.time).order_by('time').first() + prev_change = objectchanges.filter(time__lt=objectchange.time).order_by('-time').first() + + if prev_change: + diff_added = shallow_compare_dict( + prev_change.object_data, + objectchange.object_data, + exclude=['last_updated'], + ) + diff_removed = {x: prev_change.object_data.get(x) for x in diff_added} + else: + # No previous change; this is the initial change that added the object + diff_added = diff_removed = objectchange.object_data + return render(request, 'extras/objectchange.html', { 'objectchange': objectchange, + 'diff_added': diff_added, + 'diff_removed': diff_removed, + 'next_change': next_change, + 'prev_change': prev_change, 'related_changes_table': related_changes_table, 'related_changes_count': related_changes.count() }) diff --git a/netbox/templates/extras/objectchange.html b/netbox/templates/extras/objectchange.html index ee29281f9..35be29bbd 100644 --- a/netbox/templates/extras/objectchange.html +++ b/netbox/templates/extras/objectchange.html @@ -83,6 +83,35 @@ +
+
+ Difference + +
+
+ {% if diff_added == diff_removed %} + + {% if objectchange.action == 'create' %} + Object created + {% elif objectchange.action == 'delete' %} + Object deleted + {% else %} + No changes + {% endif %} + + {% else %} +
{{ diff_removed|render_json }}
+
{{ diff_added|render_json }}
+ {% endif %} +
+
diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 979f95af9..6969a60e9 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -222,3 +222,19 @@ def querydict_to_dict(querydict): key: querydict.get(key) if len(value) == 1 and key != 'pk' else querydict.getlist(key) for key, value in querydict.lists() } + + +def shallow_compare_dict(source_dict, destination_dict, exclude=None): + """ + Return a new dictionary of the different keys. The values of `destination_dict` are returned. Only the equality of + the first layer of keys/values is checked. `exclude` is a list or tuple of keys to be ignored. + """ + difference = {} + + for key in destination_dict: + if source_dict.get(key) != destination_dict[key]: + if isinstance(exclude, (list, tuple)) and key in exclude: + continue + difference[key] = destination_dict[key] + + return difference