Front Page

  1. Changing default plone site security settings
  2. Customizing viewlets
    1. Replacing the viewlet page-template
    2. Disabling/reordering viewlets
    3. Changing viewlet permissions
  3. zopectl/instance run/debug
  4. Creating new objects
  5. Actions
    1. Creating action menu subitems per xml config
    2. Disabling default actions
  6. Adding catalog entries via xml
  7. Registering a configuration profile
  8. Register a traversal class
  9. Set type specific portlets to always display by default
  10. Random tips still to check out

Changing default plone site security settings

To automatically customize the security settings of a plone site at site creation, add the following to setuphandlers.py

 from plone.app.controlpanel.security import SecurityControlPanelAdapter
 scpa = SecurityControlPanelAdapter(site)
 scpa.set_enable_self_reg(True)


Other settings are changed accordingly (See definition of that class)

Customizing viewlets

Replacing the viewlet page-template

Most viewlets are defined as classes which reference a PageTemplate file. To customize the template you need to customize the class. Here inheritance comes in handy:

 from plone.app.layout.viewlets import common as base
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile

 class PersonalBarViewlet(base.PersonalBarViewlet):
     index = ViewPageTemplateFile('personal_bar.pt')


I place this into viewlets/common.py in the theme package. The viewlet is the registered in viewlets/configure.zcml

 <browser:viewlet
     name="plone.personal_bar"
     manager="plone.app.layout.viewlets.interfaces.IPortalTop"
     class=".common.PersonalBarViewlet"
     layer="..browser.interfaces.IThemeSpecific"
     permission="zope2.View" />


The customized template file then is viewlets/personal_bar.pt.

Disabling/reordering viewlets

Viewlets can be disabled or reordered in profiles/default/viewlets.xml:

 <?xml version="1.0"?>
 <object>
   <hidden manager="plone.portaltop" skinname="Plone Default">
     <viewlet name="plone.path_bar"/>
   </hidden>
 </object


