Skip to content

Commit 7c9f470

Browse files
authored
Merge pull request #11162 from opaduchak/fix/ENG-8145
[ENG-8145] Added manual doi setting for registrations and preprints
2 parents 03bf6c1 + 7f4adf4 commit 7c9f470

File tree

7 files changed

+51
-22
lines changed

7 files changed

+51
-22
lines changed

api/preprints/serializers.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
from api.institutions.utils import update_institutions_if_user_associated
3939
from api.preprints.fields import DOIField
4040
from api.taxonomies.serializers import TaxonomizableSerializerMixin
41+
from api.waffle.utils import flag_is_active
4142
from framework.exceptions import PermissionsError, UnpublishedPendingPreprintVersionExists
43+
from osf import features
4244
from website.project import signals as project_signals
4345
from osf.exceptions import NodeStateError, PreprintStateError
4446
from osf.models import (
@@ -106,7 +108,6 @@ class PreprintSerializer(TaxonomizableSerializerMixin, MetricsSerializerMixin, J
106108
])
107109

108110
id = IDField(source='_id', read_only=True)
109-
manual_guid = ser.CharField(write_only=True, required=False, allow_null=True)
110111
type = TypeField()
111112

112113
date_created = VersionedDateTimeField(source='created', read_only=True)
@@ -500,17 +501,25 @@ class PreprintCreateSerializer(PreprintSerializer):
500501
# Overrides PreprintSerializer to make id nullable, adds `create`
501502
# TODO: add better Docstrings
502503
id = IDField(source='_id', required=False, allow_null=True)
504+
manual_guid = ser.CharField(write_only=True, required=False, allow_null=True)
505+
manual_doi = ser.CharField(write_only=True, required=False, allow_null=True)
503506

504507
def create(self, validated_data):
505508

506-
guid_str = validated_data.pop('manual_guid', None)
507509
creator = self.context['request'].user
508510
provider = validated_data.pop('provider', None)
509511
if not provider:
510512
raise exceptions.ValidationError(detail='You must specify a valid provider to create a preprint.')
511513
title = validated_data.pop('title')
512514
description = validated_data.pop('description', '')
513-
preprint = Preprint.create(provider=provider, title=title, creator=creator, description=description, guid_str=guid_str)
515+
516+
# For manual GUID and DOI assignment during creation for privileged users
517+
manual_guid = validated_data.pop('manual_guid', None)
518+
manual_doi = validated_data.pop('manual_doi', None)
519+
if manual_doi and not flag_is_active(self.context['request'], features.MANUAL_DOI_AND_GUID):
520+
raise exceptions.ValidationError(detail='Manual DOI assignment is not allowed.')
521+
522+
preprint = Preprint.create(provider=provider, title=title, creator=creator, description=description, manual_guid=manual_guid, manual_doi=manual_doi)
514523

515524
return self.update(preprint, validated_data)
516525

api/registrations/serializers.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import pytz
22
import json
3+
4+
from api.waffle.utils import flag_is_active
5+
from osf import features
36
from website.archiver.utils import normalize_unicode_filenames
47

58
from packaging.version import Version
@@ -83,7 +86,6 @@ class RegistrationSerializer(NodeSerializer):
8386
'has_supplements',
8487
])
8588

86-
manual_guid = ser.CharField(write_only=True, required=False, allow_null=True)
8789
ia_url = ser.URLField(read_only=True)
8890
reviews_state = ser.CharField(source='moderation_state', read_only=True)
8991
title = ser.CharField(required=False)
@@ -734,6 +736,10 @@ def __init__(self, *args, **kwargs):
734736
else:
735737
self.fields['draft_registration'] = ser.CharField(write_only=True)
736738

739+
# For manual GUID and DOI assignment during creation for privileged users
740+
manual_guid = ser.CharField(write_only=True, required=False, allow_null=True)
741+
manual_doi = ser.CharField(write_only=True, required=False, allow_null=True)
742+
737743
# For newer versions
738744
embargo_end_date = VersionedDateTimeField(write_only=True, allow_null=True, default=None)
739745
included_node_ids = ser.ListField(write_only=True, required=False)
@@ -788,7 +794,7 @@ def get_children_by_version(self, validated_data):
788794

