def test_update(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 doc4 = self.portal.folder1.doc4 # This tests updating link integrity information for all site content, # i.e. after migrating from a previous version. self._set_text(doc1, '<a href="doc2">a document</a>') self._set_text(doc2, '<a href="folder1/doc4">a document</a>') catalog = getUtility(ICatalog) rels = [i for i in catalog.findRelations()] for rel in rels: catalog.unindex(rel) # Just to make sure, we check that there are no references from or to # these documents at this point: self.assertEqual([i.to_object for i in getOutgoingLinks(doc1)], []) self.assertEqual([i.to_object for i in getOutgoingLinks(doc2)], []) # An update of link integrity information for all content is triggered # by browsing a specific url: transaction.commit() self.browser.open('{0:s}/updateLinkIntegrityInformation'.format( self.portal.absolute_url())) self.browser.getControl('Update').click() self.assertIn('Link integrity information updated for', self.browser.contents) # Now the linking documents should hold the correct link integrity # references: self.assertEqual([i.to_object for i in getOutgoingLinks(doc1)], [doc2, ]) self.assertEqual([i.to_object for i in getOutgoingLinks(doc2)], [doc4, ])
def test_reference_orthogonality(self): doc = self.portal.doc1 img = self.portal.image1 tag = img.restrictedTraverse('@@images').tag() # This tests the behavior when other references already exist. self.assertEqual([l for l in getOutgoingLinks(doc)], []) self.assertEqual([l for l in getIncomingLinks(doc)], []) self.assertEqual([l for l in getOutgoingLinks(img)], []) self.assertEqual([l for l in getOutgoingLinks(img)], []) # Then establish a reference between the document and image as # a related item: self._set_related_items(doc, [img, ]) self.assertEqual(self._get_related_items(doc), [img, ]) # Next edit the document body and insert a link to the image, # which should trigger the creation of a link integrity reference: self._set_text(doc, tag) self.assertEqual([l.to_object for l in getOutgoingLinks(doc)], [img]) # And the related item reference remains in place: self.assertEqual(self._get_related_items(doc), [img, ]) # Finally, edit the document body again, this time removing the # link to the image, which should trigger the removal of the # link integrity reference: self._set_text(doc, 'where did my link go?') self.assertEqual([l.to_object for l in getOutgoingLinks(doc)], []) # And again the related item reference remains in place: self.assertEqual(self._get_related_items(doc), [img, ])
def test_relative_upwards_link_generates_matching_reference(self): doc1 = self.portal.doc1 doc3 = self.portal.folder1.doc3 self._set_text(doc3, '<a href="../doc1">go!</a>') self.assertEqual(len(list(getOutgoingLinks(doc1))), 0) self.assertEqual([l.to_object for l in getOutgoingLinks(doc3)], [doc1])
def test_internal_breaches_are_dropped(self): folder1 = self.portal.folder1 create(folder1, 'Document', id='doc5', title='Test Page 5') doc1 = self.portal.doc1 doc4 = self.portal.folder1.doc4 doc5 = self.portal.folder1.doc5 self._set_text(doc1, '<a href="folder1">f1</a>') self._set_text(doc4, '<a href="doc5">d5</a><a href="../doc1">d1</a>') self._set_text(doc5, '<a href="../folder1">f1</a>') doc4_breaches = set([r.to_object for r in getOutgoingLinks(doc4)]) # the order of breaches is non-deterministic self.assertEqual(set([doc1, doc5]), doc4_breaches) self.assertEqual([r.to_object for r in getOutgoingLinks(doc5)], [folder1]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc1)], [folder1]) view = DeleteConfirmationInfo(self.portal, self.request) self.assertEqual(len(view.get_breaches([doc4])), 0) self.assertEqual(len(view.get_breaches([doc5])), 1) self.assertEqual(len(view.get_breaches([doc4, doc5])), 0) self.assertEqual(len(view.get_breaches([folder1])), 1) self.assertEqual(len(view.get_breaches([doc1])), 1) self.assertEqual(len(view.get_breaches([doc1, folder1])), 0) view = folder1.restrictedTraverse('delete_confirmation') self.assertIn('Potential link breakage', view()) view = folder1.restrictedTraverse('delete_confirmation_info') self.assertIn('Potential link breakage', view()) view = doc4.restrictedTraverse('delete_confirmation') self.assertNotIn('Potential link breakage', view()) view = doc4.restrictedTraverse('delete_confirmation_info') self.assertNotIn('Potential link breakage', view())
def test_internal_breaches_are_dropped(self): folder1 = self.portal.folder1 create(folder1, 'Document', id='doc5', title='Test Page 5') doc1 = self.portal.doc1 doc4 = self.portal.folder1.doc4 doc5 = self.portal.folder1.doc5 self._set_text(doc1, '<a href="folder1">f1</a>') self._set_text(doc4, '<a href="doc5">d5</a><a href="../doc1">d1</a>') self._set_text(doc5, '<a href="../folder1">f1</a>') doc4_breaches = set([r.to_object for r in getOutgoingLinks(doc4)]) # the order of breaches is non-deterministic self.assertEqual(set([doc1, doc5]), doc4_breaches) self.assertEqual( [r.to_object for r in getOutgoingLinks(doc5)], [folder1]) self.assertEqual( [r.to_object for r in getOutgoingLinks(doc1)], [folder1]) view = DeleteConfirmationInfo(self.portal, self.request) self.assertEqual(len(view.get_breaches([doc4])), 0) self.assertEqual(len(view.get_breaches([doc5])), 1) self.assertEqual(len(view.get_breaches([doc4, doc5])), 0) self.assertEqual(len(view.get_breaches([folder1])), 1) self.assertEqual(len(view.get_breaches([doc1])), 1) self.assertEqual(len(view.get_breaches([doc1, folder1])), 0) view = folder1.restrictedTraverse('delete_confirmation') self.assertIn('Potential link breakage', view()) view = folder1.restrictedTraverse('delete_confirmation_info') self.assertIn('Potential link breakage', view()) view = doc4.restrictedTraverse('delete_confirmation') self.assertNotIn('Potential link breakage', view()) view = doc4.restrictedTraverse('delete_confirmation_info') self.assertNotIn('Potential link breakage', view())
def test_image_tag_reference_creation(self): doc1 = self.portal.doc1 img1 = self.portal.image1 # This tests the correct creation of references used for # ensuring link integrity. Any archetype-based content object # which refers to other (local) objects by `<img>` or `<a>` tags # should create references between those objects on save. self._set_text(doc1, img1.restrictedTraverse('@@images').tag()) self.assertEqual([r.to_object for r in getOutgoingLinks(doc1)], [img1, ]) self.assertEqual([r.to_object for r in getIncomingLinks(doc1)], []) self.assertEqual([r.to_object for r in getOutgoingLinks(img1)], []) self.assertEqual([r.from_object for r in getIncomingLinks(img1)], [doc1])
def test_broken_references(self): # create a temporary document to test with doc1a = testing.create(self.portal, 'Document', id='doc1a') doc1 = self.portal.doc1 self.assertEqual(len(list(getOutgoingLinks(doc1))), 0) self._set_text(doc1, '<a href="doc1a">Doc 1a</a>') self.assertEqual(len(list(getOutgoingLinks(doc1))), 1) self.assertEqual([l.to_object for l in getOutgoingLinks(doc1)], [self.portal.doc1a]) # Now delete the target item, suppress events and test again, # the reference should be gone now. self.portal._delObject(doc1a.id, suppress_events=True) self.assertEqual([l.to_object for l in getOutgoingLinks(doc1)], [None])
def test_files_with_spaces_removal(self): doc1 = self.portal.doc1 # This tests the behaviour when removing a referenced file that has # spaces in its id. First we need to rename the existing file: self.portal.invokeFactory( 'Document', id='some spaces.doc', title='A spaces doc') self.assertIn('some spaces.doc', self.portal.objectIds()) spaces1 = self.portal['some spaces.doc'] self._set_text(doc1, '<a href="some spaces.doc">a document</a>') # The document should now have a reference to the file: self.assertEqual( [i.to_object for i in getOutgoingLinks(doc1)], [spaces1]) transaction.commit() # Then we use a browser to try to delete the referenced file. # Before we can do this we need to prevent the test framework # from choking on the exception we intentionally throw. self.browser.handleErrors = True self.browser.open('{0:s}/delete_confirmation?_authenticator={1:s}'.format( spaces1.absolute_url(), self._get_token(spaces1))) self.assertIn('Potential link breakage', self.browser.contents) self.assertIn( '<a href="http://nohost/plone/doc1">Test Page 1</a>', self.browser.contents ) self.browser.getControl(name='form.buttons.Delete').click() self.assertNotIn('some spaces.doc', self.portal.objectIds())
def test_files_with_spaces_removal(self): doc1 = self.portal.doc1 # This tests the behaviour when removing a referenced file that has # spaces in its id. First we need to rename the existing file: self.portal.invokeFactory('Document', id='some spaces.doc', title='A spaces doc') self.assertIn('some spaces.doc', self.portal.objectIds()) spaces1 = self.portal['some spaces.doc'] self._set_text(doc1, '<a href="some spaces.doc">a document</a>') # The document should now have a reference to the file: self.assertEqual([i.to_object for i in getOutgoingLinks(doc1)], [spaces1]) transaction.commit() # Then we use a browser to try to delete the referenced file. # Before we can do this we need to prevent the test framework # from choking on the exception we intentionally throw. self.browser.handleErrors = True self.browser.open( '{0:s}/delete_confirmation?_authenticator={1:s}'.format( spaces1.absolute_url(), self._get_token(spaces1))) self.assertIn('Potential link breakage', self.browser.contents) self.assertIn('<a href="http://nohost/plone/doc1">Test Page 1</a>', self.browser.contents) self.browser.getControl(name='form.buttons.Delete').click() self.assertNotIn('some spaces.doc', self.portal.objectIds())
def test_unicode_links(self): doc1 = self.portal.doc1 # This tests checks that hasIncomingLinks can now be used safely as it # eventually plays well with transaction machinery. # Add bad link, should not raise exception and there should not # be any references added. self._set_text(doc1, unicode('<a href="ö?foo=bar&baz=bam">bug</a>', 'utf-8')) self.assertEqual([l for l in getOutgoingLinks(doc1)], [])
def test_image_scale_reference_creation(self): doc1 = self.portal.doc1 img1 = self.portal.image1 # Linking image scales should also work: self._set_text( doc1, '<a href="image1/@@images/image_thumb">an image</a>') self.assertEqual([r.to_object for r in getOutgoingLinks(doc1)], [img1, ]) self.assertEqual([r.from_object for r in getIncomingLinks(img1)], [doc1, ])
def test_image_resolveuid_reference_creation(self): doc1 = self.portal.doc1 img1 = self.portal.image1 # Linking via the "resolveuid/UID" method should also work: self._set_text(doc1, '<a href="resolveuid/{0:s}">an image</a>'.format( IUUID(img1))) self.assertEqual([r.to_object for r in getOutgoingLinks(doc1)], [img1, ]) self.assertEqual([r.from_object for r in getIncomingLinks(img1)], [doc1, ])
def test_get_ref_form_snippet(self): page1 = self._create_page(_id='test1') page2 = self._create_page( text='<div data-type="snippet_tag" data-snippet-id="{}"</div>'. format(IUUID(page1))) refs = getSnippetRefs(page2) self.assertEqual([i for i in refs][0].to_object.getId(), 'test1') # should also have stored these refs for object links = getOutgoingLinks(page2) self.assertEqual([l for l in links][0].to_object.getId(), 'test1')
def test_update(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 doc4 = self.portal.folder1.doc4 # This tests updating link integrity information for all site content, # i.e. after migrating from a previous version. self._set_text(doc1, '<a href="doc2">a document</a>') self._set_text(doc2, '<a href="folder1/doc4">a document</a>') catalog = getUtility(ICatalog) rels = [i for i in catalog.findRelations()] for rel in rels: catalog.unindex(rel) # Just to make sure, we check that there are no references from or to # these documents at this point: self.assertEqual([i.to_object for i in getOutgoingLinks(doc1)], []) self.assertEqual([i.to_object for i in getOutgoingLinks(doc2)], []) # An update of link integrity information for all content is triggered # by browsing a specific url: transaction.commit() self.browser.open('{0:s}/updateLinkIntegrityInformation'.format( self.portal.absolute_url())) self.browser.getControl('Update').click() self.assertIn('Link integrity information updated for', self.browser.contents) # Now the linking documents should hold the correct link integrity # references: self.assertEqual( [i.to_object for i in getOutgoingLinks(doc1)], [ doc2, ], ) self.assertEqual( [i.to_object for i in getOutgoingLinks(doc2)], [ doc4, ], )
def test_reference_orthogonality(self): doc = self.portal.doc1 img = self.portal.image1 tag = img.restrictedTraverse('@@images').tag() # This tests the behavior when other references already exist. self.assertEqual([l for l in getOutgoingLinks(doc)], []) self.assertEqual([l for l in getIncomingLinks(doc)], []) self.assertEqual([l for l in getOutgoingLinks(img)], []) self.assertEqual([l for l in getOutgoingLinks(img)], []) # Then establish a reference between the document and image as # a related item: self._set_related_items(doc, [ img, ]) self.assertEqual(self._get_related_items(doc), [ img, ]) # Next edit the document body and insert a link to the image, # which should trigger the creation of a link integrity reference: self._set_text(doc, tag) self.assertEqual([l.to_object for l in getOutgoingLinks(doc)], [img]) # And the related item reference remains in place: self.assertEqual(self._get_related_items(doc), [ img, ]) # Finally, edit the document body again, this time removing the # link to the image, which should trigger the removal of the # link integrity reference: self._set_text(doc, 'where did my link go?') self.assertEqual([l.to_object for l in getOutgoingLinks(doc)], []) # And again the related item reference remains in place: self.assertEqual(self._get_related_items(doc), [ img, ])
def test_circular_reference_subfolder_deletion(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 doc3 = self.portal.doc3 doc4 = self.portal.folder1.doc4 folder1 = self.portal.folder1 # This tests the behaviour when removing objects # referencing each other in a circle. self._set_text(doc1, '<a href="doc2">documents...</a>') self._set_text(doc2, '<a href="doc3">go round...</a>') self._set_text(doc3, '<a href="folder1/doc4">and round.</a>') self._set_text(doc4, '<a href="../doc1">in circles.</a>') self.assertEqual([r.to_object for r in getOutgoingLinks(doc1)], [doc2]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc2)], [doc3]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc3)], [doc4]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc4)], [doc1]) view = DeleteConfirmationInfo(self.portal, self.request) self.assertEqual(len(view.get_breaches([folder1])), 1) self.assertEqual( len(view.get_breaches([doc1, doc2, doc3, folder1])), 0) self.assertEqual(len(view.get_breaches([doc2, folder1])), 2)
def test_circular_reference_subfolder_deletion(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 doc3 = self.portal.doc3 doc4 = self.portal.folder1.doc4 folder1 = self.portal.folder1 # This tests the behaviour when removing objects # referencing each other in a circle. self._set_text(doc1, '<a href="doc2">documents...</a>') self._set_text(doc2, '<a href="doc3">go round...</a>') self._set_text(doc3, '<a href="folder1/doc4">and round.</a>') self._set_text(doc4, '<a href="../doc1">in circles.</a>') self.assertEqual([r.to_object for r in getOutgoingLinks(doc1)], [doc2]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc2)], [doc3]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc3)], [doc4]) self.assertEqual([r.to_object for r in getOutgoingLinks(doc4)], [doc1]) view = DeleteConfirmationInfo(self.portal, self.request) self.assertEqual(len(view.get_breaches([folder1])), 1) self.assertEqual(len(view.get_breaches([doc1, doc2, doc3, folder1])), 0) self.assertEqual(len(view.get_breaches([doc2, folder1])), 2)
def __call__(self): valid = True for link in getOutgoingLinks(self.context): state = api.content.get_state(obj=link.to_object, default='published') if state != 'published': valid = False break headers_ordered = True try: feed = SearchFeed(api.portal.get()) adapter = queryMultiAdapter((self.context, feed), IFeedItem) html = adapter.render_content_core().strip() except Exception: html = '' if html: dom = fromstring(html) last = 1 for el in dom.cssselect('h1,h2,h3,h4,h5,h6'): idx = int(el.tag[-1]) if idx - last > 1: # means they skipped from say h1 -> h5 # h1 -> h2 is allowed headers_ordered = False break last = idx is_template = False if ITemplate.providedBy(self.context): is_template = True self.request.response.setHeader('Content-type', 'application/json') return json.dumps({ 'title': self.context.Title(), 'id': self.context.getId(), 'description': self.context.Description(), 'linksValid': valid, 'headersOrdered': headers_ordered, 'html': html_parser.unescape(html), 'template': is_template })
def test_removal_via_zmi(self): """Delete via ZMI is no longer protedted!""" doc1 = self.portal.doc1 doc2 = self.portal.doc2 # This tests ensuring link integrity when removing an object via # the ZMI. self._set_text(doc1, '<a href="doc2">a document</a>') self.assertEqual([i.to_object for i in getOutgoingLinks(doc1)], [doc2]) transaction.commit() # Then we use a browser to try to delete the referenced # document. Before we can do this we need to prevent the test # framework from choking on the exception we intentionally throw. self.browser.handleErrors = True self.browser.open('http://nohost/plone/manage_main') self.browser\ .getControl(name='ids:list')\ .getControl(value='doc2').selected = True self.browser.getControl('Delete').click() self.assertNotIn('doc2', self.portal.objectIds())
def test_breaking_header_links(self): page = self._create_page(_id='test1', text=''' <h1>Foobar 1</h1> <p>foobar 1</p> <h1>Foobar 2</h1> <p>foobar 2</p> <h2>Foobar 3</h2> <p>foobar 3</p> <h1>Foobar 4</h1> <p>foobar 4</p> ''') page2 = self._create_page(_id='test2', text=''' <div data-type="snippet_tag" data-snippet-id="{}" data-header="Foobar 2"></div>'''.format(IUUID(page))) links = getOutgoingLinks(page2) # should add link self.assertEqual([l for l in links][0].to_object.getId(), 'test1') links = getIncomingLinks(page) # should add link self.assertEqual([l for l in links][0].from_object.getId(), 'test2') # now, remove the header... page.text = RichTextValue(''' <h1>Foobar 1</h1> <p>foobar 1</p> <h2>Foobar 3</h2> <p>foobar 3</p> <h1>Foobar 4</h1> <p>foobar 4</p> ''', 'text/html', 'text/html') status_annotations = IAnnotations(self.request) self.assertFalse(bool(status_annotations.get(STATUSMESSAGEKEY))) checkSnippetReferences(page) self.assertTrue(bool(status_annotations.get(STATUSMESSAGEKEY)))