Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

message.py 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from Products.statusmessages.interfaces import IMessage
  4. from zope.interface import implementer
  5. import six
  6. import struct
  7. def _utf8(value):
  8. if isinstance(value, six.text_type):
  9. return value.encode('utf-8')
  10. elif isinstance(value, six.binary_type):
  11. return value
  12. return b''
  13. def _unicode(value):
  14. return six.text_type(value, 'utf-8', 'ignore')
  15. @implementer(IMessage)
  16. class Message(object):
  17. """A single status message.
  18. Let's make sure that this implementation actually fulfills the
  19. 'IMessage' API.
  20. >>> from zope.interface.verify import verifyClass
  21. >>> verifyClass(IMessage, Message)
  22. True
  23. >>> status = Message(u'this is a test', type=u'info')
  24. >>> status.message == 'this is a test'
  25. True
  26. >>> status.type == 'info'
  27. True
  28. It is quite common to use MessageID's as status messages:
  29. >>> from zope.i18nmessageid import MessageFactory
  30. >>> from zope.i18nmessageid import Message as I18NMessage
  31. >>> msg_factory = MessageFactory('test')
  32. >>> msg = msg_factory(u'test_message', default=u'Default text')
  33. >>> status = Message(msg, type=u'warn')
  34. >>> status.type == 'warn'
  35. True
  36. >>> type(status.message) is I18NMessage
  37. True
  38. >>> status.message.default == 'Default text'
  39. True
  40. >>> status.message.domain == u'test'
  41. True
  42. """
  43. def __init__(self, message, type=''):
  44. self.message = message
  45. self.type = type
  46. def __eq__(self, other):
  47. if not isinstance(other, Message):
  48. return False
  49. if self.message == other.message and self.type == other.type:
  50. return True
  51. return False
  52. def encode(self):
  53. """
  54. Encode to a cookie friendly format.
  55. The format consists of a two bytes length header of 11 bits for the
  56. message length and 5 bits for the type length followed by two values.
  57. """
  58. if six.PY3:
  59. fmt_tpl = '!H{0}s{1}s'
  60. else:
  61. fmt_tpl = b'!H{0}s{1}s'
  62. message = _utf8(self.message)[:0x3FF] # we can store 2^11 bytes
  63. type_ = _utf8(self.type)[:0x1F] # we can store 2^5 bytes
  64. size = (len(message) << 5) + (len(type_) & 31) # pack into 16 bits
  65. fmt = fmt_tpl.format(len(message), len(type_))
  66. return struct.pack(fmt, size, message, type_)
  67. def decode(value):
  68. """
  69. Decode messages from a cookie
  70. We return the decoded message object, and the remainder of the cookie
  71. value as bytes (it can contain further messages).
  72. We expect at least 2 bytes (size information).
  73. """
  74. if len(value) >= 2:
  75. size = struct.unpack(b'!H', value[:2])[0]
  76. msize, tsize = (size >> 5, size & 31)
  77. message = Message(
  78. _unicode(value[2:msize + 2]),
  79. _unicode(value[msize + 2:msize + tsize + 2]),
  80. )
  81. return message, value[msize + tsize + 2:]
  82. return None, b''