Ticket #13376: messages_expirity_capabilities.3.diff

File messages_expirity_capabilities.3.diff, 37.3 KB (added by marekw2143, 14 years ago)
  • contrib/messages/restrictions.py

     
     1import time as time_provider
     2from pdb import set_trace
     3
     4
     5class Restriction (object):
     6    JSON_SEPARATOR = '@'
     7
     8    def __init__(self, name):
     9        self.type = name
     10
     11    def is_expired(self):
     12        """
     13        indicates whether given message should be removed
     14        """
     15        raise NotImplementedError ()
     16
     17    def on_display (self):
     18        """
     19        called when iterated - does nothing by default
     20        """
     21        pass
     22
     23    def to_json(self):
     24        """
     25        returns json representation of restriction
     26        """
     27        raise NotImplementedError
     28
     29    def from_json_param(self, *args):
     30        """
     31        returns restriction on the basis of data encoded in json
     32        """
     33        raise NotImplementedError
     34
     35
     36    def __cmp__(self, other):
     37        if self.__eq__(other): return 0
     38        return -1
     39
     40class TimeRestriction (Restriction):
     41    JSON_TYPE_CODE = 't'
     42
     43    def __init__(self, seconds):
     44        """
     45        seconds - expiration time since now
     46        """
     47        Restriction.__init__(self, 'time')
     48        created = time_provider.time()
     49        self.expires = created + int(seconds)
     50
     51    def set_expirity_time(self, expiration_time):
     52        """
     53        Sets expilcity expiration time
     54        """
     55        self.expires = int(expiration_time)
     56
     57    def is_expired (self):
     58        return self.expires < time_provider.time()
     59
     60    def __eq__(self, other):
     61        return self.type == other.type and not bool(self.expires ^ other.expires)
     62
     63    def __hash__(self):
     64        return self.expires
     65
     66    def to_json(self):
     67        return '%s%s%s' % (self.JSON_TYPE_CODE, self.JSON_SEPARATOR, self.expires)
     68
     69    @classmethod
     70    def from_json_param(cls, expirity_time):
     71        ret = TimeRestriction(0)
     72        ret.set_expirity_time(expirity_time)
     73        return ret
     74       
     75
     76
     77class AmountRestriction (Restriction):
     78    JSON_TYPE_CODE = 'a'
     79
     80    def __init__(self, amount):
     81        assert int(amount) >= 0
     82        Restriction.__init__(self, 'amount')
     83        self.can_be_shown = int(amount)
     84
     85    def on_display (self):
     86        self.can_be_shown -= 1
     87
     88    def is_expired(self):
     89        return int(self.can_be_shown) <= 0
     90
     91    def __eq__(self, other):
     92        return self.type == other.type and not bool(self.can_be_shown ^ other.can_be_shown)
     93   
     94
     95    def __hash__(self):
     96        return self.can_be_shown
     97
     98    def to_json(self):
     99        return '%s%s%s' % (self.JSON_TYPE_CODE, self.JSON_SEPARATOR, self.can_be_shown)
     100
     101    @classmethod
     102    def from_json_param(cls, amount):
     103        return AmountRestriction(amount)
     104       
     105
  • 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 pdb import set_trace
     2from django.test import TestCase
     3from django.contrib.messages import restrictions
     4from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction
     5from django.contrib.messages.tests.time_provider import TestTimeProvider
     6
     7restrictions.time_provider = TestTimeProvider ()
     8
     9class RestrictionsTest(TestCase):
     10    def __check_expired(self, amount_restriction, iterations_amount):
     11        """
     12        Checks whether after iterations_amount of on_displayate given restriction will become expired
     13        But before iterations_amount given amount_restriction must not indicate is_expired
     14        """
     15        for i in range(iterations_amount):
     16            self.assertFalse(amount_restriction.is_expired())
     17            amount_restriction.on_display()
     18        self.assertTrue(amount_restriction.is_expired())
     19
     20    def test_amount_restrictions(self):
     21        res = AmountRestriction(4)
     22        self.__check_expired(res, 4)
     23
     24    def test_amount_restrictions_invalid_argument(self):
     25        self.assertRaises(AssertionError, AmountRestriction, -1)
     26
     27    def test_equal(self):
     28        self.assertEqual(AmountRestriction(5), AmountRestriction(5))
     29        self.assertFalse(AmountRestriction(1) == AmountRestriction(3))
     30        self.assertEqual(TimeRestriction(2), TimeRestriction(2))
     31        self.assertFalse(TimeRestriction(3) == TimeRestriction(4))
     32
     33
  • 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
     
    5659    def test_get(self):
    5760        storage = self.storage_class(self.get_request())
    5861        # Set initial data.
    59         example_messages = ['test', 'me']
     62        example_messages = [Message(constants.INFO, 'test'), Message(constants.INFO, 'me')]
     63        expected_messages = [Message(constants.INFO, 'test', restrictions = [AmountRestriction(0),]),\
     64                                     Message(constants.INFO, 'me', restrictions = [AmountRestriction(0),])]
    6065        set_cookie_data(storage, example_messages)
    6166        # Test that the message actually contains what we expect.
    62         self.assertEqual(list(storage), example_messages)
     67        self.assertEqual(list(storage), expected_messages)
    6368
    6469    def test_domain(self):
    6570        """
     
    126131        instances is properly encoded/decoded by the custom JSON
    127132        encoder/decoder classes.
    128133        """
     134        restrictions.time_provider = TestTimeProvider()
     135        restrictions.time_provider.set_act_time(0)
    129136        messages = [
    130137            {
    131138                'message': Message(constants.INFO, 'Test message'),
    132                 'message_list': [Message(constants.INFO, 'message %s') \
     139                'message_list': [Message(constants.INFO, 'message %s', \
     140                                 restrictions = [TimeRestriction(5), AmountRestriction(3), TimeRestriction(2), AmountRestriction(10)]) \
    133141                                 for x in xrange(5)] + [{'another-message': \
    134142                                 Message(constants.ERROR, 'error')}],
    135143            },
     
    139147        value = encoder.encode(messages)
    140148        decoded_messages = json.loads(value, cls=MessageDecoder)
    141149        self.assertEqual(messages, decoded_messages)
     150
     151    def transport_storage(self, response, request):
     152        request.COOKIES['messages'] = response.cookies['messages'].value
     153
  • contrib/messages/tests/base.py

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

     
     1from pdb import set_trace
    12from django.conf import settings
    23from django.contrib.messages import constants
    3 from django.contrib.messages.storage.base import BaseStorage, Message
     4from django.contrib.messages.storage.base import BaseStorage, Message, RestrictionsContainer
    45from django.http import SimpleCookie
    56from django.utils import simplejson as json
    67from django.utils.crypto import salted_hmac, constant_time_compare
    78
     9from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction
    810
    911class MessageEncoder(json.JSONEncoder):
    1012    """
     
    1214    """
    1315    message_key = '__json_message'
    1416
     17
    1518    def default(self, obj):
    1619        if isinstance(obj, Message):
    1720            message = [self.message_key, obj.level, obj.message]
    1821            if obj.extra_tags:
    1922                message.append(obj.extra_tags)
     23            message.append (obj.restrictions.to_json_obj())
    2024            return message
    2125        return super(MessageEncoder, self).default(obj)
    2226
     
    2630    Decodes JSON that includes serialized ``Message`` instances.
    2731    """
    2832
     33
     34    def create_message(self, vars):
     35        ''' creates message on the basis of encoded data '''
     36        args = vars[:-1]
     37        restrictions = vars[-1]
     38        restrictions = RestrictionsContainer.create_from_josn(restrictions)
     39        return Message(*args, **{'restrictions': restrictions})
     40
    2941    def process_messages(self, obj):
    3042        if isinstance(obj, list) and obj:
    3143            if obj[0] == MessageEncoder.message_key:
    32                 return Message(*obj[1:])
     44                return self.create_message (obj[1:])
    3345            return [self.process_messages(item) for item in obj]
    3446        if isinstance(obj, dict):
    3547            return dict([(key, self.process_messages(value))
  • contrib/messages/storage/base.py

     
     1from pdb import set_trace
    12from django.conf import settings
    23from django.utils.encoding import force_unicode, StrAndUnicode
    3 from django.contrib.messages import constants, utils
     4from django.contrib.messages import constants, utils, restrictions as res
    45
    56
    67LEVEL_TAGS = utils.get_level_tags()
    78
     9       
     10class RestrictionsContainer(list):
     11    res_map = {res.AmountRestriction.JSON_TYPE_CODE: res.AmountRestriction,
     12                res.TimeRestriction.JSON_TYPE_CODE: res.TimeRestriction}
    813
     14    def to_json_obj(self):
     15        return [r.to_json() for r in self]
     16
     17    @classmethod
     18    def create_from_josn(cls, enc_restrictions):
     19        #set_trace()
     20        ret = []
     21        for r in enc_restrictions:
     22            restriction_type, values = r.split(res.Restriction.JSON_SEPARATOR)
     23            ret.append(cls.res_map[restriction_type].from_json_param(values))
     24        return RestrictionsContainer(ret)
     25
     26    def __eq__(self, other):
     27        return set(self) == set(other)
     28
    929class Message(StrAndUnicode):
    1030    """
    1131    Represents an actual message that can be stored in any of the supported
     
    1333    or template.
    1434    """
    1535
    16     def __init__(self, level, message, extra_tags=None):
     36    def __init__(self, level, message, extra_tags=None, restrictions = []):
    1737        self.level = int(level)
    1838        self.message = message
    1939        self.extra_tags = extra_tags
    2040
    21     def _prepare(self):
     41        self.restrictions = restrictions or list([res.AmountRestriction(1)])
     42        self.restrictions = RestrictionsContainer(self.restrictions)
     43        # if not given any restriction - one show by default
     44
     45    def _prepare(self): # todo: slef.restrictions =
    2246        """
    2347        Prepares the message for serialization by forcing the ``message``
    2448        and ``extra_tags`` to unicode in case they are lazy translations.
     
    3155
    3256    def __eq__(self, other):
    3357        return isinstance(other, Message) and self.level == other.level and \
    34                                               self.message == other.message
     58                                              self.message == other.message and \
     59                                              self.restrictions == other.restrictions
    3560
    3661    def __unicode__(self):
    37         return force_unicode(self.message)
     62        return force_unicode(self.message)  + ':' + unicode('CFVB')
    3863
     64
    3965    def _get_tags(self):
    4066        label_tag = force_unicode(LEVEL_TAGS.get(self.level, ''),
    4167                                  strings_only=True)
     
    5076    tags = property(_get_tags)
    5177
    5278
     79    def active (self):
     80        for r in self.restrictions:
     81            if r.is_expired(): return False
     82        return True
     83
     84
     85    def on_display (self):
     86        for r in self.restrictions:
     87            r.on_display ()
     88
     89
    5390class BaseStorage(object):
    5491    """
    5592    This is the base backend for temporary message storage.
     
    6097
    6198    def __init__(self, request, *args, **kwargs):
    6299        self.request = request
     100        self.used = False
    63101        self._queued_messages = []
    64         self.used = False
    65102        self.added_new = False
    66103        super(BaseStorage, self).__init__(*args, **kwargs)
    67104
     
    69106        return len(self._loaded_messages) + len(self._queued_messages)
    70107
    71108    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)
     109        if not self.used:
     110            self.used = True
     111            if self._queued_messages:
     112                self._loaded_messages.extend(self._queued_messages)
     113                self._queued_messages = []
    77114
     115            active_messages = [x for x in self._loaded_messages if x.active ()]
     116            for x in active_messages:
     117                x.on_display ()
     118            self._queued_messages.extend (active_messages)
     119        return iter(self._queued_messages)
     120
     121
    78122    def __contains__(self, item):
    79123        return item in self._loaded_messages or item in self._queued_messages
    80124
     
    104148        """
    105149        raise NotImplementedError()
    106150
     151    def filter_store(self, messages, response, *args, **kwargs):
     152        ''' stores only active messages from given messages in storage '''
     153        filtered_messages = [x for x in messages if x.active ()]
     154        return self._store(filtered_messages, response, *args, **kwargs)
     155
     156
    107157    def _store(self, messages, response, *args, **kwargs):
    108158        """
    109159        Stores a list of messages, returning a list of any messages which could
     
    130180        be stored again. Otherwise, only messages added after the last
    131181        iteration will be stored.
    132182        """
     183        # if used or used and added, then _queued_messages contains all messages that should be saved
     184        # if added, then save: all messages currently stored and added ones
    133185        self._prepare_messages(self._queued_messages)
    134186        if self.used:
    135             return self._store(self._queued_messages, response)
     187            return self.filter_store(self._queued_messages, response)
    136188        elif self.added_new:
    137189            messages = self._loaded_messages + self._queued_messages
    138             return self._store(messages, response)
     190            return self.filter_store(messages, response)
    139191
    140     def add(self, level, message, extra_tags=''):
     192    def add(self, level, message, extra_tags='', restrictions = []):
    141193        """
    142194        Queues a message to be stored.
    143195
     
    152204            return
    153205        # Add the message.
    154206        self.added_new = True
    155         message = Message(level, message, extra_tags=extra_tags)
     207        message = Message(level, message, extra_tags=extra_tags, restrictions = restrictions)
    156208        self._queued_messages.append(message)
    157209
    158210    def _get_level(self):
Back to Top