#111: New portal_status_message infrastructure
Don't add portal status messages anymore to the query string, but use cookies instead.
- Proposed by
- Hanno Schlichting
- Proposal type
- Architecture
- Assigned to release
- Repository branch
- plip108-five-translationservice
- State
- completed
Motivation
So far the status messages generated in form scripts have been added to query string via '?portal_status_message=foo'. While this leads to unfriendly URL's for bookmarking and unexpected behaviour on reloading a page, it is also not possible to i18n-ize these strings in a sane manner.
Additionally there a number of collector issues around this problem for a while now. (http://dev.plone.org/plone/ticket/4094, http://dev.plone.org/plone/ticket/4057, http://dev.plone.org/plone/ticket/2979, http://dev.plone.org/plone/ticket/2842, http://dev.plone.org/plone/ticket/1922).
In the progress of implementing PLIP108 it has become obvious that some kind of change is required, as MessageID objects have to be passed to the resulting Page Template. As MessageID's are complex objects, it would have been very hard to split these into simple parts which would have been passed to the Page Template via the query string, where there would have been needed to be reconstructed again for the actual translation.
As both proposals effect the same lines in all Python scripts implementing these on different branches would have meant: Welcome to merging hell ;) So I decided to integrate these changes into the already existent plip108 branch targetted at Plone 2.5.
Proposal
As the whole status message handling isn't very Plone specific and needs a general overhaul it seems to be reasonable to create a small Zope3-ish product for this.
Therefore the statusmessages product has been created in the collective which contains a small adapter. This adapter implements a simple interface for handling status messages.
The default implementation stores all status messages in a session cookie. For a detailed description see http://plone.org/products/statusmessages.
All code adding status messages have to be adopted to the new way and the global_statusmessage template has been altered to support the new way, while keeping backwards compatibility for a while.
Implementation
As part of the statusmessages product (http://plone.org/products/statusmessages) two classes has been definied. First a simple Message class:
class IMessage(Interface):
"""A single status message."""
message = Attribute('The text of this message. Usally a Message object.')
type = Attribute('The type of this message.')
This is used to support an additional type attribute for messages like 'info', 'warn' or 'error' which will be used as CSS classes in the global_statusmessage template to be able to differentiate messages style-wise.
And secondly IStatusMessage look like this:
class IStatusMessage(Interface):
"""An adapter for the BrowserRequest to handle status messages."""
def addStatusMessage(text, type=''):
"""Add a status message."""
def showStatusMessages():
"""Removes all status messages and returns them for display."""
The actual adapter implementation is pretty straightforward and is definied in configure.zcml:
<adapter
for="zope.publisher.interfaces.browser.IBrowserRequest"
provides=".interfaces.IStatusMessage"
factory=".adapter.StatusMessage"
/>
As we don't want to add an import statement for the IStatusMessage interface in every python script, two simple wrapper functions have been added to PloneTool:
security.declarePublic('addPortalMessage')
def addPortalMessage(self, message, type='info', request=None):
""" long explanation """
if request is None:
request = self.REQUEST
IStatusMessage(request).addStatusMessage(message, type=type)
security.declarePublic('showPortalMessages')
def showPortalMessages(self, request=None):
""" long explanation """
if request is None:
request = self.REQUEST
return IStatusMessage(request).showStatusMessages()
Now this lets you finally add status messages in any Python script via:
from Products.CMFPlone import PloneMessageFactory as _ context.plone_utils.addPortalMessage(_(u'Changes saved.'))
As a benefit this implementation doesn't suffer from the 'the last message wins' problem of the former implementation, as it is now possible to add as many messages as you like and show them all.
Participants
Leonard Norrgard
Hanno Schlichting