Newer
Older

Jorrit Schaap
committed
from django.http import HttpResponse, JsonResponse, Http404
from django.shortcuts import get_object_or_404, render

Jorrit Schaap
committed
from lofar.sas.tmss.tmss.tmssapp import models

Jorrit Schaap
committed
from lofar.common.json_utils import get_default_json_object_for_schema

Jorrit Schaap
committed
from lofar.common.datetimeutils import formatDatetime
from lofar.sas.tmss.tmss.tmssapp.adapters.parset import convert_to_parset
from drf_yasg.utils import swagger_auto_schema
Jörn Künsemöller
committed
from drf_yasg.openapi import Parameter
from rest_framework.permissions import AllowAny
from rest_framework.decorators import authentication_classes, permission_classes
from django.apps import apps

Jorrit Schaap
committed
from rest_framework.decorators import api_view
Jörn Künsemöller
committed
from datetime import datetime
import dateutil.parser
Jörn Künsemöller
committed
from astropy.coordinates import SkyCoord
from astropy import units as u
from lofar.sas.tmss.tmss.tmssapp.conversions import local_sidereal_time_for_utc_and_station, local_sidereal_time_for_utc_and_longitude, timestamps_and_stations_to_sun_rise_and_set, coordinates_and_timestamps_to_separation_from_bodies

Jorrit Schaap
committed
# Note: Decorate with @api_view to get this picked up by Swagger

Jorrit Schaap
committed
def subtask_template_default_specification(request, subtask_template_pk:int):

Jorrit Schaap
committed
subtask_template = get_object_or_404(models.SubtaskTemplate, pk=subtask_template_pk)

Jorrit Schaap
committed
spec = get_default_json_object_for_schema(subtask_template.schema)
return JsonResponse(spec)

Jorrit Schaap
committed
def task_template_default_specification(request, task_template_pk:int):
task_template = get_object_or_404(models.TaskTemplate, pk=task_template_pk)
spec = get_default_json_object_for_schema(task_template.schema)
return JsonResponse(spec)
def subtask_parset(request, subtask_pk:int):

Jorrit Schaap
committed
subtask = get_object_or_404(models.Subtask, pk=subtask_pk)
parset = convert_to_parset(subtask)
return HttpResponse(str(parset), content_type='text/plain')
Jörn Künsemöller
committed
Jörn Künsemöller
committed
return render(request, os.path.join(os.environ.get('LOFARROOT'), 'SAS/TMSS/frontend','tmss_webapp/build/index.html'))
#return render(request, "../../../frontend/frontend_poc/build/index.html")
Jörn Künsemöller
committed
def task_specify_observation(request, pk=None):
task = get_object_or_404(models.TaskDraft, pk=pk)
return HttpResponse("response", content_type='text/plain')
# Allow everybody to GET our publicly available template-json-schema's
@permission_classes([AllowAny])
@authentication_classes([AllowAny])
@swagger_auto_schema(method='GET',
responses={200: 'Get the JSON schema from the template with the requested <template>, <name> and <version>',
404: 'the schema with requested <template>, <name> and <version> is not available'},
operation_description="Get the JSON schema for the given <template> with the given <name> and <version> as application/json content response.")
@api_view(['GET'])
def get_template_json_schema(request, template:str, name:str, version:str):
template_model = apps.get_model("tmssapp", template)
template_instance = get_object_or_404(template_model, name=name, version=version)
schema = template_instance.schema
response = JsonResponse(schema, json_dumps_params={"indent":2})
# config Access-Control. Our schemas use $ref url's to other schemas, mainly pointing to our own common schemas with base definitions.
# We instruct the client to allow fetching those.
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "GET, OPTIONS"
return response

Jorrit Schaap
committed
# Allow everybody to GET our publicly available station group lookups
@permission_classes([AllowAny])
@authentication_classes([AllowAny])
@swagger_auto_schema(method='GET',
responses={200: 'A JSON object with two properties: group:<the_group_name>, stations:<the_list_of_stations>',
404: 'No such group or template available'},
operation_description="Get a JSON list of stations for the given <station_group> name the the group definitions in the common_schema_template given by <template_name> and <template_version>")
@api_view(['GET'])
def get_stations_in_group(request, template_name:str, template_version:str, station_group:str):
station_schema_template = get_object_or_404(models.CommonSchemaTemplate, name=template_name, version=template_version)
station_schema = station_schema_template.schema
if 'station_group' not in station_schema.get('definitions', {}):
raise Http404('The JSON schema in template %s version %s has no station_group definitions' % (template_name, template_version))
groups = station_schema['definitions']['station_group']['anyOf']
try:
selected_group = next(g for g in groups if g['title'].lower() == station_group.lower())
except StopIteration:
raise Http404('No station_group with name "%s" found in the JSON schema. template=%s version=%s' % (station_group, template_name, template_version))
stations = selected_group['properties']['stations']['enum'][0]
return JsonResponse({'group': station_group,
'stations': stations})
Jörn Künsemöller
committed
@permission_classes([AllowAny])
@authentication_classes([AllowAny])
@swagger_auto_schema(method='GET',
responses={200: 'An isoformat timestamp of the current UTC clock of the system'},
Jörn Künsemöller
committed
operation_description="Get the current system time in UTC")
@api_view(['GET'])
Jörn Künsemöller
committed
def utc(request):
return HttpResponse(datetime.utcnow().isoformat(), content_type='text/plain')
Jörn Künsemöller
committed
@permission_classes([AllowAny])
@authentication_classes([AllowAny])
@swagger_auto_schema(method='GET',
responses={200: 'The LST time in hms format at the given UTC time and station or longitude'},
Jörn Künsemöller
committed
operation_description="Get LST time for UTC time and station or longitude",
manual_parameters=[Parameter(name='station', required=False, type='string', in_='query',
description="A station names (defaults to CS002)"),
Parameter(name='timestamp', required=False, type='string', in_='query',
description="A timestamp in isoformat (defaults to utcnow)"),
Parameter(name='longitude', required=False, type='string', in_='query',
description="A longitude as float")
Jörn Künsemöller
committed
])
@api_view(['GET'])
Jörn Künsemöller
committed
def lst(request):
# Handling optional parameters via django paths in urls.py is a pain, we access them on the request directly instead.
timestamp = request.GET.get('timestamp', None)
station = request.GET.get('station', None)
longitude = request.GET.get('longitude', None)
# conversions
if timestamp:
timestamp = dateutil.parser.parse(timestamp) # isot to datetime
if longitude:
longitude = float(longitude)
if station:
lst_lon = local_sidereal_time_for_utc_and_station(timestamp, station)
elif longitude:
lst_lon = local_sidereal_time_for_utc_and_longitude(timestamp, longitude)
else:
# fall back to defaults
lst_lon = local_sidereal_time_for_utc_and_station(timestamp)
# todo: do we want to return a dict, so users can make sure their parameters were parsed correctly instead?

