test_thread_editreply_api.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import json
  4. from django.test.client import BOUNDARY, MULTIPART_CONTENT, encode_multipart
  5. from django.urls import reverse
  6. from django.utils.encoding import smart_str
  7. from misago.acl.testutils import override_acl
  8. from misago.categories.models import Category
  9. from misago.threads import testutils
  10. from misago.users.testutils import AuthenticatedUserTestCase
  11. class EditReplyTests(AuthenticatedUserTestCase):
  12. def setUp(self):
  13. super(EditReplyTests, self).setUp()
  14. self.category = Category.objects.get(slug='first-category')
  15. self.thread = testutils.post_thread(category=self.category)
  16. self.post = testutils.reply_thread(self.thread, poster=self.user)
  17. self.api_link = reverse('misago:api:thread-post-detail', kwargs={
  18. 'thread_pk': self.thread.pk,
  19. 'pk': self.post.pk
  20. })
  21. def override_acl(self, extra_acl=None):
  22. new_acl = self.user.acl_cache
  23. new_acl['categories'][self.category.pk].update({
  24. 'can_see': 1,
  25. 'can_browse': 1,
  26. 'can_start_threads': 0,
  27. 'can_reply_threads': 0,
  28. 'can_edit_posts': 1
  29. })
  30. if extra_acl:
  31. new_acl['categories'][self.category.pk].update(extra_acl)
  32. override_acl(self.user, new_acl)
  33. def put(self, url, data=None):
  34. content = encode_multipart(BOUNDARY, data or {})
  35. return self.client.put(url, content, content_type=MULTIPART_CONTENT)
  36. def test_cant_edit_reply_as_guest(self):
  37. """user has to be authenticated to be able to edit reply"""
  38. self.logout_user()
  39. response = self.put(self.api_link)
  40. self.assertEqual(response.status_code, 403)
  41. def test_thread_visibility(self):
  42. """thread's visibility is validated"""
  43. self.override_acl({'can_see': 0})
  44. response = self.put(self.api_link)
  45. self.assertEqual(response.status_code, 404)
  46. self.override_acl({'can_browse': 0})
  47. response = self.put(self.api_link)
  48. self.assertEqual(response.status_code, 404)
  49. self.override_acl({'can_see_all_threads': 0})
  50. response = self.put(self.api_link)
  51. self.assertEqual(response.status_code, 404)
  52. def test_cant_edit_reply(self):
  53. """permission to edit reply is validated"""
  54. self.override_acl({
  55. 'can_edit_posts': 0
  56. })
  57. response = self.put(self.api_link)
  58. self.assertContains(response, "You can't edit posts in this category.", status_code=403)
  59. def test_cant_edit_other_user_reply(self):
  60. """permission to edit reply by other users is validated"""
  61. self.override_acl({
  62. 'can_edit_posts': 1
  63. })
  64. self.post.poster = None
  65. self.post.save()
  66. response = self.put(self.api_link)
  67. self.assertContains(response, "You can't edit other users posts in this category.", status_code=403)
  68. def test_closed_category(self):
  69. """permssion to edit reply in closed category is validated"""
  70. self.override_acl({
  71. 'can_close_threads': 0
  72. })
  73. self.category.is_closed = True
  74. self.category.save()
  75. response = self.put(self.api_link)
  76. self.assertContains(response, "This category is closed. You can't edit posts in it.", status_code=403)
  77. # allow to post in closed category
  78. self.override_acl({
  79. 'can_close_threads': 1
  80. })
  81. response = self.put(self.api_link)
  82. self.assertEqual(response.status_code, 400)
  83. def test_closed_thread(self):
  84. """permssion to edit reply in closed thread is validated"""
  85. self.override_acl({
  86. 'can_close_threads': 0
  87. })
  88. self.thread.is_closed = True
  89. self.thread.save()
  90. response = self.put(self.api_link)
  91. self.assertContains(response, "This thread is closed. You can't edit posts in it.", status_code=403)
  92. # allow to post in closed thread
  93. self.override_acl({
  94. 'can_close_threads': 1
  95. })
  96. response = self.put(self.api_link)
  97. self.assertEqual(response.status_code, 400)
  98. def test_protected_post(self):
  99. """permssion to edit protected post is validated"""
  100. self.override_acl({
  101. 'can_protect_posts': 0
  102. })
  103. self.post.is_protected = True
  104. self.post.save()
  105. response = self.put(self.api_link)
  106. self.assertContains(response, "This post is protected. You can't edit it.", status_code=403)
  107. # allow to post in closed thread
  108. self.override_acl({
  109. 'can_protect_posts': 1
  110. })
  111. response = self.put(self.api_link)
  112. self.assertEqual(response.status_code, 400)
  113. def test_empty_data(self):
  114. """no data sent handling has no showstoppers"""
  115. self.override_acl()
  116. response = self.put(self.api_link, data={})
  117. self.assertEqual(response.status_code, 400)
  118. self.assertEqual(json.loads(smart_str(response.content)), {
  119. 'post': [
  120. "You have to enter a message."
  121. ]
  122. })
  123. def test_edit_event(self):
  124. """events can't be edited"""
  125. self.override_acl()
  126. self.post.is_event = True
  127. self.post.save()
  128. response = self.put(self.api_link, data={})
  129. self.assertContains(response, "Events can't be edited.", status_code=403)
  130. def test_post_is_validated(self):
  131. """post is validated"""
  132. self.override_acl()
  133. response = self.put(self.api_link, data={
  134. 'post': "a",
  135. })
  136. self.assertEqual(response.status_code, 400)
  137. self.assertEqual(json.loads(smart_str(response.content)), {
  138. 'post': [
  139. "Posted message should be at least 5 characters long (it has 1)."
  140. ]
  141. })
  142. def test_edit_reply_no_change(self):
  143. """endpoint isn't bumping edits count if no change was made to post's body"""
  144. self.override_acl()
  145. self.assertEqual(self.post.edits_record.count(), 0)
  146. response = self.put(self.api_link, data={
  147. 'post': self.post.original
  148. })
  149. self.assertEqual(response.status_code, 200)
  150. self.override_acl()
  151. response = self.client.get(self.thread.get_absolute_url())
  152. self.assertContains(response, self.post.parsed)
  153. post = self.thread.post_set.order_by('id').last()
  154. self.assertEqual(post.edits, 0)
  155. self.assertEqual(post.original, self.post.original)
  156. self.assertIsNone(post.last_editor_id, self.user.id)
  157. self.assertIsNone(post.last_editor_name, self.user.username)
  158. self.assertIsNone(post.last_editor_slug, self.user.slug)
  159. self.assertEqual(self.post.edits_record.count(), 0)
  160. def test_edit_reply(self):
  161. """endpoint updates reply"""
  162. self.override_acl()
  163. self.assertEqual(self.post.edits_record.count(), 0)
  164. response = self.put(self.api_link, data={
  165. 'post': "This is test edit!"
  166. })
  167. self.assertEqual(response.status_code, 200)
  168. self.override_acl()
  169. response = self.client.get(self.thread.get_absolute_url())
  170. self.assertContains(response, "<p>This is test edit!</p>")
  171. post = self.thread.post_set.order_by('id').last()
  172. self.assertEqual(post.edits, 1)
  173. self.assertEqual(post.original, "This is test edit!")
  174. self.assertEqual(post.last_editor_id, self.user.id)
  175. self.assertEqual(post.last_editor_name, self.user.username)
  176. self.assertEqual(post.last_editor_slug, self.user.slug)
  177. self.assertEqual(self.post.edits_record.count(), 1)
  178. post_edit = post.edits_record.last()
  179. self.assertEqual(post_edit.edited_from, self.post.original)
  180. self.assertEqual(post_edit.edited_to, post.original)
  181. self.assertEqual(post_edit.editor_id, self.user.id)
  182. self.assertEqual(post_edit.editor_name, self.user.username)
  183. self.assertEqual(post_edit.editor_slug, self.user.slug)
  184. def test_edit_first_post_hidden(self):
  185. """endpoint updates hidden thread's first post"""
  186. self.override_acl({
  187. 'can_hide_threads': 1,
  188. 'can_edit_posts': 2
  189. })
  190. self.thread.is_hidden = True
  191. self.thread.save()
  192. self.thread.first_post.is_hidden = True
  193. self.thread.first_post.save()
  194. api_link = reverse('misago:api:thread-post-detail', kwargs={
  195. 'thread_pk': self.thread.pk,
  196. 'pk': self.thread.first_post.pk
  197. })
  198. response = self.put(api_link, data={
  199. 'post': "This is test edit!"
  200. })
  201. self.assertEqual(response.status_code, 200)
  202. def test_protect_post(self):
  203. """can protect post"""
  204. self.override_acl({
  205. 'can_protect_posts': 1
  206. })
  207. response = self.put(self.api_link, data={
  208. 'post': "Lorem ipsum dolor met!",
  209. 'protect': 1
  210. })
  211. self.assertEqual(response.status_code, 200)
  212. post = self.user.post_set.order_by('id').last()
  213. self.assertTrue(post.is_protected)
  214. def test_protect_post_no_permission(self):
  215. """cant protect post without permission"""
  216. self.override_acl({
  217. 'can_protect_posts': 0
  218. })
  219. response = self.put(self.api_link, data={
  220. 'post': "Lorem ipsum dolor met!",
  221. 'protect': 1
  222. })
  223. self.assertEqual(response.status_code, 200)
  224. post = self.user.post_set.order_by('id').last()
  225. self.assertFalse(post.is_protected)
  226. def test_post_unicode(self):
  227. """unicode characters can be posted"""
  228. self.override_acl()
  229. response = self.put(self.api_link, data={
  230. 'post': "Chrzążczyżewoszyce, powiat Łękółody."
  231. })
  232. self.assertEqual(response.status_code, 200)