joeforker
joeforker

Reputation: 41787

In Plone, how do I fix Archetypes content that is missing the cmf_uid() annotation?

I'm using Plone 4.3 with relstorage and I've somehow managed to lose the cmf_uid annotation on some of my content objects. This prevents collective.iterate from being able to check in content. Is there an easy way to have Plone walk through the database and re-add cmf_uid where it is missing? Already tried collective.catalogcleanup to no avail.

Upvotes: 1

Views: 75

Answers (1)

joeforker
joeforker

Reputation: 41787

Here is a script that searches the portal (passed as context) for any Document that has a non-unique cmf_uid. Many of these documents actually have no cmf_uid but the indexed cmf_uid actually comes from the parent folder via Acquisition. Since the manifestation of the problem was that plone.app.iterate was unable to check in Document, the script adds a unique cmf_uid to just the Document types that appear to have non-unique cmf_uid but actually have no cmf_uid.

Although this adds cmf_uid to all Document, it would probably be sufficient to only add the attribute to documents currently being edited in checkouts.

"""
Add missing cmf_uid to Archetypes content.

cmf_uid is required to check in working copies of content.
"""

from Products.CMFUid.UniqueIdHandlerTool import UniqueIdError
from Acquisition import aq_inner
from collections import Counter

def add_missing_uids(context):
    """
    context: the portal
    """
    portal_uidhandler = context.portal_uidhandler
    portal_uidgenerator = context.portal_uidgenerator
    catalog = context.portal_catalog
    brains = catalog.unrestrictedSearchResults()
    freq = Counter(x.cmf_uid for x in brains)
    for brain in brains:
        # If it's only in use once then it's unique enough. Otherwise it's
        # probably inheriting its indexed cmf_uid via Acquisition.
        if freq[brain.cmf_uid] < 2 or brain.portal_type != 'Document':
            continue
        ob = aq_inner(brain.getObject())
        if not portal_uidhandler.queryUid(ob):
            print brain.Type, brain.portal_type, brain.getPath()
            for i in range(3):
                try:
                    portal_uidhandler.setUid(ob, portal_uidgenerator())
                    ob.reindexObject()
                    ob.reindexObject(idxs=['modified'])
                    break
                except UniqueIdError:
                    print "RETRY"
            else:
                print "FAIL"

Upvotes: 2

Related Questions