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
1 change: 0 additions & 1 deletion admin_tests/preprints/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from osf.models.spam import SpamStatus
from osf.utils.workflows import DefaultStates, RequestTypes
from osf.utils.permissions import ADMIN
from framework.auth import Auth

from admin_tests.utilities import setup_view, setup_log_view, handle_post_view_request

Expand Down
3 changes: 3 additions & 0 deletions osf/models/admin_log_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
PREPRINT_REMOVED = 70
PREPRINT_RESTORED = 71

DOI_CREATION_FAILED = 80
DOI_UPDATE_FAILED = 81

def update_admin_log(user_id, object_id, object_repr, message, action_flag=UNKNOWN):
AdminLogEntry.objects.log_action(
user_id=user_id,
Expand Down
46 changes: 41 additions & 5 deletions osf/models/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,30 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat
# Embargoed registrations can be made public early
self.request_embargo_termination(auth.user)
return False

if not self.get_identifier_value('doi'):
try:
doi = self.request_identifier('doi')['doi']
self.set_identifier_value('doi', doi)
except Exception as e:
from osf.models.admin_log_entry import update_admin_log, DOI_CREATION_FAILED
logger.exception(
f'Failed to create DOI for registration {self._id} during set_privacy. '
f'Registration cannot be made public without a DOI.'
)
if auth and auth.user:
update_admin_log(
user_id=auth.user.id,
object_id=self._id,
object_repr=f'Registration {self.title}',
message=f'DOI creation failed during make public: {str(e)}. DataCite may be unavailable.',
action_flag=DOI_CREATION_FAILED
)
raise NodeStateError(
'Unable to make registration public: DOI creation failed. '
'This may be due to a temporary DataCite service outage. '
'Please try again later or contact support if the issue persists.'
)
self.is_public = True
elif permissions == 'private' and self.is_public:
if self.is_registration and not self.is_pending_embargo and not force:
Expand All @@ -1233,12 +1257,24 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat
if message:
status.push_status_message(message, kind='info', trust=False)

# Update existing identifiers
# Update existing identifiers metadata
if self.get_identifier_value('doi'):
update_doi_metadata_on_change(self._id)
elif self.is_registration:
doi = self.request_identifier('doi')['doi']
self.set_identifier_value('doi', doi)
try:
update_doi_metadata_on_change(self._id)
except Exception as e:
from osf.models.admin_log_entry import update_admin_log, DOI_UPDATE_FAILED
logger.exception(
f'Failed to update DOI metadata for {self._id} during set_privacy. '
)
# Log DOI metadata update failures for tracking
if auth and auth.user and self.is_registration:
update_admin_log(
user_id=auth.user.id,
object_id=self._id,
object_repr=f'Registration {self.title}',
message=f'DOI metadata update failed: {str(e)}. DataCite may be unavailable.',
action_flag=DOI_UPDATE_FAILED
)

if log:
action = NodeLog.MADE_PUBLIC if permissions == 'public' else NodeLog.MADE_PRIVATE
Expand Down
41 changes: 41 additions & 0 deletions osf_tests/test_registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.utils import timezone
from framework.auth.core import Auth
from framework.exceptions import PermissionsError
from osf.exceptions import NodeStateError
from osf.models import Node, Registration, Sanction, RegistrationSchema, NodeLog, GuidMetadataRecord
from addons.wiki.models import WikiPage
from osf.utils.permissions import ADMIN
Expand Down Expand Up @@ -373,6 +374,46 @@ def test_legacy_private_registrations_can_be_made_public(self, registration, aut
registration.set_privacy(Node.PUBLIC, auth=auth)
assert registration.is_public

def test_registration_cannot_become_public_when_doi_creation_fails(self, registration, auth):
registration.is_public = False
existing_doi = registration.get_identifier('doi')
if existing_doi:
existing_doi.delete()
registration.save()

assert registration.get_identifier_value('doi') is None

with mock.patch.object(registration, 'get_doi_client') as mock_get_client:
mock_client = mock.Mock()
mock_client.create_identifier.side_effect = Exception('DataCite API unavailable')
mock_get_client.return_value = mock_client

with pytest.raises(NodeStateError) as exc_info:
registration.set_privacy(Node.PUBLIC, auth=auth, log=False)

assert 'Unable to make registration public: DOI creation failed' in str(exc_info.value)
assert registration.is_public is False

mock_client.create_identifier.assert_called_once()

@mock.patch('osf.models.node.update_doi_metadata_on_change')
def test_registration_becomes_public_even_when_doi_metadata_update_fails(self, mock_update_doi, registration, auth):

registration.is_public = False
registration.set_identifier_value('doi', '10.1234/test.doi')
registration.save()

assert registration.get_identifier_value('doi') == '10.1234/test.doi'

mock_update_doi.side_effect = Exception('DataCite metadata update failed')

result = registration.set_privacy(Node.PUBLIC, auth=auth, log=False)

assert registration.is_public is True
assert result is True

mock_update_doi.assert_called_once_with(registration._id)


class TestRegisterNodeContributors:

Expand Down
Loading