test_threads_api.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import json
  2. from django.utils.encoding import smart_str
  3. from misago.acl.testutils import override_acl
  4. from misago.categories.models import THREADS_ROOT_NAME, Category
  5. from misago.users.testutils import AuthenticatedUserTestCase
  6. from .. import testutils
  7. from ..models import Thread
  8. from ..threadtypes import trees_map
  9. class ThreadsApiTestCase(AuthenticatedUserTestCase):
  10. def setUp(self):
  11. super(ThreadsApiTestCase, self).setUp()
  12. threads_tree_id = trees_map.get_tree_id_for_root(THREADS_ROOT_NAME)
  13. self.root = Category.objects.get(tree_id=threads_tree_id, level=0)
  14. self.category = Category.objects.get(slug='first-category')
  15. self.thread = testutils.post_thread(category=self.category)
  16. self.api_link = self.thread.get_api_url()
  17. def override_acl(self, acl=None):
  18. final_acl = self.user.acl['categories'][self.category.pk]
  19. final_acl.update({
  20. 'can_see': 1,
  21. 'can_browse': 1,
  22. 'can_see_all_threads': 1,
  23. 'can_see_own_threads': 0,
  24. 'can_hide_threads': 0,
  25. 'can_approve_content': 0,
  26. 'can_edit_posts': 0,
  27. 'can_hide_posts': 0,
  28. 'can_hide_own_posts': 0,
  29. })
  30. if acl:
  31. final_acl.update(acl)
  32. override_acl(self.user, {
  33. 'categories': {
  34. self.category.pk: final_acl
  35. }
  36. })
  37. def get_thread_json(self):
  38. response = self.client.get(self.thread.get_api_url())
  39. self.assertEqual(response.status_code, 200)
  40. return json.loads(smart_str(response.content))
  41. class ThreadRetrieveApiTests(ThreadsApiTestCase):
  42. def setUp(self):
  43. super(ThreadRetrieveApiTests, self).setUp()
  44. self.tested_links = [
  45. self.api_link,
  46. '%sposts/' % self.api_link,
  47. '%sposts/?page=1' % self.api_link,
  48. ]
  49. def test_api_returns_thread(self):
  50. """api endpoint has no showstoppers"""
  51. for link in self.tested_links:
  52. self.override_acl()
  53. response = self.client.get(link)
  54. self.assertEqual(response.status_code, 200)
  55. response_json = json.loads(smart_str(response.content))
  56. self.assertEqual(response_json['id'], self.thread.pk)
  57. self.assertEqual(response_json['title'], self.thread.title)
  58. if 'posts' in link:
  59. self.assertIn('post_set', response_json)
  60. def test_api_shows_owner_thread(self):
  61. """api handles "owned threads only"""
  62. for link in self.tested_links:
  63. self.override_acl({
  64. 'can_see_all_threads': 0
  65. })
  66. response = self.client.get(link)
  67. self.assertEqual(response.status_code, 404)
  68. self.thread.starter = self.user
  69. self.thread.save()
  70. for link in self.tested_links:
  71. self.override_acl({
  72. 'can_see_all_threads': 0
  73. })
  74. response = self.client.get(link)
  75. self.assertEqual(response.status_code, 200)
  76. def test_api_validates_category_permissions(self):
  77. """api endpoint validates category visiblity"""
  78. for link in self.tested_links:
  79. self.override_acl({
  80. 'can_see': 0
  81. })
  82. response = self.client.get(link)
  83. self.assertEqual(response.status_code, 404)
  84. for link in self.tested_links:
  85. self.override_acl({
  86. 'can_browse': 0
  87. })
  88. response = self.client.get(link)
  89. self.assertEqual(response.status_code, 404)
  90. def test_api_validates_posts_visibility(self):
  91. """api endpoint validates posts visiblity"""
  92. self.override_acl({
  93. 'can_hide_posts': 0
  94. })
  95. hidden_post = testutils.reply_thread(self.thread, is_hidden=True, message="I'am hidden test message!")
  96. response = self.client.get(self.tested_links[1])
  97. self.assertNotContains(response, hidden_post.parsed) # post's body is hidden
  98. # add permission to see hidden posts
  99. self.override_acl({
  100. 'can_hide_posts': 1
  101. })
  102. response = self.client.get(self.tested_links[1])
  103. self.assertContains(response, hidden_post.parsed) # hidden post's body is visible with permission
  104. self.override_acl({
  105. 'can_approve_content': 0
  106. })
  107. # unapproved posts shouldn't show at all
  108. unapproved_post = testutils.reply_thread(self.thread, is_unapproved=True)
  109. response = self.client.get(self.tested_links[1])
  110. self.assertNotContains(response, unapproved_post.get_absolute_url())
  111. # add permission to see unapproved posts
  112. self.override_acl({
  113. 'can_approve_content': 1
  114. })
  115. response = self.client.get(self.tested_links[1])
  116. self.assertContains(response, unapproved_post.get_absolute_url())
  117. class ThreadDeleteApiTests(ThreadsApiTestCase):
  118. def test_delete_thread(self):
  119. """DELETE to API link with permission deletes thread"""
  120. self.override_acl({
  121. 'can_hide_threads': 2
  122. })
  123. response = self.client.delete(self.api_link)
  124. self.assertEqual(response.status_code, 200)
  125. with self.assertRaises(Thread.DoesNotExist):
  126. Thread.objects.get(pk=self.thread.pk)
  127. def test_delete_thread_no_permission(self):
  128. """DELETE to API link with no permission to delete fails"""
  129. self.override_acl({
  130. 'can_hide_threads': 1
  131. })
  132. response = self.client.delete(self.api_link)
  133. self.assertEqual(response.status_code, 403)
  134. self.override_acl({
  135. 'can_hide_threads': 0
  136. })
  137. response_json = json.loads(smart_str(response.content))
  138. self.assertEqual(response_json['detail'],
  139. "You don't have permission to delete this thread.")
  140. response = self.client.delete(self.api_link)
  141. self.assertEqual(response.status_code, 403)
  142. class ThreadsReadApiTests(ThreadsApiTestCase):
  143. def setUp(self):
  144. super(ThreadsReadApiTests, self).setUp()
  145. self.api_link = '/api/threads/read/'
  146. def test_read_all_threads(self):
  147. """api sets all threads as read"""
  148. response = self.client.post(self.api_link)
  149. self.assertEqual(response.status_code, 200)
  150. self.assertEqual(self.user.categoryread_set.count(), 2)
  151. def test_read_threads_in_category(self):
  152. """api sets threads in category as read"""
  153. response = self.client.post(
  154. '%s?category=%s' % (self.api_link, self.category.pk))
  155. self.assertEqual(response.status_code, 200)
  156. self.assertEqual(self.user.categoryread_set.count(), 1)