Skip to content

Commit

Permalink
Merge pull request CenterForOpenScience#10655 from Johnetordoff/prepr…
Browse files Browse the repository at this point in the history
…int-institutions-list-api

[ENG-5844] Add preprint institution affiliation endpoint
  • Loading branch information
cslzchen authored and John Tordoff committed Jul 18, 2024
2 parents d2816bf + 3dee31b commit 29cd008
Show file tree
Hide file tree
Showing 17 changed files with 2,254 additions and 3,285 deletions.
27 changes: 27 additions & 0 deletions api/preprints/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,30 @@ def has_object_permission(self, request, view, obj):
raise exceptions.PermissionDenied(detail='Withdrawn preprints may not be edited')
return True
raise exceptions.NotFound


class PreprintInstitutionPermissionList(permissions.BasePermission):
"""
Custom permission class for checking access to a list of institutions
associated with a preprint.
Permissions:
- Allows safe methods (GET, HEAD, OPTIONS) for public preprints.
- For private preprints, checks if the user has read permissions.
Methods:
- has_object_permission: Raises MethodNotAllowed for non-safe methods and
checks if the user has the necessary permissions to access private preprints.
"""
def has_object_permission(self, request, view, obj):
if request.method not in permissions.SAFE_METHODS:
raise exceptions.MethodNotAllowed(method=request.method)

if obj.is_public:
return True

auth = get_user_auth(request)
if not auth.user:
return False
else:
return obj.has_permission(auth.user, osf_permissions.READ)
1 change: 1 addition & 0 deletions api/preprints/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@
re_path(r'^(?P<preprint_id>\w+)/review_actions/$', views.PreprintActionList.as_view(), name=views.PreprintActionList.view_name),
re_path(r'^(?P<preprint_id>\w+)/requests/$', views.PreprintRequestListCreate.as_view(), name=views.PreprintRequestListCreate.view_name),
re_path(r'^(?P<preprint_id>\w+)/subjects/$', views.PreprintSubjectsList.as_view(), name=views.PreprintSubjectsList.view_name),
re_path(r'^(?P<preprint_id>\w+)/institutions/$', views.PreprintInstitutionsList.as_view(), name=views.PreprintInstitutionsList.view_name),
]
41 changes: 37 additions & 4 deletions api/preprints/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
from rest_framework import permissions as drf_permissions

from framework.auth.oauth_scopes import CoreScopes
from osf.models import ReviewAction, Preprint, PreprintContributor
from osf.models import (
ReviewAction,
Preprint,
PreprintContributor,
Institution,
)
from osf.utils.requests import check_select_for_update

from api.actions.permissions import ReviewActionPermission
Expand All @@ -17,12 +22,11 @@
from api.base.views import JSONAPIBaseView, WaterButlerMixin
from api.base.filters import ListFilterMixin, PreprintFilterMixin
from api.base.parsers import (
JSONAPIOnetoOneRelationshipParser,
JSONAPIOnetoOneRelationshipParserForRegularJSON,
JSONAPIMultipleRelationshipsParser,
JSONAPIMultipleRelationshipsParserForRegularJSON,
JSONAPIOnetoOneRelationshipParser,
JSONAPIOnetoOneRelationshipParserForRegularJSON,
)

from api.base.utils import absolute_reverse, get_user_auth, get_object_or_error
from api.base import permissions as base_permissions
from api.citations.utils import render_citation
Expand Down Expand Up @@ -51,6 +55,7 @@
AdminOrPublic,
ContributorDetailPermissions,
PreprintFilesPermissions,
PreprintInstitutionPermissionList,
)
from api.nodes.permissions import (
ContributorOrPublic,
Expand All @@ -61,6 +66,8 @@
from api.subjects.views import BaseResourceSubjectsList
from api.base.metrics import PreprintMetricsViewMixin
from osf.metrics import PreprintDownload, PreprintView
from api.institutions.serializers import InstitutionSerializer


class PreprintMixin(NodeMixin):
serializer_class = PreprintSerializer
Expand Down Expand Up @@ -614,3 +621,29 @@ def get_default_queryset(self):

def get_queryset(self):
return self.get_queryset_from_request()


class PreprintInstitutionsList(JSONAPIBaseView, generics.ListAPIView, ListFilterMixin, PreprintMixin):
"""The documentation for this endpoint can be found [here](https://developer.osf.io/#operation/preprint_institutions_list).
"""
permission_classes = (
drf_permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
PreprintInstitutionPermissionList,
)

required_read_scopes = [CoreScopes.PREPRINTS_READ, CoreScopes.INSTITUTION_READ]
required_write_scopes = [CoreScopes.NULL]
serializer_class = InstitutionSerializer

model = Institution
view_category = 'preprints'
view_name = 'preprints-institutions'

ordering = ('-id',)

def get_resource(self):
return self.get_preprint()

def get_queryset(self):
return self.get_resource().affiliated_institutions.all()
31 changes: 31 additions & 0 deletions api_tests/preprints/views/test_preprint_delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest
from osf_tests.factories import PreprintFactory, AuthUserFactory
from api.base.settings.defaults import API_BASE

@pytest.fixture()
def user():
return AuthUserFactory()

@pytest.mark.django_db
class TestPreprintDelete:

@pytest.fixture()
def unpublished_preprint(self, user):
return PreprintFactory(creator=user, is_published=False)

@pytest.fixture()
def published_preprint(self, user):
return PreprintFactory(creator=user)

@pytest.fixture()
def url(self, user):
return '/{}preprints/{{}}/'.format(API_BASE)

def test_cannot_delete_preprints(self, app, user, url, unpublished_preprint, published_preprint):
res = app.delete(url.format(unpublished_preprint._id), auth=user.auth, expect_errors=True)
assert res.status_code == 405
assert unpublished_preprint.deleted is None

res = app.delete(url.format(published_preprint._id), auth=user.auth, expect_errors=True)
assert res.status_code == 405
assert published_preprint.deleted is None
Loading

0 comments on commit 29cd008

Please sign in to comment.