Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions isic/core/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,25 @@ def check_iptc_metadata_consistency() -> HealthCheckResult:
)


def check_published_images_have_attribution() -> HealthCheckResult:
published_without_attribution = Image.objects.filter(
accession__attribution="",
).count()

passed = published_without_attribution == 0
message = (
"All published images have attribution"
if passed
else f"{published_without_attribution} published images missing attribution"
)

return HealthCheckResult(
name="published_images_have_attribution",
passed=passed,
message=message,
)


def check_embeddings_only_for_public_images() -> HealthCheckResult:
embeddings_for_private_images = ImageEmbedding.objects.filter(image__public=False).count()

Expand Down Expand Up @@ -224,6 +243,7 @@ def check_embeddings_only_for_public_images() -> HealthCheckResult:
("every_user_has_profile", check_every_user_has_profile),
("collection_image_consistency", check_collection_image_consistency),
("iptc_metadata_consistency", check_iptc_metadata_consistency),
("published_images_have_attribution", check_published_images_have_attribution),
("embeddings_only_for_public_images", check_embeddings_only_for_public_images),
]

Expand Down
17 changes: 17 additions & 0 deletions isic/ingest/migrations/0037_publishrequest_default_attribution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.2.3 on 2026-02-23 17:38

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("ingest", "0036_add_anatom_site_hierarchical_fields"),
]

operations = [
migrations.AddField(
model_name="publishrequest",
name="default_attribution",
field=models.CharField(default="", max_length=200),
),
]
1 change: 1 addition & 0 deletions isic/ingest/models/publish_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class PublishRequest(models.Model):
# the additional collections to which the images will be added, including the magic collection
collections = models.ManyToManyField("core.Collection")
public = models.BooleanField(default=False)
default_attribution = models.CharField(max_length=200, default="")

def __str__(self) -> str:
return f"PublishRequest {self.pk}"
9 changes: 8 additions & 1 deletion isic/ingest/services/publish/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def cohort_publish_initialize(
publish_request = PublishRequest.objects.create(
creator=publisher,
public=public,
default_attribution=cohort.default_attribution,
)
publish_request.accessions.set(cohort.accessions.publishable())
publish_request.collections.set(collections)
Expand All @@ -83,6 +84,7 @@ def cohort_publish(*, publish_request: PublishRequest) -> None:
public=publish_request.public,
publisher_pk=publish_request.creator.pk,
additional_collection_ids=additional_collection_ids,
default_attribution=publish_request.default_attribution,
)


Expand All @@ -92,13 +94,18 @@ def accession_publish(
public: bool,
publisher: User,
additional_collection_ids: Iterable[int] | None = None,
default_attribution: str = "",
):
additional_collection_ids = additional_collection_ids or []

# wrapping this inside of a transaction ensures that this function can be retried easily
with lock_table_for_writes(IsicId):
if accession.attribution == "":
accession.attribution = accession.cohort.default_attribution
if not default_attribution:
raise ValueError(
"default_attribution must be provided when accession has no attribution"
)
accession.attribution = default_attribution
accession.save(update_fields=["attribution"])

image_create(
Expand Down
2 changes: 2 additions & 0 deletions isic/ingest/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ def publish_accession_task(
public: bool,
publisher_pk: int,
additional_collection_ids: list[int] | None = None,
default_attribution: str = "",
):
accession = Accession.objects.select_related("cohort").get(pk=accession_pk)
publisher = User.objects.get(pk=publisher_pk)
Expand All @@ -194,4 +195,5 @@ def publish_accession_task(
public=public,
publisher=publisher,
additional_collection_ids=additional_collection_ids,
default_attribution=default_attribution,
)
2 changes: 2 additions & 0 deletions isic/ingest/tests/test_accession.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def test_accession_reprocess(user, cohort_factory, django_capture_on_commit_call

# refresh the accession to get the blob that was generated by the celery task
accession.refresh_from_db()
accession.attribution = "test attribution"
accession.save(update_fields=["attribution"])

with django_capture_on_commit_callbacks(execute=True):
accession_publish(accession=accession, public=True, publisher=user)
Expand Down
8 changes: 7 additions & 1 deletion isic/ingest/tests/test_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,14 @@ def test_publish_copies_default_attribution(
publishable_cohort_for_attributions.save(update_fields=["default_attribution"])

with django_capture_on_commit_callbacks(execute=True):
cohort_publish_initialize(
publish_request = cohort_publish_initialize(
cohort=publishable_cohort_for_attributions,
publisher=user,
public=True,
)

assert publish_request.default_attribution == "default attribution"

published_images = Image.objects.filter(accession__cohort=publishable_cohort_for_attributions)

assert published_images.count() == 2
Expand Down Expand Up @@ -161,6 +163,8 @@ def test_unembargo_images(user, cohort_factory, django_capture_on_commit_callbac
original_blob_size=blob_path.stat().st_size,
)
accession.refresh_from_db()
accession.attribution = "test attribution"
accession.save(update_fields=["attribution"])

with django_capture_on_commit_callbacks(execute=True):
accession_publish(accession=accession, public=True, publisher=user)
Expand Down Expand Up @@ -198,6 +202,8 @@ def test_iptc_metadata_embedding(
original_blob_size=blob_path.stat().st_size,
)
accession.refresh_from_db()
accession.attribution = "test attribution"
accession.save(update_fields=["attribution"])

with django_capture_on_commit_callbacks(execute=True):
accession_publish(accession=accession, public=False, publisher=user)
Expand Down