Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
ef94460
[ENG-11081] Prevent POST /v2/nodes/ when project creation flag is active
omar-cos May 18, 2026
21447cb
Address review: use MethodNotAllowed (405) instead of PermissionDenie…
omar-cos May 20, 2026
d5be194
Merge pull request #1 from omar-cos/feature/prevent-post-v2-nodes
futa-ikeda May 20, 2026
c538c73
[ENG-11088] Prevent POST /v2/nodes/<id>/forks/ when project creation …
omar-cos May 20, 2026
c8d3686
Merge pull request #3 from omar-cos/feature/ENG-11088-prevent-post-forks
futa-ikeda May 20, 2026
0376c98
Prevent DraftNodes from getting converted into Nodes in osf/models/dr…
mkovalua May 21, 2026
2e8c208
[ENG-11089] Prevent POST /v2/nodes/<id>/children/ when project creati…
omar-cos May 21, 2026
683b16b
disable node creation from draft node is PREVENT_PROJECT_CREATION fla…
mkovalua May 22, 2026
8a8061b
add migration
mkovalua May 22, 2026
7b4931b
refactor(nodes): use tuple concatenation for NodeChildrenList permiss…
omar-cos May 22, 2026
39f6246
Merge pull request #5 from omar-cos/feature/ENG-11089-prevent-post-ch…
futa-ikeda May 22, 2026
f582e18
add 'draft node stays draft node when prevent project creation flag a…
mkovalua May 25, 2026
f29c593
move imports to file top
mkovalua May 25, 2026
cb0d6e8
code updates
mkovalua May 25, 2026
19cd969
Merge pull request #4 from mkovalua/feature/ENG-11090
futa-ikeda May 26, 2026
3ff51e2
Make new permission class for when project editing is not allowed
mkovalua Jun 15, 2026
f128961
resolve CR
mkovalua Jun 15, 2026
edb75b3
resolve CR
mkovalua Jun 15, 2026
bc5571a
Merge pull request #6 from mkovalua/feature/ENG-11394
futa-ikeda Jun 15, 2026
4134f73
Prevent project wiki updates via API
mkovalua Jun 16, 2026
15126b9
Merge pull request #7 from mkovalua/feature/ENG-11395
futa-ikeda Jun 16, 2026
49c94c3
Prevent collection submissions via API when project_read_only flag is…
omar-cos Jun 17, 2026
0bd326d
Merge pull request #8 from omar-cos/feature/1.2.1-be-prevent-collecti…
futa-ikeda Jun 18, 2026
efb2248
management command to reject all outstanding pending collection_submi…
mkovalua Jun 19, 2026
a284adb
use background task for Pending collection submissions rejection beca…
mkovalua Jun 19, 2026
388aae2
resolve CR comments
mkovalua Jun 22, 2026
6f84c74
Prevent updates to node metadata via API
mkovalua Jun 23, 2026
adc8486
Prevent node subject updates via API when project_read_only flag is a…
futa-ikeda Jun 23, 2026
202d99e
[ENG-11403] Prevent updates to node resource and funder information v…
omar-cos Jun 23, 2026
5c5ecc1
Merge pull request #9 from mkovalua/feature/ENG-11399
futa-ikeda Jun 23, 2026
955129c
resolve CR
mkovalua Jun 24, 2026
97fcdde
Merge pull request #10 from mkovalua/feature/ENG-11400
futa-ikeda Jun 24, 2026
713baec
Merge pull request #11 from futa-ikeda/feature/prevent-node-subject-u…
futa-ikeda Jun 24, 2026
ba458e3
Scope item metadata write-block to Node referents only
omar-cos Jun 24, 2026
8653fec
Address review: add PATCH/preprint tests, remove redundant flag overr…
omar-cos Jun 24, 2026
f411330
Re-trigger CI
omar-cos Jun 24, 2026
382f7ca
Prevent POST to node identifiers endpoint when PROJECT_READ_ONLY flag…
omar-cos Jun 25, 2026
b7f8851
Scope NodeIdentifierCreationNotAllowed to Node referents only
omar-cos Jun 25, 2026
9efed89
Merge pull request #12 from omar-cos/feature/prevent-custom-item-meta…
futa-ikeda Jun 25, 2026
eaef2c4
Merge pull request #13 from omar-cos/feature/prevent-node-identifier-…
futa-ikeda Jun 25, 2026
3660731
Prevent node affiliation updates via API when PROJECT_READ_ONLY flag …
omar-cos Jun 25, 2026
bc61ab4
Address review: block all write methods on node-institution endpoint
omar-cos Jun 25, 2026
441c459
Re-trigger CI
omar-cos Jun 25, 2026
8d0da82
Fix CI failures: wrap affiliation-change tests with capture_notificat…
omar-cos Jun 26, 2026
c5c4ed9
1.3.6 Prevent adding/editing node contributors via API when PROJECT_R…
omar-cos Jun 26, 2026
8f7a22a
Fix review issues: block PUT on contributor endpoints and add missing…
omar-cos Jun 26, 2026
ee7f74c
1.3.7 Prevent adding/removing linked nodes and registrations via API …
omar-cos Jun 29, 2026
b65bd94
Block PUT and PATCH on linked nodes/registrations relationship endpoi…
omar-cos Jun 29, 2026
274baa9
Fix CI failures in linked nodes/registrations read-only tests
omar-cos Jun 29, 2026
316a0fc
Use public node in test_post_allowed to satisfy view permission check
omar-cos Jun 29, 2026
12126eb
Merge pull request #14 from omar-cos/feature/prevent-node-affiliation…
futa-ikeda Jun 29, 2026
377454d
Prevent creation and edit of community metadata records via API
mkovalua Jun 29, 2026
4f15ce6
Restrict DELETE on contributor detail to self-removal when PROJECT_RE…
omar-cos Jun 29, 2026
150f74a
Resolve merge conflicts with base branch
omar-cos Jun 29, 2026
2678b11
Resolve merge conflicts with base branch
omar-cos Jun 29, 2026
1257f82
Merge pull request #15 from omar-cos/feature/prevent-node-contributor…
futa-ikeda Jun 29, 2026
1b246fd
use PROJECT_READ_ONLY flag for CedarMetadataRecord
mkovalua Jun 29, 2026
e095ca0
Resolve merge conflicts with base branch
omar-cos Jun 30, 2026
f3384d0
Merge pull request #16 from omar-cos/feature/prevent-linked-nodes-reg…
futa-ikeda Jun 30, 2026
cc85f20
Merge pull request #17 from mkovalua/feature/ENG-11414
futa-ikeda Jun 30, 2026
31d6259
Prevent node settings update based on waffle-flag
futa-ikeda Jun 30, 2026
8841d65
Merge pull request #18 from futa-ikeda/feature/project-settings
futa-ikeda Jul 1, 2026
57759bf
Prevent registrations based on projects
mkovalua Jul 2, 2026
4d61f60
1.6.4 BE/GV: Prevent new addons connection
mkovalua Jul 6, 2026
824545d
update tests
mkovalua Jul 6, 2026
87d4b78
add NodeDraftRegistrationCreationNotAllowed permission for NodeDraftR…
mkovalua Jul 6, 2026
21e6382
Merge pull request #19 from mkovalua/feature/ENG-11416
futa-ikeda Jul 7, 2026
4e58293
Merge pull request #20 from mkovalua/feature/ENG-11421
futa-ikeda Jul 8, 2026
016699e
Merge branch 'develop' into feature/prevent-project-creation
futa-ikeda Jul 8, 2026
cf971d9
1.3.15 BE: Add new Permission class for node relationships
mkovalua Jul 10, 2026
a216174
Merge branch 'feature/prevent-project-creation' into feature/ENG-11554
mkovalua Jul 10, 2026
4071398
migration fix attempt
mkovalua Jul 10, 2026
6999120
update test
mkovalua Jul 10, 2026
5494a5c
fix business logic to work with tests
mkovalua Jul 10, 2026
5ea0068
Merge pull request #21 from mkovalua/feature/ENG-11554
futa-ikeda Jul 13, 2026
1b759d6
Prevent uploads of new files and folders based on the waffle flag value.
mkovalua Jul 14, 2026
595fd3a
Merge pull request #22 from mkovalua/feature/ENG-11418
futa-ikeda Jul 14, 2026
64ab3d0
Merge branch 'develop' into feature/prevent-project-creation
futa-ikeda Jul 27, 2026
d3958f4
1.3.16 BE: Allow users to make projects public, but not private
omar-cos Aug 4, 2026
cb30922
Add coverage for PUT and non-admin edge cases on the public-only exce…
omar-cos Aug 4, 2026
af4338c
Prevent requests to projects based on waffle flag
futa-ikeda Aug 6, 2026
17a229f
1.9.3 BE: Create management command to auto-reject pending project ac…
omar-cos Aug 6, 2026
987565e
Merge pull request #23 from omar-cos/feature/1.3.16-be-allow-project-…
futa-ikeda Aug 7, 2026
490b260
Merge pull request #24 from futa-ikeda/feature/requests-prevention
futa-ikeda Aug 7, 2026
dae4be7
Fix infinite recursion in test_machine_error_is_handled_gracefully
omar-cos Aug 10, 2026
6d3fb1a
Merge pull request #25 from omar-cos/feature/1.9.3-be-reject-pending-…
futa-ikeda Aug 10, 2026
cc19de6
1.6.6 BE: Allow users to configure/disconnect existing storage addons…
mkovalua Aug 11, 2026
f6f99ef
Merge remote-tracking branch 'upstream/develop' into fix/reconcile-de…
omar-cos Aug 12, 2026
b636ecd
Reconcile migration graph: merge upstream/develop into feature base b…
omar-cos Aug 12, 2026
961d613
Merge pull request #26 from mkovalua/fix/ENG-11809
futa-ikeda Aug 12, 2026
8eaef85
1.1.14 BE: Prevent relationship from getting serialized in the API i…
mkovalua Aug 13, 2026
daf9261
Merge pull request #28 from mkovalua/feature/ENG-11939
futa-ikeda Aug 18, 2026
91b58dc
Update file upload prevention logic
futa-ikeda Aug 26, 2026
0747f31
Merge pull request #29 from futa-ikeda/file-upload
futa-ikeda Aug 26, 2026
3329f8b
Merge branch 'develop' into feature/prevent-project-creation
futa-ikeda Aug 31, 2026
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
10 changes: 10 additions & 0 deletions addons/base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,13 +387,23 @@ def _check_resource_permissions(resource, auth, action):
if required_permission == permissions.READ:
has_resource_permissions = resource.can_view_files(auth=auth)
else:
_ensure_resource_not_read_only(resource)
has_resource_permissions = resource.can_edit(auth=auth)

