test_gotoviews.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. from django.utils import timezone
  2. from misago.acl.testutils import override_acl
  3. from misago.categories.models import Category
  4. from misago.conf import settings
  5. from misago.readtracker.poststracker import save_read
  6. from misago.threads import testutils
  7. from misago.users.testutils import AuthenticatedUserTestCase
  8. GOTO_URL = '%s#post-%s'
  9. GOTO_PAGE_URL = '%s%s/#post-%s'
  10. class GotoViewTestCase(AuthenticatedUserTestCase):
  11. def setUp(self):
  12. super().setUp()
  13. self.category = Category.objects.get(slug='first-category')
  14. self.thread = testutils.post_thread(category=self.category)
  15. class GotoPostTests(GotoViewTestCase):
  16. def test_goto_first_post(self):
  17. """first post redirect url is valid"""
  18. response = self.client.get(self.thread.first_post.get_absolute_url())
  19. self.assertEqual(response.status_code, 302)
  20. self.assertEqual(
  21. response['location'],
  22. GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id)
  23. )
  24. response = self.client.get(response['location'])
  25. self.assertContains(response, self.thread.first_post.get_absolute_url())
  26. def test_goto_last_post_on_page(self):
  27. """last post on page redirect url is valid"""
  28. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
  29. post = testutils.reply_thread(self.thread)
  30. response = self.client.get(post.get_absolute_url())
  31. self.assertEqual(response.status_code, 302)
  32. self.assertEqual(
  33. response['location'], GOTO_URL % (self.thread.get_absolute_url(), post.pk)
  34. )
  35. response = self.client.get(response['location'])
  36. self.assertContains(response, post.get_absolute_url())
  37. def test_goto_first_post_on_next_page(self):
  38. """first post on next page redirect url is valid"""
  39. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
  40. post = testutils.reply_thread(self.thread)
  41. response = self.client.get(post.get_absolute_url())
  42. self.assertEqual(response.status_code, 302)
  43. self.assertEqual(
  44. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk)
  45. )
  46. response = self.client.get(response['location'])
  47. self.assertContains(response, post.get_absolute_url())
  48. def test_goto_first_post_on_page_three_out_of_five(self):
  49. """first post on next page redirect url is valid"""
  50. posts = []
  51. for _ in range(settings.MISAGO_POSTS_PER_PAGE * 4 - 1):
  52. post = testutils.reply_thread(self.thread)
  53. posts.append(post)
  54. post = posts[settings.MISAGO_POSTS_PER_PAGE * 2 - 3]
  55. response = self.client.get(post.get_absolute_url())
  56. self.assertEqual(response.status_code, 302)
  57. self.assertEqual(
  58. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 3, post.pk)
  59. )
  60. response = self.client.get(response['location'])
  61. self.assertContains(response, post.get_absolute_url())
  62. def test_goto_first_event_on_page_three_out_of_five(self):
  63. """event redirect url is valid"""
  64. posts = []
  65. for _ in range(settings.MISAGO_POSTS_PER_PAGE * 4 - 1):
  66. post = testutils.reply_thread(self.thread)
  67. posts.append(post)
  68. post = posts[settings.MISAGO_POSTS_PER_PAGE * 2 - 2]
  69. self.thread.has_events = True
  70. self.thread.save()
  71. post.is_event = True
  72. post.save()
  73. response = self.client.get(post.get_absolute_url())
  74. self.assertEqual(response.status_code, 302)
  75. self.assertEqual(
  76. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 3, post.pk)
  77. )
  78. response = self.client.get(response['location'])
  79. self.assertContains(response, post.get_absolute_url())
  80. class GotoLastTests(GotoViewTestCase):
  81. def test_goto_last_post(self):
  82. """first post redirect url is valid"""
  83. response = self.client.get(self.thread.get_last_post_url())
  84. self.assertEqual(response.status_code, 302)
  85. self.assertEqual(
  86. response['location'],
  87. GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id)
  88. )
  89. response = self.client.get(response['location'])
  90. self.assertContains(response, self.thread.last_post.get_absolute_url())
  91. def test_goto_last_post_on_page(self):
  92. """last post on page redirect url is valid"""
  93. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
  94. post = testutils.reply_thread(self.thread)
  95. response = self.client.get(self.thread.get_last_post_url())
  96. self.assertEqual(response.status_code, 302)
  97. self.assertEqual(
  98. response['location'], GOTO_URL % (self.thread.get_absolute_url(), post.pk)
  99. )
  100. response = self.client.get(response['location'])
  101. self.assertContains(response, post.get_absolute_url())
  102. class GotoNewTests(GotoViewTestCase):
  103. def test_goto_first_post(self):
  104. """first unread post redirect url is valid"""
  105. response = self.client.get(self.thread.get_new_post_url())
  106. self.assertEqual(response.status_code, 302)
  107. self.assertEqual(
  108. response['location'],
  109. GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id)
  110. )
  111. def test_goto_first_new_post(self):
  112. """first unread post redirect url in already read thread is valid"""
  113. save_read(self.user, self.thread.first_post)
  114. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  115. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
  116. testutils.reply_thread(self.thread, posted_on=timezone.now())
  117. response = self.client.get(self.thread.get_new_post_url())
  118. self.assertEqual(response.status_code, 302)
  119. self.assertEqual(
  120. response['location'], GOTO_URL % (self.thread.get_absolute_url(), post.pk)
  121. )
  122. def test_goto_first_new_post_on_next_page(self):
  123. """first unread post redirect url in already read multipage thread is valid"""
  124. save_read(self.user, self.thread.first_post)
  125. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
  126. last_post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  127. save_read(self.user, last_post)
  128. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  129. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
  130. testutils.reply_thread(self.thread, posted_on=timezone.now())
  131. response = self.client.get(self.thread.get_new_post_url())
  132. self.assertEqual(response.status_code, 302)
  133. self.assertEqual(
  134. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk)
  135. )
  136. def test_goto_first_new_post_in_read_thread(self):
  137. """goto new in read thread points to last post"""
  138. save_read(self.user, self.thread.first_post)
  139. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
  140. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  141. save_read(self.user, post)
  142. response = self.client.get(self.thread.get_new_post_url())
  143. self.assertEqual(response.status_code, 302)
  144. self.assertEqual(
  145. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk)
  146. )
  147. def test_guest_goto_first_new_post_in_thread(self):
  148. """guest goto new in read thread points to last post"""
  149. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
  150. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  151. self.logout_user()
  152. response = self.client.get(self.thread.get_new_post_url())
  153. self.assertEqual(response.status_code, 302)
  154. self.assertEqual(
  155. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk)
  156. )
  157. class GotoBestAnswerTests(GotoViewTestCase):
  158. def test_view_handles_no_best_answer(self):
  159. """if thread has no best answer, redirect to first post"""
  160. response = self.client.get(self.thread.get_best_answer_url())
  161. self.assertEqual(response.status_code, 302)
  162. self.assertEqual(
  163. response['location'],
  164. GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id),
  165. )
  166. def test_view_handles_best_answer(self):
  167. """if thread has best answer, redirect to it"""
  168. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
  169. testutils.reply_thread(self.thread, posted_on=timezone.now())
  170. best_answer = testutils.reply_thread(self.thread, posted_on=timezone.now())
  171. self.thread.set_best_answer(self.user, best_answer)
  172. self.thread.save()
  173. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
  174. testutils.reply_thread(self.thread, posted_on=timezone.now())
  175. response = self.client.get(self.thread.get_best_answer_url())
  176. self.assertEqual(response.status_code, 302)
  177. self.assertEqual(
  178. response['location'],
  179. GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, best_answer.pk),
  180. )
  181. class GotoUnapprovedTests(GotoViewTestCase):
  182. def grant_permission(self):
  183. self.user.acl_cache['categories'][self.category.pk]['can_approve_content'] = 1
  184. override_acl(self.user, self.user.acl_cache)
  185. def test_view_validates_permission(self):
  186. """view validates permission to see unapproved posts"""
  187. response = self.client.get(self.thread.get_unapproved_post_url())
  188. self.assertContains(response, "You need permission to approve content", status_code=403)
  189. self.grant_permission()
  190. response = self.client.get(self.thread.get_unapproved_post_url())
  191. self.assertEqual(response.status_code, 302)
  192. def test_view_handles_no_unapproved_posts(self):
  193. """if thread has no unapproved posts, redirect to last post"""
  194. self.grant_permission()
  195. response = self.client.get(self.thread.get_unapproved_post_url())
  196. self.assertEqual(response.status_code, 302)
  197. self.assertEqual(
  198. response['location'],
  199. GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id)
  200. )
  201. def test_view_handles_unapproved_posts(self):
  202. """if thread has unapproved posts, redirect to first of them"""
  203. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
  204. testutils.reply_thread(self.thread, posted_on=timezone.now())
  205. post = testutils.reply_thread(self.thread, is_unapproved=True, posted_on=timezone.now())
  206. for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
  207. testutils.reply_thread(self.thread, posted_on=timezone.now())
  208. self.grant_permission()
  209. response = self.client.get(self.thread.get_unapproved_post_url())
  210. self.assertEqual(response.status_code, 302)
  211. self.assertEqual(
  212. response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk)
  213. )
  214. class ThreadGotoPostTests(GotoViewTestCase):
  215. """brureforcing regression tests for regression test for #869"""
  216. def test_thread_growing_post_goto(self):
  217. """growing thread goto views don't fail"""
  218. for _ in range(60):
  219. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  220. # go to post link is valid
  221. post_url = self.client.get(post.get_absolute_url())['location']
  222. response = self.client.get(post_url)
  223. self.assertContains(response, post.get_absolute_url())
  224. # go to last post link is valid
  225. last_url = self.client.get(self.thread.get_last_post_url())['location']
  226. self.assertEqual(post_url, last_url)
  227. def test_thread_growing_event_goto(self):
  228. """growing thread goto views don't fail for events"""
  229. for i in range(60):
  230. testutils.reply_thread(self.thread, posted_on=timezone.now())
  231. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  232. post.is_event = True
  233. post.save()
  234. # go to post link is valid
  235. post_url = self.client.get(post.get_absolute_url())['location']
  236. if i == 0:
  237. # manually set events flag after first event was created
  238. self.thread.has_events = True
  239. self.thread.save()
  240. response = self.client.get(post_url)
  241. self.assertContains(response, post.get_absolute_url())
  242. # go to last post link is valid
  243. last_url = self.client.get(self.thread.get_last_post_url())['location']
  244. self.assertEqual(post_url, last_url)
  245. def test_thread_post_goto(self):
  246. """thread goto views don't fail"""
  247. for _ in range(60):
  248. testutils.reply_thread(self.thread, posted_on=timezone.now())
  249. for post in self.thread.post_set.order_by('id').iterator():
  250. # go to post link is valid
  251. post_url = self.client.get(post.get_absolute_url())['location']
  252. response = self.client.get(post_url)
  253. self.assertContains(response, post.get_absolute_url())
  254. # go to last post link is valid
  255. last_url = self.client.get(self.thread.get_last_post_url())['location']
  256. self.assertEqual(post_url, last_url)
  257. def test_thread_event_goto(self):
  258. """thread goto views don't fail for events"""
  259. for _ in range(60):
  260. testutils.reply_thread(self.thread, posted_on=timezone.now())
  261. post = testutils.reply_thread(self.thread, posted_on=timezone.now())
  262. post.is_event = True
  263. post.save()
  264. for post in self.thread.post_set.filter(is_event=True).order_by('id').iterator():
  265. # go to post link is valid
  266. post_url = self.client.get(post.get_absolute_url())['location']
  267. response = self.client.get(post_url)
  268. self.assertContains(response, post.get_absolute_url())
  269. # go to last post link is valid
  270. last_url = self.client.get(self.thread.get_last_post_url())['location']
  271. self.assertEqual(post_url, last_url)