Back to index

plone3  3.1.7
adapter.py
Go to the documentation of this file.
00001 import binascii
00002 import sys
00003 
00004 from zope.annotation.interfaces import IAnnotations
00005 from zope.i18n import translate
00006 from zope.interface import implements
00007 
00008 from Products.statusmessages import STATUSMESSAGEKEY
00009 from Products.statusmessages.message import decode
00010 from Products.statusmessages.message import Message
00011 from Products.statusmessages.interfaces import IStatusMessage
00012 
00013 import logging
00014 logger = logging.getLogger('statusmessages')
00015 
00016 class StatusMessage(object):
00017     """Adapter for the BrowserRequest to handle status messages.
00018     
00019     Let's make sure that this implementation actually fulfills the
00020     'IStatusMessage' API.
00021 
00022       >>> from zope.interface.verify import verifyClass
00023       >>> verifyClass(IStatusMessage, StatusMessage)
00024       True
00025     """
00026     implements(IStatusMessage)
00027 
00028     def __init__(self, context):
00029         self.context = context # the context must be the request
00030 
00031     def addStatusMessage(self, text, type=''):
00032         """Add a status message.
00033         """
00034         text = translate(text, context=self.context)
00035         annotations = IAnnotations(self.context)
00036 
00037         old = annotations.get(STATUSMESSAGEKEY, self.context.cookies.get(STATUSMESSAGEKEY))
00038         value = _encodeCookieValue(text, type, old=old)
00039         self.context.RESPONSE.setCookie(STATUSMESSAGEKEY, value, path='/')
00040         annotations[STATUSMESSAGEKEY] = value
00041 
00042     def showStatusMessages(self):
00043         """Removes all status messages and returns them for display.
00044         """
00045         annotations = IAnnotations(self.context)
00046         value = annotations.get(STATUSMESSAGEKEY, self.context.cookies.get(STATUSMESSAGEKEY))
00047         if value is None:
00048             return []
00049         value = _decodeCookieValue(value)
00050         # clear the existing cookie entries
00051         self.context.cookies[STATUSMESSAGEKEY] = None
00052         self.context.RESPONSE.expireCookie(STATUSMESSAGEKEY, path='/')
00053         annotations[STATUSMESSAGEKEY] = None
00054         return value
00055 
00056 
00057 def _encodeCookieValue(text, type, old=None):
00058     """Encodes text and type to a list of Messages. If there is already some old
00059        existing list, add the new Message at the end but don't add duplicate
00060        messages.
00061     """
00062     results = []
00063     message = Message(text, type=type)
00064 
00065     if old is not None:
00066         results = _decodeCookieValue(old)
00067     if not message in results:
00068         results.append(message)
00069 
00070     messages = ''.join([r.encode() for r in results])
00071     return binascii.b2a_base64(messages).rstrip()
00072 
00073 def _decodeCookieValue(string):
00074     """Decode a cookie value to a list of Messages.
00075     """
00076     results = []
00077     # Return nothing if the cookie is marked as deleted
00078     if string == 'deleted':
00079         return results
00080     # Try to decode the cookie value
00081     try:
00082         value = binascii.a2b_base64(string)
00083         while len(value) > 1: # at least 2 bytes of data
00084             message, value = decode(value)
00085             if message is not None:
00086                 results.append(message)
00087     except (binascii.Error, UnicodeEncodeError):
00088         logger.log(logging.ERROR, '%s \n%s',
00089                    'Unexpected value in statusmessages cookie',
00090                    sys.exc_value
00091                    )
00092         return []
00093 
00094     return results