Ticket #13376: messages_expirity_capabilities.4.diff
File messages_expirity_capabilities.4.diff, 35.7 KB (added by , 13 years ago) |
---|
-
django/contrib/messages/restrictions.py
1 import time as time_provider 2 3 4 class Restriction (object): 5 JSON_SEPARATOR = '@' 6 7 def __init__(self, name): 8 self.type = name 9 10 def is_expired(self): 11 """ 12 indicates whether given message should be removed 13 """ 14 raise NotImplementedError () 15 16 def on_display (self): 17 """ 18 called when iterated - does nothing by default 19 """ 20 pass 21 22 def to_json(self): 23 """ 24 returns json representation of restriction 25 """ 26 raise NotImplementedError 27 28 def from_json_param(self, *args): 29 """ 30 returns restriction on the basis of data encoded in json 31 """ 32 raise NotImplementedError 33 34 35 def __cmp__(self, other): 36 if self.__eq__(other): return 0 37 return -1 38 39 class TimeRestriction (Restriction): 40 JSON_TYPE_CODE = 't' 41 42 def __init__(self, seconds): 43 """ 44 seconds - expiration time since now 45 """ 46 Restriction.__init__(self, 'time') 47 created = time_provider.time() 48 self.expires = created + int(seconds) 49 50 def set_expirity_time(self, expiration_time): 51 """ 52 Sets expilcity expiration time 53 """ 54 self.expires = int(expiration_time) 55 56 def is_expired (self): 57 return self.expires < time_provider.time() 58 59 def __eq__(self, other): 60 return self.type == other.type and not bool(self.expires ^ other.expires) 61 62 def __hash__(self): 63 return self.expires 64 65 def to_json(self): 66 return '%s%s%s' % (self.JSON_TYPE_CODE, self.JSON_SEPARATOR, self.expires) 67 68 @classmethod 69 def from_json_param(cls, expirity_time): 70 ret = TimeRestriction(0) 71 ret.set_expirity_time(expirity_time) 72 return ret 73 74 75 76 class AmountRestriction (Restriction): 77 JSON_TYPE_CODE = 'a' 78 79 def __init__(self, amount): 80 assert int(amount) >= 0 81 Restriction.__init__(self, 'amount') 82 self.can_be_shown = int(amount) 83 84 def on_display (self): 85 self.can_be_shown -= 1 86 87 def is_expired(self): 88 return int(self.can_be_shown) <= 0 89 90 def __eq__(self, other): 91 return self.type == other.type and not bool(self.can_be_shown ^ other.can_be_shown) 92 93 94 def __hash__(self): 95 return self.can_be_shown 96 97 def to_json(self): 98 return '%s%s%s' % (self.JSON_TYPE_CODE, self.JSON_SEPARATOR, self.can_be_shown) 99 100 @classmethod 101 def from_json_param(cls, amount): 102 return AmountRestriction(amount) -
django/contrib/messages/api.py
12 12 pass 13 13 14 14 15 def add_message(request, level, message, extra_tags='', fail_silently=False ):15 def add_message(request, level, message, extra_tags='', fail_silently=False, restrictions=[]): 16 16 """ 17 17 Attempts to add a message to the request using the 'messages' app. 18 18 """ 19 19 if hasattr(request, '_messages'): 20 return request._messages.add(level, message, extra_tags )20 return request._messages.add(level, message, extra_tags, restrictions = restrictions) 21 21 if not fail_silently: 22 22 raise MessageFailure('You cannot add messages without installing ' 23 23 'django.contrib.messages.middleware.MessageMiddleware') -
django/contrib/messages/tests/restrictions.py
1 from django.test import TestCase 2 from django.contrib.messages import restrictions 3 from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction 4 from django.contrib.messages.tests.time_provider import TestTimeProvider 5 6 restrictions.time_provider = TestTimeProvider () 7 8 class 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)) -
django/contrib/messages/tests/time_provider.py
1 class 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 -
django/contrib/messages/tests/cookie.py
1 1 from django.contrib.messages import constants 2 2 from django.contrib.messages.tests.base import BaseTest 3 from django.contrib.messages.tests.time_provider import TestTimeProvider 4 from django.contrib.messages import restrictions 5 from django.contrib.messages.restrictions import TimeRestriction, AmountRestriction 3 6 from django.contrib.messages.storage.cookie import (CookieStorage, 4 7 MessageEncoder, MessageDecoder) 5 8 from django.contrib.messages.storage.base import Message … … 56 59 def test_get(self): 57 60 storage = self.storage_class(self.get_request()) 58 61 # 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),])] 60 65 set_cookie_data(storage, example_messages) 61 66 # Test that the message actually contains what we expect. 62 self.assertEqual(list(storage), ex ample_messages)67 self.assertEqual(list(storage), expected_messages) 63 68 64 69 def test_domain(self): 65 70 """ … … 126 131 instances is properly encoded/decoded by the custom JSON 127 132 encoder/decoder classes. 128 133 """ 134 restrictions.time_provider = TestTimeProvider() 135 restrictions.time_provider.set_act_time(0) 129 136 messages = [ 130 137 { 131 138 '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)]) \ 133 141 for x in xrange(5)] + [{'another-message': \ 134 142 Message(constants.ERROR, 'error')}], 135 143 }, … … 139 147 value = encoder.encode(messages) 140 148 decoded_messages = json.loads(value, cls=MessageDecoder) 141 149 self.assertEqual(messages, decoded_messages) 150 151 def transport_storage(self, response, request): 152 request.COOKIES['messages'] = response.cookies['messages'].value -
django/contrib/messages/tests/base.py
3 3 from django.conf import settings 4 4 from django.utils.translation import ugettext_lazy 5 5 from django.utils.unittest import skipIf 6 from django.contrib.messages import constants, utils, get_level, set_level 6 from django.contrib.messages import constants, utils, get_level, set_level, restrictions 7 7 from django.contrib.messages.api import MessageFailure 8 from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction 8 9 from django.contrib.messages.storage import default_storage, base 9 10 from django.contrib.messages.storage.base import Message 11 from django.contrib.messages.tests.time_provider import TestTimeProvider 10 12 from django.core.urlresolvers import reverse 11 13 14 restrictions.time_provider = TestTimeProvider() 12 15 13 16 def skipUnlessAuthIsInstalled(func): 14 17 return skipIf( … … 95 98 storage._loaded_data = data or [] 96 99 return storage 97 100 101 def read_storage(self, storage): 102 """ 103 Simulates reading all messages from given storage 104 Returns list of read messages 105 """ 106 return list(storage) 107 98 108 def test_add(self): 99 109 storage = self.get_storage() 100 110 self.assertFalse(storage.added_new) … … 170 180 response = self.client.post(add_url, data, follow=True) 171 181 self.assertRedirects(response, show_url) 172 182 self.assertTrue('messages' in response.context) 173 messages = [Message(self.levels[level], msg ) for msg in183 messages = [Message(self.levels[level], msg, restrictions = [AmountRestriction(0),]) for msg in 174 184 data['messages']] 175 185 self.assertEqual(list(response.context['messages']), messages) 176 186 for msg in data['messages']: … … 203 213 """ 204 214 settings.MESSAGE_LEVEL = constants.DEBUG 205 215 data = { 206 'messages': [' Test message%d' % x for x in xrange(10)],216 'messages': ['%d' % x for x in xrange(10)], 207 217 } 208 218 show_url = reverse('django.contrib.messages.tests.urls.show') 209 219 messages = [] … … 214 224 args=(level,)) 215 225 self.client.post(add_url, data) 216 226 response = self.client.get(show_url) 227 new_messages = [] 228 for level in ('debug', 'info', 'success', 'warning', 'error'): 229 new_messages.extend([Message(self.levels[level], msg, \ 230 restrictions = [AmountRestriction(0),]) for msg in data['messages']]) 217 231 self.assertTrue('messages' in response.context) 218 self.assertEqual(list(response.context['messages']), messages)232 self.assertEqual(list(response.context['messages']), new_messages) 219 233 for msg in data['messages']: 220 234 self.assertContains(response, msg) 221 235 … … 392 406 # Ensure the level tags constant is put back like we found it. 393 407 self.restore_setting('MESSAGE_TAGS') 394 408 base.LEVEL_TAGS = utils.get_level_tags() 409 410 def test_storing_restrictoins(self): 411 storage = self.get_storage() 412 response = self.get_response() 413 414 get_res = lambda ar1, ar2, tr1, tr2: [AmountRestriction(ar1), AmountRestriction(ar2), TimeRestriction(tr1), TimeRestriction(tr2)] 415 416 restrictions.time_provider.set_act_time(0) 417 storage.add(constants.WARNING, 'First msg', restrictions = get_res(10, 20, 30, 40)) 418 messages = self.__read_messages(storage, response) 419 self.assertEqual(len(messages), 1) 420 rest = messages[0].restrictions 421 for a in (9, 19): 422 self.assertTrue(a in [r.can_be_shown for r in rest if r.type == 'amount']) 423 for t in (30, 40): 424 self.assertTrue(t in [r.expires for r in rest if r.type == 'time']) 425 426 restrictions.time_provider.set_act_time(4) 427 storage = self.get_storage() 428 response = self.get_response() 429 storage.add(constants.WARNING, 'First msg', restrictions = get_res(10, 20, 30, 40)) 430 messages = self.__read_messages(storage, response) 431 rest = messages[0].restrictions 432 for a in (9, 19): 433 self.assertTrue(a in [r.can_be_shown for r in rest if r.type == 'amount']) 434 for t in (34, 44): 435 self.assertTrue(t in [r.expires for r in rest if r.type == 'time']) 436 437 def test_expire_default(self): 438 """ 439 Tests against message expiration in default behaviour (no explicity defined restrictions on expire -> show only once) 440 """ 441 storage = self.get_existing_storage() 442 response = self.get_response() 443 444 list (storage) 445 storage.update(response) 446 447 storing = self.stored_messages_count(storage, response) 448 self.assertEqual(storing, 0) 449 450 def test_expire_after_showing_given_amount_of_times(self): 451 """ 452 Tests against expiring message after beeing shown given amount of times 453 """ 454 storage = self.get_existing_storage() 455 response = self.get_response() 456 457 read_messages = lambda: self.__read_messages(storage, response) 458 459 storage.add(constants.WARNING, 'Third message, should be shown four times', restrictions = [AmountRestriction(4),]) 460 storage.add(constants.ERROR, "Four'th message, should be shown five times", restrictions = [AmountRestriction(5),]) 461 462 463 messages = read_messages () 464 self.assertEqual(len(messages), 4) 465 storing = self.stored_messages_count(storage, response) 466 self.assertEqual(storing, 2) 467 468 469 for i in range(2): 470 messages = read_messages () 471 self.assertEqual(len(messages), 2) 472 storing = self.stored_messages_count(storage, response) 473 self.assertEqual(storing, 2) 474 [self.assertTrue(level in [x.level for x in messages]) for level in (constants.ERROR, constants.WARNING)] 475 476 477 messages = read_messages () 478 self.assertEqual(len(messages), 2) 479 storing = self.stored_messages_count(storage, response) 480 self.assertEqual(storing, 1) 481 482 483 messages = read_messages() 484 self.assertEqual(len(messages), 1) 485 self.assertEqual(messages[0].level, constants.ERROR) 486 storing = self.stored_messages_count(storage, response) 487 self.assertEqual(storing, 0) 488 489 490 messages = read_messages() 491 self.assertEqual(len(messages), 0) 492 storing = self.stored_messages_count(storage, response) 493 self.assertEqual(storing, 0) 494 495 def test_expire_after_time(self): 496 storage = self.get_storage() 497 response = self.get_response() 498 res = restrictions 499 res.time_provider.set_act_time(0) 500 501 storage.add(constants.WARNING, 'Third message, should be shown four times', restrictions = [TimeRestriction(4),]) 502 storage.add(constants.ERROR, "Four'th message, should be shown five times", restrictions = [TimeRestriction(6),]) 503 504 for i in range(10): 505 messages = self.__read_messages(storage, response) 506 self.assertEqual(len(messages), 2) 507 storing = self.stored_messages_count(storage, response) 508 self.assertEqual(storing, 2) 509 510 res.time_provider.set_act_time(5) 511 messages = self.__read_messages(storage, response) 512 self.assertEqual(len(messages), 1) 513 self.assertEqual(messages[0].level, constants.ERROR) 514 storing = self.stored_messages_count(storage, response) 515 self.assertEqual(storing, 1) 516 517 res.time_provider.set_act_time(7) 518 messages = self.__read_messages(storage, response) 519 self.assertEqual(len(messages), 0) 520 storing = self.stored_messages_count(storage, response) 521 self.assertEqual(storing, 0) 522 523 def test_expire_fixed_restrictions(self): 524 """ 525 Check message expirity when defining few sort of restrictions 526 of different kind 527 """ 528 get_storage_and_response = lambda: (self.get_storage(), self.get_response()) 529 storage, response = get_storage_and_response() 530 get_res = lambda ar1, ar2, tr1, tr2: [AmountRestriction(ar1), AmountRestriction(ar2), TimeRestriction(tr1), TimeRestriction(tr2)] 531 532 533 def check_storage(storage, iterations, expected_amount, fnct = None): 534 """ 535 Checks whether given storage would contain expected_amount of messages before each of iterations iterations 536 Performs iterations amount of iterations 537 Calls fnct at the end of each iteration 538 """ 539 for i in range(iterations): #read 2 times 540 messages = self.__read_messages(storage, response) 541 self.assertEqual(len(messages), expected_amount) 542 storing = self.stored_messages_count(storage, response) 543 self.assertEqual(storing, expected_amount) 544 if fnct: fnct() 545 546 # first - expires after amount of showing 547 restrictions.time_provider.set_act_time(0) 548 storage.add(constants.ERROR, "Some message", restrictions = get_res(7, 30, 5, 20)) 549 storage.add(constants.INFO, "another message", restrictions = get_res(3, 10, 4, 11)) 550 check_storage(storage, 2, 2) 551 messages = self.__read_messages(storage, response) # 3 times read 552 self.assertEqual(len(messages), 2) 553 storing = self.stored_messages_count(storage, response) 554 self.assertEqual(storing, 1) 555 check_storage(storage, 3, 1) 556 557 558 storage, response = get_storage_and_response() 559 restrictions.time_provider.set_act_time(0) 560 storage.add(constants.ERROR, "Some message", restrictions = get_res(7, 30, 5, 20)) 561 storage.add(constants.INFO, "another message", restrictions = get_res(3, 10, 4, 11)) 562 restrictions.time_provider.set_act_time(2) 563 check_storage(storage, 2, 2, lambda:restrictions.time_provider.set_act_time(3)) 564 565 # second - expires after amount of time 566 storage, response = get_storage_and_response() 567 restrictions.time_provider.set_act_time(0) 568 storage.add(constants.ERROR, "Some message", restrictions = get_res(10, 30, 5, 20)) 569 storage.add(constants.INFO, "another message", restrictions = get_res(10, 20, 3, 11)) 570 check_storage(storage, 2, 2) 571 restrictions.time_provider.set_act_time(2) 572 check_storage(storage, 2, 2) 573 restrictions.time_provider.set_act_time(4) 574 check_storage(storage, 2, 1) 575 576 def transport_storage(self, response, request): 577 """ 578 Transports storage from response to request 579 This method can be overriden by subclasses 580 """ 581 582 def __read_messages(self, storage, response):#simulate next call to render messages 583 """ 584 Simulates iterating storage in template 585 Returns messages from that iteration that would be returned 586 """ 587 messages = self.read_storage(storage) 588 storage.update(response) 589 self.transport_storage (response, storage.request) 590 storage.used = False 591 storage._queued_messages = [] 592 del storage._loaded_data 593 return messages -
django/contrib/messages/tests/__init__.py
2 2 from django.contrib.messages.tests.fallback import FallbackTest 3 3 from django.contrib.messages.tests.middleware import MiddlewareTest 4 4 from django.contrib.messages.tests.session import SessionTest 5 from django.contrib.messages.tests.restrictions import RestrictionsTest 6 from django.contrib.messages.tests.message import MessageTest -
django/contrib/messages/tests/fallback.py
1 1 from django.contrib.messages import constants 2 from django.contrib.messages.storage.base import Message 3 from django.contrib.messages.restrictions import AmountRestriction 2 4 from django.contrib.messages.storage.fallback import (FallbackStorage, 3 5 CookieStorage) 4 6 from django.contrib.messages.tests.base import BaseTest … … 44 46 cookie_storage = self.get_cookie_storage(storage) 45 47 46 48 # 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)] 48 51 set_cookie_data(cookie_storage, example_messages) 49 52 50 53 # Overwrite the _get method of the fallback storage to prove it is not … … 52 55 self.get_session_storage(storage)._get = None 53 56 54 57 # Test that the message actually contains what we expect. 55 self.assertEqual(list(storage), ex ample_messages)58 self.assertEqual(list(storage), expected_messages) 56 59 57 60 def test_get_empty(self): 58 61 request = self.get_request() … … 72 75 session_storage = self.get_session_storage(storage) 73 76 74 77 # 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)] 76 80 set_cookie_data(cookie_storage, example_messages[:4] + 77 81 [CookieStorage.not_finished]) 78 82 set_session_data(session_storage, example_messages[4:]) 79 83 80 84 # Test that the message actually contains what we expect. 81 self.assertEqual(list(storage), ex ample_messages)85 self.assertEqual(list(storage), expected_messages) 82 86 83 87 def test_get_fallback_only(self): 84 88 request = self.get_request() … … 87 91 session_storage = self.get_session_storage(storage) 88 92 89 93 # 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)] 91 95 set_cookie_data(cookie_storage, [CookieStorage.not_finished], 92 96 encode_empty=True) 93 97 set_session_data(session_storage, example_messages) … … 102 106 session_storage = self.get_session_storage(storage) 103 107 104 108 # 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')]) 107 111 108 112 # When updating, previously used but no longer needed backends are 109 113 # flushed. … … 173 177 self.assertEqual(cookie_storing, 0) 174 178 session_storing = self.stored_session_messages_count(storage, response) 175 179 self.assertEqual(session_storing, 1) 180 181 def transport_storage(self, response, request): 182 request.COOKIES['messages'] = response.cookies['messages'].value -
django/contrib/messages/tests/session.py
1 1 from django.contrib.messages.tests.base import BaseTest 2 2 from django.contrib.messages.storage.session import SessionStorage 3 from django.contrib.messages.storage.base import Message 3 4 4 5 5 6 def set_session_data(storage, messages): … … 32 33 def test_get(self): 33 34 storage = self.storage_class(self.get_request()) 34 35 # Set initial data. 35 example_messages = [ 'test', 'me']36 example_messages = [Message(1, 'test') , Message(1, 'me')] 36 37 set_session_data(storage, example_messages) 37 38 # Test that the message actually contains what we expect. 38 39 self.assertEqual(list(storage), example_messages) -
django/contrib/messages/tests/message.py
1 from django.test import TestCase 2 from django.contrib.messages.storage.base import Message 3 from django.contrib.messages import restrictions 4 from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction, time_provider 5 from django.contrib.messages.tests.time_provider import TestTimeProvider 6 from django.contrib.messages import constants 7 8 9 class 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() -
django/contrib/messages/storage/cookie.py
1 1 from django.conf import settings 2 from django.contrib.messages.storage.base import BaseStorage, Message 2 from django.contrib.messages.storage.base import BaseStorage, Message, RestrictionsContainer 3 3 from django.http import SimpleCookie 4 4 from django.utils import simplejson as json 5 5 from django.utils.crypto import salted_hmac, constant_time_compare 6 from django.contrib.messages.restrictions import AmountRestriction, TimeRestriction 6 7 7 8 8 9 class MessageEncoder(json.JSONEncoder): … … 11 12 """ 12 13 message_key = '__json_message' 13 14 15 14 16 def default(self, obj): 15 17 if isinstance(obj, Message): 16 18 message = [self.message_key, obj.level, obj.message] 17 19 if obj.extra_tags: 18 20 message.append(obj.extra_tags) 21 message.append (obj.restrictions.to_json_obj()) 19 22 return message 20 23 return super(MessageEncoder, self).default(obj) 21 24 … … 25 28 Decodes JSON that includes serialized ``Message`` instances. 26 29 """ 27 30 31 32 def create_message(self, vars): 33 ''' creates message on the basis of encoded data ''' 34 args = vars[:-1] 35 restrictions = vars[-1] 36 restrictions = RestrictionsContainer.create_from_josn(restrictions) 37 return Message(*args, **{'restrictions': restrictions}) 38 28 39 def process_messages(self, obj): 29 40 if isinstance(obj, list) and obj: 30 41 if obj[0] == MessageEncoder.message_key: 31 return Message(*obj[1:])42 return self.create_message (obj[1:]) 32 43 return [self.process_messages(item) for item in obj] 33 44 if isinstance(obj, dict): 34 45 return dict([(key, self.process_messages(value)) -
django/contrib/messages/storage/base.py
1 1 from django.conf import settings 2 2 from django.utils.encoding import force_unicode, StrAndUnicode 3 from django.contrib.messages import constants, utils 3 from django.contrib.messages import constants, utils, restrictions as res 4 4 5 5 6 6 LEVEL_TAGS = utils.get_level_tags() 7 7 8 8 9 class RestrictionsContainer(list): 10 res_map = {res.AmountRestriction.JSON_TYPE_CODE: res.AmountRestriction, 11 res.TimeRestriction.JSON_TYPE_CODE: res.TimeRestriction} 12 13 def to_json_obj(self): 14 return [r.to_json() for r in self] 15 16 @classmethod 17 def create_from_josn(cls, enc_restrictions): 18 #set_trace() 19 ret = [] 20 for r in enc_restrictions: 21 restriction_type, values = r.split(res.Restriction.JSON_SEPARATOR) 22 ret.append(cls.res_map[restriction_type].from_json_param(values)) 23 return RestrictionsContainer(ret) 24 25 def __eq__(self, other): 26 return set(self) == set(other) 27 9 28 class Message(StrAndUnicode): 10 29 """ 11 30 Represents an actual message that can be stored in any of the supported … … 13 32 or template. 14 33 """ 15 34 16 def __init__(self, level, message, extra_tags=None ):35 def __init__(self, level, message, extra_tags=None, restrictions = []): 17 36 self.level = int(level) 18 37 self.message = message 19 38 self.extra_tags = extra_tags 20 39 21 def _prepare(self): 40 self.restrictions = restrictions or list([res.AmountRestriction(1)]) 41 self.restrictions = RestrictionsContainer(self.restrictions) 42 # if not given any restriction - one show by default 43 44 def _prepare(self): # todo: slef.restrictions = 22 45 """ 23 46 Prepares the message for serialization by forcing the ``message`` 24 47 and ``extra_tags`` to unicode in case they are lazy translations. … … 31 54 32 55 def __eq__(self, other): 33 56 return isinstance(other, Message) and self.level == other.level and \ 34 self.message == other.message 57 self.message == other.message and \ 58 self.restrictions == other.restrictions 35 59 36 60 def __unicode__(self): 37 61 return force_unicode(self.message) 38 62 63 39 64 def _get_tags(self): 40 65 label_tag = force_unicode(LEVEL_TAGS.get(self.level, ''), 41 66 strings_only=True) … … 50 75 tags = property(_get_tags) 51 76 52 77 78 def active (self): 79 for r in self.restrictions: 80 if r.is_expired(): return False 81 return True 82 83 84 def on_display (self): 85 for r in self.restrictions: 86 r.on_display () 87 88 53 89 class BaseStorage(object): 54 90 """ 55 91 This is the base backend for temporary message storage. … … 60 96 61 97 def __init__(self, request, *args, **kwargs): 62 98 self.request = request 99 self.used = False 63 100 self._queued_messages = [] 64 self.used = False65 101 self.added_new = False 66 102 super(BaseStorage, self).__init__(*args, **kwargs) 67 103 68 104 def __len__(self): 69 return len(self._loaded_messages) + len(self._queued_messages) 105 # in case that there was a call for render template which would cause iterating throught messages, 106 # and then (e.g. in some middleware, would be call for iterating through messages (e.g. by iterating of context['messages']) 107 # TODO: implement a way to access messages without affecting callign __iter__ method 108 all_msgs = set(self._loaded_messages + self._queued_messages) 109 return len(all_msgs) 110 #return len(self._loaded_messages) + len(self._queued_messages) 70 111 71 112 def __iter__(self): 72 self.used = True73 if self._queued_messages:74 self._loaded_messages.extend(self._queued_messages)75 self._queued_messages = []76 return iter(self._loaded_messages)113 if not self.used: 114 self.used = True 115 if self._queued_messages: 116 self._loaded_messages.extend(self._queued_messages) 117 self._queued_messages = [] 77 118 119 active_messages = [x for x in self._loaded_messages if x.active ()] 120 for x in active_messages: 121 x.on_display () 122 self._queued_messages.extend (m for m in active_messages if m not in self._queued_messages) 123 return iter(self._queued_messages) 124 125 78 126 def __contains__(self, item): 79 127 return item in self._loaded_messages or item in self._queued_messages 80 128 … … 104 152 """ 105 153 raise NotImplementedError() 106 154 155 def filter_store(self, messages, response, *args, **kwargs): 156 ''' stores only active messages from given messages in storage ''' 157 filtered_messages = [x for x in messages if x.active ()] 158 return self._store(filtered_messages, response, *args, **kwargs) 159 160 107 161 def _store(self, messages, response, *args, **kwargs): 108 162 """ 109 163 Stores a list of messages, returning a list of any messages which could … … 130 184 be stored again. Otherwise, only messages added after the last 131 185 iteration will be stored. 132 186 """ 187 # if used or used and added, then _queued_messages contains all messages that should be saved 188 # if added, then save: all messages currently stored and added ones 133 189 self._prepare_messages(self._queued_messages) 134 190 if self.used: 135 return self. _store(self._queued_messages, response)191 return self.filter_store(self._queued_messages, response) 136 192 elif self.added_new: 137 193 messages = self._loaded_messages + self._queued_messages 138 return self. _store(messages, response)194 return self.filter_store(messages, response) 139 195 140 def add(self, level, message, extra_tags='' ):196 def add(self, level, message, extra_tags='', restrictions = []): 141 197 """ 142 198 Queues a message to be stored. 143 199 … … 152 208 return 153 209 # Add the message. 154 210 self.added_new = True 155 message = Message(level, message, extra_tags=extra_tags )211 message = Message(level, message, extra_tags=extra_tags, restrictions = restrictions) 156 212 self._queued_messages.append(message) 157 213 158 214 def _get_level(self):