Skip to content

Commit 0d7a1af

Browse files
authored
Merge pull request #11709 from CenterForOpenScience/feature/pbs-26-6
Merge Feature/pbs-26-6 into develop
2 parents 7b9333a + 6330798 commit 0d7a1af

46 files changed

Lines changed: 1427 additions & 62 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/gen-report/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ runs:
44
using: "composite"
55
steps:
66
- name: Archive code coverage results
7-
uses: actions/upload-artifact@v4
7+
uses: actions/upload-artifact@v7
88
with:
99
name: ${{github.job}} HTML REPORT
1010
path: report.html
1111
- name: Generate Report
12-
uses: dorny/test-reporter@v2
12+
uses: dorny/test-reporter@v3
1313
if: success() || failure() # run this step even if previous step failed
1414
with:
1515
name: ${{github.job}} REPORT # Name of the check run which will be created

.github/actions/start-build/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ runs:
44
using: "composite"
55
steps:
66
- id: cache-objects
7-
uses: actions/cache@v4
7+
uses: actions/cache@v5
88
with:
99
path: ~/.cache
1010
key: reqs_${{ hashFiles('poetry.lock') }}
@@ -16,7 +16,7 @@ runs:
1616
with:
1717
ELASTICSEARCH6_ARCHIVE: ${{ env.ELASTICSEARCH6_ARCHIVE }}
1818
- name: Set up Python 3.12
19-
uses: actions/setup-python@v5
19+
uses: actions/setup-python@v6
2020
with:
2121
python-version: '3.12'
2222
- name: Install lxml

.github/workflows/test-build.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
build-cache:
1818
runs-on: ubuntu-22.04
1919
steps:
20-
- uses: actions/checkout@v2
20+
- uses: actions/checkout@v6
2121
- id: cache-objects
22-
uses: actions/cache@v4
22+
uses: actions/cache@v5
2323
with:
2424
path: ~/.cache
2525
key: reqs_${{ hashFiles('poetry.lock') }}
@@ -50,7 +50,7 @@ jobs:
5050
# Maps tcp port 5432 on service container to the host
5151
- 5432:5432
5252
steps:
53-
- uses: actions/checkout@v2
53+
- uses: actions/checkout@v6
5454
- uses: ./.github/actions/start-build
5555
- name: Run tests
5656
run: poetry run python3 -m invoke test-ci-addons --junit
@@ -77,7 +77,7 @@ jobs:
7777
# Maps tcp port 5432 on service container to the host
7878
- 5432:5432
7979
steps:
80-
- uses: actions/checkout@v2
80+
- uses: actions/checkout@v6
8181
- uses: ./.github/actions/start-build
8282
- name: Run tests
8383
run: poetry run python3 -m invoke test-ci-website --junit
@@ -104,7 +104,7 @@ jobs:
104104
# Maps tcp port 5432 on service container to the host
105105
- 5432:5432
106106
steps:
107-
- uses: actions/checkout@v2
107+
- uses: actions/checkout@v6
108108
- uses: ./.github/actions/start-build
109109
- name: NVM & yarn install
110110
run: poetry run python3 -m invoke assets --dev
@@ -133,7 +133,7 @@ jobs:
133133
# Maps tcp port 5432 on service container to the host
134134
- 5432:5432
135135
steps:
136-
- uses: actions/checkout@v2
136+
- uses: actions/checkout@v6
137137
- uses: ./.github/actions/start-build
138138
- name: Run tests
139139
run: poetry run python3 -m invoke test-ci-api2 --junit
@@ -161,7 +161,7 @@ jobs:
161161
# Maps tcp port 5432 on service container to the host
162162
- 5432:5432
163163
steps:
164-
- uses: actions/checkout@v2
164+
- uses: actions/checkout@v6
165165
- uses: ./.github/actions/start-build
166166
- name: Run tests
167167
run: poetry run python3 -m invoke test-ci-api3-and-osf --junit
@@ -194,7 +194,7 @@ jobs:
194194
- 1025:1025
195195
- 8025:8025
196196
steps:
197-
- uses: actions/checkout@v2
197+
- uses: actions/checkout@v6
198198
- uses: ./.github/actions/start-build
199199
- name: Run tests
200200
run: poetry run python3 -m invoke test-ci-mailhog -n 1 --junit
@@ -222,7 +222,7 @@ jobs:
222222
# Maps tcp port 5432 on service container to the host
223223
- 5432:5432
224224
steps:
225-
- uses: actions/checkout@v2
225+
- uses: actions/checkout@v6
226226
- uses: ./.github/actions/start-build
227227
- name: Run tests
228228
run: poetry run python3 -m invoke test-ci-scripts -n 1 --junit

