Skip to content
Open
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
29 changes: 26 additions & 3 deletions api/crossref/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from api.crossref.permissions import RequestComesFromMailgun
from osf.models import Preprint, NotificationTypeEnum
from osf.models.base import Guid
from website import settings
from website.preprints.tasks import mint_doi_on_crossref_fail

Expand Down Expand Up @@ -48,6 +49,23 @@ def post(self, request):
if record.get('status').lower() == 'success' and doi:
msg = record.find('msg').text
created = bool(msg == 'Successfully added')
# Unversioned DOIs (no _vN suffix, e.g. 10.31233/osf.io/tnaqp) are routing
# aliases that always resolve to the latest version via OSF's GUID routing.
# Store them as 'doi_unversioned' on the v1 preprint so we can track which
# preprint series have had their unversioned DOI registered.
_, version = Guid.split_guid(guid) if guid else (None, None)
if not version:
logger.info(f'Unversioned DOI confirmed by CrossRef: {doi}')
if created and guid:
v1_preprint = Preprint.objects.filter(
versioned_guids__guid___id=guid,
versioned_guids__version=1,
).first()
if v1_preprint:
v1_preprint.set_identifier_value(category='doi_unversioned', value=doi)
dois_processed += 1
continue

legacy_doi = preprint.get_identifier(category='legacy_doi')
if created or legacy_doi:
# Sets preprint_doi_created and saves the preprint
Expand All @@ -67,9 +85,14 @@ def post(self, request):
if 'Relation target DOI does not exist' in record.find('msg').text:
logger.warning('Related publication DOI does not exist, sending metadata again without it...')
mint_doi_on_crossref_fail.apply_async(kwargs={'preprint_id': preprint._id})
# This error occurs when a single preprint is being updated several times in a row with the same metadata [#PLAT-944]
elif 'less or equal to previously submitted version' in record.find('msg').text and record_count == 2:
break
# This error occurs when a single preprint is being updated several times in a row
# with the same metadata [#PLAT-944]. Previously this broke out of the loop when
# record_count == 2 (single DOI submitted twice). Now batches legitimately contain
# 2 records (versioned + unversioned DOI), so we continue instead of break to allow
# the remaining record to be processed.
elif 'less or equal to previously submitted version' in record.find('msg').text:
dois_processed += 1
continue
else:
unexpected_errors = True
logger.info(f'Creation success email received from CrossRef for preprints: {guids}')
Expand Down
3 changes: 2 additions & 1 deletion api/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,8 @@ def post(self, request, *args, **kwargs):

user.date_last_logged_in = timezone.now()
user.external_identity[provider][provider_id] = 'VERIFIED'
user.social[provider.lower()] = provider_id
if provider.lower() in OSFUser.SOCIAL_FIELDS:
user.social[provider.lower()] = provider_id
del user.email_verifications[token]
user.verification_key = generate_verification_key()
user.save()
Expand Down
88 changes: 88 additions & 0 deletions api_tests/crossref/views/test_crossref_email_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,91 @@ def test_confirmation_marks_legacy_doi_as_deleted(self, app, url, preprint):
app.post(url, context_data)

assert preprint.identifiers.get(category='legacy_doi').deleted

def test_unversioned_doi_confirmation_skips_identifier_update(self, app, url, preprint):
versioned_doi = settings.DOI_FORMAT.format(
prefix=preprint.provider.doi_prefix, guid=preprint._id
)
preprint.set_identifier_value(category='doi', value=versioned_doi)

base_guid = preprint.get_guid()._id # no _vN suffix
unversioned_doi = settings.DOI_FORMAT.format(
prefix=preprint.provider.doi_prefix, guid=base_guid
)
dual_confirmation_xml = """
<?xml version="1.0" encoding="UTF-8"?>
<doi_batch_diagnostic status="completed" sp="cs3.crossref.org">
<submission_id>1390675999</submission_id>
<batch_id>{batch_id}</batch_id>
<record_diagnostic status="Success">
<doi>{versioned_doi}</doi>
<msg>Successfully updated</msg>
</record_diagnostic>
<record_diagnostic status="Success">
<doi>{unversioned_doi}</doi>
<msg>Successfully added</msg>
</record_diagnostic>
<batch_data>
<record_count>2</record_count>
<success_count>2</success_count>
<warning_count>0</warning_count>
<failure_count>0</failure_count>
</batch_data>
</doi_batch_diagnostic>
""".format(
batch_id=preprint._id,
versioned_doi=versioned_doi,
unversioned_doi=unversioned_doi,
)

context_data = self.make_mailgun_payload(crossref_response=dual_confirmation_xml)
with capture_notifications(expect_none=True):
app.post(url, context_data)

preprint.reload()
assert preprint.get_identifier_value('doi') == versioned_doi
assert preprint.get_identifier_value('doi_unversioned') == unversioned_doi

def test_unversioned_doi_confirmation_update_does_not_store_doi_unversioned(self, app, url, preprint):
versioned_doi = settings.DOI_FORMAT.format(
prefix=preprint.provider.doi_prefix, guid=preprint._id
)
preprint.set_identifier_value(category='doi', value=versioned_doi)

base_guid = preprint.get_guid()._id
unversioned_doi = settings.DOI_FORMAT.format(
prefix=preprint.provider.doi_prefix, guid=base_guid
)
update_confirmation_xml = """
<?xml version="1.0" encoding="UTF-8"?>
<doi_batch_diagnostic status="completed" sp="cs3.crossref.org">
<submission_id>1390676000</submission_id>
<batch_id>{batch_id}</batch_id>
<record_diagnostic status="Success">
<doi>{versioned_doi}</doi>
<msg>Successfully updated</msg>
</record_diagnostic>
<record_diagnostic status="Success">
<doi>{unversioned_doi}</doi>
<msg>Successfully updated</msg>
</record_diagnostic>
<batch_data>
<record_count>2</record_count>
<success_count>2</success_count>
<warning_count>0</warning_count>
<failure_count>0</failure_count>
</batch_data>
</doi_batch_diagnostic>
""".format(
batch_id=preprint._id,
versioned_doi=versioned_doi,
unversioned_doi=unversioned_doi,
)

context_data = self.make_mailgun_payload(crossref_response=update_confirmation_xml)
with capture_notifications(expect_none=True):
app.post(url, context_data)

preprint.reload()
assert preprint.get_identifier_value('doi') == versioned_doi
assert preprint.get_identifier_value('doi_unversioned') is None
Loading
Loading