Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3487223
[ENG-8514] Remove CSRF protection from reset password api v2 POST (#1…
antkryt Aug 15, 2025
7a03e98
add background color prop to Brand (#11254)
antkryt Aug 15, 2025
8cf2f9c
fix flaky test_serialized_metadata
antkryt Aug 18, 2025
8e04d5c
fix throttle test
antkryt Aug 21, 2025
7a53306
reset throttle cache
antkryt Aug 21, 2025
81d4edf
Merge pull request #11265 from antkryt/fix/ENG-8656
Johnetordoff Aug 25, 2025
2678991
Merge branch 'feature/pbs-25-16' of https://github.com/CenterForOpenS…
Johnetordoff Aug 26, 2025
7cdebec
Merge pull request #11268 from Johnetordoff/fix/ENG-8552
Johnetordoff Aug 26, 2025
f6ede63
don't ignore components when create a view-only link
ihorsokhanexoft Aug 27, 2025
cae9889
fixed updating subscribe_osf_general_email subscription
ihorsokhanexoft Aug 28, 2025
fb62bc9
[ENG-7277] Update doc to include version as relationship (#11262)
Vlad0n20 Aug 28, 2025
2d54110
Merge pull request #11270 from ihorsokhanexoft/fix/ENG-8743
Johnetordoff Aug 28, 2025
ae7afd4
added tests
ihorsokhanexoft Aug 29, 2025
3a25592
[ENG-8691] Wrong server on reset password email (#11271)
antkryt Sep 2, 2025
00c74cd
enable filtering for linked-nodes endpoint (#11273)
antkryt Sep 2, 2025
d88bc14
remove deleted users from institutional dashboard (#11261)
ihorsokhanexoft Sep 2, 2025
b498d1b
fixed tests
ihorsokhanexoft Sep 2, 2025
d6b7edb
Merge pull request #11269 from ihorsokhanexoft/fix/ENG-8742
Johnetordoff Sep 2, 2025
104db68
[ENG-7803] Update text on VOL modal for registration (#11279)
Vlad0n20 Sep 4, 2025
a35b02a
add a file removal feature for a node (registration) using admin panel
mkovalua Sep 8, 2025
b6466bb
delete file only for archived registration when it is not possible fr…
mkovalua Sep 8, 2025
74ea703
remove file from scheme response blocks
mkovalua Sep 8, 2025
46006ca
delete file from registration and metadata and keep it for original p…
mkovalua Sep 9, 2025
e4c5743
fix merge coflicts of feature/ENG-8740 with feature/pbs-25-19
mkovalua Sep 19, 2025
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: 1 addition & 0 deletions admin/nodes/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@
re_path(r'^(?P<guid>[a-z0-9]+)/update_moderation_state/$', views.NodeUpdateModerationStateView.as_view(), name='node-update-mod-state'),
re_path(r'^(?P<guid>[a-z0-9]+)/resync_datacite/$', views.NodeResyncDataCiteView.as_view(), name='resync-datacite'),
re_path(r'^(?P<guid>[a-z0-9]+)/revert/$', views.NodeRevertToDraft.as_view(), name='revert-to-draft'),
re_path(r'^(?P<guid>[a-z0-9]+)/remove_file/$', views.NodeRemoveFileView.as_view(), name='remove-file'),
]
36 changes: 35 additions & 1 deletion admin/nodes/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.utils import timezone
from django.core.exceptions import PermissionDenied, ValidationError
from django.urls import NoReverseMatch
from django.db import transaction
from django.db.models import F, Case, When, IntegerField
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
Expand All @@ -27,14 +28,17 @@
from api.caching.tasks import update_storage_usage_cache

from osf.exceptions import NodeStateError, RegistrationStuckError
from osf.management.commands.change_node_region import _update_schema_meta
from osf.models import (
Guid,
OSFUser,
NodeLog,
AbstractNode,
Registration,
RegistrationProvider,
RegistrationApproval,
SpamStatus
SpamStatus,
TrashedFile
)
from osf.models.admin_log_entry import (
update_admin_log,
Expand Down Expand Up @@ -697,6 +701,36 @@ def post(self, request, *args, **kwargs):
return redirect(self.get_success_url())


class NodeRemoveFileView(NodeMixin, View):
""" Allows an authorized user to remove file from node.
"""
permission_required = 'osf.change_node'

def post(self, request, *args, **kwargs):
def _remove_file_from_schema_response_blocks(registration, removed_file_id):
file_input_keys = registration.registration_schema.schema_blocks.filter(
block_type='file-input'
).values_list('registration_response_key', flat=True)
for schema_response in registration.schema_responses.all():
for block in schema_response.response_blocks.filter(schema_key__in=file_input_keys):
if not block.response:
continue
block.response = [entry for entry in block.response if entry.get('file_id') not in removed_file_id]
block.save()

node = self.get_object()
guid_id = request.POST.get('remove-file-guid', '').strip()
guid = Guid.load(guid_id)

# delete file from registration and metadata and keep it for original project
if guid and (file := guid.referent) and (file.target == node) and not isinstance(file, TrashedFile):
with transaction.atomic():
file.delete()
_update_schema_meta(file.target)
_remove_file_from_schema_response_blocks(node, [file._id, file.copied_from._id])
return redirect(self.get_success_url())


class RemoveStuckRegistrationsView(NodeMixin, View):
""" Allows an authorized user to remove a registrations if it's stuck in the archiving process.
"""
Expand Down
1 change: 1 addition & 0 deletions admin/templates/nodes/node.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<a href="{% url 'nodes:search' %}" class="btn btn-primary"> <i class="fa fa-search"></i></a>
<a href="{% url 'nodes:node-logs' guid=node.guid %}" class="btn btn-primary">View Logs</a>
{% include "nodes/remove_node.html" with node=node %}
{% include "nodes/remove_file.html" with node=node %}
{% include "nodes/registration_force_archive.html" with node=node %}
{% include "nodes/make_private.html" with node=node %}
{% include "nodes/make_public.html" with node=node %}
Expand Down
36 changes: 36 additions & 0 deletions admin/templates/nodes/remove_file.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% if node.is_registration and node.archived %}
<a data-toggle="modal" data-target="#confirmDeleteFileModal" class="btn btn-danger">
Delete File
</a>
<div id="confirmDeleteFileModal" class="modal fade well" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form class="well" method="post" action="{% url 'nodes:remove-file' guid=node.guid %}">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">x</button>
<h3>Enter file to delete</h3>
</div>
{% csrf_token %}

<div class="modal-body">
<div style="display:flex; align-items:center; gap:12px;">
<label for="file-guid" style="margin:0; white-space:nowrap;">File guid:</label>
<input id="file-guid"
type="text"
name="remove-file-guid"
class="form-control"
required
style="flex:1; min-width:0;">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger" name="action" value="ham" type="submit">Confirm</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
</form>
</div>
</div>
</div>
{% endif %}
13 changes: 8 additions & 5 deletions osf/management/commands/change_node_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@ def _update_blocks(file_block_map, original_id, cloned_id):
block.save()

def _update_schema_meta(node):
logger.info('Updating legacy schema information...')
node.registration_responses = node.schema_responses.latest('-created').all_responses
node.registered_meta[node.registration_schema._id] = node.expand_registration_responses()
node.save()
logger.info('Updated legacy schema information.')
try:
logger.info('Updating legacy schema information...')
node.registration_responses = node.schema_responses.latest('-created').all_responses
node.registered_meta[node.registration_schema._id] = node.expand_registration_responses()
node.save()
logger.info('Updated legacy schema information.')
except Exception:
logger.error('There is no data in schema responses to update legacy schema information.')

def _copy_and_clone_versions(original_file, cloned_file, src_bucket, dest_bucket, dest_bucket_name, dest_region):
for v in original_file.versions.order_by('identifier').all():
Expand Down
Loading