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 check_object(self, obj, excluded_path=None): """Check one object for breaches. Breaches originating from excluded_path are ignored. """ breaches = {} direct_links = getIncomingLinks(obj) has_breaches = False for direct_link in direct_links: source_path = direct_link.from_path if not source_path: # link is broken continue if excluded_path and source_path.startswith(excluded_path): # source is in excluded_path continue source = direct_link.from_object if not breaches.get('sources'): breaches['sources'] = [] breaches['sources'].append({ 'uid': IUUID(source), 'title': source.Title(), 'url': source.absolute_url(), 'accessible': self.is_accessible(source), }) has_breaches = True if has_breaches: breaches['target'] = { 'uid': IUUID(obj), 'title': obj.Title(), 'url': obj.absolute_url(), 'portal_type': obj.portal_type, 'type_title': self.get_portal_type_title(obj), } return breaches
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_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_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_renaming_referenced_item(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 # This tests makes sure items that are linked to can still be # renamed (see the related bug report in #6608). First we need # to create the necessary links: self._set_text(doc1, '<a href="doc2">doc2</a>') self.assertEqual([i.from_object for i in getIncomingLinks(doc2)], [doc1]) # Make changes visible to testbrowseropen transaction.commit() # Then we use a browser to rename the referenced image: self.browser.handleErrors = True self.browser.open('{0:s}/object_rename?_authenticator={1:s}'.format( doc1.absolute_url(), self._get_token(doc1))) self.browser.getControl(name='form.widgets.new_id').value = 'nuname' self.browser.getControl(name='form.buttons.Rename').click() self.assertIn("Renamed 'doc1' to 'nuname'.", self.browser.contents) transaction.commit() self.assertNotIn('doc1', self.portal.objectIds()) self.assertIn('nuname', self.portal.objectIds()) self.assertIn(doc1, [i.from_object for i in getIncomingLinks(doc2)]) # We simply use a browser to try to delete a content item. self.browser.open(doc2.absolute_url()) self.browser.getLink('Delete').click() self.assertIn('Do you really want to delete this item?', self.browser.contents) self.assertIn('nuname', self.portal.objectIds()) # Link breakabe page should be shown self.assertIn('Potential link breakage', self.browser.contents) self.assertIn('<a href="http://nohost/plone/nuname">Test Page 1</a>', self.browser.contents) self.browser.getControl(name='form.buttons.Delete').click() self.assertNotIn('doc2', self.portal.objectIds())
def test_renaming_referenced_item(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 # This tests makes sure items that are linked to can still be # renamed (see the related bug report in #6608). First we need # to create the necessary links: self._set_text(doc1, '<a href="doc2">doc2</a>') self.assertEqual( [i.from_object for i in getIncomingLinks(doc2)], [doc1]) # Make changes visible to testbrowseropen transaction.commit() # Then we use a browser to rename the referenced image: self.browser.handleErrors = True self.browser.open('{0:s}/object_rename?_authenticator={1:s}'.format( doc1.absolute_url(), self._get_token(doc1))) self.browser.getControl(name='form.widgets.new_id').value = 'nuname' self.browser.getControl(name='form.buttons.Rename').click() self.assertIn("Renamed 'doc1' to 'nuname'.", self.browser.contents) transaction.commit() self.assertNotIn('doc1', self.portal.objectIds()) self.assertIn('nuname', self.portal.objectIds()) self.assertIn(doc1, [i.from_object for i in getIncomingLinks(doc2)]) # We simply use a browser to try to delete a content item. self.browser.open(doc2.absolute_url()) self.browser.getLink('Delete').click() self.assertIn( 'Do you really want to delete this item?', self.browser.contents) self.assertIn('nuname', self.portal.objectIds()) # Link breakabe page should be shown self.assertIn('Potential link breakage', self.browser.contents) self.assertIn('<a href="http://nohost/plone/nuname">Test Page 1</a>', self.browser.contents) self.browser.getControl(name='form.buttons.Delete').click() self.assertNotIn('doc2', self.portal.objectIds())
def checkSnippetReferences(obj): """ Checks if this content is a snippet on any other content. If it is, make sure the header setting is not ruined """ registry = getUtility(IRegistry) evaluator = ExpressionEvaluator() expression = Expression( registry.get('uwosh.snippets.render_expression', 'context/text/output|context/getText|nothing')) obj_headers = [] html = evaluator.evaluate(expression, obj) if not html: return dom = fromstring(html) for el in dom.cssselect('h1,h2,h3,h4,h5,h6'): if el.text_content(): obj_headers.append(el.text_content().strip()) broken = [] for link in getIncomingLinks(obj): if not link.from_object: continue for text in findTextAreas(link.from_object): if not text or not link.from_object: continue dom = fromstring(text) for el in dom.cssselect('[data-snippet-id="{}"]'.format( IUUID(obj))): header = el.attrib.get('data-header') if not header: continue if header not in obj_headers: # broken reference broken.append({'header': header, 'link': link.from_object}) if len(broken) > 0: # show status message warning names = set() for b in broken: names.add('{}:{}'.format(b['link'].absolute_url(), b['header'])) message = 'Broken snippet references: {}'.format(', '.join(names)) api.portal.show_message(message=message, request=getRequest(), type='error')
def checkSnippetReferences(obj): """ Checks if this content is a snippet on any other content. If it is, make sure the header setting is not ruined """ registry = getUtility(IRegistry) evaluator = ExpressionEvaluator() expression = Expression(registry.get('uwosh.snippets.render_expression', 'context/text/output|context/getText|nothing')) obj_headers = [] html = evaluator.evaluate(expression, obj) if not html: return dom = fromstring(html) for el in dom.cssselect('h1,h2,h3,h4,h5,h6'): if el.text_content(): obj_headers.append(el.text_content().strip()) broken = [] for link in getIncomingLinks(obj): for text in findTextAreas(link.from_object): if not text: continue dom = fromstring(text) for el in dom.cssselect('[data-snippet-id="{}"]'.format(IUUID(obj))): header = el.attrib.get('data-header') if not header: continue if header not in obj_headers: # broken reference broken.append({ 'header': header, 'link': link.from_object }) if len(broken) > 0: # show status message warning names = set() for b in broken: names.add('{}:{}'.format(b['link'].absolute_url(), b['header'])) message = 'Broken snippet references: {}'.format( ', '.join(names) ) api.portal.show_message(message=message, request=getRequest(), type='error')
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_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)))
def get_qch_warnings(self, items=None): if items is None: items = [self.context] qch_warnings = [] catalog = getToolByName(self.context, 'portal_catalog') for to_del_object in items: temp = to_del_object.getPhysicalPath() obj_path = '/'.join(to_del_object.getPhysicalPath())+'/' subobjects = catalog.searchResults(path={'query': obj_path}) for subobject in subobjects: links = getIncomingLinks(subobject.getObject()) link_list = [] for link in links: #link_list.append(link.from_object.absolute_url()) add_to_list = True for to_del in items: to_del_path = to_del.absolute_url()+'/' #'/'.join(to_del.getPhysicalPath())+'/' if to_del_path in link.from_object.absolute_url()+'/': add_to_list = False if add_to_list: link_list.append(link.from_object.absolute_url()) if len(link_list) > 0: qch_warnings.append({'subobject': subobject.getURL(), 'subobjectPath': str(subobject.getPath()), 'links': link_list}) return qch_warnings