Skip to content

Commit

Permalink
add preprint institutions relationship list
Browse files Browse the repository at this point in the history
  • Loading branch information
John Tordoff committed Jun 27, 2024
1 parent b4bd45a commit 15fddb5
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 7 deletions.
1 change: 0 additions & 1 deletion api/preprints/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
NodeTagField,
)
from api.base.metrics import MetricsSerializerMixin
from api.base.serializers import BaseAPISerializer
from api.taxonomies.serializers import TaxonomizableSerializerMixin
from framework.auth import Auth
from framework.exceptions import PermissionsError
Expand Down
25 changes: 20 additions & 5 deletions api/preprints/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,29 +652,44 @@ def get_queryset(self):
return self.get_resource().affiliated_institutions.all()


class PrprintInstitutionsRelationship(JSONAPIBaseView, generics.RetrieveUpdateDestroyAPIView, generics.CreateAPIView, PreprintMixin):
class PreprintInstitutionsRelationshipList(JSONAPIBaseView, generics.RetrieveUpdateDestroyAPIView, PreprintMixin):
""" """
permission_classes = (
drf_permissions.IsAuthenticatedOrReadOnly,
base_permissions.TokenHasScope,
WriteOrPublicForRelationshipInstitutions,
)
required_read_scopes = [CoreScopes.NODE_BASE_READ]
required_write_scopes = [CoreScopes.NODE_BASE_WRITE]
required_read_scopes = [CoreScopes.PREPRINTS_READ]
required_write_scopes = [CoreScopes.PREPRINTS_WRITE]
serializer_class = PreprintsInstitutionRelationshipSerializer
parser_classes = (JSONAPIRelationshipParser, JSONAPIRelationshipParserForRegularJSON, )

view_category = 'preprints'
view_name = 'preprint-relationships-institutions'

def get_resource(self):
return self.get_preprint(check_object_permissions=False)
return self.get_preprint()

def get_object(self):
preprint = self.get_resource()
obj = {
'data': preprint.affiliated_institutions.all(),
'self': preprint,
}
self.check_object_permissions(self.request, obj)
return obj

def perform_destroy(self, instance):
data = self.request.data['data']
user = self.request.user
current_insts = {inst._id: inst for inst in instance['data']}
node = instance['self']

for val in data:
if val['id'] in current_insts:
if not user.is_affiliated_with_institution(current_insts[val['id']]) and not node.has_permission(user, ADMIN):
raise PermissionDenied
node.remove_affiliated_institution(inst=current_insts[val['id']], user=user)
node.save()

def create(self, *args, **kwargs):
return super().create(*args, **kwargs)
1 change: 0 additions & 1 deletion api/requests/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,3 @@ def has_object_permission(self, request, view, obj):
# Requesters may edit their comment or submit their request
return is_requester
return False

163 changes: 163 additions & 0 deletions api_tests/preprints/views/test_preprint_institutions_relationship.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import pytest

from api.base.settings.defaults import API_BASE
from osf_tests.factories import (
PreprintFactory,
AuthUserFactory,
InstitutionFactory,
)


@pytest.mark.django_db
class TestPreprintInstitutionsList:

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

@pytest.fixture()
def admin_with_institutional_affilation(self, institution, preprint):
user = AuthUserFactory()
preprint.add_permission(user, 'admin')
user.add_or_update_affiliated_institution(institution)
return user

@pytest.fixture()
def no_auth_with_institutional_affilation(self, institution):
user = AuthUserFactory()
user.add_or_update_affiliated_institution(institution)
return user

@pytest.fixture()
def admin_without_institutional_affilation(self, institution, preprint):
user = AuthUserFactory()
preprint.add_permission(user, 'admin')
return user

@pytest.fixture()
def institution(self):
return InstitutionFactory()

@pytest.fixture()
def preprint(self):
return PreprintFactory()

@pytest.fixture()
def url(self, preprint):
return f'/{API_BASE}preprints/{preprint._id}/relationships/institutions/'

def test_update_affiliated_institutions_add(self, app, user, admin_with_institutional_affilation, admin_without_institutional_affilation, preprint, url,
institution):
update_institutions_payload = {
'data': [{'type': 'institutions', 'id': institution._id}]
}

res = app.put_json_api(
url,
update_institutions_payload,
auth=user.auth,
expect_errors=True
)
assert res.status_code == 403

res = app.put_json_api(
url,
update_institutions_payload,
auth=admin_without_institutional_affilation.auth,
expect_errors=True
)
assert res.status_code == 400
assert res.json['errors'][0]['detail'] == f'User is not affiliated with {institution.name},'

res = app.put_json_api(
url,
update_institutions_payload,
auth=admin_with_institutional_affilation.auth
)
assert res.status_code == 201

preprint.reload()
assert institution in preprint.affiliated_institutions.all()

log = preprint.logs.latest()
assert log.action == 'affiliated_institution_added'
assert log.params['institution'] == {
'id': institution._id,
'name': institution.name
}

def test_update_affiliated_institutions_remove(self, app, user, admin_with_institutional_affilation, no_auth_with_institutional_affilation, admin_without_institutional_affilation, preprint, url,
institution):

preprint.affiliated_institutions.add(institution)
preprint.save()

update_institutions_payload = {
'data': []
}

res = app.put_json_api(
url,
update_institutions_payload,
auth=user.auth,
expect_errors=True
)
assert res.status_code == 403

res = app.put_json_api(
url,
update_institutions_payload,
auth=no_auth_with_institutional_affilation.auth,
expect_errors=True
)
assert res.status_code == 403

res = app.put_json_api(
url,
update_institutions_payload,
auth=admin_without_institutional_affilation.auth,
expect_errors=True
)
assert res.status_code == 201 # you can always remove it you are an admin

res = app.put_json_api(
url,
update_institutions_payload,
auth=admin_with_institutional_affilation.auth
)
assert res.status_code == 201

preprint.reload()
assert institution not in preprint.affiliated_institutions.all()

log = preprint.logs.latest()
assert log.action == 'affiliated_institution_removed'
assert log.params['institution'] == {
'id': institution._id,
'name': institution.name
}

def test_preprint_institutions_list_get(self, app, user, admin_with_institutional_affilation, admin_without_institutional_affilation, preprint, url,
institution):
# For testing purposes
preprint.is_public = False
preprint.save()

res = app.get(url, expect_errors=True)
assert res.status_code == 401

res = app.get(url, auth=user.auth, expect_errors=True)
assert res.status_code == 403

res = app.get(url, auth=admin_without_institutional_affilation.auth, expect_errors=True)
assert res.status_code == 200

assert res.status_code == 200
assert not res.json['data']

res = app.get(url, auth=admin_with_institutional_affilation.auth)
assert res.status_code == 200

preprint.add_institutional_affilation(institution)
assert res.json['data'][0]['id'] == institution._id
assert res.json['data'][0]['type'] == 'institution'

0 comments on commit 15fddb5

Please sign in to comment.