From 10c9296f856871a670f318777c554a2d2467ed26 Mon Sep 17 00:00:00 2001 From: goose-life <32566441+goose-life@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:14:09 +0200 Subject: [PATCH 1/3] return whole portion from get_provision_element, rename to get_portion --- indigo_api/models/documents.py | 4 ++-- indigo_api/serializers.py | 2 +- indigo_app/views/documents.py | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/indigo_api/models/documents.py b/indigo_api/models/documents.py index dd60d8fb0..92d367a51 100644 --- a/indigo_api/models/documents.py +++ b/indigo_api/models/documents.py @@ -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) diff --git a/indigo_api/serializers.py b/indigo_api/serializers.py index 3e3cd52e9..3a4c3fa8f 100644 --- a/indigo_api/serializers.py +++ b/indigo_api/serializers.py @@ -488,7 +488,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') diff --git a/indigo_app/views/documents.py b/indigo_app/views/documents.py index e0c647a06..968da4b3f 100644 --- a/indigo_app/views/documents.py +++ b/indigo_app/views/documents.py @@ -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): From 2990bf106c52e66761d065e5bc90cea589921b81 Mon Sep 17 00:00:00 2001 From: goose-life <32566441+goose-life@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:20:14 +0200 Subject: [PATCH 2/3] add element_id to DocumentAPISerializer, use instead of DocumentDiffSerializer --- indigo_api/serializers.py | 12 +--------- indigo_api/views/documents.py | 23 +++++++++++++++---- .../indigo/views/document_editor.js | 7 +++--- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/indigo_api/serializers.py b/indigo_api/serializers.py index 3a4c3fa8f..4361ba238 100644 --- a/indigo_api/serializers.py +++ b/indigo_api/serializers.py @@ -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() @@ -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 diff --git a/indigo_api/views/documents.py b/indigo_api/views/documents.py index 294232800..8e081bbb7 100644 --- a/indigo_api/views/documents.py +++ b/indigo_api/views/documents.py @@ -24,6 +24,7 @@ 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 @@ -31,7 +32,7 @@ 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 ..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, \ @@ -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() @@ -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']) + # this will set the local_doc's content as the 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).decode('utf-8') - remote_doc.content = differ.preprocess_xml_str(remote_doc.document_xml).decode('utf-8') + + 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).decode('utf-8') element_id = serializer.validated_data.get('element_id') if element_id: diff --git a/indigo_app/static/javascript/indigo/views/document_editor.js b/indigo_app/static/javascript/indigo/views/document_editor.js index 6d7594f88..443d10312 100644 --- a/indigo_app/static/javascript/indigo/views/document_editor.js +++ b/indigo_app/static/javascript/indigo/views/document_editor.js @@ -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") { From 2de2e2c61f39dbd9fd832971fa7839d979bfa87f Mon Sep 17 00:00:00 2001 From: goose-life <32566441+goose-life@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:46:37 +0200 Subject: [PATCH 3/3] nuke superfluous decodes, unused imports --- indigo_api/views/documents.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indigo_api/views/documents.py b/indigo_api/views/documents.py index 8e081bbb7..f9b6be252 100644 --- a/indigo_api/views/documents.py +++ b/indigo_api/views/documents.py @@ -31,7 +31,7 @@ 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 ..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 @@ -439,7 +439,7 @@ def post(self, request, document_id): # this will set the local_doc's content as the 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).decode('utf-8') + local_doc.content = differ.preprocess_xml_str(local_doc.document_xml) provision_eid = serializer.validated_data.get('provision_eid') if provision_eid: @@ -451,7 +451,7 @@ def post(self, request, document_id): else: # full document mode - remote_doc.content = differ.preprocess_xml_str(remote_doc.document_xml).decode('utf-8') + remote_doc.content = differ.preprocess_xml_str(remote_doc.document_xml) element_id = serializer.validated_data.get('element_id') if element_id: