-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathdoi.py
147 lines (130 loc) · 5.22 KB
/
doi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from django.conf import settings
import requests
if TYPE_CHECKING:
from dandiapi.api.models import Version
# All of the required DOI configuration settings
DANDI_DOI_SETTINGS = [
(settings.DANDI_DOI_API_URL, 'DANDI_DOI_API_URL'),
(settings.DANDI_DOI_API_USER, 'DANDI_DOI_API_USER'),
(settings.DANDI_DOI_API_PASSWORD, 'DANDI_DOI_API_PASSWORD'),
(settings.DANDI_DOI_API_PREFIX, 'DANDI_DOI_API_PREFIX'),
]
logger = logging.getLogger(__name__)
def doi_configured() -> bool:
return any(setting is not None for setting, _ in DANDI_DOI_SETTINGS)
# TODO(asmacdo) findable dois
# def _generate_doi_data(version: Version, event: str):
def _generate_doi_data(version: Version, version_doi=True):
from dandischema.datacite import to_datacite
publish = settings.DANDI_DOI_PUBLISH
# Use the DANDI test datacite instance as a placeholder if PREFIX isn't set
prefix = settings.DANDI_DOI_API_PREFIX or '10.80507'
dandiset_id = version.dandiset.identifier
version_id = version.version
if version_doi:
doi = f'{prefix}/dandi.{dandiset_id}/{version_id}'
else:
doi = f'{prefix}/dandi.{dandiset_id}'
metadata = version.metadata
metadata['doi'] = doi
# TODO(asmacdo) findable dois
# datacite_body = to_datacite(metadata, event=event)
datacite_body = to_datacite(metadata, version_doi=version_doi)
return (doi, datacite_body)
def update_dandiset_doi(version: Version) -> str:
payload = {
"data": {
"attributes": {
"url": version.metadata["url"]
}
}
}
if doi_configured():
logger.info(f"updating {version.dandiset} DOI {version.dandiset.doi} pointer to {version.metadata['url']}!")
try:
requests.put(
f"{settings.DANDI_DOI_API_URL}/{version.dandiset.doi}",
json=payload,
auth=requests.auth.HTTPBasicAuth(
settings.DANDI_DOI_API_USER,
settings.DANDI_DOI_API_PASSWORD,
),
timeout=30,
).raise_for_status()
except requests.exceptions.HTTPError as e:
logger.exception('Failed to update Dandiset DOI %s', version.dandiset.doi)
logger.exception(payload)
if e.response:
logger.exception(e.response.text)
raise
else:
logger.debug("Skipping Datacite API usage, doi is not configured.")
def create_dandiset_doi(version: Version) -> str:
doi, request_body = _generate_doi_data(version, version_doi=False)
if doi_configured():
try:
requests.post(
settings.DANDI_DOI_API_URL,
json=request_body,
auth=requests.auth.HTTPBasicAuth(
settings.DANDI_DOI_API_USER,
settings.DANDI_DOI_API_PASSWORD,
),
timeout=30,
).raise_for_status()
except requests.exceptions.HTTPError as e:
logger.exception('Failed to create DOI %s', doi)
logger.exception(request_body)
if e.response:
logger.exception(e.response.text)
raise
return doi
def create_version_doi(version: Version) -> str:
doi, request_body = _generate_doi_data(version, version_doi=True)
# If DOI isn't configured, skip the API call
if doi_configured():
try:
requests.post(
settings.DANDI_DOI_API_URL,
json=request_body,
auth=requests.auth.HTTPBasicAuth(
settings.DANDI_DOI_API_USER,
settings.DANDI_DOI_API_PASSWORD,
),
timeout=30,
).raise_for_status()
except requests.exceptions.HTTPError as e:
logger.exception('Failed to create DOI %s', doi)
logger.exception(request_body)
if e.response:
logger.exception(e.response.text)
raise
else:
print("DOI NOT CONFIGURED!!!")
return doi
def delete_doi(doi: str) -> None:
# If DOI isn't configured, skip the API call
if doi_configured():
doi_url = settings.DANDI_DOI_API_URL.rstrip('/') + '/' + doi
with requests.Session() as s:
s.auth = (settings.DANDI_DOI_API_USER, settings.DANDI_DOI_API_PASSWORD)
try:
r = s.get(doi_url, headers={'Accept': 'application/vnd.api+json'})
r.raise_for_status()
except requests.exceptions.HTTPError as e:
if e.response and e.response.status_code == requests.codes.not_found:
logger.warning('Tried to get data for nonexistent DOI %s', doi)
return
logger.exception('Failed to fetch data for DOI %s', doi)
raise
if r.json()['data']['attributes']['state'] == 'draft':
try:
s.delete(doi_url).raise_for_status()
except requests.exceptions.HTTPError:
logger.exception('Failed to delete DOI %s', doi)
raise
else:
logger.debug('Skipping DOI deletion for %s since not configured', doi)