Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provision-level PiT comparison #2330

Merged
merged 3 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions indigo_api/models/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,14 +548,14 @@ def change_date(self, new_date, user, comment=None):
self.expression_date = new_date
self.save_with_revision(user, comment=comment)

def get_provision_element(self, provision_eid):
def get_portion(self, provision_eid):
provision_xml = self.doc.get_portion_element(provision_eid)
if provision_xml is None:
return None
portion = StructuredDocument.for_document_type('portion')()
portion.frbr_uri = self.frbr_uri
portion.main_content.append(provision_xml)
return portion.main
return portion

def update_provision_xml(self, provision_eid, provision_xml):
xml = etree.fromstring(provision_xml)
Expand Down
14 changes: 2 additions & 12 deletions indigo_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ class DocumentAPISerializer(serializers.Serializer):
xml = serializers.CharField()
language = serializers.CharField(min_length=3, max_length=3)
provision_eid = serializers.CharField(allow_blank=True)
element_id = serializers.CharField(required=False, allow_null=True, allow_blank=True)

def validate_xml(self, xml):
""" mostly copied from DocumentSerializer.validate()
Expand Down Expand Up @@ -488,7 +489,7 @@ def updated_xml(self):
return document.document_xml
# otherwise, return only the provision being edited (NOT including the outer akn tag)
# if we used the full XML for the analysis, grab only the appropriate provision as a portion
xml = document.get_provision_element(provision_eid) if self.use_full_xml else document.doc.portion
xml = document.get_portion(provision_eid).main if self.use_full_xml else document.doc.portion
return etree.tostring(xml, encoding='unicode')


Expand Down Expand Up @@ -714,14 +715,3 @@ def get_url(self, instance):
'work_id': instance.amended_work.pk,
'pk': instance.pk,
})


class DocumentDiffSerializer(serializers.Serializer):
""" Helper to handle input elements for the /document/xxx/diff API
"""
document = DocumentSerializer(required=True)
element_id = serializers.CharField(required=False, allow_null=True)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['document'].instance = self.instance
27 changes: 21 additions & 6 deletions indigo_api/views/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@
from django_filters.rest_framework import DjangoFilterBackend
from cobalt import StructuredDocument

from lxml import etree
import lxml.html.diff

from indigo.analysis.differ import AKNHTMLDiffer
from indigo.analysis.refs.base import markup_document_refs
from indigo.plugins import plugins
from indigo.xmlutils import parse_html_str
from ..models import Document, Annotation, DocumentActivity, Task, Language, Work
from ..serializers import DocumentSerializer, RenderSerializer, ParseSerializer, DocumentAPISerializer, VersionSerializer, AnnotationSerializer, DocumentActivitySerializer, TaskSerializer, DocumentDiffSerializer
from ..models import Document, Annotation, DocumentActivity, Task
from ..serializers import DocumentSerializer, RenderSerializer, ParseSerializer, DocumentAPISerializer, VersionSerializer, AnnotationSerializer, DocumentActivitySerializer, TaskSerializer
from ..renderers import AkomaNtosoRenderer, PDFRenderer, EPUBRenderer, HTMLRenderer, ZIPRenderer
from indigo_api.exporters import HTMLExporter
from ..authz import DocumentPermissions, AnnotationPermissions, ModelPermissions, RelatedDocumentPermissions, \
Expand Down Expand Up @@ -424,7 +425,8 @@ def manipulate_xml(self):

class DocumentDiffView(DocumentResourceView, APIView):
def post(self, request, document_id):
serializer = DocumentDiffSerializer(instance=self.document, data=self.request.data)
serializer = DocumentAPISerializer(instance=self.document, data=self.request.data)
serializer.use_full_xml = False
serializer.is_valid(raise_exception=True)

differ = AKNHTMLDiffer()
Expand All @@ -433,10 +435,23 @@ def post(self, request, document_id):

# set this up to be the modified document
remote_doc = Document.objects.get(pk=local_doc.pk)
serializer.fields['document'].update_document(local_doc, serializer.validated_data['document'])

local_doc.content = differ.preprocess_xml_str(local_doc.document_xml).decode('utf-8')
remote_doc.content = differ.preprocess_xml_str(remote_doc.document_xml).decode('utf-8')
# this will set the local_doc's content as the <portion> in provision mode,
# and update it with the latest unsaved changes regardless
serializer.set_content()
local_doc.content = differ.preprocess_xml_str(local_doc.document_xml)

provision_eid = serializer.validated_data.get('provision_eid')
if provision_eid:
portion = remote_doc.get_portion(provision_eid)
# the same structure as the 'xml' we're getting from the browser: akn/portion/portionBody/element
remote_xml = etree.tostring(portion.root, encoding='unicode')
remote_doc.work.work_uri.doctype = 'portion'
remote_doc.content = differ.preprocess_xml_str(remote_xml)

else:
# full document mode
remote_doc.content = differ.preprocess_xml_str(remote_doc.document_xml)

element_id = serializer.validated_data.get('element_id')
if element_id:
Expand Down
7 changes: 3 additions & 4 deletions indigo_app/static/javascript/indigo/views/document_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,12 @@
},

renderComparisonDiff: function() {
var self = this,
data = {};
let self = this;

if (!this.comparisonDocumentId) return;

data.document = this.document.toJSON();
data.document.content = this.document.content.toXml();
const data = this.document.content.toSimplifiedJSON();
// slight difference to provision_eid -- doesn't treat the document XML as a portion
data.element_id = this.xmlElement.getAttribute('eId');

if (!data.element_id && this.xmlElement.tagName !== "akomaNtoso") {
Expand Down
5 changes: 3 additions & 2 deletions indigo_app/views/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,11 @@ class DocumentProvisionDetailView(DocumentDetailView):
def get(self, request, *args, **kwargs):
document = self.get_object()
self.eid = self.kwargs.get('eid')
self.provision_xml = document.get_provision_element(self.eid)
if self.provision_xml is None:
provision_xml = document.get_portion(self.eid)
if provision_xml is None:
messages.error(request, _("No provision with this id found: '%(eid)s'") % {"eid": self.eid})
return redirect('choose_document_provision', doc_id=document.id)
self.provision_xml = provision_xml.main
return super().get(request, *args, **kwargs)

def get_context_data(self, **kwargs):
Expand Down
Loading