test_gotoviews.py 14 KB

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