789795
def create(self, validated_data):
790796

791-
guid_str = validated_data.pop('manual_guid', None)
797+
manual_guid = validated_data.pop('manual_guid', None)
792798
auth = get_user_auth(self.context['request'])
793799
draft = validated_data.pop('draft', None)
794800
registration_choice = self.get_registration_choice_by_version(validated_data)
@@ -813,7 +819,7 @@ def create(self, validated_data):
813819
)
814820

815821
try:
816-
registration = draft.register(auth, save=True, child_ids=children, guid_str=guid_str)
822+
registration = draft.register(auth, save=True, child_ids=children, manual_guid=manual_guid)
817823
except NodeStateError as err:
818824
raise exceptions.ValidationError(err)
819825

@@ -826,6 +832,11 @@ def create(self, validated_data):
826832
except ValidationError as err:
827833
raise exceptions.ValidationError(err.message)
828834
else:
835+
manual_doi = validated_data.pop('manual_doi', None)
836+
if manual_doi:
837+
if not flag_is_active(self.context['request'], features.MANUAL_DOI_AND_GUID):
838+
raise exceptions.ValidationError(detail='Manual DOI assignment is not allowed.')
839+
registration.set_identifier_value('doi', manual_doi)
829840
try:
830841
registration.require_approval(auth.user)
831842
except NodeStateError as err:

osf/features.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
# 5. When a flag name is no longer referenced anywhere in this repo or in the Ember app remove it from this list.
1313
flags:
1414

15+
- flag_name: MANUAL_DOI_AND_GUID
16+
name: manual_doi_and_guid
17+
note: This is used to allow certain product staff members to manually assign doi and guid during Registration or
18+
Preprint creation. DO NOT CHANGE UNLESS ABSOLUTELY NECESSARY.
19+
everyone: false
20+
1521
- flag_name: ENABLE_GV
1622
name: gravy_waffle
1723
note: This is used to enable GravyValet, the system responible for addons, this will remove the files widget on the

osf/models/draft_node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def convert_draft_node_to_node(self, auth):
5858
)
5959
return
6060