Jorrit Schaap
committed
return HttpResponse(str(lst_lon), content_type='text/plain')
Jörn Künsemöller
committed
@permission_classes([AllowAny])
@authentication_classes([AllowAny])
@swagger_auto_schema(method='GET',
responses={200: 'A JSON object with sunrise, sunset, day and night of the given stations at the given timestamps'},
operation_description="Get sunrise, sunset, day and night for stations and timestamps.\n\n"
"Example request: /api/util/sun_rise_and_set?stations=CS002,CS005×tamps=2020-05-01,2020-09-09T11-11-00",
Jörn Künsemöller
committed
manual_parameters=[Parameter(name='stations', required=False, type='string', in_='query',
description="comma-separated list of station names"),
Parameter(name='timestamps', required=False, type='string', in_='query',
description="comma-separated list of isoformat timestamps")])
@api_view(['GET'])
Jörn Künsemöller
committed
def get_sun_rise_and_set(request):
"""
returns sunrise and sunset at the given stations and timestamps, or today at LOFAR core if none specified.
example request: /api/util/sun_rise_and_set?stations=CS002,CS005×tamps=2020-05-01,2020-09-09T11-11-00
"""
timestamps = request.GET.get('timestamps', None)
stations = request.GET.get('stations', None)
if timestamps is None:
timestamps = [datetime.utcnow()]

Jorrit Schaap
committed
else:
Jörn Künsemöller
committed
timestamps = timestamps.split(',')
timestamps = [dateutil.parser.parse(timestamp) for timestamp in timestamps] # isot to datetime
if stations is None:
stations = ["CS002"]
Jörn Künsemöller
committed
else:
stations = stations.split(',')

Jorrit Schaap
committed
Jörn Künsemöller
committed
return JsonResponse(timestamps_and_stations_to_sun_rise_and_set(timestamps, stations))

Jorrit Schaap
committed
Jörn Künsemöller
committed
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
@permission_classes([AllowAny])
@authentication_classes([AllowAny])
@swagger_auto_schema(method='GET',
responses={200: 'A JSON object with angular distances of the given sky coordinates from the given solar system bodies at the given timestamps and stations. \n'
'Outer list contains results per coordinate in given order, inner list per timestamp.'},
operation_description="Get angular distances of the given sky coordinates from the given solar system bodies at all given timestamps and stations. \n\n"
"Example request: /api/util/sun_rise_and_set?coordinates=,CS005×tamps=2020-05-01,2020-09-09T11-11-00",
manual_parameters=[Parameter(name='ras', required=True, type='string', in_='query',
description="comma-separated list of right ascensions (celestial longitudes)"),
Parameter(name='decs', required=True, type='string', in_='query',
description="comma-separated list of declinations (celestial latitude)"),
Parameter(name='stations', required=False, type='string', in_='query',
description="comma-separated list of station names"),
Parameter(name='timestamps', required=False, type='string', in_='query',
description="comma-separated list of isoformat timestamps"),
Parameter(name='bodies', required=False, type='string', in_='query',
description="comma-separated list of solar system bodies")])
@api_view(['GET'])
def get_angular_separation_from_bodies(request):
'''
returns angular distances of the given sky coordinates from the given astronomical objects at the given timestamps and stations
'''
stations = request.GET.get('stations', None)
timestamps = request.GET.get('timestamps', None)
ras = request.GET.get('ras', None)
decs = request.GET.get('decs', None)
bodies = request.GET.get('bodies', None)
if timestamps is None:
timestamps = [datetime.utcnow()]
else:
timestamps = timestamps.split(',')
timestamps = [dateutil.parser.parse(timestamp) for timestamp in timestamps] # isot to datetime
if bodies is None:
bodies = ['sun', 'moon', 'jupiter']
else:
bodies = bodies.split(',')
if stations is None:
stations = ["CS002"]
else:
stations = stations.split(',')
if ras is None or decs is None:
raise ValueError("Please provide celestial coordinates in radians/J2000 via the 'ras' and 'decs' the properties.")
coords = []
longitudes = ras.split(',')
latitudes = decs.split(',')
for ra, dec in zip(longitudes, latitudes):
coords.append(SkyCoord(ra=ra, dec=dec, unit=u.rad, equinox='J2000'))
sep_dict = coordinates_and_timestamps_to_separation_from_bodies(coords=coords, stations=stations, bodies=bodies, timestamps=timestamps)
for station, v in sep_dict.items():
for coord in v:
for object, angles in coord.items():
coord[object] = [angle.rad for angle in angles]
return JsonResponse(sep_dict)