Add support for comparing document versions
This commit is contained in:
@@ -43,7 +43,7 @@ from .links import (document_page_transformation_list, document_page_transformat
|
||||
document_page_navigation_last, document_page_zoom_in, document_page_zoom_out,
|
||||
document_page_rotate_right, document_page_rotate_left, document_page_view_reset,
|
||||
document_multiple_clear_transformations, document_multiple_delete,
|
||||
document_multiple_download)
|
||||
document_multiple_download, document_version_text_compare)
|
||||
from .links import document_clear_image_cache
|
||||
from .statistics import get_statistics
|
||||
|
||||
@@ -59,6 +59,7 @@ bind_links([Document], [document_view_simple, document_edit, document_print, doc
|
||||
|
||||
# Document Version links
|
||||
bind_links([DocumentVersion], [document_version_revert, document_version_download])
|
||||
bind_links(['document_version_list', 'upload_version', 'document_version_revert', 'document_version_text_compare', 'document_version_show_diff_text'], [document_version_text_compare], menu_name='sidebar')
|
||||
|
||||
secondary_menu_links = [document_list_recent, document_list]
|
||||
|
||||
|
||||
@@ -321,3 +321,33 @@ class DocumentDownloadForm(forms.Form):
|
||||
if len(self.document_versions) > 1:
|
||||
self.fields['compressed'].initial = True
|
||||
self.fields['compressed'].widget.attrs.update({'disabled': True})
|
||||
|
||||
|
||||
class DocumentVersionCompareForm(forms.Form):
|
||||
left_version = forms.ChoiceField(label=_(u'Source version'), required=True)
|
||||
right_version = forms.ChoiceField(label=_(u'Destination version'), required=True)
|
||||
|
||||
def make_choices(self):
|
||||
return [(version.pk, unicode(version)) for version in self.document.versions.all()]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.document = kwargs.pop('document')
|
||||
super(DocumentVersionCompareForm, self).__init__(*args, **kwargs)
|
||||
choices = self.make_choices()
|
||||
self.fields['left_version'].choices = choices
|
||||
self.fields['left_version'].initial = choices[-2][0] if len(choices) > 1 else choices[-1][0]
|
||||
|
||||
self.fields['right_version'].choices = choices
|
||||
self.fields['right_version'].initial = choices[-1][0]
|
||||
|
||||
|
||||
class DocumentVersionDiffForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
contents = kwargs.pop('contents', None)
|
||||
super(DocumentVersionDiffForm, self).__init__(*args, **kwargs)
|
||||
self.fields['contents'].initial = contents
|
||||
|
||||
contents = forms.CharField(
|
||||
label=_(u'Contents'),
|
||||
widget=TextAreaDiv()
|
||||
)
|
||||
|
||||
@@ -11,7 +11,8 @@ from .permissions import (PERMISSION_DOCUMENT_CREATE,
|
||||
PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS,
|
||||
PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT,
|
||||
PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE,
|
||||
PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW)
|
||||
PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW,
|
||||
PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE)
|
||||
|
||||
from .conf.settings import ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL
|
||||
|
||||
@@ -83,6 +84,7 @@ document_page_view_reset = Link(text=_(u'reset view'), klass='no-parent-history'
|
||||
# Document versions
|
||||
document_version_list = Link(text=_(u'versions'), view='document_version_list', args='object.pk', sprite='page_world', permissions=[PERMISSION_DOCUMENT_VIEW])
|
||||
document_version_revert = Link(text=_(u'revert'), view='document_version_revert', args='object.pk', sprite='page_refresh', permissions=[PERMISSION_DOCUMENT_VERSION_REVERT], conditional_disable=is_current_version)
|
||||
document_version_text_compare = Link(text=_(u'compare (text)'), view='document_version_text_compare', args='object.pk', sprite='table_relationship', permissions=[PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE])
|
||||
|
||||
# Document type related links
|
||||
document_type_list = Link(text=_(u'document type list'), view='document_type_list', sprite='layout', permissions=[PERMISSION_DOCUMENT_TYPE_VIEW])
|
||||
|
||||
@@ -23,3 +23,5 @@ PERMISSION_DOCUMENT_TYPE_VIEW = Permission.objects.register(documents_setup_name
|
||||
PERMISSION_DOCUMENT_TYPE_EDIT = Permission.objects.register(documents_setup_namespace, 'document_type_edit', _(u'Edit document types'))
|
||||
PERMISSION_DOCUMENT_TYPE_DELETE = Permission.objects.register(documents_setup_namespace, 'document_type_delete', _(u'Delete document types'))
|
||||
PERMISSION_DOCUMENT_TYPE_CREATE = Permission.objects.register(documents_setup_namespace, 'document_type_create', _(u'Create document types'))
|
||||
|
||||
PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE = Permission.objects.register(documents_setup_namespace, 'document_versions_text_compare', _(u'Compare document version textually'))
|
||||
|
||||
@@ -36,6 +36,8 @@ urlpatterns = patterns('documents.views',
|
||||
url(r'^(?P<document_pk>\d+)/version/all/$', 'document_version_list', (), 'document_version_list'),
|
||||
url(r'^document/version/(?P<document_version_pk>\d+)/download/$', 'document_download', (), 'document_version_download'),
|
||||
url(r'^document/version/(?P<document_version_pk>\d+)/revert/$', 'document_version_revert', (), 'document_version_revert'),
|
||||
url(r'^document/(?P<document_pk>\d+)/version_compare/text/$', 'document_version_text_compare', (), 'document_version_text_compare'),
|
||||
url(r'^document/version/show/text/diff/(?P<left_document_version_pk>\d+)/vs/(?P<right_document_version_pk>\d+)/$', 'document_version_show_diff_text', (), 'document_version_show_diff_text'),
|
||||
|
||||
url(r'^multiple/clear_transformations/$', 'document_multiple_clear_transformations', (), 'document_multiple_clear_transformations'),
|
||||
url(r'^duplicates/list/$', 'document_find_all_duplicates', (), 'document_find_all_duplicates'),
|
||||
|
||||
@@ -40,17 +40,20 @@ from .permissions import (PERMISSION_DOCUMENT_CREATE,
|
||||
PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS,
|
||||
PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT,
|
||||
PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE,
|
||||
PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW)
|
||||
PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW,
|
||||
PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE)
|
||||
from .events import history_document_edited
|
||||
from .forms import (DocumentForm_edit, DocumentPropertiesForm,
|
||||
DocumentPreviewForm, DocumentPageForm,
|
||||
DocumentPageTransformationForm, DocumentContentForm,
|
||||
DocumentPageForm_edit, DocumentPageForm_text, PrintForm,
|
||||
DocumentTypeForm, DocumentTypeFilenameForm,
|
||||
DocumentTypeFilenameForm_create, DocumentDownloadForm)
|
||||
DocumentTypeFilenameForm_create, DocumentDownloadForm,
|
||||
DocumentVersionCompareForm, DocumentVersionDiffForm)
|
||||
from .models import (Document, DocumentType, DocumentPage,
|
||||
DocumentPageTransformation, RecentDocument, DocumentTypeFilename,
|
||||
DocumentVersion)
|
||||
from .widgets import diff_widget
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -1364,3 +1367,60 @@ def document_version_revert(request, document_version_pk):
|
||||
'message': _(u'All later version after this one will be deleted too.'),
|
||||
'form_icon': u'page_refresh.png',
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def document_version_text_compare(request, document_pk):
|
||||
document = get_object_or_404(Document, pk=document_pk)
|
||||
|
||||
try:
|
||||
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE])
|
||||
except PermissionDenied:
|
||||
AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE, request.user, document)
|
||||
|
||||
RecentDocument.objects.add_document_for_user(request.user, document)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = DocumentVersionCompareForm(document=document, data=request.POST)
|
||||
if form.is_valid():
|
||||
return HttpResponseRedirect(reverse('document_version_show_diff_text', args=[form.cleaned_data['left_version'], form.cleaned_data['right_version']]))
|
||||
else:
|
||||
form = DocumentVersionCompareForm(document=document)
|
||||
|
||||
return render_to_response('generic_form.html', {
|
||||
'object': document,
|
||||
'title': _(u'Textually compare versions of document: %s') % document,
|
||||
'form': form,
|
||||
'submit_label': _(u'Compare'),
|
||||
'submit_icon_famfam': 'table_relationship',
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def document_version_show_diff_text(request, left_document_version_pk, right_document_version_pk):
|
||||
left_document_version = get_object_or_404(DocumentVersion, pk=left_document_version_pk)
|
||||
right_document_version = get_object_or_404(DocumentVersion, pk=right_document_version_pk)
|
||||
|
||||
try:
|
||||
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE])
|
||||
except PermissionDenied:
|
||||
# Make sure user has the compare permission for both document
|
||||
# versions' root documents
|
||||
AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE, request.user, left_document_version.document)
|
||||
AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERSIONS_TEXT_COMPARE, request.user, right_document_version.document)
|
||||
|
||||
context = {
|
||||
'form': DocumentVersionDiffForm(contents=diff_widget(left_document_version.content, right_document_version.content)),
|
||||
'read_only': True
|
||||
}
|
||||
|
||||
if left_document_version.document == right_document_version.document:
|
||||
context['object'] = left_document_version.document
|
||||
context['title'] = _(u'Textual difference between version %(version1)s and %(version2)s of document: %(document)s') % {
|
||||
'version1': left_document_version, 'version2': right_document_version,
|
||||
'document': left_document_version.document}
|
||||
else:
|
||||
context['title'] = _(u'Textual difference between document: %(document1)s and %(document2)s.') % {
|
||||
'document1': left_document_version.document, 'document2': right_document_version.document}
|
||||
|
||||
return render_to_response('generic_form.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import diff_match_patch
|
||||
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@@ -85,3 +87,18 @@ def document_html_widget(document, view='document_thumbnail', click_view=None, p
|
||||
)
|
||||
|
||||
return mark_safe(u''.join(result))
|
||||
|
||||
|
||||
def diff_widget(version1, version2):
|
||||
|
||||
dmp = diff_match_patch.diff_match_patch()
|
||||
dmp.Diff_Timeout = 1 # Don't spend more than 1 seconds on a diff.
|
||||
|
||||
differences = dmp.diff_main(version1, version2)
|
||||
dmp.diff_cleanupSemantic(differences)
|
||||
pretty = dmp.diff_prettyHtml(differences)
|
||||
#patch=dmp.patch_make(differences)
|
||||
#text = dmp.patch_toText(patch)
|
||||
return mark_safe(dmp.diff_prettyHtml(differences))
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ bind_links([WatchFolder], [setup_web_form_list, setup_staging_folder_list, setup
|
||||
bind_links([WatchFolder], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
|
||||
|
||||
# Document version
|
||||
bind_links(['document_version_list', 'upload_version', 'document_version_revert'], [upload_version], menu_name='sidebar')
|
||||
bind_links(['document_version_list', 'upload_version', 'document_version_revert', 'document_version_text_compare', 'document_version_show_diff_text'], [upload_version], menu_name='sidebar')
|
||||
|
||||
bind_links(['setup_source_transformation_create', 'setup_source_transformation_edit', 'setup_source_transformation_delete', 'setup_source_transformation_list'], [setup_source_transformation_create], menu_name='sidebar')
|
||||
|
||||
|
||||
@@ -72,3 +72,4 @@ GitPython==0.3.2.RC1
|
||||
|
||||
elementtree==1.2.7-20070827-preview
|
||||
Pygments==1.5
|
||||
diff-match-patch==20120106
|
||||
|
||||
Reference in New Issue
Block a user