if not (has_resource_permissions or _check_hierarchical_permissions(resource, auth, action)):
raise HTTPError(http_status.HTTP_403_FORBIDDEN)
return True


def _ensure_resource_not_read_only(resource):
"""Block file/folder writes via Waterbutler while the resource is in read-only mode."""
if not isinstance(resource, Node):
return

if flag_is_active(request, features.PROJECT_READ_ONLY):
raise HTTPError(http_status.HTTP_403_FORBIDDEN, message='This project is read-only; file writes are disabled.')


def _get_permission_for_action(action):
if action in _READ_ACTIONS:
return permissions.READ
Expand Down
4 changes: 4 additions & 0 deletions admin/management/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@
name='remove_orcid_from_user_social'),
re_path(r'^migrate_funder_names_to_ror', views.MigrateFunderNamesToRor.as_view(),
name='migrate_funder_names_to_ror'),
re_path(r'^reject_pending_collection_submissions', views.RejectPendingCollectionSubmissions.as_view(),
name='reject_pending_collection_submissions'),
re_path(r'^reject_pending_node_requests', views.RejectPendingNodeRequests.as_view(),
name='reject_pending_node_requests'),
]
34 changes: 34 additions & 0 deletions admin/management/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from osf.management.commands.sync_doi_metadata import sync_doi_metadata, sync_doi_empty_metadata_dataarchive_registrations
from osf.management.commands.populate_notification_types import populate_notification_types
from osf.management.commands.remove_orcid_from_user_social import remove_orcid_from_user_social
from osf.management.commands.reject_pending_collection_submissions import reject_pending_collection_submissions
from osf.management.commands.reject_pending_node_requests import reject_pending_node_requests
from scripts.find_spammy_content import manage_spammy_content
from django.urls import reverse
from django.shortcuts import redirect
Expand Down Expand Up @@ -228,3 +230,35 @@ def post(self, request):
for _line in _out_io.getvalue().split('\n'):
messages.info(request, _line)
return redirect(reverse('management:commands'))


