Ticket #13376: messages_expirity_capabilities.2.diff

File messages_expirity_capabilities.2.diff, 35.8 KB (added by marekw2143, 13 years ago)
  • contrib/messages/restrictions.py

     
     1import time as time_provider
     2
     3
     4class Restriction (object):
     5    def __init__(self, name):
     6        self.type = name
     7
     8    def is_expired(self):
     9        ''' indicates whether given message should be removed '''
     10        raise NotImplementedError ()
     11
     12    def on_display (self):
     13        ''' called when iterated - does nothing by default '''
     14
     15
     16class TimeRestriction (Restriction):
     17    def __init__(self, seconds):
     18        """
     19        seconds - expiration time since now
     20        """
     21        Restriction.__init__(self, 'time')
     22        created = time_provider.time()
     23        self.expires = created + int(seconds)
     24
     25    def set_expirity_time(self, expiration_time):
     26        """
     27        Sets expilcity expiration time
     28        """
     29        self.expires = int(expiration_time)
     30
     31    def is_expired (self):
     32        return self.expires < time_provider.time()
     33
     34    def __eq__(self, other):
     35        return self.expires == other.expires
     36
     37
     38class AmountRestriction (Restriction):
     39    def __init__(self, amount):
     40        assert int(amount) >= 0
     41        Restriction.__init__(self, 'amount')
     42        self.can_be_shown = int(amount)
     43
     44    def on_display (self):
     45        self.can_be_shown -= 1
     46
     47    def is_expired(self):
     48        return int(self.can_be_shown) <= 0
     49
     50    def __eq__(self, other):
     51        return self.can_be_shown == other.can_be_shown
     52
  • contrib/messages/api.py

     
    1313    pass
    1414
    1515
    16 def add_message(request, level, message, extra_tags='', fail_silently=False):
     16def add_message(request, level, message, extra_tags='', fail_silently=False, restrictions = []):
    1717    """
    1818    Attempts to add a message to the request using the 'messages' app, falling
    1919    back to the user's message_set if MessageMiddleware hasn't been enabled.
    2020    """
    2121    if hasattr(request, '_messages'):
    22         return request._messages.add(level, message, extra_tags)
     22        return request._messages.add(level, message, extra_tags, restrictions = restrictions)
    2323    if hasattr(request, 'user') and request.user.is_authenticated():
    2424        return request.user.message_set.create(message=message)
    2525    if not fail_silently:
  • contrib/messages/tests/restrictions.py

     
     1from django.test import TestCase
     2from django.contrib.messages import restrictions
     3from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction
     4from django.contrib.messages.tests.time_provider import TestTimeProvider
     5
     6restrictions.time_provider = TestTimeProvider ()
     7
     8class RestrictionsTest(TestCase):
     9    def __check_expired(self, amount_restriction, iterations_amount):
     10        """
     11        Checks whether after iterations_amount of on_displayate given restriction will become expired
     12        But before iterations_amount given amount_restriction must not indicate is_expired
     13        """
     14        for i in range(iterations_amount):
     15            self.assertFalse(amount_restriction.is_expired())
     16            amount_restriction.on_display()
     17        self.assertTrue(amount_restriction.is_expired())
     18
     19    def test_amount_restrictions(self):
     20        res = AmountRestriction(4)
     21        self.__check_expired(res, 4)
     22
     23    def test_amount_restrictions_invalid_argument(self):
     24        self.assertRaises(AssertionError, AmountRestriction, -1)
     25
     26    def test_equal(self):
     27        self.assertEqual(AmountRestriction(5), AmountRestriction(5))
     28        self.assertFalse(AmountRestriction(1) == AmountRestriction(3))
     29        self.assertEqual(TimeRestriction(2), TimeRestriction(2))
     30        self.assertFalse(TimeRestriction(3) == TimeRestriction(4))
     31
  • contrib/messages/tests/time_provider.py

     
     1class TestTimeProvider(object):
     2    def __init__(self, act_time = 0):
     3        self.act_time = act_time
     4    def set_act_time(self, act_time):
     5        self.act_time = act_time
     6    def time(self):
     7        return self.act_time
     8    def inc_act_time(self):
     9        self.act_time += 1
  • contrib/messages/tests/cookie.py

     
    11from django.contrib.messages import constants
    22from django.contrib.messages.tests.base import BaseTest
     3from django.contrib.messages.tests.time_provider import TestTimeProvider
     4from django.contrib.messages import restrictions
     5from django.contrib.messages.restrictions import TimeRestriction, AmountRestriction
    36from django.contrib.messages.storage.cookie import CookieStorage, \
    47                                            MessageEncoder, MessageDecoder
    58from django.contrib.messages.storage.base import Message
     
    4649    def test_get(self):
    4750        storage = self.storage_class(self.get_request())
    4851        # Set initial data.
    49         example_messages = ['test', 'me']
     52        example_messages = [Message(constants.INFO, 'test'), Message(constants.INFO, 'me')]
     53        expected_messages = [Message(constants.INFO, 'test', restrictions = [AmountRestriction(0),]),\
     54                                     Message(constants.INFO, 'me', restrictions = [AmountRestriction(0),])]
    5055        set_cookie_data(storage, example_messages)
    5156        # Test that the message actually contains what we expect.
    52         self.assertEqual(list(storage), example_messages)
     57        self.assertEqual(list(storage), expected_messages)
    5358
    5459    def test_get_bad_cookie(self):
    5560        request = self.get_request()
     
    9196        instances is properly encoded/decoded by the custom JSON
    9297        encoder/decoder classes.
    9398        """
     99        restrictions.time_provider = TestTimeProvider()
     100        restrictions.time_provider.set_act_time(0)
    94101        messages = [
    95102            {
    96103                'message': Message(constants.INFO, 'Test message'),
    97                 'message_list': [Message(constants.INFO, 'message %s') \
     104                'message_list': [Message(constants.INFO, 'message %s', \
     105                                 restrictions = [TimeRestriction(5), AmountRestriction(3), TimeRestriction(2), AmountRestriction(10)]) \
    98106                                 for x in xrange(5)] + [{'another-message': \
    99107                                 Message(constants.ERROR, 'error')}],
    100108            },
     
    104112        value = encoder.encode(messages)
    105113        decoded_messages = json.loads(value, cls=MessageDecoder)
    106114        self.assertEqual(messages, decoded_messages)
     115
     116    def transport_storage(self, response, request):
     117        request.COOKIES['messages'] = response.cookies['messages'].value
     118
  • contrib/messages/tests/base.py

     
    55from django.conf import settings
    66from django.utils.translation import ugettext_lazy
    77from django.utils.unittest import skipIf
    8 from django.contrib.messages import constants, utils, get_level, set_level
     8from django.contrib.messages import constants, utils, get_level, set_level, restrictions
    99from django.contrib.messages.api import MessageFailure
     10from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction
    1011from django.contrib.messages.storage import default_storage, base
    1112from django.contrib.messages.storage.base import Message
     13from django.contrib.messages.tests.time_provider import TestTimeProvider
    1214from django.core.urlresolvers import reverse
    1315from django.contrib.auth.models import User
    1416
     17restrictions.time_provider = TestTimeProvider()
    1518
    1619def skipUnlessAuthIsInstalled(func):
    1720    return skipIf(
     
    102105        storage._loaded_data = data or []
    103106        return storage
    104107
     108    def read_storage(self, storage):
     109        """
     110        Simulates reading all messages from given storage
     111        Returns list of read messages
     112        """
     113        return list(storage)
     114
    105115    def test_add(self):
    106116        storage = self.get_storage()
    107117        self.assertFalse(storage.added_new)
     
    177187            response = self.client.post(add_url, data, follow=True)
    178188            self.assertRedirects(response, show_url)
    179189            self.assertTrue('messages' in response.context)
    180             messages = [Message(self.levels[level], msg) for msg in
     190            messages = [Message(self.levels[level], msg, restrictions = [AmountRestriction(0),]) for msg in
    181191                                                         data['messages']]
    182192            self.assertEqual(list(response.context['messages']), messages)
    183193            for msg in data['messages']:
     
    210220        """
    211221        settings.MESSAGE_LEVEL = constants.DEBUG
    212222        data = {
    213             'messages': ['Test message %d' % x for x in xrange(10)],
     223            'messages': ['%d' % x for x in xrange(10)],
    214224        }
    215225        show_url = reverse('django.contrib.messages.tests.urls.show')
    216226        messages = []
     
    221231                              args=(level,))
    222232            self.client.post(add_url, data)
    223233        response = self.client.get(show_url)
     234        new_messages = []
     235        for level in ('debug', 'info', 'success', 'warning', 'error'):
     236            new_messages.extend([Message(self.levels[level], msg, \
     237                                         restrictions = [AmountRestriction(0),]) for msg in data['messages']])
    224238        self.assertTrue('messages' in response.context)
    225         self.assertEqual(list(response.context['messages']), messages)
     239        self.assertEqual(list(response.context['messages']), new_messages)
    226240        for msg in data['messages']:
    227241            self.assertContains(response, msg)
    228242
     
    437451            # Ensure the level tags constant is put back like we found it.
    438452            self.restore_setting('MESSAGE_TAGS')
    439453            base.LEVEL_TAGS = utils.get_level_tags()
     454
     455    def test_storing_restrictoins(self):
     456        storage = self.get_storage()
     457        response = self.get_response()
     458
     459        get_res = lambda ar1, ar2, tr1, tr2: [AmountRestriction(ar1), AmountRestriction(ar2), TimeRestriction(tr1), TimeRestriction(tr2)]
     460       
     461        restrictions.time_provider.set_act_time(0)
     462        storage.add(constants.WARNING, 'First msg', restrictions = get_res(10, 20, 30, 40))
     463        messages = self.__read_messages(storage, response)
     464        self.assertEqual(len(messages), 1)
     465        rest = messages[0].restrictions
     466        for a in (9, 19):
     467            self.assertTrue(a in [r.can_be_shown for r in rest if r.type == 'amount'])
     468        for t in (30, 40):
     469            self.assertTrue(t in [r.expires for r in rest if r.type == 'time'])
     470
     471        restrictions.time_provider.set_act_time(4)
     472        storage = self.get_storage()
     473        response = self.get_response()
     474        storage.add(constants.WARNING, 'First msg', restrictions = get_res(10, 20, 30, 40))
     475        messages = self.__read_messages(storage, response)
     476        rest = messages[0].restrictions
     477        for a in (9, 19):
     478            self.assertTrue(a in [r.can_be_shown for r in rest if r.type == 'amount'])
     479        for t in (34, 44):
     480            self.assertTrue(t in [r.expires for r in rest if r.type == 'time'])
     481
     482    def test_expire_default(self):
     483        """
     484        Tests against message expiration in default behaviour (no explicity defined restrictions on expire -> show only once)
     485        """
     486        storage = self.get_existing_storage()
     487        response = self.get_response()
     488       
     489        list (storage)
     490        storage.update(response)
     491       
     492        storing = self.stored_messages_count(storage, response)
     493        self.assertEqual(storing, 0)
     494
     495    def test_expire_after_showing_given_amount_of_times(self):
     496        """
     497        Tests against expiring message after beeing shown given amount of times
     498        """
     499        storage = self.get_existing_storage()
     500        response = self.get_response()
     501
     502        read_messages = lambda: self.__read_messages(storage, response)
     503
     504        storage.add(constants.WARNING, 'Third message, should be shown four times', restrictions = [AmountRestriction(4),])
     505        storage.add(constants.ERROR, "Four'th message, should be shown five times", restrictions = [AmountRestriction(5),])
     506
     507
     508        messages = read_messages ()
     509        self.assertEqual(len(messages), 4)
     510        storing = self.stored_messages_count(storage, response)
     511        self.assertEqual(storing, 2)
     512
     513
     514        for i in range(2):
     515            messages = read_messages ()
     516            self.assertEqual(len(messages), 2)
     517            storing = self.stored_messages_count(storage, response)
     518            self.assertEqual(storing, 2)
     519            [self.assertTrue(level in [x.level for x in messages]) for level in (constants.ERROR, constants.WARNING)]
     520
     521
     522        messages = read_messages ()
     523        self.assertEqual(len(messages), 2)
     524        storing = self.stored_messages_count(storage, response)
     525        self.assertEqual(storing, 1)
     526
     527
     528        messages = read_messages()
     529        self.assertEqual(len(messages), 1)
     530        self.assertEqual(messages[0].level, constants.ERROR)
     531        storing = self.stored_messages_count(storage, response)
     532        self.assertEqual(storing, 0)
     533
     534
     535        messages = read_messages()
     536        self.assertEqual(len(messages), 0)
     537        storing = self.stored_messages_count(storage, response)
     538        self.assertEqual(storing, 0)
     539
     540    def test_expire_after_time(self):
     541        storage = self.get_storage()
     542        response = self.get_response()
     543        res = restrictions
     544        res.time_provider.set_act_time(0)
     545
     546        storage.add(constants.WARNING, 'Third message, should be shown four times', restrictions = [TimeRestriction(4),])
     547        storage.add(constants.ERROR, "Four'th message, should be shown five times", restrictions = [TimeRestriction(6),])
     548
     549        for i in range(10):
     550            messages = self.__read_messages(storage, response)
     551            self.assertEqual(len(messages), 2)
     552            storing = self.stored_messages_count(storage, response)
     553            self.assertEqual(storing, 2)
     554
     555        res.time_provider.set_act_time(5)
     556        messages = self.__read_messages(storage, response)
     557        self.assertEqual(len(messages), 1)
     558        self.assertEqual(messages[0].level, constants.ERROR)
     559        storing = self.stored_messages_count(storage, response)
     560        self.assertEqual(storing, 1)
     561
     562        res.time_provider.set_act_time(7)
     563        messages = self.__read_messages(storage, response)
     564        self.assertEqual(len(messages), 0)
     565        storing = self.stored_messages_count(storage, response)
     566        self.assertEqual(storing, 0)
     567
     568    def test_expire_fixed_restrictions(self):
     569        """
     570        Check message expirity when defining few sort of restrictions
     571        of different kind
     572        """
     573        get_storage_and_response = lambda: (self.get_storage(), self.get_response())
     574        storage, response = get_storage_and_response()
     575        get_res = lambda ar1, ar2, tr1, tr2: [AmountRestriction(ar1), AmountRestriction(ar2), TimeRestriction(tr1), TimeRestriction(tr2)]
     576
     577
     578        def check_storage(storage, iterations, expected_amount, fnct = None):
     579            """
     580            Checks whether given storage would contain expected_amount of messages before each of iterations iterations
     581            Performs iterations amount of iterations
     582            Calls fnct at the end of each iteration
     583            """
     584            for i in range(iterations): #read 2 times
     585                messages = self.__read_messages(storage, response)
     586                self.assertEqual(len(messages), expected_amount)
     587                storing = self.stored_messages_count(storage, response)
     588                self.assertEqual(storing, expected_amount)
     589                if fnct: fnct()
     590
     591        # first - expires after amount of showing
     592        restrictions.time_provider.set_act_time(0)
     593        storage.add(constants.ERROR, "Some message", restrictions = get_res(7, 30, 5, 20))
     594        storage.add(constants.INFO, "another message", restrictions = get_res(3, 10, 4, 11))
     595        check_storage(storage, 2, 2)
     596        messages = self.__read_messages(storage, response) # 3 times read
     597        self.assertEqual(len(messages), 2)
     598        storing = self.stored_messages_count(storage, response)
     599        self.assertEqual(storing, 1)
     600        check_storage(storage, 3, 1)
     601           
     602
     603        storage, response = get_storage_and_response()
     604        restrictions.time_provider.set_act_time(0)
     605        storage.add(constants.ERROR, "Some message", restrictions = get_res(7, 30, 5, 20))
     606        storage.add(constants.INFO, "another message", restrictions = get_res(3, 10, 4, 11))
     607        restrictions.time_provider.set_act_time(2)
     608        check_storage(storage, 2, 2, lambda:restrictions.time_provider.set_act_time(3))
     609 
     610        # second - expires after amount of time
     611        storage, response = get_storage_and_response()
     612        restrictions.time_provider.set_act_time(0)
     613        storage.add(constants.ERROR, "Some message", restrictions = get_res(10, 30, 5, 20))
     614        storage.add(constants.INFO, "another message", restrictions = get_res(10, 20, 3, 11))
     615        check_storage(storage, 2, 2)
     616        restrictions.time_provider.set_act_time(2)
     617        check_storage(storage, 2, 2)
     618        restrictions.time_provider.set_act_time(4)
     619        check_storage(storage, 2, 1)
     620
     621    def transport_storage(self, response, request):
     622        """
     623        Transports storage from response to request
     624        This method can be overriden by subclasses
     625        """
     626
     627    def __read_messages(self, storage, response):#simulate next call to render messages
     628        """
     629        Simulates iterating storage in template
     630        Returns messages from that iteration that would be returned
     631        """
     632        messages = self.read_storage(storage)
     633        storage.update(response)
     634        self.transport_storage (response, storage.request)
     635        storage.used = False 
     636        storage._queued_messages = []
     637        del storage._loaded_data
     638        return messages
     639
  • contrib/messages/tests/__init__.py

     
     1from django.contrib.messages.tests.session import SessionTest
    12from django.contrib.messages.tests.cookie import CookieTest
    23from django.contrib.messages.tests.fallback import FallbackTest
    3 from django.contrib.messages.tests.middleware import MiddlewareTest
    4 from django.contrib.messages.tests.session import SessionTest
     4from django.contrib.messages.tests.restrictions import RestrictionsTest
     5from django.contrib.messages.tests.message import MessageTest
    56from django.contrib.messages.tests.user_messages import \
    67                                           UserMessagesTest, LegacyFallbackTest
     8
     9from django.contrib.messages.tests.middleware import MiddlewareTest
     10
  • contrib/messages/tests/fallback.py

     
    11from django.contrib.messages import constants
     2from django.contrib.messages.storage.base import Message
    23from django.contrib.messages.storage.fallback import FallbackStorage, \
    34    CookieStorage
    45from django.contrib.messages.tests.base import BaseTest
    56from django.contrib.messages.tests.cookie import set_cookie_data, \
    67    stored_cookie_messages_count
     8from django.contrib.messages.restrictions import AmountRestriction
    79from django.contrib.messages.tests.session import set_session_data, \
    810    stored_session_messages_count
    911
     
    4446        cookie_storage = self.get_cookie_storage(storage)
    4547
    4648        # Set initial cookie data.
    47         example_messages = [str(i) for i in range(5)]
     49        example_messages = [Message(constants.INFO, str(i)) for i in range(5)]
     50        expected_messages = [Message(constants.INFO, str(i), restrictions = [AmountRestriction(0),]) for i in range(5)]
    4851        set_cookie_data(cookie_storage, example_messages)
    4952
    5053        # Overwrite the _get method of the fallback storage to prove it is not
     
    5255        self.get_session_storage(storage)._get = None
    5356
    5457        # Test that the message actually contains what we expect.
    55         self.assertEqual(list(storage), example_messages)
     58        self.assertEqual(list(storage), expected_messages)
    5659
    5760    def test_get_empty(self):
    5861        request = self.get_request()
     
    7275        session_storage = self.get_session_storage(storage)
    7376
    7477        # Set initial cookie and session data.
    75         example_messages = [str(i) for i in range(5)]
     78        example_messages = [Message(constants.INFO, str(i)) for i in range(5)]
     79        expected_messages = [Message(constants.INFO, str(i), restrictions = [AmountRestriction(0),]) for i in range(5)]
    7680        set_cookie_data(cookie_storage, example_messages[:4] +
    7781                        [CookieStorage.not_finished])
    7882        set_session_data(session_storage, example_messages[4:])
    7983
    8084        # Test that the message actually contains what we expect.
    81         self.assertEqual(list(storage), example_messages)
     85        self.assertEqual(list(storage), expected_messages)
    8286
    8387    def test_get_fallback_only(self):
    8488        request = self.get_request()
     
    8791        session_storage = self.get_session_storage(storage)
    8892
    8993        # Set initial cookie and session data.
    90         example_messages = [str(i) for i in range(5)]
     94        example_messages = [Message(constants.INFO, str(i)) for i in range(5)]
    9195        set_cookie_data(cookie_storage, [CookieStorage.not_finished],
    9296                        encode_empty=True)
    9397        set_session_data(session_storage, example_messages)
     
    102106        session_storage = self.get_session_storage(storage)
    103107
    104108        # Set initial cookie and session data.
    105         set_cookie_data(cookie_storage, ['cookie', CookieStorage.not_finished])
    106         set_session_data(session_storage, ['session'])
     109        set_cookie_data(cookie_storage, [Message(constants.INFO, 'cookie'), CookieStorage.not_finished])
     110        set_session_data(session_storage, [Message(constants.INFO, 'session')])
    107111
    108112        # When updating, previously used but no longer needed backends are
    109113        # flushed.
     
    173177        self.assertEqual(cookie_storing, 0)
    174178        session_storing = self.stored_session_messages_count(storage, response)
    175179        self.assertEqual(session_storing, 1)
     180
     181    def transport_storage(self, response, request):
     182        request.COOKIES['messages'] = response.cookies['messages'].value
  • contrib/messages/tests/session.py

     
    11from django.contrib.messages.tests.base import BaseTest
    22from django.contrib.messages.storage.session import SessionStorage
     3from django.contrib.messages.storage.base import Message
    34
    45
    56def set_session_data(storage, messages):
     
    3233    def test_get(self):
    3334        storage = self.storage_class(self.get_request())
    3435        # Set initial data.
    35         example_messages = ['test', 'me']
     36        example_messages = [Message(1, 'test') , Message(1, 'me')]
    3637        set_session_data(storage, example_messages)
    3738        # Test that the message actually contains what we expect.
    3839        self.assertEqual(list(storage), example_messages)
  • contrib/messages/tests/message.py

     
     1from django.test import TestCase
     2from django.contrib.messages.storage.base import Message
     3from django.contrib.messages import restrictions
     4from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction, time_provider
     5from django.contrib.messages.tests.time_provider import TestTimeProvider
     6from django.contrib.messages import constants
     7
     8
     9class MessageTest(TestCase):
     10    def setUp(self):
     11        self.tp = restrictions.time_provider = TestTimeProvider ()
     12    def __check_active(self, msg, iterations):
     13        """
     14        Reads msg given amount of iterations, and after each read
     15        checks whether before each read message is active
     16        """
     17        for i in range(iterations):
     18            self.assertTrue(msg.active())
     19            msg.on_display()
     20        self.assertFalse(msg.active())
     21        msg.on_display()
     22        self.assertFalse(msg.active())
     23
     24    def test_active_default(self):
     25        msg = Message(constants.INFO, "Test message")
     26        self.__check_active(msg, 1)
     27
     28    def test_active_custom_one_amount_restriction(self):
     29        msg = Message(constants.INFO, "Test message", restrictions = [AmountRestriction(3),])
     30        self.__check_active(msg, 3)
     31
     32    def test_active_custom_few_amount_restriction(self):
     33        msg = Message(constants.INFO, "Test message", restrictions = [AmountRestriction(x) for x in (2, 3, 5)])
     34        self.__check_active(msg, 2)
     35
     36    def test_active_custom_one_time_restriction(self):
     37        msg = Message(constants.INFO, "Test message", restrictions = [TimeRestriction(3),])
     38        def check_iter():
     39            for i in range(10): # iteration doesn't have direct impact for TimeRestriction
     40                self.assertTrue(msg.active())
     41                msg.on_display()
     42        check_iter()
     43        self.tp.set_act_time(3)
     44        check_iter()
     45        self.tp.set_act_time(4)
     46        self.assertFalse(msg.active())
     47
     48
     49    def test_mixed_restrictions(self):
     50        get_restrictions = lambda:[TimeRestriction(3), TimeRestriction(5), AmountRestriction(2), AmountRestriction(3)]
     51        get_msg = lambda:Message(constants.INFO, "Test message", restrictions = get_restrictions())
     52
     53        msg = get_msg()
     54        for i in range(2):
     55            self.assertTrue(msg.active())
     56            msg.on_display()
     57        self.assertFalse(msg.active())
     58
     59        msg = get_msg()
     60        self.assertTrue(msg.active())
     61        msg.on_display()
     62        self.assertTrue(msg.active())
     63        self.tp.set_act_time(4)
     64        self.assertFalse(msg.active())
     65        for i in range(10):
     66            self.assertFalse(msg.active())
     67            msg.on_display()
     68       
     69           
  • contrib/messages/tests/user_messages.py

     
    11from django import http
    22from django.contrib.auth.models import User
     3from django.contrib.messages import constants
     4from django.contrib.messages.storage.base import Message
    35from django.contrib.messages.storage.user_messages import UserMessagesStorage,\
    46    LegacyFallbackStorage
    57from django.contrib.messages.tests.base import skipUnlessAuthIsInstalled
     
    6062        storage = self.storage_class(request)
    6163        cookie_storage = self.get_cookie_storage(storage)
    6264        self.user.message_set.create(message='user message')
    63         set_cookie_data(cookie_storage, ['cookie'])
     65        set_cookie_data(cookie_storage, [Message(constants.INFO,'cookie')])
    6466
    6567        # Test that the message actually contains what we expect.
    6668        self.assertEqual(len(storage), 2)
    6769        self.assertEqual(list(storage)[0].message, 'user message')
    68         self.assertEqual(list(storage)[1], 'cookie')
     70        self.assertEqual(list(storage)[1].message, 'cookie')
    6971
    7072LegacyFallbackTest = skipUnlessAuthIsInstalled(LegacyFallbackTest)
  • contrib/messages/storage/cookie.py

     
    55from django.utils import simplejson as json
    66from django.utils.crypto import salted_hmac, constant_time_compare
    77
     8from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction
    89
    910class MessageEncoder(json.JSONEncoder):
    1011    """
     
    1213    """
    1314    message_key = '__json_message'
    1415
     16    def __encode_restriction (self, r):
     17        if r.type == 'amount': ret = '%s@%s' % ('a', r.can_be_shown)
     18        elif r.type == 'time': ret = '%s@%s' % ('t', r.expires)
     19        return ret
     20
    1521    def default(self, obj):
    1622        if isinstance(obj, Message):
    1723            message = [self.message_key, obj.level, obj.message]
    1824            if obj.extra_tags:
    1925                message.append(obj.extra_tags)
     26            restrictions = [self.__encode_restriction(r) for r in obj.restrictions]
     27            message.append (restrictions)
    2028            return message
    2129        return super(MessageEncoder, self).default(obj)
    2230
     
    2533    """
    2634    Decodes JSON that includes serialized ``Message`` instances.
    2735    """
     36    def __get_restrictions (self, restrictions):
     37        def _get_r(type, value):
     38            if type == 'a':  return AmountRestriction (value)
     39            elif type == 't':
     40                ret = TimeRestriction(0)
     41                ret.set_expirity_time(value)
     42                return ret
     43        ret = []
     44        for r in restrictions:
     45            rtype, value = r.split('@')
     46            added = _get_r (rtype, value)
     47            ret.append (added)
     48        return ret
    2849
     50
     51    def create_message(self, vars):
     52        ''' creates message on the basis of encoded data '''
     53        args = vars[:-1]
     54        restrictions = vars[-1]
     55        restrictions = self.__get_restrictions (restrictions)
     56        return Message(*args, **{'restrictions': restrictions})
     57
    2958    def process_messages(self, obj):
    3059        if isinstance(obj, list) and obj:
    3160            if obj[0] == MessageEncoder.message_key:
    32                 return Message(*obj[1:])
     61                return self.create_message (obj[1:])
    3362            return [self.process_messages(item) for item in obj]
    3463        if isinstance(obj, dict):
    3564            return dict([(key, self.process_messages(value))
     
    148177        # with the data.
    149178        self.used = True
    150179        return None
     180 
     181    def transport_storage(self, response, request):
     182        storage.request.COOKIES['messages'] = response.cookies['messages'].value
  • contrib/messages/storage/base.py

     
    11from django.conf import settings
    22from django.utils.encoding import force_unicode, StrAndUnicode
    3 from django.contrib.messages import constants, utils
     3from django.contrib.messages import constants, utils, restrictions as res
    44
    55
    66LEVEL_TAGS = utils.get_level_tags()
    77
     8       
    89
    910class Message(StrAndUnicode):
    1011    """
     
    1314    or template.
    1415    """
    1516
    16     def __init__(self, level, message, extra_tags=None):
     17    def __init__(self, level, message, extra_tags=None, restrictions = []):
    1718        self.level = int(level)
    1819        self.message = message
    1920        self.extra_tags = extra_tags
    2021
    21     def _prepare(self):
     22        self.restrictions = restrictions or list([res.AmountRestriction(1)])
     23        # if not given any restriction - one show by default
     24
     25    def _prepare(self): # todo: slef.restrictions =
    2226        """
    2327        Prepares the message for serialization by forcing the ``message``
    2428        and ``extra_tags`` to unicode in case they are lazy translations.
     
    3135
    3236    def __eq__(self, other):
    3337        return isinstance(other, Message) and self.level == other.level and \
    34                                               self.message == other.message
     38                                              self.message == other.message and \
     39                                              self.restrictions == other.restrictions
    3540
    3641    def __unicode__(self):
    37         return force_unicode(self.message)
     42        return force_unicode(self.message)  + ':' + unicode('CFVB')
    3843
     44
    3945    def _get_tags(self):
    4046        label_tag = force_unicode(LEVEL_TAGS.get(self.level, ''),
    4147                                  strings_only=True)
     
    5056    tags = property(_get_tags)
    5157
    5258
     59    def active (self):
     60        for r in self.restrictions:
     61            if r.is_expired(): return False
     62        return True
     63
     64
     65    def on_display (self):
     66        for r in self.restrictions:
     67            r.on_display ()
     68
     69
    5370class BaseStorage(object):
    5471    """
    5572    This is the base backend for temporary message storage.
     
    6077
    6178    def __init__(self, request, *args, **kwargs):
    6279        self.request = request
     80        self.used = False
    6381        self._queued_messages = []
    64         self.used = False
    6582        self.added_new = False
    6683        super(BaseStorage, self).__init__(*args, **kwargs)
    6784
     
    6986        return len(self._loaded_messages) + len(self._queued_messages)
    7087
    7188    def __iter__(self):
    72         self.used = True
    73         if self._queued_messages:
    74             self._loaded_messages.extend(self._queued_messages)
    75             self._queued_messages = []
    76         return iter(self._loaded_messages)
     89        if not self.used:
     90            self.used = True
     91            if self._queued_messages:
     92                self._loaded_messages.extend(self._queued_messages)
     93                self._queued_messages = []
    7794
     95            active_messages = [x for x in self._loaded_messages if x.active ()]
     96            for x in active_messages:
     97                x.on_display ()
     98            self._queued_messages.extend (active_messages)
     99        return iter(self._queued_messages)
     100
     101
    78102    def __contains__(self, item):
    79103        return item in self._loaded_messages or item in self._queued_messages
    80104
     
    104128        """
    105129        raise NotImplementedError()
    106130
     131    def filter_store(self, messages, response, *args, **kwargs):
     132        ''' stores only active messages from given messages in storage '''
     133        filtered_messages = [x for x in messages if x.active ()]
     134        return self._store(filtered_messages, response, *args, **kwargs)
     135
     136
    107137    def _store(self, messages, response, *args, **kwargs):
    108138        """
    109139        Stores a list of messages, returning a list of any messages which could
     
    130160        be stored again. Otherwise, only messages added after the last
    131161        iteration will be stored.
    132162        """
     163        # if used or used and added, then _queued_messages contains all messages that should be saved
     164        # if added, then save: all messages currently stored and added ones
    133165        self._prepare_messages(self._queued_messages)
    134166        if self.used:
    135             return self._store(self._queued_messages, response)
     167            return self.filter_store(self._queued_messages, response)
    136168        elif self.added_new:
    137169            messages = self._loaded_messages + self._queued_messages
    138             return self._store(messages, response)
     170            return self.filter_store(messages, response)
    139171
    140     def add(self, level, message, extra_tags=''):
     172    def add(self, level, message, extra_tags='', restrictions = []):
    141173        """
    142174        Queues a message to be stored.
    143175
     
    152184            return
    153185        # Add the message.
    154186        self.added_new = True
    155         message = Message(level, message, extra_tags=extra_tags)
     187        message = Message(level, message, extra_tags=extra_tags, restrictions = restrictions)
    156188        self._queued_messages.append(message)
    157189
    158190    def _get_level(self):
Back to Top