test_attachments_middleware.py 10.0 KB

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