Skip to content

Commit a04eb74

Browse files
committed
move doi handling for update to celery task
1 parent f4f8894 commit a04eb74

File tree

8 files changed

+131
-166
lines changed

8 files changed

+131
-166
lines changed

dandiapi/api/doi.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,39 @@ def _create_dandiset_draft_doi(draft_version: Version) -> None:
101101
draft_version.save()
102102

103103

104+
def _update_draft_version_doi(draft_version: Version) -> None:
105+
"""
106+
Update or create a Draft DOI for a dandiset with the latest metadata.
107+
108+
This is called when a draft version's metadata is updated for a dandiset
109+
that has never been published.
110+
111+
Args:
112+
draft_version: The draft version of the dandiset with updated metadata.
113+
"""
114+
# Skip for dandisets that have published versions
115+
if draft_version.dandiset.versions.exclude(version='draft').exists():
116+
return
117+
118+
# Generate DOI payload with updated metadata
119+
dandiset_doi, dandiset_doi_payload = generate_doi_data(
120+
draft_version,
121+
version_doi=False, # Generate a Dandiset DOI, not a Version DOI
122+
event=None, # Keep as Draft DOI
123+
)
124+
125+
# Create or update the DOI
126+
create_or_update_doi(dandiset_doi_payload)
127+
128+
# If the version doesn't have a DOI yet, store it
129+
if draft_version.doi is None:
130+
draft_version.doi = dandiset_doi
131+
draft_version.save()
132+
logger.info('Created new Draft DOI %s', dandiset_doi)
133+
else:
134+
logger.info('Updated Draft DOI %s with new metadata', draft_version.doi)
135+
136+
104137
def _handle_publication_dois(version_id: int) -> None:
105138
"""
106139
Create and update DOIs for a published version.

dandiapi/api/services/dandiset/__init__.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -132,36 +132,3 @@ def unstar_dandiset(*, user, dandiset: Dandiset) -> int:
132132

133133
DandisetStar.objects.filter(user=user, dandiset=dandiset).delete()
134134
return dandiset.star_count
135-
136-
137-
def update_draft_version_doi(draft_version: Version) -> None:
138-
"""
139-
Update or create a Draft DOI for a dandiset with the latest metadata.
140-
141-
This is called when a draft version's metadata is updated for a dandiset
142-
that has never been published.
143-
144-
Args:
145-
draft_version: The draft version of the dandiset with updated metadata.
146-
"""
147-
# Skip for dandisets that have published versions
148-
if draft_version.dandiset.versions.exclude(version='draft').exists():
149-
return
150-
151-
# Generate DOI payload with updated metadata
152-
dandiset_doi, dandiset_doi_payload = doi.generate_doi_data(
153-
draft_version,
154-
version_doi=False, # Generate a Dandiset DOI, not a Version DOI
155-
event=None, # Keep as Draft DOI
156-
)
157-
158-
# Create or update the DOI
159-
doi.create_or_update_doi(dandiset_doi_payload)
160-
161-
# If the version doesn't have a DOI yet, store it
162-
if draft_version.doi is None:
163-
draft_version.doi = dandiset_doi
164-
draft_version.save()
165-
logger.info('Created new Draft DOI %s', dandiset_doi)
166-
else:
167-
logger.info('Updated Draft DOI %s with new metadata', draft_version.doi)

dandiapi/api/tasks/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,15 @@ def create_dandiset_draft_doi_task(version_id: int) -> None:
125125
except Exception:
126126
# Log error but allow dandiset creation to proceed
127127
logger.exception('Failed to create Draft DOI for dandiset %s', version.dandiset.identifier)
128+
129+
130+
@shared_task(soft_time_limit=60)
131+
def update_draft_version_doi_task(version_id: int) -> None:
132+
from dandiapi.api.doi import _update_draft_version_doi
133+
134+
version = Version.objects.get(id=version_id)
135+
try:
136+
_update_draft_version_doi(version)
137+
except Exception:
138+
# Log error but allow version update to proceed
139+
logger.exception('Failed to update Draft DOI for dandiset %s', version.dandiset.identifier)

dandiapi/api/tests/test_audit.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ def test_audit_update_metadata(api_client, draft_version, user, mocker):
123123
dandiset = draft_version.dandiset
124124
add_dandiset_owner(dandiset, user)
125125

126-
mock_update_doi = mocker.patch('dandiapi.api.views.version.update_draft_version_doi')
127126
# Edit its metadata.
128127
metadata = draft_version.metadata
129128
metadata['foo'] = 'bar'
@@ -145,7 +144,6 @@ def test_audit_update_metadata(api_client, draft_version, user, mocker):
145144
metadata = rec.details['metadata']
146145
assert metadata['name'] == 'baz'
147146
assert metadata['foo'] == 'bar'
148-
mock_update_doi.assert_called_once()
149147

150148

151149
@pytest.mark.django_db

dandiapi/api/tests/test_dandiset.py

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from dandiapi.api.asset_paths import add_asset_paths, add_version_asset_paths
1010
from dandiapi.api.models import Dandiset, Version
11-
from dandiapi.api.services.dandiset import update_draft_version_doi
1211
from dandiapi.api.services.permissions.dandiset import (
1312
add_dandiset_owner,
1413
get_dandiset_owners,
@@ -1356,69 +1355,3 @@ def test_dandiset_list_starred(api_client, user, dandiset_factory):
13561355
def test_dandiset_list_starred_unauthenticated(api_client):
13571356
response = api_client.get('/api/dandisets/', {'starred': True})
13581357
assert response.status_code == 401
1359-
1360-
1361-
@pytest.mark.django_db
1362-
def test_update_draft_version_doi_no_previous_doi(draft_version, mocker):
1363-
"""Test updating a draft DOI when none exists yet."""
1364-
# Set up mocks
1365-
mock_generate_doi = mocker.patch('dandiapi.api.doi.generate_doi_data')
1366-
mock_generate_doi.return_value = ('10.48324/dandi.000123', {'data': {'attributes': {}}})
1367-
1368-
mock_create_doi = mocker.patch('dandiapi.api.doi.create_or_update_doi')
1369-
mock_create_doi.return_value = '10.48324/dandi.000123'
1370-
1371-
update_draft_version_doi(draft_version)
1372-
1373-
# Verify the mocks were called correctly
1374-
mock_generate_doi.assert_called_once_with(
1375-
draft_version,
1376-
version_doi=False,
1377-
event=None
1378-
)
1379-
mock_create_doi.assert_called_once_with({'data': {'attributes': {}}})
1380-
1381-
# Verify the DOI was stored in the draft version
1382-
assert draft_version.doi == '10.48324/dandi.000123'
1383-
1384-
1385-
@pytest.mark.django_db
1386-
def test_update_draft_version_doi_existing_doi(draft_version, mocker):
1387-
"""Test updating a draft DOI when one already exists."""
1388-
# Set existing DOI
1389-
draft_version.doi = '10.48324/dandi.000123'
1390-
draft_version.save()
1391-
1392-
# Set up mocks
1393-
mock_generate_doi = mocker.patch('dandiapi.api.doi.generate_doi_data')
1394-
mock_generate_doi.return_value = ('10.48324/dandi.000123', {'data': {'attributes': {}}})
1395-
1396-
mock_create_doi = mocker.patch('dandiapi.api.doi.create_or_update_doi')
1397-
mock_create_doi.return_value = '10.48324/dandi.000123'
1398-
1399-
update_draft_version_doi(draft_version)
1400-
1401-
# Verify the mocks were called correctly
1402-
mock_generate_doi.assert_called_once_with(
1403-
draft_version,
1404-
version_doi=False,
1405-
event=None
1406-
)
1407-
mock_create_doi.assert_called_once_with({'data': {'attributes': {}}})
1408-
1409-
# Verify the DOI is still the same
1410-
assert draft_version.doi == '10.48324/dandi.000123'
1411-
1412-
1413-
@pytest.mark.django_db
1414-
def test_update_draft_version_doi_published_version(draft_version, published_version, mocker):
1415-
"""Test that update_draft_version_doi is a no-op for dandisets with published versions."""
1416-
# Set up mocks
1417-
mock_generate_doi = mocker.patch('dandiapi.api.doi.generate_doi_data')
1418-
mock_create_doi = mocker.patch('dandiapi.api.doi.create_or_update_doi')
1419-
1420-
update_draft_version_doi(draft_version)
1421-
1422-
# Verify no DOI operations were performed
1423-
mock_generate_doi.assert_not_called()
1424-
mock_create_doi.assert_not_called()

dandiapi/api/tests/test_doi.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
from dandiapi.api.doi import _create_dandiset_draft_doi
5+
from dandiapi.api.doi import _create_dandiset_draft_doi, _update_draft_version_doi
66

77

88
@pytest.mark.django_db
@@ -27,4 +27,70 @@ def test__create_dandiset_draft_doi(draft_version, mocker):
2727
mock_create_doi.assert_called_once_with({'data': {'attributes': {}}})
2828

2929
# Verify the DOI was stored in the draft version
30-
assert draft_version.doi == '10.48324/dandi.000123'
30+
assert draft_version.doi == '10.48324/dandi.000123'
31+
32+
33+
@pytest.mark.django_db
34+
def test_update_draft_version_doi_no_previous_doi(draft_version, mocker):
35+
"""Test updating a draft DOI when none exists yet."""
36+
# Set up mocks
37+
mock_generate_doi = mocker.patch('dandiapi.api.doi.generate_doi_data')
38+
mock_generate_doi.return_value = ('10.48324/dandi.000123', {'data': {'attributes': {}}})
39+
40+
mock_create_doi = mocker.patch('dandiapi.api.doi.create_or_update_doi')
41+
mock_create_doi.return_value = '10.48324/dandi.000123'
42+
43+
_update_draft_version_doi(draft_version)
44+
45+
# Verify the mocks were called correctly
46+
mock_generate_doi.assert_called_once_with(
47+
draft_version,
48+
version_doi=False,
49+
event=None
50+
)
51+
mock_create_doi.assert_called_once_with({'data': {'attributes': {}}})
52+
53+
# Verify the DOI was stored in the draft version
54+
assert draft_version.doi == '10.48324/dandi.000123'
55+
56+
57+
@pytest.mark.django_db
58+
def test_update_draft_version_doi_existing_doi(draft_version, mocker):
59+
"""Test updating a draft DOI when one already exists."""
60+
# Set existing DOI
61+
draft_version.doi = '10.48324/dandi.000123'
62+
draft_version.save()
63+
64+
# Set up mocks
65+
mock_generate_doi = mocker.patch('dandiapi.api.doi.generate_doi_data')
66+
mock_generate_doi.return_value = ('10.48324/dandi.000123', {'data': {'attributes': {}}})
67+
68+
mock_create_doi = mocker.patch('dandiapi.api.doi.create_or_update_doi')
69+
mock_create_doi.return_value = '10.48324/dandi.000123'
70+
71+
_update_draft_version_doi(draft_version)
72+
73+
# Verify the mocks were called correctly
74+
mock_generate_doi.assert_called_once_with(
75+
draft_version,
76+
version_doi=False,
77+
event=None
78+
)
79+
mock_create_doi.assert_called_once_with({'data': {'attributes': {}}})
80+
81+
# Verify the DOI is still the same
82+
assert draft_version.doi == '10.48324/dandi.000123'
83+
84+
85+
@pytest.mark.django_db
86+
def test_update_draft_version_doi_published_version(draft_version, published_version, mocker):
87+
"""Test that update_draft_version_doi is a no-op for dandisets with published versions."""
88+
# Set up mocks
89+
mock_generate_doi = mocker.patch('dandiapi.api.doi.generate_doi_data')
90+
mock_create_doi = mocker.patch('dandiapi.api.doi.create_or_update_doi')
91+
92+
_update_draft_version_doi(draft_version)
93+
94+
# Verify no DOI operations were performed
95+
mock_generate_doi.assert_not_called()
96+
mock_create_doi.assert_not_called()

0 commit comments

Comments
 (0)