admin/base/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
re_path(r'^cedar_metadata_templates/', include('admin.cedar.urls', namespace='cedar_metadata_templates')),
3838
re_path(r'^draft_registrations/', include('admin.draft_registrations.urls', namespace='draft_registrations')),
3939
re_path(r'^files/', include('admin.files.urls', namespace='files')),
40+
re_path(r'^share_reindex/', include('admin.share_reindex.urls', namespace='share_reindex')),
4041
]),
4142
),
4243
]

admin/nodes/urls.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
re_path(r'^flagged_spam$', views.NodeFlaggedSpamList.as_view(), name='flagged-spam'),
99
re_path(r'^known_spam$', views.NodeKnownSpamList.as_view(), name='known-spam'),
1010
re_path(r'^known_ham$', views.NodeKnownHamList.as_view(), name='known-ham'),
11+
re_path(r'^embargo_report/$', views.EmbargoReportView.as_view(), name='embargo-report'),
1112
re_path(r'^doi_backlog_list/$', views.DoiBacklogListView.as_view(), name='doi-backlog-list'),
1213
re_path(r'^approval_backlog_list/$', views.ApprovalBacklogListView.as_view(), name='approval-backlog-list'),
1314
re_path(r'^confirm_approve_backlog_list/$', views.ConfirmApproveBacklogView.as_view(), name='confirm-approve-backlog-list'),
@@ -51,4 +52,7 @@
5152
re_path(r'^(?P<guid>[a-z0-9]+)/system_tags/(?P<tag_id>[a-z0-9]+)/remove/$', views.NodeRemoveSystemTag.as_view(), name='remove-system-tag'),
5253
re_path(r'^(?P<guid>[a-z0-9]+)/update_permissions/$', views.NodeUpdatePermissionsView.as_view(), name='update-permissions'),
5354
re_path(r'^(?P<guid>[a-z0-9]+)/remove_file/$', views.NodeRemoveFileView.as_view(), name='remove-file'),
55+
re_path(r'^(?P<guid>[a-z0-9]+)/add_osfstorage_file/$', views.NodeAddOsfStorageFileView.as_view(), name='add-osfstorage-file'),
56+
re_path(r'^(?P<guid>[a-z0-9]+)/remove_osfstorage_file/$', views.NodeRemoveOsfStorageFileView.as_view(), name='remove-osfstorage-file'),
57+
5458
]

admin/nodes/views.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
View,
1717
FormView,
1818
ListView,
19+
TemplateView
1920
)
21+
from django.core.paginator import Paginator, InvalidPage
2022

2123
from admin.base.forms import GuidForm
2224
from admin.base.utils import change_embargo_date
2325
from admin.base.views import GuidView
2426
from admin.nodes.forms import AddSystemTagForm, RegistrationDateForm
2527
from admin.notifications.views import delete_selected_notifications
28+
from addons.osfstorage.models import OsfStorageFolder
2629
from api.caching.tasks import update_storage_usage_cache
2730
from api.share.utils import update_share
2831
from framework import status
@@ -39,6 +42,7 @@
3942
SpamStatus,
4043
TrashedFile
4144
)
45+
from osf.models.sanctions import Embargo
4246
from osf.models.admin_log_entry import (
4347
update_admin_log,
4448
NODE_REMOVED,
@@ -50,6 +54,7 @@
5054
REINDEX_SHARE,
5155
REINDEX_ELASTIC,
5256
)
57+
from osf.models.files import File
5358
from osf.utils.permissions import ADMIN, API_CONTRIBUTOR_PERMISSIONS
5459
from scripts.approve_registrations import approve_past_pendings
5560
from website import settings, search
@@ -474,6 +479,54 @@ def get_context_data(self, **kwargs):
474479
}
475480

