Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 51 additions & 3 deletions coldfront/plugins/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers

from coldfront.core.allocation.models import Allocation, AllocationChangeRequest
from coldfront.core.project.models import Project, ProjectUser
from coldfront.core.allocation.models import Allocation, AllocationAttribute, AllocationChangeRequest, AllocationUser
from coldfront.core.project.models import Project, ProjectAttribute, ProjectUser
from coldfront.core.resource.models import Resource


Expand Down Expand Up @@ -37,6 +37,8 @@ class AllocationSerializer(serializers.ModelSerializer):
resource = serializers.ReadOnlyField(source="get_resources_as_string")
project = serializers.SlugRelatedField(slug_field="title", read_only=True)
status = serializers.SlugRelatedField(slug_field="name", read_only=True)
allocation_users = serializers.SerializerMethodField()
allocation_attributes = serializers.SerializerMethodField()

class Meta:
model = Allocation
Expand All @@ -45,8 +47,39 @@ class Meta:
"project",
"resource",
"status",
"allocation_users",
"allocation_attributes",
)

def get_allocation_users(self, obj):
request = self.context.get("request", None)
if request and request.query_params.get("allocation_users") in ["true", "True"]:
return AllocationUserSerializer(obj.allocationuser_set, many=True, read_only=True).data
return None

def get_allocation_attributes(self, obj):
request = self.context.get("request", None)
if request and request.query_params.get("allocation_attributes") in ["true", "True"]:
return AllocationAttributeSerializer(obj.allocationattribute_set, many=True, read_only=True).data
return None


class AllocationUserSerializer(serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field="username", read_only=True)
status = serializers.SlugRelatedField(slug_field="name", read_only=True)

class Meta:
model = AllocationUser
fields = ("user", "status")


class AllocationAttributeSerializer(serializers.ModelSerializer):
allocation_attribute_type = serializers.SlugRelatedField(slug_field="name", read_only=True)

class Meta:
model = AllocationAttribute
fields = ("allocation_attribute_type", "value")


class AllocationRequestSerializer(serializers.ModelSerializer):
project = serializers.SlugRelatedField(slug_field="title", read_only=True)
Expand Down Expand Up @@ -145,15 +178,24 @@ class Meta:
fields = ("user", "role", "status")


class ProjectAttributeSerializer(serializers.ModelSerializer):
proj_attr_type = serializers.SlugRelatedField(slug_field="name", read_only=True)

class Meta:
model = ProjectAttribute
fields = ("proj_attr_type", "value")


class ProjectSerializer(serializers.ModelSerializer):
pi = serializers.SlugRelatedField(slug_field="username", read_only=True)
status = serializers.SlugRelatedField(slug_field="name", read_only=True)
project_users = serializers.SerializerMethodField()
allocations = serializers.SerializerMethodField()
project_attributes = serializers.SerializerMethodField()

class Meta:
model = Project
fields = ("id", "title", "pi", "status", "project_users", "allocations")
fields = ("id", "title", "pi", "status", "project_users", "allocations", "project_attributes")

def get_project_users(self, obj):
request = self.context.get("request", None)
Expand All @@ -166,3 +208,9 @@ def get_allocations(self, obj):
if request and request.query_params.get("allocations") in ["true", "True"]:
return ProjAllocationSerializer(obj.allocation_set, many=True, read_only=True).data
return None

def get_project_attributes(self, obj):
request = self.context.get("request", None)
if request and request.query_params.get("project_attributes") in ["true", "True"]:
return ProjectAttributeSerializer(obj.projectattribute_set, many=True, read_only=True).data
return None
57 changes: 51 additions & 6 deletions coldfront/plugins/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
from coldfront.core.allocation.models import Allocation
from coldfront.core.project.models import Project
from coldfront.core.test_helpers.factories import (
AllocationAttributeFactory,
AllocationFactory,
AllocationUserFactory,
PAttributeTypeFactory,
ProjectAttributeFactory,
ProjectAttributeTypeFactory,
ProjectFactory,
ProjectStatusChoiceFactory,
ProjectUserFactory,
ResourceFactory,
UserFactory,
)
Expand All @@ -27,16 +33,18 @@ class ColdfrontAPI(APITestCase):
def setUpTestData(self):
"""Test Data setup for ColdFront REST API tests."""
self.admin_user = UserFactory(is_staff=True, is_superuser=True)
pat = ProjectAttributeTypeFactory(attribute_type=PAttributeTypeFactory(name="Text"))

project = ProjectFactory(status=ProjectStatusChoiceFactory(name="Active"))
allocation = AllocationFactory(project=project)
allocation.resources.add(ResourceFactory(name="test"))
self.pi_user = project.pi

for i in range(0, 10):
for i in range(10):
project = ProjectFactory(status=ProjectStatusChoiceFactory(name="Active"))
ProjectUserFactory(project=project, user=self.admin_user)
ProjectAttributeFactory(project=project, proj_attr_type=pat)

allocation = AllocationFactory(project=project)
allocation.resources.add(ResourceFactory(name="test"))
AllocationUserFactory(allocation=allocation, user=self.admin_user)
AllocationAttributeFactory(allocation=allocation)
self.pi_user = project.pi

def test_requires_login(self):
"""Test that the API requires authentication"""
Expand Down Expand Up @@ -70,6 +78,26 @@ def test_allocation_api_permissions(self):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)

def test_allocation_query_params(self):
"""Test that specifying the query parameters returns the related
information"""
# login as admin
self.client.force_login(self.admin_user)
response = self.client.get("/api/allocations/?allocation_users=true", format="json")
for alloc in response.json():
self.assertEqual(len(alloc["allocation_users"]), 1)
self.assertIsNone(alloc["allocation_attributes"])

response = self.client.get("/api/allocations/?allocation_attributes=true", format="json")
for alloc in response.json():
self.assertIsNone(alloc["allocation_users"])
self.assertEqual(len(alloc["allocation_attributes"]), 1)

response = self.client.get("/api/allocations/?allocation_users=true&allocation_attributes=true", format="json")
for alloc in response.json():
self.assertEqual(len(alloc["allocation_users"]), 1)
self.assertEqual(len(alloc["allocation_attributes"]), 1)

def test_project_api_permissions(self):
"""Confirm permissions for project API:
admin user should be able to access everything
Expand All @@ -86,6 +114,23 @@ def test_project_api_permissions(self):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)

def test_project_query_params(self):
"""Test that specifying the query parameters returns the related
information"""
# login as admin
self.client.force_login(self.admin_user)
response = self.client.get("/api/projects/?project_users=true", format="json")
for proj in response.json():
self.assertEqual(len(proj["project_users"]), 1)

response = self.client.get("/api/projects/?project_attributes=true", format="json")
for proj in response.json():
self.assertEqual(len(proj["project_attributes"]), 1)

response = self.client.get("/api/projects/?allocations=true", format="json")
for proj in response.json():
self.assertEqual(len(proj["allocations"]), 1)

def test_user_api_permissions(self):
"""Test that accessing the user API view as an admin returns all
allocations, and that accessing it as a user is forbidden"""
Expand Down
19 changes: 19 additions & 0 deletions coldfront/plugins/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ class ResourceViewSet(viewsets.ReadOnlyModelViewSet):


class AllocationViewSet(viewsets.ReadOnlyModelViewSet):
"""
Query parameters:
- allocation_users (default false)
Show related user data.
- allocation_attributes (default false)
Show related attribute data.
"""

serializer_class = serializers.AllocationSerializer
# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

Expand All @@ -71,6 +79,12 @@ def get_queryset(self):

allocations = allocations.order_by("project")

if self.request.query_params.get("allocation_users") in ["True", "true"]:
allocations = allocations.prefetch_related("allocationuser_set")

if self.request.query_params.get("allocation_attributes") in ["True", "true"]:
allocations = allocations.prefetch_related("allocationattribute_set")

return allocations


Expand Down Expand Up @@ -271,6 +285,8 @@ class ProjectViewSet(viewsets.ReadOnlyModelViewSet):
Show related allocation data.
- project_users (default false)
Show related user data.
- project_attributes (default false)
Show related attribute data.
"""

serializer_class = serializers.ProjectSerializer
Expand Down Expand Up @@ -301,6 +317,9 @@ def get_queryset(self):
if self.request.query_params.get("allocations") in ["True", "true"]:
projects = projects.prefetch_related("allocation_set")

if self.request.query_params.get("project_attributes") in ["True", "true"]:
projects = projects.prefetch_related("projectattribute_set")

return projects.order_by("pi")


Expand Down
Loading