from unittest.mock import Mock import pytest from rest_framework import serializers from .. import test from ...conf.test import override_dynamic_settings from ..api.postingendpoint import PostingEndpoint from ..api.postingendpoint.attachments import ( AttachmentsMiddleware, validate_attachments_count, ) from ..models import Attachment, AttachmentType @pytest.fixture def context(default_category, dynamic_settings, user, user_acl): thread = test.post_thread(category=default_category) post = thread.first_post post.update_fields = [] return { "category": default_category, "thread": thread, "post": post, "settings": dynamic_settings, "user": user, "user_acl": user_acl, } def create_attachment(*, post=None, user=None): return Attachment.objects.create( secret=Attachment.generate_new_secret(), filetype=AttachmentType.objects.order_by("id").last(), post=post, size=1000, uploader=user if user else None, uploader_name=user.username if user else "testuser", uploader_slug=user.slug if user else "testuser", filename="testfile_%s.zip" % (Attachment.objects.count() + 1), ) def test_middleware_is_used_if_user_has_permission_to_upload_attachments(context): context["user_acl"]["max_attachment_size"] = 1024 middleware = AttachmentsMiddleware(**context) assert middleware.use_this_middleware() def test_middleware_is_not_used_if_user_has_no_permission_to_upload_attachments( context ): context["user_acl"]["max_attachment_size"] = 0 middleware = AttachmentsMiddleware(**context) assert not middleware.use_this_middleware() def test_middleware_handles_no_data(context): middleware = AttachmentsMiddleware( request=Mock(data={}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() assert serializer.is_valid() def test_middleware_handles_empty_data(context): middleware = AttachmentsMiddleware( request=Mock(data={"attachments": []}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() assert serializer.is_valid() def test_data_validation_fails_if_attachments_data_is_not_iterable(context): middleware = AttachmentsMiddleware( request=Mock(data={"attachments": "none"}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() assert not serializer.is_valid() def test_data_validation_fails_if_attachments_data_has_non_int_values(context): middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [1, "b"]}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() assert not serializer.is_valid() @override_dynamic_settings(post_attachments_limit=2) def test_data_validation_fails_if_attachments_data_is_longer_than_allowed(context): middleware = AttachmentsMiddleware( request=Mock(data={"attachments": range(5)}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() assert not serializer.is_valid() def test_middleware_adds_attachment_to_new_post(context): new_attachment = create_attachment(user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [new_attachment.id]}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) new_attachment.refresh_from_db() assert new_attachment.post == context["post"] def test_middleware_adds_attachment_to_attachments_cache(context): new_attachment = create_attachment(user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [new_attachment.id]}), mode=PostingEndpoint.START, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) attachments_cache = context["post"].attachments_cache assert len(attachments_cache) == 1 assert attachments_cache[0]["id"] == new_attachment.id def test_middleware_adds_attachment_to_existing_post(context): new_attachment = create_attachment(user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [new_attachment.id]}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) new_attachment.refresh_from_db() assert new_attachment.post == context["post"] def test_middleware_adds_attachment_to_post_with_existing_attachment(context): old_attachment = create_attachment(post=context["post"]) new_attachment = create_attachment(user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [old_attachment.id, new_attachment.id]}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) new_attachment.refresh_from_db() assert new_attachment.post == context["post"] old_attachment.refresh_from_db() assert old_attachment.post == context["post"] def test_middleware_adds_attachment_to_existing_attachments_cache(context): old_attachment = create_attachment(post=context["post"]) new_attachment = create_attachment(user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [old_attachment.id, new_attachment.id]}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) attachments_cache = context["post"].attachments_cache assert len(attachments_cache) == 2 assert attachments_cache[0]["id"] == new_attachment.id assert attachments_cache[1]["id"] == old_attachment.id def test_other_user_attachment_cant_be_added_to_post(context): attachment = create_attachment() middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [attachment.id]}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) attachment.refresh_from_db() assert not attachment.post def test_other_post_attachment_cant_be_added_to_new_post(context, default_category): post = test.post_thread(category=default_category).first_post attachment = create_attachment(post=post, user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": [attachment.id]}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) attachment.refresh_from_db() assert attachment.post == post def test_middleware_removes_attachment_from_post(context): attachment = create_attachment(post=context["post"], user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) context["post"].refresh_from_db() assert not context["post"].attachment_set.exists() def test_middleware_removes_attachment_from_attachments_cache(context): attachment = create_attachment(post=context["post"], user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) assert not context["post"].attachments_cache def test_middleware_deletes_attachment_removed_from_post(context): attachment = create_attachment(post=context["post"], user=context["user"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) with pytest.raises(Attachment.DoesNotExist): attachment.refresh_from_db() def test_middleware_blocks_user_from_removing_other_user_attachment_without_permission( context ): attachment = create_attachment(post=context["post"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() assert not serializer.is_valid() middleware.save(serializer) attachment.refresh_from_db() assert attachment.post == context["post"] def test_middleware_allows_user_with_permission_to_remove_other_user_attachment( context ): context["user_acl"]["can_delete_other_users_attachments"] = True attachment = create_attachment(post=context["post"]) middleware = AttachmentsMiddleware( request=Mock(data={"attachments": []}), mode=PostingEndpoint.EDIT, **context ) serializer = middleware.get_serializer() serializer.is_valid() middleware.save(serializer) context["post"].refresh_from_db() assert not context["post"].attachment_set.exists() def test_attachments_count_validator_allows_attachments_within_limit(): settings = Mock(post_attachments_limit=5) validate_attachments_count(range(5), settings) def test_attachments_count_validator_raises_validation_error_on_too_many_attachmes(): settings = Mock(post_attachments_limit=2) with pytest.raises(serializers.ValidationError): validate_attachments_count(range(5), settings)