diff --git a/dandiapi/api/mail.py b/dandiapi/api/mail.py index 4d94dfcfb..63d5192f4 100644 --- a/dandiapi/api/mail.py +++ b/dandiapi/api/mail.py @@ -43,8 +43,17 @@ def user_greeting_name(user: User, socialaccount: SocialAccount = None) -> str: return social_user['username'] -def build_message(subject: str, message: str, to: list[str], html_message: str | None = None): - email_message = mail.EmailMultiAlternatives(subject=subject, body=message, to=to) +def build_message( # noqa: PLR0913 + to: list[str], + subject: str, + message: str, + html_message: str | None = None, + cc: list[str] | None = None, + bcc: list[str] | None = None, +): + email_message = mail.EmailMultiAlternatives( + subject=subject, body=message, to=to, cc=cc, bcc=bcc + ) if html_message is not None: email_message.attach_alternative(html_message, 'text/html') return email_message @@ -206,3 +215,29 @@ def send_dandiset_unembargoed_message(dandiset: Dandiset): messages = [build_dandiset_unembargoed_message(dandiset)] with mail.get_connection() as connection: connection.send_messages(messages) + + +def build_dandiset_unembargo_failed_message(dandiset: Dandiset): + dandiset_context = { + 'identifier': dandiset.identifier, + } + + render_context = {**BASE_RENDER_CONTEXT, 'dandiset': dandiset_context} + html_message = render_to_string('api/mail/dandiset_unembargo_failed.html', render_context) + return build_message( + subject=f'DANDI: Unembargo failed for dandiset {dandiset.identifier}', + message=strip_tags(html_message), + html_message=html_message, + to=[owner.email for owner in dandiset.owners], + bcc=[settings.DANDI_DEV_EMAIL], + ) + + +def send_dandiset_unembargo_failed_message(dandiset: Dandiset): + logger.info( + 'Sending dandiset unembargo failed message for dandiset %s to dandiset owners and devs', + dandiset.identifier, + ) + messages = [build_dandiset_unembargo_failed_message(dandiset)] + with mail.get_connection() as connection: + connection.send_messages(messages) diff --git a/dandiapi/api/tasks/__init__.py b/dandiapi/api/tasks/__init__.py index 2a7fa9318..98b919604 100644 --- a/dandiapi/api/tasks/__init__.py +++ b/dandiapi/api/tasks/__init__.py @@ -4,6 +4,7 @@ from celery.utils.log import get_task_logger from dandiapi.api.doi import delete_doi +from dandiapi.api.mail import send_dandiset_unembargo_failed_message from dandiapi.api.manifests import ( write_assets_jsonld, write_assets_yaml, @@ -82,4 +83,10 @@ def unembargo_dandiset_task(dandiset_id: int): from dandiapi.api.services.embargo import unembargo_dandiset ds = Dandiset.objects.get(pk=dandiset_id) - unembargo_dandiset(ds) + + # If the unembargo fails for any reason, send an email, but continue the error propagation + try: + unembargo_dandiset(ds) + except Exception: + send_dandiset_unembargo_failed_message(ds) + raise diff --git a/dandiapi/api/templates/api/mail/dandiset_unembargo_failed.html b/dandiapi/api/templates/api/mail/dandiset_unembargo_failed.html new file mode 100644 index 000000000..176a49476 --- /dev/null +++ b/dandiapi/api/templates/api/mail/dandiset_unembargo_failed.html @@ -0,0 +1,6 @@ +There was an error during the unembargo of dandiset +{{dandiset.identifier }}. This has been reported to the developers, and will be +investigated as soon as possible. We hope to have this resolved soon! Please avoid making any major changes to this +dandiset in the meantime, as that may hinder or delay the process of resolving this issue. +


+You are receiving this email because you are an owner of this dandiset. \ No newline at end of file diff --git a/dandiapi/api/tests/test_unembargo.py b/dandiapi/api/tests/test_unembargo.py index f59d9fc59..9740ecebf 100644 --- a/dandiapi/api/tests/test_unembargo.py +++ b/dandiapi/api/tests/test_unembargo.py @@ -14,6 +14,7 @@ ) from dandiapi.api.services.embargo.exceptions import DandisetActiveUploadsError from dandiapi.api.services.exceptions import DandiError +from dandiapi.api.tasks import unembargo_dandiset_task if TYPE_CHECKING: from dandiapi.api.models.asset import AssetBlob @@ -162,3 +163,19 @@ def test_unembargo_dandiset( owner_email_set = {user.email for user in owners} mailoutbox_to_email_set = set(mailoutbox[0].to) assert owner_email_set == mailoutbox_to_email_set + + +@pytest.mark.django_db() +def test_unembargo_dandiset_task_failure(draft_version_factory, mailoutbox): + # Intentionally set the status to embargoed so the task will fail + draft_version = draft_version_factory(dandiset__embargo_status=Dandiset.EmbargoStatus.EMBARGOED) + ds: Dandiset = draft_version.dandiset + + with pytest.raises(DandiError): + unembargo_dandiset_task.delay(ds.pk) + + assert mailoutbox + assert 'Unembargo failed' in mailoutbox[0].subject + payload = mailoutbox[0].message().get_payload()[0].get_payload() + assert ds.identifier in payload + assert 'error during the unembargo' in payload