From 33dae189f4db1ab27a2509ef88b4998df229ee2d Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Wed, 27 May 2026 17:32:51 -0400 Subject: [PATCH] Validate collection sharing constraints in the API view Add checks to reject sharing a collection with yourself or sharing a magic collection, before the Celery task is dispatched. Previously, the self-share case would awkwardly fail in the task when it hit the `collectionshare_grantor_grantee_diff_check` database constraint. --- isic/core/api/collection.py | 10 +++++++++- isic/core/tests/test_api_collection.py | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/isic/core/api/collection.py b/isic/core/api/collection.py index 48e96ffb3..4df4f4a09 100644 --- a/isic/core/api/collection.py +++ b/isic/core/api/collection.py @@ -215,7 +215,9 @@ class CollectionShareIn(Schema): notify: bool = True -@router.post("/{id}/share/", response={202: None, 404: dict, 403: dict}, include_in_schema=False) +@router.post( + "/{id}/share/", response={202: None, 400: dict, 403: dict, 404: dict}, include_in_schema=False +) def collection_share_to_users(request, id: int, payload: CollectionShareIn): qs = get_visible_objects(request.user, "core.view_collection", Collection.objects.all()) collection = get_object_or_404(qs.distinct(), id=id) @@ -223,6 +225,12 @@ def collection_share_to_users(request, id: int, payload: CollectionShareIn): if not request.user.is_staff: return 403, {"error": "You do not have permission to share this collection."} + if collection.is_magic: + return 400, {"error": "Magic collections cannot be shared."} + + if any(user_id == request.user.id for user_id in payload.user_ids): + return 400, {"error": "Cannot share a collection with yourself."} + share_collection_with_users_task.delay_on_commit( collection.id, request.user.id, payload.user_ids, notify=payload.notify ) diff --git a/isic/core/tests/test_api_collection.py b/isic/core/tests/test_api_collection.py index 31e780927..97ae0eca4 100644 --- a/isic/core/tests/test_api_collection.py +++ b/isic/core/tests/test_api_collection.py @@ -233,6 +233,28 @@ def test_core_api_collection_remove_from_list( } +@pytest.mark.django_db +def test_core_api_collection_share_self(staff_client, staff_user, private_collection): + r = staff_client.post( + reverse("api:collection_share_to_users", args=[private_collection.pk]), + {"user_ids": [staff_user.pk]}, + content_type="application/json", + ) + assert r.status_code == 400 + + +@pytest.mark.django_db +def test_core_api_collection_share_magic(staff_client, cohort_factory, collection_factory, user): + collection = collection_factory(public=False) + cohort_factory(collection=collection) + r = staff_client.post( + reverse("api:collection_share_to_users", args=[collection.pk]), + {"user_ids": [user.pk]}, + content_type="application/json", + ) + assert r.status_code == 400 + + @pytest.mark.django_db def test_core_api_collection_share( staff_client,