test_attachments_middleware.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. from unittest.mock import Mock
  2. import pytest
  3. from rest_framework import serializers
  4. from .. import test
  5. from ...conf.test import override_dynamic_settings
  6. from ..api.postingendpoint import PostingEndpoint
  7. from ..api.postingendpoint.attachments import (
  8. AttachmentsMiddleware,
  9. validate_attachments_count,
  10. )
  11. from ..models import Attachment, AttachmentType
  12. @pytest.fixture
  13. def context(default_category, dynamic_settings, user, user_acl):
  14. thread = test.post_thread(category=default_category)
  15. post = thread.first_post
  16. post.update_fields = []
  17. return {
  18. "category": default_category,
  19. "thread": thread,
  20. "post": post,
  21. "settings": dynamic_settings,
  22. "user": user,
  23. "user_acl": user_acl,
  24. }
  25. def create_attachment(*, post=None, user=None):
  26. return Attachment.objects.create(
  27. secret=Attachment.generate_new_secret(),
  28. filetype=AttachmentType.objects.order_by("id").last(),
  29. post=post,
  30. size=1000,
  31. uploader=user if user else None,
  32. uploader_name=user.username if user else "testuser",
  33. uploader_slug=user.slug if user else "testuser",
  34. filename="testfile_%s.zip" % (Attachment.objects.count() + 1),
  35. )
  36. def test_middleware_is_used_if_user_has_permission_to_upload_attachments(context):
  37. context["user_acl"]["max_attachment_size"] = 1024
  38. middleware = AttachmentsMiddleware(**context)
  39. assert middleware.use_this_middleware()
  40. def test_middleware_is_not_used_if_user_has_no_permission_to_upload_attachments(
  41. context
  42. ):
  43. context["user_acl"]["max_attachment_size"] = 0
  44. middleware = AttachmentsMiddleware(**context)
  45. assert not middleware.use_this_middleware()
  46. def test_middleware_handles_no_data(context):
  47. middleware = AttachmentsMiddleware(
  48. request=Mock(data={}), mode=PostingEndpoint.START, **context
  49. )
  50. serializer = middleware.get_serializer()
  51. assert serializer.is_valid()
  52. def test_middleware_handles_empty_data(context):
  53. middleware = AttachmentsMiddleware(
  54. request=Mock(data={"attachments": []}), mode=PostingEndpoint.START, **context
  55. )
  56. serializer = middleware.get_serializer()
  57. assert serializer.is_valid()
  58. def test_data_validation_fails_if_attachments_data_is_not_iterable(context):
  59. middleware = AttachmentsMiddleware(
  60. request=Mock(data={"attachments": "none"}),
  61. mode=PostingEndpoint.START,
  62. **context
  63. )
  64. serializer = middleware.get_serializer()
  65. assert not serializer.is_valid()
  66. def test_data_validation_fails_if_attachments_data_has_non_int_values(context):
  67. middleware = AttachmentsMiddleware(
  68. request=Mock(data={"attachments": [1, "b"]}),
  69. mode=PostingEndpoint.START,
  70. **context
  71. )
  72. serializer = middleware.get_serializer()
  73. assert not serializer.is_valid()
  74. @override_dynamic_settings(post_attachments_limit=2)
  75. def test_data_validation_fails_if_attachments_data_is_longer_than_allowed(context):
  76. middleware = AttachmentsMiddleware(
  77. request=Mock(data={"attachments": range(5)}),
  78. mode=PostingEndpoint.START,
  79. **context
  80. )
  81. serializer = middleware.get_serializer()
  82. assert not serializer.is_valid()
  83. def test_middleware_adds_attachment_to_new_post(context):
  84. new_attachment = create_attachment(user=context["user"])
  85. middleware = AttachmentsMiddleware(
  86. request=Mock(data={"attachments": [new_attachment.id]}),
  87. mode=PostingEndpoint.START,
  88. **context
  89. )
  90. serializer = middleware.get_serializer()
  91. serializer.is_valid()
  92. middleware.save(serializer)
  93. new_attachment.refresh_from_db()
  94. assert new_attachment.post == context["post"]
  95. def test_middleware_adds_attachment_to_attachments_cache(context):
  96. new_attachment = create_attachment(user=context["user"])
  97. middleware = AttachmentsMiddleware(
  98. request=Mock(data={"attachments": [new_attachment.id]}),
  99. mode=PostingEndpoint.START,
  100. **context
  101. )
  102. serializer = middleware.get_serializer()
  103. serializer.is_valid()
  104. middleware.save(serializer)
  105. attachments_cache = context["post"].attachments_cache
  106. assert len(attachments_cache) == 1
  107. assert attachments_cache[0]["id"] == new_attachment.id
  108. def test_middleware_adds_attachment_to_existing_post(context):
  109. new_attachment = create_attachment(user=context["user"])
  110. middleware = AttachmentsMiddleware(
  111. request=Mock(data={"attachments": [new_attachment.id]}),
  112. mode=PostingEndpoint.EDIT,
  113. **context
  114. )
  115. serializer = middleware.get_serializer()
  116. serializer.is_valid()
  117. middleware.save(serializer)
  118. new_attachment.refresh_from_db()
  119. assert new_attachment.post == context["post"]
  120. def test_middleware_adds_attachment_to_post_with_existing_attachment(context):
  121. old_attachment = create_attachment(post=context["post"])
  122. new_attachment = create_attachment(user=context["user"])
  123. middleware = AttachmentsMiddleware(
  124. request=Mock(data={"attachments": [old_attachment.id, new_attachment.id]}),
  125. mode=PostingEndpoint.EDIT,
  126. **context
  127. )
  128. serializer = middleware.get_serializer()
  129. serializer.is_valid()
  130. middleware.save(serializer)
  131. new_attachment.refresh_from_db()
  132. assert new_attachment.post == context["post"]
  133. old_attachment.refresh_from_db()
  134. assert old_attachment.post == context["post"]
  135. def test_middleware_adds_attachment_to_existing_attachments_cache(context):
  136. old_attachment = create_attachment(post=context["post"])
  137. new_attachment = create_attachment(user=context["user"])
  138. middleware = AttachmentsMiddleware(
  139. request=Mock(data={"attachments": [old_attachment.id, new_attachment.id]}),
  140. mode=PostingEndpoint.EDIT,
  141. **context
  142. )
  143. serializer = middleware.get_serializer()
  144. serializer.is_valid()
  145. middleware.save(serializer)
  146. attachments_cache = context["post"].attachments_cache
  147. assert len(attachments_cache) == 2
  148. assert attachments_cache[0]["id"] == new_attachment.id
  149. assert attachments_cache[1]["id"] == old_attachment.id
  150. def test_other_user_attachment_cant_be_added_to_post(context):
  151. attachment = create_attachment()
  152. middleware = AttachmentsMiddleware(
  153. request=Mock(data={"attachments": [attachment.id]}),
  154. mode=PostingEndpoint.EDIT,
  155. **context
  156. )
  157. serializer = middleware.get_serializer()
  158. serializer.is_valid()
  159. middleware.save(serializer)
  160. attachment.refresh_from_db()
  161. assert not attachment.post
  162. def test_other_post_attachment_cant_be_added_to_new_post(context, default_category):
  163. post = test.post_thread(category=default_category).first_post
  164. attachment = create_attachment(post=post, user=context["user"])
  165. middleware = AttachmentsMiddleware(
  166. request=Mock(data={"attachments": [attachment.id]}),
  167. mode=PostingEndpoint.EDIT,
  168. **context
  169. )
  170. serializer = middleware.get_serializer()
  171. serializer.is_valid()
  172. middleware.save(serializer)
  173. attachment.refresh_from_db()
  174. assert attachment.post == post
  175. def test_middleware_removes_attachment_from_post(context):
  176. attachment = create_attachment(post=context["post"], user=context["user"])
  177. middleware = AttachmentsMiddleware(
  178. request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context
  179. )
  180. serializer = middleware.get_serializer()
  181. serializer.is_valid()
  182. middleware.save(serializer)
  183. context["post"].refresh_from_db()
  184. assert not context["post"].attachment_set.exists()
  185. def test_middleware_removes_attachment_from_attachments_cache(context):
  186. attachment = create_attachment(post=context["post"], user=context["user"])
  187. middleware = AttachmentsMiddleware(
  188. request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context
  189. )
  190. serializer = middleware.get_serializer()
  191. serializer.is_valid()
  192. middleware.save(serializer)
  193. assert not context["post"].attachments_cache
  194. def test_middleware_deletes_attachment_removed_from_post(context):
  195. attachment = create_attachment(post=context["post"], user=context["user"])
  196. middleware = AttachmentsMiddleware(
  197. request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context
  198. )
  199. serializer = middleware.get_serializer()
  200. serializer.is_valid()
  201. middleware.save(serializer)
  202. with pytest.raises(Attachment.DoesNotExist):
  203. attachment.refresh_from_db()
  204. def test_middleware_blocks_user_from_removing_other_user_attachment_without_permission(
  205. context
  206. ):
  207. attachment = create_attachment(post=context["post"])
  208. middleware = AttachmentsMiddleware(
  209. request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context
  210. )
  211. serializer = middleware.get_serializer()
  212. assert not serializer.is_valid()
  213. middleware.save(serializer)
  214. attachment.refresh_from_db()
  215. assert attachment.post == context["post"]
  216. def test_middleware_allows_user_with_permission_to_remove_other_user_attachment(
  217. context
  218. ):
  219. context["user_acl"]["can_delete_other_users_attachments"] = True
  220. attachment = create_attachment(post=context["post"])
  221. middleware = AttachmentsMiddleware(
  222. request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context
  223. )
  224. serializer = middleware.get_serializer()
  225. serializer.is_valid()
  226. middleware.save(serializer)
  227. context["post"].refresh_from_db()
  228. assert not context["post"].attachment_set.exists()
  229. def test_attachments_count_validator_allows_attachments_within_limit():
  230. settings = Mock(post_attachments_limit=5)
  231. validate_attachments_count(range(5), settings)
  232. def test_attachments_count_validator_raises_validation_error_on_too_many_attachmes():
  233. settings = Mock(post_attachments_limit=2)
  234. with pytest.raises(serializers.ValidationError):
  235. validate_attachments_count(range(5), settings)