from base64 import encodestring, decodestring from pickle import dumps, loads import sys from zope.interface import implements from Products.statusmessages import STATUSMESSAGEKEY from Products.statusmessages.message import Message from Products.statusmessages.interfaces import IStatusMessage import logging logger = logging.getLogger('statusmessages') class StatusMessage(object): """Adapter for the BrowserRequest to handle status messages. Let's make sure that this implementation actually fulfills the 'IStatusMessage' API. >>> from zope.interface.verify import verifyClass >>> verifyClass(IStatusMessage, StatusMessage) True """ implements(IStatusMessage) def __init__(self, context): self.context = context # the context must be the request def addStatusMessage(self, text, type=''): """Add a status message. """ value = _encodeCookieValue(text, type, old=self.context.cookies.get(STATUSMESSAGEKEY)) self.context.cookies[STATUSMESSAGEKEY] = value self.context.RESPONSE.setCookie(STATUSMESSAGEKEY, value, path='/') def showStatusMessages(self): """Removes all status messages and returns them for display. """ value = self.context.cookies.get(STATUSMESSAGEKEY) if value is None: return [] value = _decodeCookieValue(value) # clear the existing cookie entries self.context.cookies[STATUSMESSAGEKEY] = None self.context.RESPONSE.expireCookie(STATUSMESSAGEKEY, path='/') return value def _encodeCookieValue(text, type, old=None): """Encodes text and type to a list of Messages. If there is already some old existing list, add the new Message at the end. """ results = [] message = Message(text, type=type) if old is not None: results = _decodeCookieValue(old) results.append(message) # we have to remove any newlines or the cookie value will be invalid return encodestring(dumps(results)).replace('\n','') def _decodeCookieValue(string): """Decode a cookie value to a list of Messages. The value has to be a base64 encoded pickle of a list of Messages. If it contains anything else, it will be ignored for security reasons. """ results = [] # Return nothing if the cookie is marked as deleted if string == 'deleted': return results # Try to decode the cookie value try: values = loads(decodestring(string)) except: # If there's anything unexpected in the string ignore it logger.log(logging.ERROR, '%s \n%s', 'Unexpected value in statusmessages cookie', sys.exc_value ) return [] if type(values) is list: # simple security check for value in values: if isinstance(value, Message): # and another simple check results.append(value) return results