476481

482+
class EmbargoReportView(PermissionRequiredMixin, TemplateView):
483+
"""Report view for inspecting current and overdue embargoed registrations.
484+
485+
Shows:
486+
- pending embargoes that should have been activated
487+
- active embargoes that are past their end date
488+
- upcoming active embargoes
489+
"""
490+
template_name = 'nodes/embargo_report.html'
491+
permission_required = 'osf.view_registration'
492+
raise_exception = True
493+
494+
def get_context_data(self, **kwargs):
495+
context = super().get_context_data(**kwargs)
496+
pending_embargoes = Embargo.objects.pending_embargoes().select_related('initiated_by')
497+
active_embargoes = Embargo.objects.active_embargoes().select_related('initiated_by')
498+
499+
pending_overdue_embargoes = [
500+
embargo for embargo in pending_embargoes
501+
if embargo.should_be_embargoed
502+
]
503+
504+
overdue_embargoes = [
505+
embargo for embargo in active_embargoes
506+
if embargo.should_be_completed
507+
]
508+
509+
upcoming_queryset = active_embargoes.filter(
510+
end_date__gte=timezone.now(),
511+
).order_by('end_date')
512+
513+
page_number = self.request.GET.get('page') or 1
514+
paginator = Paginator(upcoming_queryset, 10)
515+
try:
516+
upcoming_page = paginator.page(page_number)
517+
except InvalidPage:
518+
upcoming_page = paginator.page(1)
519+
520+
context.update({
521+
'now': timezone.now(),
522+
'pending_overdue_embargoes': pending_overdue_embargoes,
523+
'overdue_embargoes': overdue_embargoes,
524+
'upcoming_embargoes': upcoming_page.object_list,
525+
'upcoming_page': upcoming_page,
526+
})
527+
return context
528+
529+
477530
class ConfirmApproveBacklogView(RegistrationListView):
478531
template_name = 'nodes/registration_approval_list.html'
479532
permission_required = 'osf.view_registrationapproval'
@@ -846,6 +899,72 @@ def _remove_file_from_schema_response_blocks(registration, removed_file_id):
846899
return redirect(self.get_success_url())
847900

848901

902+
class NodeAddOsfStorageFileView(NodeMixin, View):
903+
""" Allows an authorized user to add a file to osfstorage of an archived node.
904+
"""
905+
permission_required = 'osf.change_node'
906+
907+
def post(self, request, *args, **kwargs):
908+
registration = self.get_object()
909+
guid_id = request.POST.get('file-guid', '').strip()
910+
guid = Guid.load(guid_id)
911+
if not guid:
912+
messages.error(request, 'No file found with the provided guid.')
913+
return redirect(self.get_success_url())
914+
915+
file = guid.referent
916+
if not isinstance(file, File):
917+
messages.error(request, 'The guid provided does not correspond to a file.')
918+
return redirect(self.get_success_url())
919+
920+
parent_node = registration.registered_from
921+
if not parent_node:
922+
messages.error(request, 'The registration does not have the parent node.')
923+
return redirect(self.get_success_url())
924+
925+
if not parent_node.files.filter(id=file.id).exists():
926+
messages.error(request, 'The file with the provided guid is not part of the parent node.')
927+
return redirect(self.get_success_url())
928+
929+
osfstorage = registration.get_addon('osfstorage')
930+
# copy file to Archive of OSF Storage folder
931+
archive_folder = OsfStorageFolder.objects.filter(
932+
parent=osfstorage.get_root(),
933+
name=osfstorage.archive_folder_name
934+
).first()
935+
file.copy_under(archive_folder)
936+
messages.success(request, 'The file was successfully added.')
937+
return redirect(self.get_success_url())
938+
939+
940+
class NodeRemoveOsfStorageFileView(NodeMixin, View):
941+
""" Allows an authorized user to remove a file from osfstorage of an archived node.
942+
"""
943+
permission_required = 'osf.change_node'
944+
945+
def post(self, request, *args, **kwargs):
946+
registration = self.get_object()
947+
guid_id = request.POST.get('file-guid', '').strip()
948+
guid = Guid.load(guid_id)
949+
if not guid:
950+
messages.error(request, 'No file found with the provided guid.')
951+
return redirect(self.get_success_url())
952+
953+
file = guid.referent
954+
if not isinstance(file, File):
955+
messages.error(request, 'The guid provided does not correspond to a file.')
956+
return redirect(self.get_success_url())
957+
958+
registration_file = registration.files.filter(id=file.id)
959+
if not registration_file.exists():
960+
messages.error(request, 'The file with the provided guid is not part of the registration.')
961+
return redirect(self.get_success_url())
962+
963+
registration_file.delete()
964+
messages.success(request, 'The file was successfully removed.')
965+
return redirect(self.get_success_url())
966+
967+
849968
class RemoveStuckRegistrationsView(NodeMixin, View):
850969
""" Allows an authorized user to remove a registrations if it's stuck in the archiving process.
851970
"""

