diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5d074d38e6..95b7dcb06c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -22,7 +22,7 @@ Changelog * Fix: Disabled autocomplete dropdowns on date/time chooser fields (Janneke Janssen) * Fix: Split up `wagtail.admin.forms` to make it less prone to circular imports (Matt Westcott) * Fix: Disable linking to root page in rich text, making the page non-functional (Matt Westcott) - * Fix: Pages should be editable and save-able even if there are broken links in rich text (Matt Westcott) + * Fix: Pages should be editable and save-able even if there are broken page or document links in rich text (Matt Westcott) 2.2.2 (29.08.2018) diff --git a/docs/releases/2.3.rst b/docs/releases/2.3.rst index 8f931848e5..341a69e69f 100644 --- a/docs/releases/2.3.rst +++ b/docs/releases/2.3.rst @@ -45,7 +45,7 @@ Bug fixes * Disabled autocomplete dropdowns on date/time chooser fields (Janneke Janssen) * Split up ``wagtail.admin.forms`` to make it less prone to circular imports (Matt Westcott) * Disable linking to root page in rich text, making the page non-functional (Matt Westcott) - * Pages should be editable and save-able even if there are broken links in rich text (Matt Westcott) + * Pages should be editable and save-able even if there are broken page or document links in rich text (Matt Westcott) Upgrade considerations ====================== diff --git a/wagtail/admin/tests/test_contentstate.py b/wagtail/admin/tests/test_contentstate.py index dbe9f24e06..800a634528 100644 --- a/wagtail/admin/tests/test_contentstate.py +++ b/wagtail/admin/tests/test_contentstate.py @@ -390,6 +390,28 @@ class TestHtmlToContentState(TestCase):

a document link

''' )) + self.assertContentStateEqual(result, { + 'entityMap': { + '0': { + 'mutability': 'MUTABLE', 'type': 'DOCUMENT', + 'data': {'id': 9999} + } + }, + 'blocks': [ + { + 'inlineStyleRanges': [], 'text': 'a document link', 'depth': 0, 'type': 'unstyled', 'key': '00000', + 'entityRanges': [{'offset': 2, 'length': 8, 'key': 0}] + }, + ] + }) + + def test_document_link_with_missing_id(self): + converter = ContentstateConverter(features=['document-link']) + result = json.loads(converter.from_database_format( + ''' +

a document link

+ ''' + )) self.assertContentStateEqual(result, { 'entityMap': { '0': { diff --git a/wagtail/documents/rich_text.py b/wagtail/documents/rich_text.py index 06d9c7ef99..c876b4bd9d 100644 --- a/wagtail/documents/rich_text.py +++ b/wagtail/documents/rich_text.py @@ -13,7 +13,7 @@ def document_linktype_handler(attrs): try: doc = Document.objects.get(id=attrs['id']) return '' % escape(doc.url) - except Document.DoesNotExist: + except (Document.DoesNotExist, KeyError): return "" @@ -31,7 +31,11 @@ class DocumentLinkHandler: doc = Document.objects.get(id=attrs['id']) return '' % (doc.id, escape(doc.url)) except Document.DoesNotExist: - return "" + # Preserve the ID attribute for troubleshooting purposes, even though it + # points to a missing document + return '' % attrs['id'] + except KeyError: + return '' EditorHTMLDocumentLinkConversionRule = [ @@ -62,10 +66,15 @@ class DocumentLinkElementHandler(LinkElementHandler): def get_attribute_data(self, attrs): Document = get_document_model() try: - doc = Document.objects.get(id=attrs['id']) - except Document.DoesNotExist: + id = int(attrs['id']) + except (KeyError, ValueError): return {} + try: + doc = Document.objects.get(id=id) + except Document.DoesNotExist: + return {'id': id} + return { 'id': doc.id, 'url': doc.url, diff --git a/wagtail/documents/tests/test_rich_text.py b/wagtail/documents/tests/test_rich_text.py index 26f6fceb91..c7e5cc94fe 100644 --- a/wagtail/documents/tests/test_rich_text.py +++ b/wagtail/documents/tests/test_rich_text.py @@ -14,16 +14,29 @@ class TestDocumentRichTextLinkHandler(TestCase): self.assertEqual(result, {'id': 'test-id'}) + def test_expand_db_attributes(self): + result = document_linktype_handler({'id': 1}) + self.assertEqual(result, + '') + def test_expand_db_attributes_document_does_not_exist(self): result = document_linktype_handler({'id': 0}) self.assertEqual(result, '') + def test_expand_db_attributes_with_missing_id(self): + result = document_linktype_handler({}) + self.assertEqual(result, '') + def test_expand_db_attributes_for_editor(self): result = DocumentLinkHandler.expand_db_attributes({'id': 1}) self.assertEqual(result, '') - def test_expand_db_attributes_not_for_editor(self): - result = document_linktype_handler({'id': 1}) + def test_expand_db_attributes_for_editor_preserves_id_of_nonexistent_document(self): + result = DocumentLinkHandler.expand_db_attributes({'id': 0}) self.assertEqual(result, - '') + '') + + def test_expand_db_attributes_for_editor_with_missing_id(self): + result = DocumentLinkHandler.expand_db_attributes({}) + self.assertEqual(result, '')