diff --git a/isic/core/api/image.py b/isic/core/api/image.py index 3276c55f..a0a69cfa 100644 --- a/isic/core/api/image.py +++ b/isic/core/api/image.py @@ -309,6 +309,8 @@ def image_set_pinned(request, id: int, payload: SetPinned): qs = get_visible_objects(request.user, "core.view_image", Image.objects.all()) image = get_object_or_404(qs.distinct(), id=id) if payload.pinned: + if not image.public: + return 400, {"error": "Cannot pin a private image."} last_pin = Image.objects.aggregate(Max("pinned")).get("pinned__max") or 0 image.pinned = last_pin + 1 else: diff --git a/isic/core/migrations/0043_image_image_pinned_implies_public.py b/isic/core/migrations/0043_image_image_pinned_implies_public.py new file mode 100644 index 00000000..09d89d14 --- /dev/null +++ b/isic/core/migrations/0043_image_image_pinned_implies_public.py @@ -0,0 +1,22 @@ +# Generated by Django 5.2.15 on 2026-07-02 17:17 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0042_pinned_images"), + ("ingest", "0043_alter_rcmcase_id"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddConstraint( + model_name="image", + constraint=models.CheckConstraint( + condition=models.Q(("pinned__isnull", True), ("public", True), _connector="OR"), + name="image_pinned_implies_public", + ), + ), + ] diff --git a/isic/core/models/image.py b/isic/core/models/image.py index 42e53c7f..5e3f445d 100644 --- a/isic/core/models/image.py +++ b/isic/core/models/image.py @@ -68,6 +68,13 @@ class Image(CreationSortedTimeStampedModel): class Meta(CreationSortedTimeStampedModel.Meta): ordering = ["created"] + constraints = [ + CheckConstraint( + name="image_pinned_implies_public", + condition=Q(pinned__isnull=True) | Q(public=True), + ), + ] + indexes = [ # icontains uses Upper(name) for searching GinIndex(OpClass(Upper("isic"), name="gin_trgm_ops"), name="isic_name_gin"), diff --git a/isic/core/templates/core/image_detail/actions_menu.html b/isic/core/templates/core/image_detail/actions_menu.html index ec01a76a..59c8d48f 100644 --- a/isic/core/templates/core/image_detail/actions_menu.html +++ b/isic/core/templates/core/image_detail/actions_menu.html @@ -10,10 +10,21 @@