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)
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
.
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)
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" />
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)
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...
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)
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>
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>
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>
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)
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)
(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