I could not get this to work for the document-content viewlets (those inside the document frame in /@@manage-viewlets. ATM, I just change the viewlet permissions so ordinary users don't see them anymore (See next section)

Changing viewlet permissions

First, look up the viewlet in eggs/plone.app.layout*/plone/app/layout/viewlets/configure.zcml and copy the section into your own configure.zcml. Then you can easily change the permisson setting

 <browser:viewlet
     name="plone.belowcontenttitle.documentbyline"
     manager="plone.app.layout.viewlets.interfaces.IBelowContentTitle"
     class="plone.app.layout.viewlets.content.DocumentBylineViewlet"
     layer="..browser.interfaces.IThemeSpecific"
     permission="zope2.ViewManagementScreens" />

zopectl/instance run/debug

To get a complete zope/plone environment within zopectl run or zopectl debug you need to call the following function

def setupenv(user, portal):
    global app

    import AccessControl.SecurityManagement
    AccessControl.SecurityManagement.newSecurityManager(
        None, app.acl_users.getUserById(user).__of__(app.acl_users))

    import Testing.makerequest
    app = Testing.makerequest.makerequest(app)

    import zope.app.component.hooks
    zope.app.component.hooks.setSite(portal)

Creating new objects

Use parent.invokeFactory(id=<id>, type_name='<portal type>'). Afterwards, all the fields can be set using the 'set' accessors (if they are portal types)

However, this sometimes is not enough:

 from zope import event
 from Products.Archetypes.event import ObjectInitializedEvent

 def makeObject(container, type_name, id, **kw):
     id = container.invokeFactory(id=id, type_name=type_name, **kw)
     ob = getattr(container,id)
     event.notify(ObjectInitializedEvent(ob))
     if hasattr(aq_base(ob), 'at_post_create_script'):
         ob.at_post_create_script()
     if hasattr(aq_base(ob), 'manage_afterPortalFactoryCreate'):
         ob.manage_afterPortalFactoryCreate()


The names of the portal type accessors are not defined in the interface but in the schema and need not have anything to do with the attribute names. And the additional keywoard arguments can again be different. I don't know exactly, where to find this information...

Actions

Creating action menu subitems per xml config

Here an example. The foloowing file needs to be placed into the profiles/default folder.

<?xml version="1.0"?>
<object name="portal_actions" meta_type="Plone Actions Tool"
        xmlns:i18n="http://xml.zope.org/namespaces/i18n">

  <object name="object_buttons" meta_type="CMF Action Category">

    <object name="[name of action, some id]" meta_type="CMF Action">
      <property name="title">[title in action drop-down menu]</property>
      <property name="description"></property>
      <property name="url_expr">[url to call for this action]</property>
      <property name="icon_expr"></property>
      <property name="available_expr">[exprssion called to check for action availability]</property>
      <property name="permissions"><element value="[permission name]"/></property>
      <property name="visible">True</property>
    </object>

  </object>

</object>

And here some example content:

 url == string:${plone_context_state/canonical_object_url}/someId
 check == python:object.portal_type == 'SomeType
 permission == Manage portal

plone_context_state/canoical_object_url is the url of the object we are at right now. The example url here will call the someId view on this object.

object is the object in question (like context or self in python code)

Disabling default actions

To disable default actions (e.g. 'login') first find the corresponding action in eggs/Plone-*.egg/Products/CMFPlone/profiles/default/actions.xml. You then need to copy the object to your own profiles/default/actions.xml like thus:

 <?xml version="1.0"?>
 <object name="portal_actions" meta_type="Plone Actions Tool"
    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
  <object name="user" meta_type="CMF Action Category">
   <object name="login" meta_type="CMF Action" i18n:domain="plone">
    <property name="visible">False</property>
   </object>
  </object>
 </object>

Adding catalog entries via xml

This is done in profiles/default/catalog.xml

<?xml version="1.0"?>
<object name="portal_catalog" meta_type="Plone Catalog Tool">
    <index name="[index_name]" meta_type="FieldIndex">
        <indexed_attr value="[attribute to index]"/>
    </index>
    <column value="[name of metadata column]"/>
</object>

Registering a configuration profile

Most of the ZMI stuff is configured using a configuration profile. To add this to a project, include the following in the main zcml file:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
    i18n_domain="freitag.website">

  <genericsetup:registerProfile
      name="default"
      title="[profile title]"
      directory="profiles/default"
      description='[profile description]'
      provides="Products.GenericSetup.interfaces.EXTENSION" />

</configure>

Register a traversal class

To register a traversal, place the following in configure.zcml

<adapter
    for="Products.CMFPlone.interfaces.IPloneSiteRoot
         zope.publisher.interfaces.http.IHTTPRequest"
    provides="zope.publisher.interfaces.IPublishTraverse"
    factory="[dotted path to traverser class]" />

This will call the class when traversing the plone site root object. The class should look like this:

from Products.CMFPlone.interfaces import IPloneSiteRoot
from zope.publisher.interfaces.http import IHTTPRequest
from ZPublisher.BaseRequest import DefaultPublishTraverse

class MyTraverser(DefaultPublishTraverse):
    adapts(IPloneSiteRoot, IHTTPRequest)

    def publishTraverse(self, request, name):
        # Do stuff. Return the object found at 'name'
        # The current context is at self.context
        # or revert to normal traversal
        return super(MyTraverser, self).publishTraverse(request, name)

Set type specific portlets to always display by default

This can be placed into the object initializaton function (afterAdd hook, initializeArchetype) or be done programmatically when adding objects

 from zope.component import getMultiAdapter, getUtility
 from plone.portlets.interfaces import IPortletManager
 from plone.portlets.interfaces import ILocalPortletAssignmentManager
 from plone.portlets.constants import CONTENT_TYPE_CATEGORY

 # See plone.app.portlets.browser.manage.ManageContextualPortlets.set_blacklist_status
 portletManager = getUtility(IPortletManager, name='plone.rightcolumn')
 assignable = getMultiAdapter((ob, portletManager), ILocalPortletAssignmentManager)
 assignable.setBlacklistStatus(CONTENT_TYPE_CATEGORY, False)

Random tips still to check out

 (10:00:10)  g0dil:  collective.indexing: verschiebt indexing operationen auf transaktionsgrenzen
 (10:00:10)  g0dil:  experimental.catalogqueryplan: Optimiert catalogzugriffe bei komplexeren anfragen deutlich
 (10:00:10)  g0dil:  experimental.contentcreation: muss ich noich gucken
 (10:00:10)  g0dil:  experimental.opaquespeedup: noch gucken
 (10:00:10)  g0dil:  archetypes.schematuing: Cache archetype schemata per request

Zope Clockservice