class RejectPendingCollectionSubmissions(ManagementCommandPermissionView):

def post(self, request):
user_guid = request.user._id
comment = request.POST.get('comment', '').strip()
if not user_guid:
messages.error(request, 'A user GUID must be provided.')
return redirect(reverse('management:commands'))
reject_pending_collection_submissions.apply_async(kwargs={
'user_guid': user_guid,
'comment': comment,
})
messages.success(request, 'Pending collection submissions have been queued for rejection.')
return redirect(reverse('management:commands'))


class RejectPendingNodeRequests(ManagementCommandPermissionView):

def post(self, request):
user_guid = request.user._id
comment = request.POST.get('comment', '').strip()
if not user_guid:
messages.error(request, 'A user GUID must be provided.')
return redirect(reverse('management:commands'))
reject_pending_node_requests.apply_async(kwargs={
'user_guid': user_guid,
'comment': comment,
})
messages.success(request, 'Pending project access requests have been queued for rejection.')
return redirect(reverse('management:commands'))
31 changes: 31 additions & 0 deletions admin/templates/management/commands.html
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,37 @@ <h4><u>Update ROR funder names to be consistent and proper.</u></h4>
<input class="btn btn-success" type="submit" value="Run" />
</nav>
</form>
</section>
<section>
<h4><u>Reject pending collection submissions</u></h4>
<p>
Use this management command to reject all collection submissions currently in the pending state.
</p>
<form method="post"
action="{% url 'management:reject_pending_collection_submissions'%}">
{% csrf_token %}
Comment: <input type="text" name="comment" style="width: 550px;"
placeholder="Leave blank for default rejection message 'This collection submission has been rejected.'" />
<nav>
<input class="btn btn-success" type="submit" value="Run" />
</nav>
</form>
</section>
<section>
<h4><u>Reject pending project access requests</u></h4>
<p>
Use this management command to reject all project access requests (including institutional
curator requests) currently in the pending state.
</p>
<form method="post"
action="{% url 'management:reject_pending_node_requests'%}">
{% csrf_token %}
Comment: <input type="text" name="comment" style="width: 550px;"
placeholder="Leave blank for default rejection message 'This project is now read-only, so this access request has been automatically rejected.'" />
<nav>
<input class="btn btn-success" type="submit" value="Run" />
</nav>
</form>
</section>
</div>
</section>
Expand Down
12 changes: 11 additions & 1 deletion api/cedar_metadata_records/permissions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import logging

