def modifiedCoverTile(obj, event): """Ensure link integrity on Rich Text tiles. Keyword arguments: obj -- Dexterity-based object that was modified event -- event fired """ pu = api.portal.get_tool('portal_url') if pu is None: # `getObjectFromLinks` is not possible without access # to `portal_url` return rc = api.portal.get_tool('reference_catalog') if rc is None: # `updateReferences` is not possible without access # to `reference_catalog` return referenceable_parent = IReferenceable(obj.context, None) if referenceable_parent is None: # `updateReferences` is not possible # if parent object isn't referenceable return refs = set() for name, value in obj.data.items(): if isinstance(value, RichTextValue): value = value.raw if not value: continue links = extractLinks(value) refs |= getObjectsFromLinks(obj.context, links) updateReferences(IReferenceable(obj.context), referencedRelationship, refs)
def getObjectsFromLinks(base, links): """ determine actual objects refered to by given links """ objects = set() url = base.absolute_url() scheme, host, path, query, frag = urlsplit(url) for link in links: s, h, path, q, f = urlsplit(link) # relative or local url if (not s and not h) or (s == scheme and h == host): # Paths should always be strings if isinstance(path, unicode): path = path.encode('utf-8') obj, extra = findObject(base, path) if obj: if IOFSImage.providedBy(obj): # use atimage object for scaled images obj = aq_parent(obj) if not IReferenceable.providedBy(obj): try: obj = IReferenceable(obj) except: continue objects.add(obj) return objects
def test_circular_reference_subfolder_deletion(self): doc1 = self.portal.doc1 doc2 = self.portal.doc2 doc4 = self.portal.folder1.doc4 # This tests the behaviour when removing three object # referencing each other in a circle. This situation cannot be # resolved completely, since the removal events are fired # separately. However, the circle gets "broken up" when # confirming the removal of the first object, and no further # confirmation form are necessary: self._set_text(doc1, '<a href="doc2">documents...</a>') self._set_text(doc2, '<a href="folder1/doc4">linking...</a>') self._set_text(doc4, '<a href="../doc1">in circles.</a>') self.assertEqual(IReferenceable(doc1).getReferences(), [doc2, ]) self.assertEqual(IReferenceable(doc2).getReferences(), [doc4, ]) self.assertEqual(IReferenceable(doc4).getReferences(), [doc1, ]) self.assertRaises(exceptions.LinkIntegrityNotificationException, self.portal.manage_delObjects, ['doc1', 'doc2', ], self.request) transaction.abort() self.portal.manage_delObjects( ['doc1', 'doc2', 'folder1', ], self.request) self.assertNotIn('doc1', self.portal) self.assertNotIn('doc2', self.portal) self.assertNotIn('folder1', self.portal)
def moved_handler(obj, event): """Remove object from uid_catalog and add it back""" # Not sure if this is the proper way to handle it. # it is needed because of what happens in Products.ZCatalog.Catalog.py # line 317. # When path has changed, the object cannot be found, and we end up with # old and invalid uids. uid_catalog, ref_catalog = _get_catalogs(obj) uid = IUUID(obj.aq_base, None) if uid: results = uid_catalog(UID=uid) if len(results) > 0: old_obj = results[0] uid_catalog.uncatalog_object(old_obj.getPath()) path = '/'.join(obj.getPhysicalPath()) uid_catalog.catalog_object(obj, path) # AT API annotations = IATReferenceable(obj)._getReferenceAnnotations() if not annotations: return for ref in annotations.objectValues(): url = getRelURL(ref_catalog, ref.getPhysicalPath()) if event.oldName and event.newName: url = event.oldName + url[len(event.newName):] uid_catalog_rid = uid_catalog.getrid(url) ref_catalog_rid = ref_catalog.getrid(url) if uid_catalog_rid is not None: uid_catalog.uncatalog_object(url) if ref_catalog_rid is not None: ref_catalog.uncatalog_object(url)
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(IReferenceable(doc1).getReferences(), [img1]) self.assertEqual(IReferenceable(img1).getBackReferences(), [doc1])
def working_copy(self): adapted = IReferenceable(self.context, None) if adapted is None: return None refs = adapted.getBRefs(WorkingCopyRelation.relationship) if len(refs) > 0: return refs[0] else: return None
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(IReferenceable(doc1).getReferences(), [img1]) self.assertEqual(IReferenceable(img1).getBackReferences(), [doc1])
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(IReferenceable(doc1).getReferences(), [img1]) self.assertEqual(IReferenceable(doc1).getBackReferences(), []) self.assertEqual(IReferenceable(img1).getReferences(), []) self.assertEqual(IReferenceable(img1).getBackReferences(), [doc1])
def get_references(self): """ AT references """ try: from Products.Archetypes.interfaces import IReferenceable if not IReferenceable.providedBy(self.context): return except: return self['_atrefs'] = {} self['_atbrefs'] = {} relationships = self.context.getRelationships() for rel in relationships: self['_atrefs'][rel] = [] refs = self.context.getRefs(relationship=rel) for ref in refs: if ref is not None: self['_atrefs'][rel].append('/'.join( ref.getPhysicalPath())) brelationships = self.context.getBRelationships() for brel in brelationships: self['_atbrefs'][brel] = [] brefs = self.context.getBRefs(relationship=brel) for bref in brefs: if bref is not None: self['_atbrefs'][brel].append('/'.join( bref.getPhysicalPath()))
def update_links(event): obj = event.object if is_outdated(obj) or not is_publically_visible(obj): return temporary = hasattr(obj, 'meta_type') and \ obj.meta_type == TempFolder.meta_type if temporary: # Objects that are temporary (read: portal_factory) and do not have a # (stable) URL (yet) do not need to be crawled: relative links will be # off quickly and we can't really use the UID anyway. return try: link_checker = getToolByName(obj, 'portal_linkchecker').aq_inner except AttributeError: return if not link_checker.active: return retriever = IRetriever(obj, None) if retriever is not None: sm = getSecurityManager() if not sm.checkPermission(ModifyPortalContent, obj): return if (not IReferenceable.providedBy(obj)): return async = getUtility(IAsyncService) tpath = '/'.join(obj.getPhysicalPath()) job = async .queueJob(retrieve_async, obj, tpath, online=True) callback = job.addCallbacks(failure=job_failure_callback) callback # for pep
def _notifyOfCopyTo(self, container, op=0): """In the case of a move (op=1) we need to make sure references are mainained for all referencable objects within the one being moved. manage_renameObject calls _notifyOfCopyTo so that the object being renamed doesn't lose its references. But manage_renameObject calls _delObject which calls manage_beforeDelete on all the children of the object being renamed which deletes all references for children of the object being renamed. Here is a patch that does recursive calls for _notifyOfCopyTo to address that problem. """ # XXX this doesn't appear to be necessary anymore, if it is # it needs to be used in BaseBTreeFolder as well, it currently # is not. BaseObject._notifyOfCopyTo(self, container, op=op) # keep reference info internally when op == 1 (move) # because in those cases we need to keep refs if op==1: self._v_cp_refs = 1 for child in self.contentValues(): if IReferenceable.providedBy(child): child._notifyOfCopyTo(self, op)
def _notifyOfCopyTo(self, container, op=0): """In the case of a move (op=1) we need to make sure references are mainained for all referencable objects within the one being moved. manage_renameObject calls _notifyOfCopyTo so that the object being renamed doesn't lose its references. But manage_renameObject calls _delObject which calls manage_beforeDelete on all the children of the object being renamed which deletes all references for children of the object being renamed. Here is a patch that does recursive calls for _notifyOfCopyTo to address that problem. """ # XXX this doesn't appear to be necessary anymore, if it is # it needs to be used in BaseBTreeFolder as well, it currently # is not. BaseObject._notifyOfCopyTo(self, container, op=op) # keep reference info internally when op == 1 (move) # because in those cases we need to keep refs if op == 1: self._v_cp_refs = 1 for child in self.contentValues(): if IReferenceable.providedBy(child): child._notifyOfCopyTo(self, op)
def transmogrify(self, item): path = self.get_path(item) obj = self.get_object(item) uid = item.get(self.uidkey, "") if not uid: raise NothingToDoHere at_uid = ATIReferenceable.providedBy(obj) dx_uid = DXIReferenceable.providedBy(obj) old_uid = obj.UID() if old_uid != uid: # Code from plone.app.transmogrifier used for AT objects: if at_uid: if not old_uid: setattr(obj, AT_UUID_ATTR, uid) else: obj._setUID(uid) elif dx_uid: setattr(obj, DX_UID_ATTR, uid) else: #Don't ask, JUST DO IT! # If the attribute is not used as UID, it # is not used as anything else as well, # and at least the desired UID value stays recorded in the # object, allowing for a post-migration retrieval setattr(obj, DEFAULT_UID_ATTR, uid) return item
def modified_handler(obj, event): """Reindex object in uid_catalog""" uid_catalog, ref_catalog = _get_catalogs(obj) path = '/'.join(obj.getPhysicalPath()) uid_catalog.catalog_object(obj, path) # AT API annotations = IATReferenceable(obj)._getReferenceAnnotations() if not annotations: return for ref in annotations.objectValues(): url = getRelURL(ref_catalog, ref.getPhysicalPath()) uid_catalog.catalog_object(ref, url) ref_catalog.catalog_object(ref, url) ref._catalogRefs(uid_catalog, uid_catalog, ref_catalog)
def test_removal_via_zmi(self): 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(IReferenceable(doc1).getReferences(), [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.assertIn('Potential link breakage', self.browser.contents) self.assertIn('<a href="http://nohost/plone/doc1">Test Page 1</a>', self.browser.contents) # After we have acknowledged the breach in link integrity the # document should have been deleted: self.browser.getControl(name='delete').click() self.assertNotIn('doc2', self.portal.objectIds())
def checkout_allowed(self): """Check if a checkout is allowed. """ context = aq_inner(self.context) checkPermission = getSecurityManager().checkPermission if not interfaces.IIterateAware.providedBy(context): return False if not IReferenceable.providedBy(context): return False archiver = interfaces.IObjectArchiver(context) if not archiver.isVersionable(): return False # check if there is an existing checkout if len(context.getBRefs(WorkingCopyRelation.relationship)) > 0: return False # check if it is a checkout or contains a checkout if recursivelyCheckForWorkingCopies(context): return False # check if it is contained by a checkout if recursivelyCheckParentsForWorkingCopies(context): return False # check the permission if not checkPermission(permissions.CheckoutPermission, context): return False return True
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(IReferenceable(doc1).getReferences(), [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}/object_delete?_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='delete').click() self.assertNotIn('some spaces.doc', self.portal.objectIds())
def __iter__(self): for item in self.previous: pathkey = self.pathkey(*item.keys())[0] uidkey = self.uidkey(*item.keys())[0] if not pathkey or not uidkey: # not enough info yield item continue path = item[pathkey] uid = item[uidkey] obj = traverse(self.context, str(path).lstrip('/'), None) if obj is None: # path doesn't exist yield item continue if IReferenceable.providedBy(obj): oldUID = obj.UID() if oldUID != uid: if not oldUID: setattr(obj, UUID_ATTR, uid) else: obj._setUID(uid) if IAttributeUUID.providedBy(obj): IMutableUUID(obj).set(uid) yield item
def modifiedDexterity(obj, event): """ a dexterity based object was modified """ pu = getToolByName(obj, 'portal_url', None) if pu is None: # `getObjectFromLinks` is not possible without access # to `portal_url` return rc = getToolByName(obj, 'reference_catalog', None) if rc is None: # `updateReferences` is not possible without access # to `reference_catalog` return fti = getUtility(IDexterityFTI, name=obj.portal_type) schema = fti.lookupSchema() additional_schema = getAdditionalSchemata(context=obj, portal_type=obj.portal_type) schemas = [i for i in additional_schema] + [schema] refs = set() for schema in schemas: for name, field in getFieldsInOrder(schema): if isinstance(field, RichText): # Only check for "RichText" ? value = getattr(schema(obj), name) if not value: continue links = extractLinks(value.raw) refs |= getObjectsFromLinks(obj, links) updateReferences(IReferenceable(obj), referencedRelationship, refs)
def update_links(event): obj = event.object if is_outdated(obj) or not is_publically_visible(obj): return temporary = hasattr(obj, 'meta_type') and \ obj.meta_type == TempFolder.meta_type if temporary: # Objects that are temporary (read: portal_factory) and do not have a # (stable) URL (yet) do not need to be crawled: relative links will be # off quickly and we can't really use the UID anyway. return try: link_checker = getToolByName(obj, 'portal_linkchecker').aq_inner except AttributeError: return if not link_checker.active: return retriever = IRetriever(obj, None) if retriever is not None: sm = getSecurityManager() if not sm.checkPermission(ModifyPortalContent, obj): return if (not IReferenceable.providedBy(obj)): return async = getUtility(IAsyncService) tpath = '/'.join(obj.getPhysicalPath()) job = async.queueJob(retrieve_async, obj, tpath, online=True) callback = job.addCallbacks(failure=job_failure_callback) callback # for pep
def get_references(self): """ AT references """ try: from Products.Archetypes.interfaces import IReferenceable if not IReferenceable.providedBy(self.context): return except: return self['_atrefs'] = {} self['_atbrefs'] = {} relationships = self.context.getRelationships() for rel in relationships: self['_atrefs'][rel] = [] refs = self.context.getRefs(relationship=rel) for ref in refs: if ref is not None: self['_atrefs'][rel].append('/'.join(ref.getPhysicalPath())) brelationships = self.context.getBRelationships() for brel in brelationships: self['_atbrefs'][brel] = [] brefs = self.context.getBRefs(relationship=brel) for bref in brefs: if bref is not None: self['_atbrefs'][brel].append('/'.join(bref.getPhysicalPath()))
def beforeChange_at_uuid(self): """Load AT universal uid.""" self._checkLoadAttr('UID') if IReferenceable.providedBy(self.old): self.UID = self.old.UID() self.old._uncatalogUID(self.parent) else: self.UID = None
def test_rename_updates_ref_catalog(self): doc1 = self.portal['doc1'] doc2 = self.portal['doc2'] ref_catalog = self.portal.reference_catalog doc1.text = RichTextValue('<a href="doc2">doc2</a>') modified(doc1) self.assertEquals(1, len(ref_catalog())) self.assertEquals([doc2], IReferenceable(doc1).getReferences()) ref_brain = ref_catalog()[0] self.assertTrue(ref_brain.getPath().startswith('doc1')) self.portal.manage_renameObject(id='doc1', new_id='new_name') modified(doc1) self.assertEquals(1, len(ref_catalog())) ref_brain = ref_catalog()[0] self.assertTrue(ref_brain.getPath().startswith('new_name')) self.assertEquals([doc2], IReferenceable(doc1).getReferences())
def migrate_at_uuid(self): """Migrate AT universal uid """ if not IReferenceable.providedBy(self.old): return # old object doesn't support AT uuids uid = self.old.UID() self.old._uncatalogUID(self.parent) self.new._setUID(uid)
def test_unicode_links(self): doc1 = self.portal.doc1 # This tests checks that isLinked 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(IReferenceable(doc1).getReferences(), [])
def getuid(self): if HAS_PLONE_UUID: uid = IUUID(self.context, None) if uid is not None: return uid if HAS_AT: if IReferenceable.providedBy(self.context): return self.context.UID() return None
def getSourceId(self, name, filename, instance, fresh=False): sid = '' if IReferenceable.providedBy(instance): sid = sid + instance.UID() sid = "%s_%s" % (sid, self.make_prefix()) sid = "%s_%s" % (sid, name) fname = self.getNormalizedName(filename) if fname: sid = '%s_%s' % (sid, fname) return sid
def prepareIterateObjectTabs(self, *args, **kwargs): tabs = self.prepareObjectTabs(*args, **kwargs) if IReferenceable.providedBy(self.context): iterate_control = plone.app.iterate.browser.control.Control(self.context, self.request) if tabs and iterate_control.checkout_allowed(): for tab in [e for e in tabs if e['id'] == 'edit']: tab['url'] = self.context.absolute_url() + '/@@content-checkout' return tabs
def test_upgrade(self): doc3 = self.portal['doc3'] doc1 = self.portal['doc1'] self.assertTrue(IReferenceable.providedBy(doc3)) doc3.setText('<a href="doc1">doc1</a>', mimetype='text/html') doc3.addReference(doc1, relationship=referencedRelationship) self.assertFalse(hasIncomingLinks(doc1)) self.assertFalse(hasIncomingLinks(doc3)) migrate_linkintegrity_relations(self.portal) self.assertTrue(hasIncomingLinks(doc1)) self.assertFalse(hasIncomingLinks(doc3))
def migrate_at_uuid(self): """Migrate AT universal uid """ if not IReferenceable.providedBy(self.old): return # old object doesn't support AT uuids uid = self.old.UID() self.old._uncatalogUID(self.parent) if queryAdapter(self.new, IMutableUUID): IMutableUUID(self.new).set(str(uid)) else: self.new._setUID(uid)
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>') IReferenceable(doc1).deleteReferences(relationship='isReferencing') IReferenceable(doc2).deleteReferences(relationship='isReferencing') # Just to make sure, we check that there are no references from or to # these documents at this point: self.assertEqual(IReferenceable(doc1).getReferences(), []) self.assertEqual(IReferenceable(doc2).getReferences(), []) # 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(IReferenceable(doc1).getReferences(), [ doc2, ]) self.assertEqual(IReferenceable(doc2).getReferences(), [ doc4, ])
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(IReferenceable(doc2).getBackReferences(), [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.assertEqual(IReferenceable(doc2).getBackReferences(), [doc1]) # 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.browser.getControl(name='form.buttons.Delete').click() 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)
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(IReferenceable(doc1).getReferences()), 0) self._set_text(doc1, '<a href="doc1a">Doc 1a</a>') self.assertEqual(len(IReferenceable(doc1).getReferences()), 1) self.assertEqual(IReferenceable(doc1).getReferences()[0].id, self.portal.doc1a.id) # Now delete the target item, suppress events and test again, # the reference should be broken now. self.portal._delObject(doc1a.id, suppress_events=True) self.assertEqual(IReferenceable(doc1).getReferences(), [None]) # If we now try to update the linking document again in order to # remove the link, things used to break raising a # ``ReferenceException``. This should be handled more # gracefully now: self._set_text(doc1, 'foo!') self.assertEqual(IReferenceable(doc1).getReferences(), [])
def migrate_at_uuid(self): """Migrate AT universal uid """ if not IReferenceable.providedBy(self.old): return # old object doesn't support AT uuids uid = self.old.UID() self.old._uncatalogUID(self.parent) if UUID_ATTR: # Prevent object deletion triggering UID related magic setattr(self.old, UUID_ATTR, None) if queryAdapter(self.new, IMutableUUID): IMutableUUID(self.new).set(str(uid)) else: self.new._setUID(uid)
def __call__(self, skipRedirect=False, **args): context = self.context request = context.REQUEST if IReferenceable.providedBy(context): plone_utils = getToolByName(context, 'plone_utils') uid = request.get('uid', '') remoteUrl = request.get('remoteUrl', '') if not remoteUrl: message = u'No URL was given, nothing has been added.' else: util = getUtility(ISearchUrlSettings) urlTuples = util.urls existing = list() existing_idx = list() pc = context.portal_catalog for item in urlTuples: if item.url == remoteUrl: res = pc(UID=item.provider) title = len(res) and res[0].Title or 'None' url = len(res) and res[0].getURL() or '' existing.append("existing:list=%s|%s" % (title, url)) existing_idx.append(urlTuples.index(item)) if len(existing): if not request.get('override', False): message = u"The URL is already registered" path = context.absolute_url() + "/%s?%s" % ( request.get('template_id', ''), '&'.join(existing) ) plone_utils.addPortalMessage(message) skipRedirect = True self.request.RESPONSE.redirect(path) return else: existing_idx.reverse() for idx in existing_idx: del urlTuples[idx] urlTuples.append(SearchUrlTuple(remoteUrl, uid)) util.urls = urlTuples message = (u'"%s" has been added to search urls' % unicode(context.title_or_id(), 'utf-8')) else: message = (u'"%s" could not be added to the search, because ist' 'is not referenceable' % unicode(context.title_or_id(), 'utf-8')) if not skipRedirect: path = context.absolute_url() plone_utils.addPortalMessage(message) self.request.RESPONSE.redirect(path)
def test_remove_cleans_ref_catalog(self): doc1 = self.portal['doc1'] doc2 = self.portal['doc2'] doc1_refs = IReferenceable(doc1) doc2_refs = IReferenceable(doc2) doc1_refs.addReference(doc2_refs, relationship='fooRelationship') ref_catalog = self.portal.reference_catalog self.assertEquals(1, len(ref_catalog())) self.assertEquals([doc1], doc2_refs.getBackReferences()) self.portal.manage_delObjects(['doc1']) self.assertEquals(0, len(ref_catalog())) self.assertEquals([], doc2_refs.getBackReferences())
def apply_referenceable_behavior(context): # See plone.app.referenceablebehavior.uidcatalog. uid_catalog = getToolByName(context, 'uid_catalog') portal_catalog = getToolByName(context, 'portal_catalog') brains = portal_catalog( meta_type=['Dexterity Item', 'Dexterity Container']) for brain in brains: obj = brain.getObject() if IReferenceable.providedBy(obj): path = '/'.join(obj.getPhysicalPath()) logger.info( """Applying referenceable behavior for object at path %s""", path) uid_catalog.catalog_object(obj, path)
def test_rename_updates_ref_catalog(self): doc1 = self.portal['doc1'] doc2 = self.portal['doc2'] doc1_refs = IReferenceable(doc1) doc2_refs = IReferenceable(doc2) doc1_refs.addReference(doc2_refs, relationship='fooRelationship') ref_catalog = self.portal.reference_catalog self.assertEquals(1, len(ref_catalog())) self.assertEquals([doc2], doc1_refs.getReferences()) ref_brain = ref_catalog()[0] self.assertTrue(ref_brain.getPath().startswith('doc1')) self.portal.manage_renameObject(id='doc1', new_id='new_name') doc1 = self.portal['new_name'] doc1_refs = IReferenceable(doc1) self.assertEquals(1, len(ref_catalog())) ref_brain = ref_catalog()[0] self.assertTrue(ref_brain.getPath().startswith('new_name')) self.assertEquals([doc2], doc1_refs.getReferences())
def test_file_reference_linkintegrity_page_is_shown(self): doc1 = self.portal.doc1 file2 = testing.create(self.portal, 'File', id='file2', file=testing.GIF) self._set_text(doc1, '<a href="file2">A File</a>') self.assertEqual(IReferenceable(doc1).getReferences(), [file2]) self.assertIn('file2', self.portal.objectIds()) token = self._get_token(file2) self.request['_authenticator'] = token # Make changes visible to test browser transaction.commit() self.browser.handleErrors = True self.browser.addHeader( 'Authorization', 'Basic {0:s}:{1:s}'.format(TEST_USER_NAME, TEST_USER_PASSWORD)) delete_url = '{0:s}/object_delete?_authenticator={1:s}'.format( file2.absolute_url(), token) # Try to remove but cancel self.browser.open(delete_url) # Validate text self.assertIn('Potential link breakage', self.browser.contents) self.assertIn('removeConfirmationAction', self.browser.contents) self.assertIn('<a href="http://nohost/plone/doc1">Test Page 1</a>', self.browser.contents) self.assertIn('Would you like to delete it anyway?', self.browser.contents) # Click cancel button, item should stay in place self.browser.getControl(name='cancel').click() self.assertEqual(self.browser.url, self.portal.absolute_url()) self.assertIn('Removal cancelled.', self.browser.contents) self.assertIn('file2', self.portal.objectIds()) # Try to remove and confirm self.browser.open(delete_url) self.browser.getControl(name='delete').click() self.assertNotIn('file2', self.portal.objectIds())
def links(self): if not IReferenceable.providedBy(self.context): return [] value = [] tasks = self.context.getBRefs('task_issues') tasks = sorted( tasks, lambda a, b: cmp(a.ModificationDate(), b.ModificationDate())) for task in tasks: value.append( dict(iterationid=task.getPhysicalPath()[-3], title=abbreviate(task.Title() or task.getId(), width=25), url=task.absolute_url(), state=self.workflow.getInfoFor(task, 'review_state'))) return value
def links(self): if not IReferenceable.providedBy(self.context): return [] value = [] tasks = self.context.getBRefs('task_issues') tasks = sorted(tasks, lambda a, b: cmp(a.ModificationDate(), b.ModificationDate())) for task in tasks: value.append( dict(iterationid=task.getPhysicalPath()[-3], title=abbreviate(task.Title() or task.getId(), width=25), url=task.absolute_url(), state=self.workflow.getInfoFor(task, 'review_state'))) return value
def getObjectsFromLinks(base, links): """ determine actual objects refered to by given links """ objects = set() url = base.absolute_url() scheme, host, path, query, frag = urlsplit(url) for link in links: try: s, h, path, q, f = urlsplit(link) except ValueError: continue if (not s and not h) or (s == scheme and h == host): # relative or local url obj, extra = findObject(base, path) if obj: if IOFSImage.providedBy(obj): obj = aq_parent(obj) # use atimage object for scaled images if not IReferenceable.providedBy(obj): try: obj = IReferenceable(obj) except: continue objects.add(obj) return objects
def manageLink(self, obj, normalled): # need IObject iface for catalog brains if hasattr(obj, 'getObject'): # brain, other sort of pseudo object obj = obj.getObject() if not IReferenceable.providedBy(obj): # backlink not possible return mark(obj, IWickedTarget) self.refcat.addReference(obj, self.context, relationship=self.relation, referenceClass=self.refKlass) objuid = IUID(obj) path = '/'.join(obj.getPhysicalPath()) data = dict(path=path, icon=obj.getIcon(), uid=objuid) self.cm.set((intern(str(normalled)), objuid), [data])
def checkout_allowed(self): """Check if a checkout is allowed. """ context = aq_inner(self.context) if not interfaces.IIterateAware.providedBy(context): return False if not IReferenceable.providedBy(context): return False archiver = interfaces.IObjectArchiver(context) if not archiver.isVersionable(): return False # check if there is an existing checkout if len(context.getBRefs(WorkingCopyRelation.relationship)) > 0: return False # check if its is a checkout if len(context.getRefs(WorkingCopyRelation.relationship)) > 0: return False return True
def LCRetrieveByDate(self, skiplist=[]): """Retrieves the links from all objects in the site by Date.""" sincedate = DateTime()-6*30 since = self.REQUEST.get('since') if since is not None: since = DateTime(since) sincedate = since or sincedate offline = self.REQUEST.get('offline', '') pwt = self.portal_workflow lc = self.portal_linkchecker async = getUtility(IAsyncService) sm = getSecurityManager() try: server = lc.database._getWebServiceConnection() except: server = None if server is None and offline!='1': raise RuntimeError, "The site could not be crawled because no " \ "connection to the lms could be established." # # Not actually necessary on every crawl, but it doesn't seem to work # # in the installer, so this seems the next logical place to do it. # self.portal_catalog.reindexIndex('portal_linkchecker_uid', self.REQUEST) if 1: # gather all objects that are of a type we can check for links objects = self.portal_catalog(Language='all', modified={'query':sincedate,'range':'min'}) os_ = len(objects) zLOG.LOG('CMFLinkChecker', zLOG.INFO, "%d objects will be crawled" % os_) i = 0 for res in objects: i += 1 zLOG.LOG("CMFLinkChecker", zLOG.BLATHER, "Site Crawl Status", "%s of %s (%s)" % (i, os_, res.getPath())) ob = res.getObject() if ob is None: # Maybe the catalog isn't up to date continue outdated = IAnnotatable.providedBy(ob) and \ IAnnotations(ob).get(ANNOTATION_KEY, False) or False if outdated: zLOG.LOG("CMFLinkChecker", zLOG.INFO, "unregistering %s, object is outdated" % res.getPath()) links = lc.database.getLinksForObject(ob) link_ids = [x.getId() for x in links] job = async.queueJob(unregister_async, lc, link_ids) callback = job.addCallbacks(failure=job_failure_callback) continue try: state = pwt.getInfoFor(ob, 'review_state') except: state = "undefined" if state not in ALLOWED_STATES: zLOG.LOG("CMFLinkChecker", zLOG.BLATHER, "unregistering, object is not public: %s" % state) links = lc.database.getLinksForObject(ob) link_ids = [x.getId() for x in links] job = async.queueJob(unregister_async, lc, link_ids) callback = job.addCallbacks(failure=job_failure_callback) continue if not sm.checkPermission(ModifyPortalContent, ob): continue if (not IReferenceable.providedBy(ob)): continue job = async.queueJob(retrieve_async, ob, res.getPath(), online=True) callback = job.addCallbacks(failure=job_failure_callback) if not i % 500 : transaction.savepoint() zLOG.LOG('CMFLinkChecker', zLOG.INFO, "Crawling site - commited after %d objects" %(i)) return "finished"
def getWorkingCopy(self): if IReferenceable.providedBy(self.context): refs = self.context.getBRefs(WorkingCopyRelation.relationship) if refs: return refs[0]
def get_original(self, context): if IReferenceable.providedBy(context): refs = context.getRefs(WorkingCopyRelation.relationship) if refs: return refs[0]
def retrieve(self): ST = [] pc = self.portal_catalog link_checker = self.portal_linkchecker async = getUtility(IAsyncService) sm = getSecurityManager() # INitialize the helperattribute to store paths to retrieve objpaths = getattr(link_checker, 'objpaths', None) cleanup = self.REQUEST.get('cleanup', False) if objpaths is None or cleanup=='1': link_checker.objpaths = [] objpaths = [] # Check wheter we start fresh or need to resume resume = self.REQUEST.get('resume') debug = self.REQUEST.get('debug') LOG("LCRetrieveByPath", INFO, "Resuming retrieval with %s paths" % len(objpaths)) if len(objpaths)==0 and not resume: path = self.REQUEST.get('path', '/'.join(self.getPhysicalPath())) alllangs = self.portal_languages.getSupportedLanguages() langs = self.REQUEST.get('langs', alllangs) print "path: %s" %path if "%s" in path: paths = [path%lang for lang in langs] else: paths = [path] LOG("LCRetrieveByPath", INFO, "Starting retrieval") for path in paths: LOG("LCRetrieveByPath", INFO, "> Path %s"%path) results = pc(Language='all', path=path) objpaths = [x.getPath() for x in results] link_checker.objpaths += objpaths LOG("LCRetrieveByPath", INFO, "> %s results found"%len(results)) # DONE Retrieving objpaths, start checkretrieval cnt = 0 objpaths = [x for x in link_checker.objpaths] total = len(objpaths) for path in objpaths: if debug: print path try: ob = self.unrestrictedTraverse(path) except: continue if not ob: continue if not sm.checkPermission(ModifyPortalContent, ob): continue if (not IReferenceable.providedBy(ob)): continue outdated = IAnnotatable.providedBy(ob) and \ IAnnotations(ob).get(ANNOTATION_KEY, False) or False if outdated: LOG("CMFLinkChecker", INFO, "unregistering %s, object is outdated" % path) links = link_checker.database.getLinksForObject(ob) link_ids = [x.getId() for x in links] job = async.queueJob(unregister_async, link_checker, link_ids) job.addCallbacks(failure=job_failure_callback) continue if not is_publically_visible(ob): LOG('CMFLinkChecker', INFO, "Skipping %s, obj is not public" % path) continue job = async.queueJob(retrieve_async, ob, path, online=True) job.addCallbacks(failure=job_failure_callback) LOG("LCRetrieveByPath", INFO, "> Retrieved %s"%path) ST.append("retrieved %s" % path) link_checker.objpaths.remove(path) link_checker._p_changed = 1 cnt += 1 if cnt%10==0: transaction.commit() LOG("LCRetrieveByPath", INFO, "Committing %s of %s" %(cnt, total)) LOG("LCRetrieveByPath", INFO, "Fertig") return "\n".join(ST)
def getRatingVariance(obj, portal, **kw): if not IReferenceable.providedBy(obj): return None rt = getToolByName(obj, 'portal_ratings') return rt.getRatingSumSquared(obj.UID())
def getHitCount(obj, portal, **kw): if not IReferenceable.providedBy(obj): return None rt = getToolByName(obj, 'portal_ratings') return rt.getHitCount(obj.UID())