admin/preprints/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
re_path(r'^(?P<guid>\w+)/remove_user/(?P<user_id>[a-z0-9]+)/$', views.PreprintRemoveContributorView.as_view(), name='remove-user'),
1818
re_path(r'^(?P<guid>\w+)/make_private/$', views.PreprintMakePrivate.as_view(), name='make-private'),
1919
re_path(r'^(?P<guid>\w+)/fix_editing/$', views.PreprintFixEditing.as_view(), name='fix-editing'),
20+
re_path(r'^(?P<guid>\w+)/fix_coi/$', views.PreprintFixCOI.as_view(), name='fix-coi'),
2021
re_path(r'^(?P<guid>\w+)/make_public/$', views.PreprintMakePublic.as_view(), name='make-public'),
2122
re_path(r'^(?P<guid>\w+)/remove/$', views.PreprintDeleteView.as_view(), name='remove'),
2223
re_path(r'^(?P<guid>\w+)/restore/$', views.PreprintDeleteView.as_view(), name='restore'),

admin/preprints/views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,22 @@ def post(self, request, *args, **kwargs):
668668
return redirect(self.get_success_url())
669669

670670

671+
class PreprintFixCOI(PreprintMixin, View):
672+
""" Allows an authorized user to manually fix conflict of interest field.
673+
"""
674+
permission_required = 'osf.change_preprint'
675+
676+
def post(self, request, *args, **kwargs):
677+
preprint = self.get_object()
678+
if preprint.conflict_of_interest_statement and not preprint.has_coi:
679+
preprint.update_has_coi(auth=request, has_coi=True, ignore_permission=True)
680+
messages.success(request, 'The COI was successfully fixed.')
681+
else:
682+
messages.error(request, 'The COI is either already fixed or the preprint does not have conflict of interest set.')
683+
684+
return redirect(self.get_success_url())
685+
686+
671687
class PreprintMakePublic(PreprintMixin, View):
672688
""" Allows an authorized user to manually make a private preprint public.
673689
"""

admin/registration_schemas/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class RegistrationSchemaDetailView(FormView, PermissionRequiredMixin, TemplateVi
1717
Allows authorized users to view and edit some attributes of a Registration Schema.
1818
"""
1919
template_name = 'registration_schemas/registration_schema.html'
20-
permission_required = 'osf.view_registration_schema'
20+
permission_required = 'osf.view_registrationschema'
2121
raise_exception = True
2222
form_class = RegistrationSchemaEditForm
2323

@@ -143,7 +143,7 @@ class RegistrationSchemaListView(PermissionRequiredMixin, ListView):
143143
Allows authorized users to view all Registration Schema.
144144
"""
145145
template_name = 'registration_schemas/registration_schema_list.html'
146-
permission_required = 'osf.view_registration_schema'
146+
permission_required = 'osf.view_registrationschema'
147147
raise_exception = True
148148

149149
def get_queryset(self):

admin/share_reindex/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)