from rest_framework import permissions
import waffle
from rest_framework import exceptions, permissions

from api.base.utils import get_user_auth

from osf import features
from osf.models import BaseFileNode, CedarMetadataRecord, Node, Registration

logger = logging.getLogger(__name__)
Expand All @@ -27,3 +29,11 @@ def has_object_permission(self, request, view, obj):
return permission_source.can_edit(auth)
return permission_source.is_public or permission_source.can_view(auth)
return permission_source.can_edit(auth)


class CedarMetadataRecordsNotAllowed(permissions.BasePermission):

def has_permission(self, request, view):
if request.method in ('POST', 'PUT', 'PATCH') and waffle.flag_is_active(request, features.PROJECT_READ_ONLY):
raise exceptions.MethodNotAllowed(request.method, detail='This action is no longer available. Contact support if you have any questions.')
return True
4 changes: 3 additions & 1 deletion api/cedar_metadata_records/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)
from api.base.versioning import PrivateVersioning
from api.base.views import JSONAPIBaseView
from api.cedar_metadata_records.permissions import CedarMetadataRecordPermission
from api.cedar_metadata_records.permissions import CedarMetadataRecordPermission, CedarMetadataRecordsNotAllowed
from api.cedar_metadata_records.serializers import (
CedarMetadataRecordsCreateSerializer,
CedarMetadataRecordsDetailSerializer,
Expand All @@ -30,6 +30,7 @@ class CedarMetadataRecordCreate(JSONAPIBaseView, CreateAPIView):
permission_classes = (
drf_permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
CedarMetadataRecordsNotAllowed,
)
required_read_scopes = [CoreScopes.NULL]
required_write_scopes = [CoreScopes.CEDAR_METADATA_RECORD_WRITE]
Expand All @@ -50,6 +51,7 @@ class CedarMetadataRecordDetail(JSONAPIBaseView, RetrieveUpdateDestroyAPIView):
CedarMetadataRecordPermission,
drf_permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
CedarMetadataRecordsNotAllowed,
)
required_read_scopes = [CoreScopes.CEDAR_METADATA_RECORD_READ]
required_write_scopes = [CoreScopes.CEDAR_METADATA_RECORD_WRITE]
Expand Down
9 changes: 9 additions & 0 deletions api/collections/permissions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import io

