test_readtracker.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. from datetime import timedelta
  2. from django.contrib.auth import get_user_model
  3. from django.test import TestCase
  4. from django.utils import timezone
  5. from misago.acl import add_acl
  6. from misago.categories.models import Category
  7. from misago.threads import testutils
  8. from misago.users.models import AnonymousUser
  9. from misago.readtracker import categoriestracker, threadstracker
  10. class ReadTrackerTests(TestCase):
  11. def setUp(self):
  12. self.categories = list(Category.objects.all_categories()[:1])
  13. self.category = self.categories[0]
  14. User = get_user_model()
  15. self.user = User.objects.create_user("Bob", "bob@test.com", "Pass.123")
  16. self.anon = AnonymousUser()
  17. def post_thread(self, datetime):
  18. return testutils.post_thread(
  19. category=self.category,
  20. started_on=datetime
  21. )
  22. class CategorysTrackerTests(ReadTrackerTests):
  23. def test_anon_empty_category_read(self):
  24. """anon users content is always read"""
  25. categoriestracker.make_read_aware(self.anon, self.categories)
  26. self.assertIsNone(self.category.last_post_on)
  27. self.assertTrue(self.category.is_read)
  28. def test_anon_category_with_recent_reply_read(self):
  29. """anon users content is always read"""
  30. categoriestracker.make_read_aware(self.anon, self.categories)
  31. self.category.last_post_on = timezone.now()
  32. self.assertTrue(self.category.is_read)
  33. def test_empty_category_is_read(self):
  34. """empty category is read for signed in user"""
  35. categoriestracker.make_read_aware(self.user, self.categories)
  36. self.assertTrue(self.category.is_read)
  37. def test_make_read_aware_sets_read_flag_for_empty_category(self):
  38. """make_read_aware sets read flag on empty category"""
  39. categoriestracker.make_read_aware(self.anon, self.categories)
  40. self.assertTrue(self.category.is_read)
  41. categoriestracker.make_read_aware(self.user, self.categories)
  42. self.assertTrue(self.category.is_read)
  43. def test_make_read_aware_sets_read_flag_for_category_with_old_thread(self):
  44. """make_read_aware sets read flag on category with old thread"""
  45. self.category.last_post_on = self.user.joined_on - timedelta(days=1)
  46. categoriestracker.make_read_aware(self.user, self.categories)
  47. self.assertTrue(self.category.is_read)
  48. def test_make_read_aware_sets_unread_flag_for_category_with_new_thread(self):
  49. """make_read_aware sets unread flag on category with new thread"""
  50. self.category.last_post_on = self.user.joined_on + timedelta(days=1)
  51. categoriestracker.make_read_aware(self.user, self.categories)
  52. self.assertFalse(self.category.is_read)
  53. def test_sync_record_for_empty_category(self):
  54. """sync_record sets read flag on empty category"""
  55. add_acl(self.user, self.categories)
  56. categoriestracker.sync_record(self.user, self.category)
  57. self.user.categoryread_set.get(category=self.category)
  58. categoriestracker.make_read_aware(self.user, self.categories)
  59. self.assertTrue(self.category.is_read)
  60. def test_sync_record_for_category_with_old_thread_and_reply(self):
  61. """
  62. sync_record sets read flag on category with old thread,
  63. then changes flag to unread when new reply is posted
  64. """
  65. self.post_thread(self.user.joined_on - timedelta(days=1))
  66. add_acl(self.user, self.categories)
  67. categoriestracker.sync_record(self.user, self.category)
  68. self.user.categoryread_set.get(category=self.category)
  69. categoriestracker.make_read_aware(self.user, self.categories)
  70. self.assertTrue(self.category.is_read)
  71. thread = self.post_thread(self.user.joined_on + timedelta(days=1))
  72. categoriestracker.sync_record(self.user, self.category)
  73. categoriestracker.make_read_aware(self.user, self.categories)
  74. self.assertFalse(self.category.is_read)
  75. def test_sync_record_for_category_with_new_thread(self):
  76. """
  77. sync_record sets read flag on category with old thread,
  78. then keeps flag to unread when new reply is posted
  79. """
  80. self.post_thread(self.user.joined_on + timedelta(days=1))
  81. add_acl(self.user, self.categories)
  82. categoriestracker.sync_record(self.user, self.category)
  83. self.user.categoryread_set.get(category=self.category)
  84. categoriestracker.make_read_aware(self.user, self.categories)
  85. self.assertFalse(self.category.is_read)
  86. self.post_thread(self.user.joined_on + timedelta(days=1))
  87. categoriestracker.sync_record(self.user, self.category)
  88. categoriestracker.make_read_aware(self.user, self.categories)
  89. self.assertFalse(self.category.is_read)
  90. def test_sync_record_for_category_with_deleted_threads(self):
  91. """unread category reverts to read after its emptied"""
  92. self.post_thread(self.user.joined_on + timedelta(days=1))
  93. self.post_thread(self.user.joined_on + timedelta(days=1))
  94. self.post_thread(self.user.joined_on + timedelta(days=1))
  95. add_acl(self.user, self.categories)
  96. categoriestracker.sync_record(self.user, self.category)
  97. categoriestracker.make_read_aware(self.user, self.categories)
  98. self.assertFalse(self.category.is_read)
  99. self.category.thread_set.all().delete()
  100. self.category.synchronize()
  101. self.category.save()
  102. categoriestracker.make_read_aware(self.user, self.categories)
  103. self.assertTrue(self.category.is_read)
  104. def test_sync_record_for_category_with_many_threads(self):
  105. """sync_record sets unread flag on category with many threads"""
  106. self.post_thread(self.user.joined_on + timedelta(days=1))
  107. self.post_thread(self.user.joined_on - timedelta(days=1))
  108. self.post_thread(self.user.joined_on + timedelta(days=1))
  109. self.post_thread(self.user.joined_on - timedelta(days=1))
  110. add_acl(self.user, self.categories)
  111. categoriestracker.sync_record(self.user, self.category)
  112. self.user.categoryread_set.get(category=self.category)
  113. categoriestracker.make_read_aware(self.user, self.categories)
  114. self.assertFalse(self.category.is_read)
  115. self.post_thread(self.user.joined_on + timedelta(days=1))
  116. categoriestracker.sync_record(self.user, self.category)
  117. categoriestracker.make_read_aware(self.user, self.categories)
  118. self.assertFalse(self.category.is_read)
  119. def test_read_leaf_category(self):
  120. """read_category reads leaf category for user"""
  121. categoriestracker.read_category(self.user, self.category)
  122. self.assertTrue(self.user.categoryread_set.get(category=self.category))
  123. def test_read_root_category(self):
  124. """read_category reads category and its subcategories for user"""
  125. root_category = Category.objects.root_category()
  126. categoriestracker.read_category(self.user, root_category)
  127. root_read = self.user.categoryread_set.get(category=root_category)
  128. child_read = self.user.categoryread_set.get(category=self.category)
  129. self.assertEqual(root_read.last_read_on, child_read.last_read_on)
  130. class ThreadsTrackerTests(ReadTrackerTests):
  131. def setUp(self):
  132. super(ThreadsTrackerTests, self).setUp()
  133. self.thread = self.post_thread(timezone.now() - timedelta(days=10))
  134. def reply_thread(self, is_hidden=False, is_moderated=False):
  135. self.post = testutils.reply_thread(
  136. thread=self.thread,
  137. is_hidden=is_hidden,
  138. is_moderated=is_moderated,
  139. posted_on=timezone.now())
  140. return self.post
  141. def test_thread_read_for_guest(self):
  142. """threads are always read for guests"""
  143. threadstracker.make_read_aware(self.anon, self.thread)
  144. self.assertTrue(self.thread.is_read)
  145. self.reply_thread()
  146. threadstracker.make_read_aware(self.anon, [self.thread])
  147. self.assertTrue(self.thread.is_read)
  148. def test_thread_read_for_user(self):
  149. """thread is read for user"""
  150. threadstracker.make_read_aware(self.user, self.thread)
  151. self.assertTrue(self.thread.is_read)
  152. def test_thread_replied_unread_for_user(self):
  153. """replied thread is unread for user"""
  154. self.reply_thread(self.thread)
  155. threadstracker.make_read_aware(self.user, self.thread)
  156. self.assertFalse(self.thread.is_read)
  157. def _test_thread_read(self):
  158. """thread read flag is set for user, then its set as unread by reply"""
  159. self.reply_thread(self.thread)
  160. add_acl(self.user, self.categories)
  161. threadstracker.make_read_aware(self.user, self.thread)
  162. self.assertFalse(self.thread.is_read)
  163. threadstracker.read_thread(self.user, self.thread, self.post)
  164. threadstracker.make_read_aware(self.user, self.thread)
  165. self.assertTrue(self.thread.is_read)
  166. categoriestracker.make_read_aware(self.user, self.categories)
  167. self.assertTrue(self.category.is_read)
  168. self.thread.last_post_on = timezone.now()
  169. self.thread.save()
  170. self.category.synchronize()
  171. self.category.save()
  172. self.reply_thread()
  173. threadstracker.make_read_aware(self.user, self.thread)
  174. self.assertFalse(self.thread.is_read)
  175. categoriestracker.make_read_aware(self.user, self.categories)
  176. self.assertFalse(self.category.is_read)
  177. posts = [post for post in self.thread.post_set.order_by('id')]
  178. threadstracker.make_posts_read_aware(self.user, self.thread, posts)
  179. for post in posts[:-1]:
  180. self.assertTrue(post.is_read)
  181. self.assertFalse(posts[-1].is_read)