61-
def register_node(self, schema, auth, draft_registration, parent=None, child_ids=None, provider=None, guid_str=None):
61+
def register_node(self, schema, auth, draft_registration, parent=None, child_ids=None, provider=None, manual_guid=None):
6262
"""Converts the DraftNode to a Node, copies editable fields from the DraftRegistration back to the Node,
6363
and then registers the Node
6464
@@ -73,4 +73,4 @@ def register_node(self, schema, auth, draft_registration, parent=None, child_ids
7373
self.copy_editable_fields(draft_registration, save=True)
7474

7575
# Calls super on Node, since self is no longer a DraftNode
76-
return super(Node, self).register_node(schema, auth, draft_registration, parent, child_ids, provider, guid_str)
76+
return super(Node, self).register_node(schema, auth, draft_registration, parent=parent, child_ids=child_ids, provider=provider, manual_guid=manual_guid)

osf/models/node.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,7 @@ def subscribe_contributors_to_node(self):
13951395
contributor=user,
13961396
auth=None, email_template='default', permissions=perm)
13971397

1398-
def register_node(self, schema, auth, draft_registration, parent=None, child_ids=None, provider=None, guid_str=None):
1398+
def register_node(self, schema, auth, draft_registration, parent=None, child_ids=None, provider=None, manual_guid=None):
13991399
"""Make a frozen copy of a node.
14001400
14011401
:param schema: Schema object
@@ -1439,12 +1439,12 @@ def register_node(self, schema, auth, draft_registration, parent=None, child_ids
14391439
# Need to save here in order to set many-to-many fields, set is_public to false to avoid Spam filter/reindexing.
14401440
registered.is_public = False
14411441

1442-
if guid_str:
1443-
if not check_manually_assigned_guid(guid_str):
1444-
raise ValidationError(f'GUID cannot be manually assigned: guid_str={guid_str}.')
1442+
if manual_guid:
1443+
if not check_manually_assigned_guid(manual_guid):
1444+
raise ValidationError(f'GUID cannot be manually assigned: guid_str={manual_guid}.')
14451445
from osf.models import Guid
1446-
guid_obj = Guid.objects.create(_id=guid_str)
1447-
registered._manual_guid = guid_str
1446+
guid_obj = Guid.objects.create(_id=manual_guid)
1447+
registered._manual_guid = manual_guid
14481448
# Initial save to just to create the PK
14491449
registered.save(manually_assign_guid=True)
14501450
guid_obj.referent = registered

osf/models/preprint.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ def __unicode__(self):
344344
return '{} ({} preprint) (guid={}){}'.format(self.title, 'published' if self.is_published else 'unpublished', self._id, ' with supplemental files on ' + self.node.__unicode__() if self.node else '')
345345

346346
@classmethod
347-
def create(cls, provider, title, creator, description, guid_str=None):
347+
def create(cls, provider, title, creator, description, manual_guid=None, manual_doi=None):
348348
"""Customized creation process to support preprint versions and versioned guid.
349349
"""
350350
# Step 1: Create the preprint obj
@@ -356,10 +356,10 @@ def create(cls, provider, title, creator, description, guid_str=None):
356356
)
357357
preprint.save(guid_ready=False)
358358
# Step 2: Create the base guid obj
359-
if guid_str:
360-
if not check_manually_assigned_guid(guid_str):
361-
raise ValidationError(f'GUID cannot be manually assigned: guid_str={guid_str}.')
362-
base_guid_obj = Guid.objects.create(_id=guid_str)
359+
if manual_guid:
360+
if not check_manually_assigned_guid(manual_guid):
361+
raise ValidationError(f'GUID cannot be manually assigned: guid_str={manual_guid}.')
362+
base_guid_obj = Guid.objects.create(_id=manual_guid)
363363
else:
364364
base_guid_obj = Guid.objects.create()
365365
base_guid_obj.referent = preprint
@@ -375,7 +375,7 @@ def create(cls, provider, title, creator, description, guid_str=None):
375375
guid=base_guid_obj
376376
)
377377
versioned_guid.save()
378-
preprint.save(guid_ready=True, first_save=True)
378+
preprint.save(guid_ready=True, first_save=True, manual_doi=manual_doi)
379379

380380
return preprint
381381

@@ -985,6 +985,7 @@ def save(self, *args, **kwargs):
985985
raise IntegrityError(err_msg)
986986

987987
first_save = kwargs.pop('first_save', False)
988+
manual_doi = kwargs.pop('manual_doi', None)
988989
set_creator_as_contributor = kwargs.pop('set_creator_as_contributor', True)
989990
saved_fields = self.get_dirty_fields() or []
990991

@@ -1009,6 +1010,8 @@ def save(self, *args, **kwargs):
10091010
# thus no need to set creator as the first contributor immediately
10101011
if set_creator_as_contributor:
10111012
self._add_creator_as_contributor()
1013+
if manual_doi:
1014+
self.set_identifier_value('doi', manual_doi)
10121015

10131016
if (not first_save and 'is_published' in saved_fields) or self.is_published:
10141017
update_or_enqueue_on_preprint_updated(preprint_id=self._id, saved_fields=saved_fields)

osf/models/registrations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ def unescape_registration_file_names(self, registration_responses):
13661366
upload['file_name'] = html.unescape(upload['file_name'])
13671367
return registration_responses
13681368

1369-
def register(self, auth, save=False, child_ids=None, guid_str=None):
1369+
def register(self, auth, save=False, child_ids=None, manual_guid=None):
13701370
node = self.branched_from
13711371

13721372
if not self.title:
@@ -1379,7 +1379,7 @@ def register(self, auth, save=False, child_ids=None, guid_str=None):
13791379
draft_registration=self,
13801380
child_ids=child_ids,
13811381
provider=self.provider,
1382-
guid_str=guid_str,
1382+
manual_guid=manual_guid,
13831383
)
13841384
self.registered_node = registration
13851385
self.add_status_log(auth.user, DraftRegistrationLog.REGISTERED)

0 commit comments

Comments
 (0)