test_attachments_middleware.py 8.8 KB

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