Skip to content

Commit d33faf4

Browse files
committed
Merge branch 'hotfix/25.18.2'
2 parents dd21741 + 51df37c commit d33faf4

File tree

8 files changed

+113
-26
lines changed

8 files changed

+113
-26
lines changed

CHANGELOG

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

33
We follow the CalVer (https://calver.org/) versioning scheme: YY.MINOR.MICRO.
44

5+
25.18.2 (2025-12-19)
6+
====================
7+
8+
- Remove users from sitemap
9+
- Fix error when making registrations public
10+
- Fix PR templates
11+
512
25.18.1 (2025-12-10)
613
====================
714

PULL_REQUEST_TEMPLATE.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515

1616
## QA Notes
1717

18-
Please make verification statements inspired by your code and what your code touches.
19-
- Verify
20-
- Verify
2118

22-
What are the areas of risk?
23-
24-
Any concerns/considerations/questions that development raised?
19+
<!-- Please make verification statements inspired by your code and what your code touches.
20+
- Verify
21+
- Verify
22+
What are the areas of risk?
23+
Any concerns/considerations/questions that development raised?
24+
-->
2525

2626
## Documentation
2727

osf/models/admin_log_entry.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
PREPRINT_REMOVED = 70
3535
PREPRINT_RESTORED = 71
3636

37+
DOI_CREATION_FAILED = 80
38+
DOI_UPDATE_FAILED = 81
39+
3740
def update_admin_log(user_id, object_id, object_repr, message, action_flag=UNKNOWN):
3841
AdminLogEntry.objects.log_action(
3942
user_id=user_id,

osf/models/node.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,30 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat
12251225
# Embargoed registrations can be made public early
12261226
self.request_embargo_termination(auth.user)
12271227
return False
1228+
1229+
if not self.get_identifier_value('doi'):
1230+
try:
1231+
doi = self.request_identifier('doi')['doi']
1232+
self.set_identifier_value('doi', doi)
1233+
except Exception as e:
1234+
from osf.models.admin_log_entry import update_admin_log, DOI_CREATION_FAILED
1235+
logger.exception(
1236+
f'Failed to create DOI for registration {self._id} during set_privacy. '
1237+
f'Registration cannot be made public without a DOI.'
1238+
)
1239+
if auth and auth.user:
1240+
update_admin_log(
1241+
user_id=auth.user.id,
1242+
object_id=self._id,
1243+
object_repr=f'Registration {self.title}',
1244+
message=f'DOI creation failed during make public: {str(e)}. DataCite may be unavailable.',
1245+
action_flag=DOI_CREATION_FAILED
1246+
)
1247+
raise NodeStateError(
1248+
'Unable to make registration public: DOI creation failed. '
1249+
'This may be due to a temporary DataCite service outage. '
1250+
'Please try again later or contact support if the issue persists.'
1251+
)
12281252
self.is_public = True
12291253
elif permissions == 'private' and self.is_public:
12301254
if self.is_registration and not self.is_pending_embargo and not force:
@@ -1244,12 +1268,24 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat
12441268
if message:
12451269
status.push_status_message(message, kind='info', trust=False)
12461270

1247-
# Update existing identifiers
1271+
# Update existing identifiers metadata
12481272
if self.get_identifier_value('doi'):
1249-
update_doi_metadata_on_change(self._id)
1250-
elif self.is_registration:
1251-
doi = self.request_identifier('doi')['doi']
1252-
self.set_identifier_value('doi', doi)
1273+
try:
1274+
update_doi_metadata_on_change(self._id)
1275+
except Exception as e:
1276+
from osf.models.admin_log_entry import update_admin_log, DOI_UPDATE_FAILED
1277+
logger.exception(
1278+
f'Failed to update DOI metadata for {self._id} during set_privacy. '
1279+
)
1280+
# Log DOI metadata update failures for tracking
1281+
if auth and auth.user and self.is_registration:
1282+
update_admin_log(
1283+
user_id=auth.user.id,
1284+
object_id=self._id,
1285+
object_repr=f'Registration {self.title}',
1286+
message=f'DOI metadata update failed: {str(e)}. DataCite may be unavailable.',
1287+
action_flag=DOI_UPDATE_FAILED
1288+
)
12531289

12541290
if log:
12551291
action = NodeLog.MADE_PUBLIC if permissions == 'public' else NodeLog.MADE_PRIVATE

osf_tests/test_generate_sitemap.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ def all_included_links(self, user_admin_project_public, user_admin_project_priva
131131
# Return urls of all fixtures
132132
urls_to_include = [item['loc'] for item in settings.SITEMAP_STATIC_URLS]
133133
urls_to_include.extend([
134-
user_admin_project_public.url,
135-
user_admin_project_private.url,
134+
# user_admin_project_public.url,
135+
# user_admin_project_private.url,
136136
project_registration_public.url + 'overview',
137137
project_preprint_osf.url + 'overview',
138138
project_preprint_other.url + 'overview',

osf_tests/test_registrations.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.utils import timezone
77
from framework.auth.core import Auth
88
from framework.exceptions import PermissionsError
9+
from osf.exceptions import NodeStateError
910
from osf.models import Node, Registration, Sanction, RegistrationSchema, NodeLog, GuidMetadataRecord
1011
from addons.wiki.models import WikiPage
1112
from osf.utils.permissions import ADMIN
@@ -373,6 +374,46 @@ def test_legacy_private_registrations_can_be_made_public(self, registration, aut
373374
registration.set_privacy(Node.PUBLIC, auth=auth)
374375
assert registration.is_public
375376

377+
def test_registration_cannot_become_public_when_doi_creation_fails(self, registration, auth):
378+
registration.is_public = False
379+
existing_doi = registration.get_identifier('doi')
380+
if existing_doi:
381+
existing_doi.delete()
382+
registration.save()
383+
384+
assert registration.get_identifier_value('doi') is None
385+
386+
with mock.patch.object(registration, 'get_doi_client') as mock_get_client:
387+
mock_client = mock.Mock()
388+
mock_client.create_identifier.side_effect = Exception('DataCite API unavailable')
389+
mock_get_client.return_value = mock_client
390+
391+
with pytest.raises(NodeStateError) as exc_info:
392+
registration.set_privacy(Node.PUBLIC, auth=auth, log=False)
393+
394+
assert 'Unable to make registration public: DOI creation failed' in str(exc_info.value)
395+
assert registration.is_public is False
396+
397+
mock_client.create_identifier.assert_called_once()
398+
399+
@mock.patch('osf.models.node.update_doi_metadata_on_change')
400+
def test_registration_becomes_public_even_when_doi_metadata_update_fails(self, mock_update_doi, registration, auth):
401+
402+
registration.is_public = False
403+
registration.set_identifier_value('doi', '10.1234/test.doi')
404+
registration.save()
405+
406+
assert registration.get_identifier_value('doi') == '10.1234/test.doi'
407+
408+
mock_update_doi.side_effect = Exception('DataCite metadata update failed')
409+
410+
result = registration.set_privacy(Node.PUBLIC, auth=auth, log=False)
411+
412+
assert registration.is_public is True
413+
assert result is True
414+
415+
mock_update_doi.assert_called_once_with(registration._id)
416+
376417

377418
class TestRegisterNodeContributors:
378419

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "OSF",
3-
"version": "25.18.1",
3+
"version": "25.18.2",
44
"description": "Facilitating Open Science",
55
"repository": "https://github.com/CenterForOpenScience/osf.io",
66
"author": "Center for Open Science",

scripts/generate_sitemap.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,18 @@ def generate(self):
169169
progress.increment()
170170
progress.stop()
171171

172-
# User urls
173-
objs = OSFUser.objects.filter(is_active=True).exclude(date_confirmed__isnull=True).values_list('guids___id', flat=True)
174-
progress.start(objs.count(), 'USER: ')
175-
for obj in objs:
176-
try:
177-
config = settings.SITEMAP_USER_CONFIG
178-
config['loc'] = urljoin(settings.DOMAIN, f'/{obj}/')
179-
self.add_url(config)
180-
except Exception as e:
181-
self.log_errors('USER', obj, e)
182-
progress.increment()
183-
progress.stop()
172+
# # User urls
173+
# objs = OSFUser.objects.filter(is_active=True).exclude(date_confirmed__isnull=True).values_list('guids___id', flat=True)
174+
# progress.start(objs.count(), 'USER: ')
175+
# for obj in objs:
176+
# try:
177+
# config = settings.SITEMAP_USER_CONFIG
178+
# config['loc'] = urljoin(settings.DOMAIN, f'/{obj}/')
179+
# self.add_url(config)
180+
# except Exception as e:
181+
# self.log_errors('USER', obj, e)
182+
# progress.increment()
183+
# progress.stop()
184184

185185
# AbstractNode urls (Nodes and Registrations, no Collections)
186186
objs = (AbstractNode.objects

0 commit comments

Comments
 (0)