Skip to content
Snippets Groups Projects
Commit a0881832 authored by Todd Dembrey's avatar Todd Dembrey
Browse files

Refactor the comparison to pull the code into a seperate file

parent f5f69863
No related branches found
No related tags found
No related merge requests found
from difflib import SequenceMatcher
import bleach
from django.utils.html import format_html
from django.utils.text import mark_safe
def wrap_with_span(text, class_name):
return format_html('<span class="{}">{}</span>', class_name, mark_safe(text))
def wrap_deleted(text):
return wrap_with_span(text, 'deleted')
def wrap_added(text):
return wrap_with_span(text, 'added')
def compare(answer_a, answer_b, should_bleach=True):
if not answer_a and not answer_b:
# This catches the case where both results are None and we cant compare
return answer_b
if isinstance(answer_a, dict) or isinstance(answer_b, dict):
# TODO: handle file dictionaries
return answer_b
if should_bleach:
answer_a = bleach.clean(answer_a)
answer_b = bleach.clean(answer_b)
diff = SequenceMatcher(None, answer_a, answer_b)
output = []
added = []
deleted = []
for opcode, a0, a1, b0, b1 in diff.get_opcodes():
if opcode == 'equal':
if a1 - a0 > 2 or not (added or deleted):
# if there is more than 2 chars the same commit the added and removed text
if added:
output.append(wrap_added(''.join(added)))
added = []
if deleted:
output.append(wrap_deleted(''.join(deleted)))
deleted = []
output.append(diff.a[a0:a1])
else:
# ignore the small gap pretend it has been both added and removed
added.append(diff.a[a0:a1])
deleted.append(diff.a[a0:a1])
elif opcode == 'insert':
added.append(diff.b[b0:b1])
elif opcode == 'delete':
deleted.append(diff.a[a0:a1])
elif opcode == 'replace':
deleted.append(diff.a[a0:a1])
added.append(diff.b[b0:b1])
# Handle text not added to the output already
if added == deleted:
output.append(added)
else:
if added:
output.append(wrap_deleted(''.join(deleted)))
if deleted:
output.append(wrap_added(''.join(added)))
return mark_safe(''.join(output))
from difflib import SequenceMatcher
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
...@@ -28,6 +26,7 @@ from opentech.apply.utils.views import DelegateableView, ViewDispatcher ...@@ -28,6 +26,7 @@ from opentech.apply.utils.views import DelegateableView, ViewDispatcher
from opentech.apply.users.models import User from opentech.apply.users.models import User
from .blocks import MustIncludeFieldBlock from .blocks import MustIncludeFieldBlock
from .differ import compare
from .forms import ProgressSubmissionForm, UpdateReviewersForm, UpdateSubmissionLeadForm from .forms import ProgressSubmissionForm, UpdateReviewersForm, UpdateSubmissionLeadForm
from .models import ApplicationSubmission, ApplicationRevision from .models import ApplicationSubmission, ApplicationRevision
from .tables import AdminSubmissionsTable, SubmissionFilter, SubmissionFilterAndSearch from .tables import AdminSubmissionsTable, SubmissionFilter, SubmissionFilterAndSearch
...@@ -266,65 +265,13 @@ class RevisionListView(ListView): ...@@ -266,65 +265,13 @@ class RevisionListView(ListView):
class RevisionCompareView(TemplateView): class RevisionCompareView(TemplateView):
template_name = 'funds/revisions_compare.html' template_name = 'funds/revisions_compare.html'
def wrap(self, class_name, text): def compare_revisions(self, from_data, to_data):
return format_html('<span class="{}">{}</span>', class_name, mark_safe(text))
def deleted(self, text):
return self.wrap('deleted', text)
def added(self, text):
return self.wrap('added', text)
def compare_answer(self, answer_a, answer_b):
if not answer_a and not answer_b:
# This catches the case where both results are None and we cant compare
return answer_b
if isinstance(answer_a, dict) or isinstance(answer_b, dict):
# TODO: handle file dictionaries
return answer_b
diff = SequenceMatcher(None, answer_a, answer_b)
output = []
added = ''
deleted = ''
for opcode, a0, a1, b0, b1 in diff.get_opcodes():
if opcode == 'equal':
if a1 - a0 > 2 or not (added or deleted):
if added:
output.append(self.added(added))
added = ''
if deleted:
output.append(self.deleted(deleted))
deleted = ''
output.append(diff.a[a0:a1])
else:
added += diff.a[a0:a1]
deleted += diff.a[a0:a1]
elif opcode == 'insert':
added += diff.b[b0:b1]
elif opcode == 'delete':
deleted += diff.a[a0:a1]
elif opcode == 'replace':
deleted += diff.a[a0:a1]
added += diff.b[b0:b1]
if added == deleted:
output.append(added)
else:
if added:
output.append(self.deleted(deleted))
if deleted:
output.append(self.added(added))
return mark_safe(''.join(output))
def compare(self, from_data, to_data):
diffed_form_data = { diffed_form_data = {
field: self.compare_answer(from_data.form_data.get(field), to_data.form_data[field]) field: compare(from_data.form_data.get(field), to_data.form_data[field])
for field in to_data.form_data for field in to_data.form_data
} }
diffed_answers = [ diffed_answers = [
self.compare_answer(*fields) compare(*fields, should_bleach=False)
for fields in zip(from_data.fields, to_data.fields) for fields in zip(from_data.fields, to_data.fields)
] ]
to_data.form_data = diffed_form_data to_data.form_data = diffed_form_data
...@@ -334,7 +281,7 @@ class RevisionCompareView(TemplateView): ...@@ -334,7 +281,7 @@ class RevisionCompareView(TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
from_revision = ApplicationSubmission.objects.get(id=self.kwargs['from']) from_revision = ApplicationSubmission.objects.get(id=self.kwargs['from'])
to_revision = ApplicationSubmission.objects.get(id=self.kwargs['to']) to_revision = ApplicationSubmission.objects.get(id=self.kwargs['to'])
diff = self.compare(from_revision, to_revision) diff = self.compare_revisions(from_revision, to_revision)
return super().get_context_data( return super().get_context_data(
submission=ApplicationSubmission.objects.get(id=self.kwargs['submission_pk']), submission=ApplicationSubmission.objects.get(id=self.kwargs['submission_pk']),
diff=diff, diff=diff,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment