Skip to content

Commit 762526d

Browse files
authored
GOATS-739: Extend API to fetch program information from GPP. (#331)
1 parent f3a60ba commit 762526d

14 files changed

Lines changed: 194 additions & 2 deletions

File tree

docs/changes/331.new.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Extended the API to allow fetching program information from GPP.

src/goats_tom/api_views/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .dragons_recipes import DRAGONSRecipesViewSet
1010
from .dragons_reduce import DRAGONSReduceViewSet
1111
from .dragons_runs import DRAGONSRunsViewSet
12+
from .gpp import GPPProgramViewSet
1213
from .recipes_module import RecipesModuleViewSet
1314
from .reduceddatum import ReducedDatumViewSet
1415
from .run_processor import RunProcessorViewSet
@@ -28,4 +29,5 @@
2829
"DRAGONSDataViewSet",
2930
"ReducedDatumViewSet",
3031
"AstroDatalabViewSet",
32+
"GPPProgramViewSet",
3133
]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .programs import GPPProgramViewSet
2+
3+
__all__ = ["GPPProgramViewSet"]

src/goats_tom/api_views/gpp/observations.py

Whitespace-only changes.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Handles grabbing programs and program details from GPP."""
2+
3+
__all__ = ["GPPProgramViewSet"]
4+
5+
from asgiref.sync import async_to_sync
6+
from django.conf import settings
7+
from gpp_client import GPPClient
8+
from rest_framework import permissions
9+
from rest_framework.exceptions import PermissionDenied
10+
from rest_framework.request import Request
11+
from rest_framework.response import Response
12+
from rest_framework.viewsets import GenericViewSet, mixins
13+
14+
15+
class GPPProgramViewSet(
16+
GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin
17+
):
18+
serializer_class = None
19+
permission_classes = [permissions.IsAuthenticated]
20+
queryset = None
21+
22+
def list(self, request: Request, *args, **kwargs) -> Response:
23+
"""Return a list of GPP programs associated with the authenticated user.
24+
25+
Parameters
26+
----------
27+
request : Request
28+
The HTTP request object, including user context.
29+
30+
Returns
31+
-------
32+
Response
33+
A DRF Response object containing a list of GPP programs.
34+
35+
Raises
36+
------
37+
PermissionDenied
38+
If the authenticated user has not configured GPP login credentials.
39+
"""
40+
if not hasattr(request.user, "gpplogin"):
41+
raise PermissionDenied(
42+
"GPP login credentials are not configured for this user."
43+
)
44+
credentials = request.user.gpplogin
45+
46+
# Setup client to communicate with GPP.
47+
client = GPPClient(url=settings.GPP_URL, token=credentials.token)
48+
programs = async_to_sync(client.program.get_all)()
49+
50+
return Response(programs)
51+
52+
def retrieve(self, request: Request, *args, **kwargs) -> Response:
53+
"""Return details for a specific GPP program by program ID.
54+
55+
Parameters
56+
----------
57+
request : Request
58+
The HTTP request object, including user context.
59+
60+
Returns
61+
-------
62+
Response
63+
A DRF Response object containing the details of the requested program.
64+
65+
Raises
66+
------
67+
PermissionDenied
68+
If the authenticated user has not configured GPP login credentials.
69+
KeyError
70+
If 'pk' (the program ID) is not present in kwargs.
71+
"""
72+
program_id = kwargs["pk"]
73+
74+
# Check if GPP credentials have been added.
75+
if not hasattr(request.user, "gpplogin"):
76+
# Return with the proper error
77+
raise PermissionDenied(
78+
"GPP login credentials are not configured for this user."
79+
)
80+
credentials = request.user.gpplogin
81+
82+
# Setup client to communicate with GPP.
83+
client = GPPClient(url=settings.GPP_URL, token=credentials.token)
84+
program = async_to_sync(client.program.get_by_id)(program_id=program_id)
85+
86+
return Response(program)

src/goats_tom/tests/factories/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .dragons_recipe import DRAGONSRecipeFactory
66
from .dragons_reduce import DRAGONSReduceFactory
77
from .dragons_run import DRAGONSRunFactory
8-
from .logins import AstroDatalabLoginFactory, GOALoginFactory
8+
from .logins import AstroDatalabLoginFactory, GOALoginFactory, GPPLoginFactory
99
from .recipes_module import RecipesModuleFactory
1010
from .reduceddatum import ReducedDatumFactory
1111
from .user import UserFactory
@@ -23,4 +23,5 @@
2323
"RecipesModuleFactory",
2424
"ReducedDatumFactory",
2525
"UserFactory",
26+
"GPPLoginFactory",
2627
]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .astro_datalab import AstroDatalabLoginFactory
22
from .goa import GOALoginFactory
3+
from .gpp import GPPLoginFactory
34

4-
__all__ = ["GOALoginFactory", "AstroDatalabLoginFactory"]
5+
__all__ = ["GOALoginFactory", "AstroDatalabLoginFactory", "GPPLoginFactory"]

src/goats_tom/tests/factories/logins/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,14 @@ class UsernamePasswordLoginFactory(BaseLoginFactory):
2222
upper_case=True,
2323
lower_case=True,
2424
)
25+
26+
27+
class TokenLoginFactory(BaseLoginFactory):
28+
token = factory.Faker(
29+
"password",
30+
length=24,
31+
special_chars=True,
32+
digits=True,
33+
upper_case=True,
34+
lower_case=True,
35+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from goats_tom.models import (
2+
GPPLogin,
3+
)
4+
5+
from .base import TokenLoginFactory
6+
7+
8+
class GPPLoginFactory(TokenLoginFactory):
9+
"""Factory for GPPLogin."""
10+
class Meta:
11+
model = GPPLogin

src/goats_tom/tests/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@
360360
# 'plotly', 'plotly_white', 'plotly_dark', 'ggplot2', 'seaborn', 'simple_white', 'none'
361361
PLOTLY_THEME = "plotly_dark"
362362

363+
GPP_URL = "test"
364+
363365
try:
364366
from local_settings import * # noqa
365367
except ImportError:

0 commit comments

Comments
 (0)