import waffle
from rest_framework import permissions
from rest_framework.exceptions import NotFound, MethodNotAllowed

from api.base.exceptions import Gone
from api.base.parsers import JSONSchemaParser
from api.base.utils import get_user_auth, assert_resource_type, get_object_or_error
from osf import features
from osf.models import AbstractNode, Preprint, Collection, CollectionSubmission, CollectionProvider
from osf.utils.permissions import WRITE, ADMIN

Expand Down Expand Up @@ -47,6 +49,13 @@ def has_object_permission(self, request, view, obj):
return request.method in permissions.SAFE_METHODS
return True

class CollectionSubmissionsNotAllowed(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == 'POST' and waffle.flag_is_active(request, features.PROJECT_READ_ONLY):
raise MethodNotAllowed(request.method, detail='This action is no longer available. Contact support if you have any questions.')
return True


class CanSubmitToCollectionOrPublic(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
assert isinstance(obj, (CollectionSubmission, Collection, CollectionProvider)), f'obj must be a Collection or CollectionSubmission, got {obj}'
Expand Down
2 changes: 2 additions & 0 deletions api/collections/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
CollectionWriteOrPublicForRelationshipPointers,
CanSubmitToCollectionOrPublic,
CanUpdateDeleteCollectionSubmissionOrPublic,
CollectionSubmissionsNotAllowed,
ReadOnlyIfCollectedRegistration,
)
from api.collections.serializers import (
Expand Down Expand Up @@ -324,6 +325,7 @@ def perform_destroy(self, instance):
class CollectionSubmissionList(JSONAPIBaseView, generics.ListCreateAPIView, CollectionMixin, ListFilterMixin):
permission_classes = (
drf_permissions.IsAuthenticatedOrReadOnly,
CollectionSubmissionsNotAllowed,
CanSubmitToCollectionOrPublic,
base_permissions.TokenHasScope,
)
Expand Down
21 changes: 19 additions & 2 deletions api/custom_metadata/permissions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from rest_framework import permissions
import waffle
from rest_framework import exceptions, permissions

from api.base.utils import get_user_auth
from osf.models import GuidMetadataRecord, BaseFileNode
from osf import features
from osf.models import GuidMetadataRecord, BaseFileNode, Node


class CustomMetadataPermission(permissions.BasePermission):
Expand All @@ -17,3 +19,18 @@ def has_object_permission(self, request, view, obj):
return delegate_obj.is_public or delegate_obj.can_view(auth)
else:
return delegate_obj.can_edit(auth)


class ItemMetadataEditingNotAllowed(permissions.BasePermission):

def has_object_permission(self, request, view, obj):
assert isinstance(obj, GuidMetadataRecord)
if request.method in permissions.SAFE_METHODS:
return True
delegate_obj = obj.guid.referent
if isinstance(delegate_obj, Node) and waffle.flag_is_active(request, features.PROJECT_READ_ONLY):
raise exceptions.MethodNotAllowed(
request.method,
detail='This action is no longer available. Contact support if you have any questions.',
)
return True
3 changes: 2 additions & 1 deletion api/custom_metadata/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from api.base.views import JSONAPIBaseView

import osf.models as osfdb
from .permissions import CustomMetadataPermission
from .permissions import CustomMetadataPermission, ItemMetadataEditingNotAllowed
from .serializers import CustomFileMetadataSerializer, CustomItemMetadataSerializer


Expand Down Expand Up @@ -43,6 +43,7 @@ class CustomItemMetadataDetail(JSONAPIBaseView, rest_framework.generics.Retrieve
CustomMetadataPermission,
rest_framework.permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
ItemMetadataEditingNotAllowed,
)

required_read_scopes = [CoreScopes.GUIDS_READ]
Expand Down
15 changes: 15 additions & 0 deletions api/draft_registrations/permissions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import waffle
from rest_framework import permissions
from rest_framework.exceptions import MethodNotAllowed

from api.base.exceptions import Conflict
from api.base.utils import get_user_auth, assert_resource_type
from osf import features
from osf.models import (
DraftRegistration,
AbstractNode,
Expand Down Expand Up @@ -121,3 +124,15 @@ def has_permission(self, request, view):
raise Conflict(f"Registry {provider.name} is closed for new submissions. Please start a new registration with a different registry.")

return True


class ProjectBasedDraftRegistrationNotAllowed(permissions.BasePermission):
"""
Prevent creating draft registrations branched from a project (or other node) when the
PROJECT_READ_ONLY waffle flag is active. No-project draft registrations are still allowed.
"""

def has_permission(self, request, view):
if request.method == 'POST' and request.data.get('branched_from') and waffle.flag_is_active(request, features.PROJECT_READ_ONLY):
raise MethodNotAllowed(request.method, detail='This action is no longer available. Contact support if you have any questions.')
return True
2 changes: 2 additions & 0 deletions api/draft_registrations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
DraftRegistrationPermission,
IsAdminContributor,
CanSubmitDraftRegistrationToProvider,
ProjectBasedDraftRegistrationNotAllowed,
)
from api.draft_registrations.serializers import (
DraftRegistrationSerializer,
Expand Down Expand Up @@ -54,6 +55,7 @@ class DraftRegistrationList(NodeDraftRegistrationsList):
drf_permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
DraftRegistrationPermission,
ProjectBasedDraftRegistrationNotAllowed,
CanSubmitDraftRegistrationToProvider,
)

Expand Down
13 changes: 12 additions & 1 deletion api/institutions/permissions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from rest_framework import permissions
import waffle
from rest_framework import exceptions, permissions

from api.base.utils import get_user_auth
from osf import features


class UserIsAffiliated(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
Expand All @@ -11,3 +14,11 @@ def has_object_permission(self, request, view, obj):
return True
else:
return user.is_affiliated_with_institution(obj['self'])


class InstitutionNodesDeleteNotAllowed(permissions.BasePermission):

def has_permission(self, request, view):
if request.method == 'DELETE' and waffle.flag_is_active(request, features.PROJECT_READ_ONLY):
raise exceptions.MethodNotAllowed(request.method, detail='This action is no longer available. Contact support if you have any questions.')
return True
3 changes: 2 additions & 1 deletion api/institutions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
InstitutionUserMetricsSerializer,
InstitutionSummaryMetricsSerializer,
)
from api.institutions.permissions import UserIsAffiliated
from api.institutions.permissions import UserIsAffiliated, InstitutionNodesDeleteNotAllowed


class InstitutionMixin:
Expand Down Expand Up @@ -348,6 +348,7 @@ class InstitutionNodesRelationship(JSONAPIBaseView, generics.RetrieveDestroyAPIV
drf_permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
UserIsAffiliated,
InstitutionNodesDeleteNotAllowed,
)
required_read_scopes = [CoreScopes.NODE_BASE_READ, CoreScopes.INSTITUTION_READ]
required_write_scopes = [CoreScopes.NODE_BASE_WRITE]
Expand Down
Loading
Loading