Thursday, October 16, 2008

How to change add permision of another product content

In a customer project I have had to use CalendarX. CalendarX uses "Add portal content" for content add permission. But they wanted that only "Manager" be able to add a calendar. I could have gone straightforward by overriding "getNotAddableTypes" script in portal_skins, but I chose to try to patch the product from mine (let's call it "my.product").

I first tried to import CalendarX and change the permission name with a simple monkey patch, but I immediately had to dig into zope initialization process: "my.product" is imported after Products.CalendarX, because "my.product" gets loaded by Products.Five initialisation, and Five is loaded after CalendarX.. so my patch arrives too late in the init process. What to do? try harder! I found I could reload the product after having patched the permission.

Honestly I don't know if it can raise issue, and I would prefer something that looks less "hacky", but...
So, here is the guilty code!
# this is my/product/__init__.py
import logging
LOG = logging.getLogger(__name__)

def initialize(context):
"""Initializer called when used as a Zope 2 product."""

from Products import CalendarX
cxf_perm = "%s: Add CalendarX content" % (PROJECT_NAME,)
setDefaultRoles(cxf_perm, ('Manager',))
CalendarX.DEFAULT_ADD_CONTENT_PERMISSION = cxf_perm
CalendarX.config.DEFAULT_ADD_CONTENT_PERMISSION = cxf_perm

# also patch this, else it will try to register the profile twice
# and the registry will complain
from Products.GenericSetup.registry import ProfileRegistry
dummy_registry = ProfileRegistry()
std_registry = CalendarX.profile_registry
CalendarX.profile_registry = dummy_registry

# FIXME: is there anything cleaner to get app?
app = context._ProductContext__app
from OFS import Application
Application.reinstall_product(app, 'CalendarX')
CalendarX.profile_registry = std_registry
LOG.info("patched CalendarX.DEFAULT_ADD_CONTENT_PERMISSION: use '%s'"
% cxf_perm)