test_attachments_middleware.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. from rest_framework import serializers
  2. from misago.acl.testutils import override_acl
  3. from misago.categories.models import Category
  4. from misago.conf import settings
  5. from misago.threads import testutils
  6. from misago.threads.api.postingendpoint import PostingEndpoint
  7. from misago.threads.api.postingendpoint.attachments import (
  8. AttachmentsMiddleware, validate_attachments_count)
  9. from misago.threads.models import Attachment, AttachmentType
  10. from misago.users.testutils import AuthenticatedUserTestCase
  11. class RequestMock(object):
  12. def __init__(self, data=None):
  13. self.data = data or {}
  14. class AttachmentsMiddlewareTests(AuthenticatedUserTestCase):
  15. def setUp(self):
  16. super(AttachmentsMiddlewareTests, self).setUp()
  17. self.category = Category.objects.get(slug='first-category')
  18. self.thread = testutils.post_thread(category=self.category)
  19. self.post = self.thread.first_post
  20. self.post.update_fields = []
  21. self.override_acl()
  22. self.filetype = AttachmentType.objects.order_by('id').last()
  23. def override_acl(self, new_acl=None):
  24. override_acl(self.user, new_acl or {'max_attachment_size': 1024})
  25. def mock_attachment(self, user=True, post=None):
  26. return Attachment.objects.create(
  27. secret=Attachment.generate_new_secret(),
  28. filetype=self.filetype,
  29. post=post,
  30. size=1000,
  31. uploader=self.user if user else None,
  32. uploader_name=self.user.username,
  33. uploader_slug=self.user.slug,
  34. uploader_ip='127.0.0.1',
  35. filename='testfile_{}.zip'.format(Attachment.objects.count() + 1),
  36. )
  37. def test_use_this_middleware(self):
  38. """use_this_middleware returns False if we can't upload attachments"""
  39. middleware = AttachmentsMiddleware(user=self.user)
  40. self.override_acl({'max_attachment_size': 0})
  41. self.assertFalse(middleware.use_this_middleware())
  42. self.override_acl({'max_attachment_size': 1024})
  43. self.assertTrue(middleware.use_this_middleware())
  44. def test_middleware_is_optional(self):
  45. """middleware is optional"""
  46. INPUTS = [{}, {'attachments': []}]
  47. for test_input in INPUTS:
  48. middleware = AttachmentsMiddleware(
  49. request=RequestMock(test_input),
  50. mode=PostingEndpoint.START,
  51. user=self.user,
  52. post=self.post,
  53. )
  54. serializer = middleware.get_serializer()
  55. self.assertTrue(serializer.is_valid())
  56. def test_middleware_validates_ids(self):
  57. """middleware validates attachments ids"""
  58. INPUTS = ['none', ['a', 'b', 123], range(settings.MISAGO_POST_ATTACHMENTS_LIMIT + 1)]
  59. for test_input in INPUTS:
  60. middleware = AttachmentsMiddleware(
  61. request=RequestMock({
  62. 'attachments': test_input
  63. }),
  64. mode=PostingEndpoint.START,
  65. user=self.user,
  66. post=self.post,
  67. )
  68. serializer = middleware.get_serializer()
  69. self.assertFalse(serializer.is_valid(), "%r shouldn't validate" % test_input)
  70. def test_get_initial_attachments(self):
  71. """get_initial_attachments returns list of attachments already existing on post"""
  72. middleware = AttachmentsMiddleware(
  73. request=RequestMock(),
  74. mode=PostingEndpoint.EDIT,
  75. user=self.user,
  76. post=self.post,
  77. )
  78. serializer = middleware.get_serializer()
  79. attachments = serializer.get_initial_attachments(
  80. middleware.mode, middleware.user, middleware.post
  81. )
  82. self.assertEqual(attachments, [])
  83. attachment = self.mock_attachment(post=self.post)
  84. attachments = serializer.get_initial_attachments(
  85. middleware.mode, middleware.user, middleware.post
  86. )
  87. self.assertEqual(attachments, [attachment])
  88. def test_get_new_attachments(self):
  89. """get_initial_attachments returns list of attachments already existing on post"""
  90. middleware = AttachmentsMiddleware(
  91. request=RequestMock(),
  92. mode=PostingEndpoint.EDIT,
  93. user=self.user,
  94. post=self.post,
  95. )
  96. serializer = middleware.get_serializer()
  97. attachments = serializer.get_new_attachments(middleware.user, [1, 2, 3])
  98. self.assertEqual(attachments, [])
  99. attachment = self.mock_attachment()
  100. attachments = serializer.get_new_attachments(middleware.user, [attachment.pk])
  101. self.assertEqual(attachments, [attachment])
  102. # only own orphaned attachments may be assigned to posts
  103. other_user_attachment = self.mock_attachment(user=False)
  104. attachments = serializer.get_new_attachments(middleware.user, [other_user_attachment.pk])
  105. self.assertEqual(attachments, [])
  106. def test_cant_delete_attachment(self):
  107. """middleware validates if we have permission to delete other users attachments"""
  108. self.override_acl({
  109. 'max_attachment_size': 1024,
  110. 'can_delete_other_users_attachments': False,
  111. })
  112. attachment = self.mock_attachment(user=False, post=self.post)
  113. self.assertIsNone(attachment.uploader)
  114. serializer = AttachmentsMiddleware(
  115. request=RequestMock({
  116. 'attachments': []
  117. }),
  118. mode=PostingEndpoint.EDIT,
  119. user=self.user,
  120. post=self.post,
  121. ).get_serializer()
  122. self.assertFalse(serializer.is_valid())
  123. def test_add_attachments(self):
  124. """middleware adds attachments to post"""
  125. attachments = [
  126. self.mock_attachment(),
  127. self.mock_attachment(),
  128. ]
  129. middleware = AttachmentsMiddleware(
  130. request=RequestMock({
  131. 'attachments': [a.pk for a in attachments]
  132. }),
  133. mode=PostingEndpoint.EDIT,
  134. user=self.user,
  135. post=self.post,
  136. )
  137. serializer = middleware.get_serializer()
  138. self.assertTrue(serializer.is_valid())
  139. middleware.save(serializer)
  140. # attachments were associated with post
  141. self.assertEqual(self.post.update_fields, ['attachments_cache'])
  142. self.assertEqual(self.post.attachment_set.count(), 2)
  143. attachments_filenames = list(reversed([a.filename for a in attachments]))
  144. self.assertEqual([a['filename'] for a in self.post.attachments_cache],
  145. attachments_filenames)
  146. def test_remove_attachments(self):
  147. """middleware removes attachment from post and db"""
  148. attachments = [
  149. self.mock_attachment(post=self.post),
  150. self.mock_attachment(post=self.post),
  151. ]
  152. middleware = AttachmentsMiddleware(
  153. request=RequestMock({
  154. 'attachments': [attachments[0].pk]
  155. }),
  156. mode=PostingEndpoint.EDIT,
  157. user=self.user,
  158. post=self.post,
  159. )
  160. serializer = middleware.get_serializer()
  161. self.assertTrue(serializer.is_valid())
  162. middleware.save(serializer)
  163. # attachments were associated with post
  164. self.assertEqual(self.post.update_fields, ['attachments_cache'])
  165. self.assertEqual(self.post.attachment_set.count(), 1)
  166. self.assertEqual(Attachment.objects.count(), 1)
  167. attachments_filenames = [attachments[0].filename]
  168. self.assertEqual([a['filename'] for a in self.post.attachments_cache],
  169. attachments_filenames)
  170. def test_steal_attachments(self):
  171. """middleware validates if attachments are already assigned to other posts"""
  172. other_post = testutils.reply_thread(self.thread)
  173. attachments = [
  174. self.mock_attachment(post=other_post),
  175. self.mock_attachment(),
  176. ]
  177. middleware = AttachmentsMiddleware(
  178. request=RequestMock({
  179. 'attachments': [attachments[0].pk, attachments[1].pk]
  180. }),
  181. mode=PostingEndpoint.EDIT,
  182. user=self.user,
  183. post=self.post,
  184. )
  185. serializer = middleware.get_serializer()
  186. self.assertTrue(serializer.is_valid())
  187. middleware.save(serializer)
  188. # only unassociated attachment was associated with post
  189. self.assertEqual(self.post.update_fields, ['attachments_cache'])
  190. self.assertEqual(self.post.attachment_set.count(), 1)
  191. self.assertEqual(Attachment.objects.get(pk=attachments[0].pk).post, other_post)
  192. self.assertEqual(Attachment.objects.get(pk=attachments[1].pk).post, self.post)
  193. def test_edit_attachments(self):
  194. """middleware removes and adds attachments to post"""
  195. attachments = [
  196. self.mock_attachment(post=self.post),
  197. self.mock_attachment(post=self.post),
  198. self.mock_attachment(),
  199. ]
  200. middleware = AttachmentsMiddleware(
  201. request=RequestMock({
  202. 'attachments': [attachments[0].pk, attachments[2].pk]
  203. }),
  204. mode=PostingEndpoint.EDIT,
  205. user=self.user,
  206. post=self.post,
  207. )
  208. serializer = middleware.get_serializer()
  209. self.assertTrue(serializer.is_valid())
  210. middleware.save(serializer)
  211. # attachments were associated with post
  212. self.assertEqual(self.post.update_fields, ['attachments_cache'])
  213. self.assertEqual(self.post.attachment_set.count(), 2)
  214. attachments_filenames = [attachments[2].filename, attachments[0].filename]
  215. self.assertEqual([a['filename'] for a in self.post.attachments_cache],
  216. attachments_filenames)
  217. class ValidateAttachmentsCountTests(AuthenticatedUserTestCase):
  218. def test_validate_attachments_count(self):
  219. """too large count of attachments is rejected"""
  220. validate_attachments_count(range(settings.MISAGO_POST_ATTACHMENTS_LIMIT))
  221. with self.assertRaises(serializers.ValidationError):
  222. validate_attachments_count(range(settings.MISAGO_POST_ATTACHMENTS_LIMIT + 1))