From 8612887ce9c8dfdac05307010ac6ad0ac542c304 Mon Sep 17 00:00:00 2001 From: Vlad0n20 <137097005+Vlad0n20@users.noreply.github.com> Date: Wed, 4 Feb 2026 07:07:11 +0200 Subject: [PATCH 1/4] [ENG-10042] Fix/eng 10042 (#11551) * Update RegistrationActionSerializer * Update RegistrationActionSerializer --- api/actions/serializers.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/api/actions/serializers.py b/api/actions/serializers.py index d572ee41654..a4ab5b71d83 100644 --- a/api/actions/serializers.py +++ b/api/actions/serializers.py @@ -26,6 +26,7 @@ ) from osf.utils.workflows import ( + ApprovalStates, DefaultStates, DefaultTriggers, ReviewStates, @@ -278,6 +279,31 @@ def create(self, validated_data): comment = validated_data.pop('comment', '') user = validated_data.pop('user') + pending_schema_response_updates = target.schema_responses.filter( + reviews_state__in=[ + ApprovalStates.UNAPPROVED.db_name, + ApprovalStates.PENDING_MODERATION.db_name, + ], + previous_response__isnull=False, # Only updates, not initial submissions + ).order_by('-created') + + if pending_schema_response_updates.exists(): + pending_response = pending_schema_response_updates.first() + short_message = 'This registration has a pending update' + long_message = ( + f'This registration has a pending schema response update (ID: {pending_response._id}) ' + f'that must be moderated. Please use the schema response actions endpoint to approve or reject ' + f'the update instead of creating a registration action.' + ) + raise HTTPError( + http_status.HTTP_400_BAD_REQUEST, + data={ + 'message_short': short_message, + 'message_long': long_message, + 'schema_response_id': pending_response._id, + }, + ) + sanction = target.sanction try: From c705963bda4b38eaf6f5775d35b7f42114e8b5e0 Mon Sep 17 00:00:00 2001 From: Vlad0n20 <137097005+Vlad0n20@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:11:02 +0200 Subject: [PATCH 2/4] [ENG-10042] Fix/eng 10042 (#11593) Revert BE changes meant to fix 10042 and replace with FE changes. --- api/actions/serializers.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/api/actions/serializers.py b/api/actions/serializers.py index a4ab5b71d83..d572ee41654 100644 --- a/api/actions/serializers.py +++ b/api/actions/serializers.py @@ -26,7 +26,6 @@ ) from osf.utils.workflows import ( - ApprovalStates, DefaultStates, DefaultTriggers, ReviewStates, @@ -279,31 +278,6 @@ def create(self, validated_data): comment = validated_data.pop('comment', '') user = validated_data.pop('user') - pending_schema_response_updates = target.schema_responses.filter( - reviews_state__in=[ - ApprovalStates.UNAPPROVED.db_name, - ApprovalStates.PENDING_MODERATION.db_name, - ], - previous_response__isnull=False, # Only updates, not initial submissions - ).order_by('-created') - - if pending_schema_response_updates.exists(): - pending_response = pending_schema_response_updates.first() - short_message = 'This registration has a pending update' - long_message = ( - f'This registration has a pending schema response update (ID: {pending_response._id}) ' - f'that must be moderated. Please use the schema response actions endpoint to approve or reject ' - f'the update instead of creating a registration action.' - ) - raise HTTPError( - http_status.HTTP_400_BAD_REQUEST, - data={ - 'message_short': short_message, - 'message_long': long_message, - 'schema_response_id': pending_response._id, - }, - ) - sanction = target.sanction try: From 0805fef72ea05e85b48babcf0264d34a272c695d Mon Sep 17 00:00:00 2001 From: Ihor Sokhan Date: Thu, 12 Mar 2026 09:53:25 +0200 Subject: [PATCH 3/4] fixed non-consistent COI --- admin/preprints/urls.py | 1 + admin/preprints/views.py | 16 ++++++++++ admin/templates/preprints/fix_coi.html | 21 +++++++++++++ admin/templates/preprints/preprint.html | 1 + admin_tests/preprints/test_views.py | 39 +++++++++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 admin/templates/preprints/fix_coi.html diff --git a/admin/preprints/urls.py b/admin/preprints/urls.py index d6eabdd870c..960e2e297e5 100644 --- a/admin/preprints/urls.py +++ b/admin/preprints/urls.py @@ -17,6 +17,7 @@ re_path(r'^(?P\w+)/remove_user/(?P[a-z0-9]+)/$', views.PreprintRemoveContributorView.as_view(), name='remove-user'), re_path(r'^(?P\w+)/make_private/$', views.PreprintMakePrivate.as_view(), name='make-private'), re_path(r'^(?P\w+)/fix_editing/$', views.PreprintFixEditing.as_view(), name='fix-editing'), + re_path(r'^(?P\w+)/fix_coi/$', views.PreprintFixCOI.as_view(), name='fix-coi'), re_path(r'^(?P\w+)/make_public/$', views.PreprintMakePublic.as_view(), name='make-public'), re_path(r'^(?P\w+)/remove/$', views.PreprintDeleteView.as_view(), name='remove'), re_path(r'^(?P\w+)/restore/$', views.PreprintDeleteView.as_view(), name='restore'), diff --git a/admin/preprints/views.py b/admin/preprints/views.py index 99d18d83650..3153ae301c8 100644 --- a/admin/preprints/views.py +++ b/admin/preprints/views.py @@ -668,6 +668,22 @@ def post(self, request, *args, **kwargs): return redirect(self.get_success_url()) +class PreprintFixCOI(PreprintMixin, View): + """ Allows an authorized user to manually fix conflict of interest field. + """ + permission_required = 'osf.change_preprint' + + def post(self, request, *args, **kwargs): + preprint = self.get_object() + if preprint.conflict_of_interest_statement and not preprint.has_coi: + preprint.update_has_coi(auth=request, has_coi=True, ignore_permission=True) + messages.success(request, 'The COI was successfully fixed.') + else: + messages.error(request, 'The COI is either already fixed or the preprint does not have conflict of interest set.') + + return redirect(self.get_success_url()) + + class PreprintMakePublic(PreprintMixin, View): """ Allows an authorized user to manually make a private preprint public. """ diff --git a/admin/templates/preprints/fix_coi.html b/admin/templates/preprints/fix_coi.html new file mode 100644 index 00000000000..6ee06e66130 --- /dev/null +++ b/admin/templates/preprints/fix_coi.html @@ -0,0 +1,21 @@ +{% if perms.osf.change_node %} + + Fix COI + + +{% endif %} diff --git a/admin/templates/preprints/preprint.html b/admin/templates/preprints/preprint.html index d716b60aeb7..36066a94ccf 100644 --- a/admin/templates/preprints/preprint.html +++ b/admin/templates/preprints/preprint.html @@ -28,6 +28,7 @@ {% include "preprints/make_public.html" with preprint=preprint %} {% include "preprints/make_published.html" with preprint=preprint %} {% include "preprints/fix_editing.html" with preprint=preprint %} + {% include "preprints/fix_coi.html" with preprint=preprint %} {% include "preprints/assign_new_version.html" with preprint=preprint %} diff --git a/admin_tests/preprints/test_views.py b/admin_tests/preprints/test_views.py index efd571a5772..5582c1b07eb 100644 --- a/admin_tests/preprints/test_views.py +++ b/admin_tests/preprints/test_views.py @@ -960,3 +960,42 @@ def test_osf_admin_can_create_new_version_with_unregistered_contributors(self, p preprint.refresh_from_db() assert len(preprint.get_preprint_versions()) == 2 + + +@pytest.mark.urls('admin.base.urls') +class TestPreprintFixCOIView: + + @pytest.fixture() + def plain_view(self): + return views.PreprintFixCOI + + def test_admin_user_can_fix_coi_only_when_coi_is_set(self, user, preprint, plain_view): + admin_group = Group.objects.get(name='osf_admin') + preprint.has_coi = False + preprint.conflict_of_interest_statement = 'some text' + preprint.save() + + request = RequestFactory().post(reverse('preprints:fix-coi', kwargs={'guid': preprint._id})) + request.user = user + patch_messages(request) + + admin_group.permissions.add(Permission.objects.get(codename='change_preprint')) + user.groups.add(admin_group) + + plain_view.as_view()(request, guid=preprint._id) + preprint.reload() + + assert preprint.has_coi + assert preprint.conflict_of_interest_statement == 'some text' + + # this case is not fixable because the preprint doesn't have COI statement set but has_coi = True + # which means we should add COI text by ourselves + preprint.has_coi = True + preprint.conflict_of_interest_statement = '' + preprint.save() + + plain_view.as_view()(request, guid=preprint._id) + preprint.reload() + + assert preprint.has_coi + assert preprint.conflict_of_interest_statement == '' From 23f0a832b54a74699edf70432e9cdd278549e284 Mon Sep 17 00:00:00 2001 From: Ihor Sokhan Date: Thu, 12 Mar 2026 10:00:34 +0200 Subject: [PATCH 4/4] fixed permission in a template --- admin/templates/preprints/fix_coi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/templates/preprints/fix_coi.html b/admin/templates/preprints/fix_coi.html index 6ee06e66130..1324c4b53c5 100644 --- a/admin/templates/preprints/fix_coi.html +++ b/admin/templates/preprints/fix_coi.html @@ -1,4 +1,4 @@ -{% if perms.osf.change_node %} +{% if perms.osf.change_preprint %} Fix COI