527 lines
22 KiB
Python
527 lines
22 KiB
Python
"""
|
|
API endpoints for AJAX requests and data retrieval.
|
|
"""
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.http import JsonResponse
|
|
from django.utils import timezone
|
|
from django.views import View
|
|
|
|
from ..models import ObjItem
|
|
from ..utils import format_coordinate, format_coords_display, format_frequency, format_symbol_rate
|
|
|
|
|
|
class GetLocationsView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting locations by satellite ID in GeoJSON format."""
|
|
|
|
def get(self, request, sat_id):
|
|
locations = (
|
|
ObjItem.objects.filter(parameter_obj__id_satellite=sat_id)
|
|
.select_related(
|
|
"geo_obj",
|
|
"parameter_obj",
|
|
"parameter_obj__polarization",
|
|
)
|
|
)
|
|
|
|
if not locations.exists():
|
|
return JsonResponse({"error": "Объектов не найдено"}, status=404)
|
|
|
|
features = []
|
|
for loc in locations:
|
|
if not hasattr(loc, "geo_obj") or not loc.geo_obj or not loc.geo_obj.coords:
|
|
continue
|
|
|
|
param = getattr(loc, 'parameter_obj', None)
|
|
if not param:
|
|
continue
|
|
|
|
features.append(
|
|
{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [loc.geo_obj.coords[0], loc.geo_obj.coords[1]],
|
|
},
|
|
"properties": {
|
|
"pol": param.polarization.name if param.polarization else "-",
|
|
"freq": param.frequency * 1000000 if param.frequency else 0,
|
|
"name": loc.name or "-",
|
|
"id": loc.geo_obj.id,
|
|
},
|
|
}
|
|
)
|
|
|
|
return JsonResponse({"type": "FeatureCollection", "features": features})
|
|
|
|
|
|
class LyngsatDataAPIView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting LyngSat source data."""
|
|
|
|
def get(self, request, lyngsat_id):
|
|
from lyngsatapp.models import LyngSat
|
|
|
|
try:
|
|
lyngsat = LyngSat.objects.select_related(
|
|
'id_satellite',
|
|
'polarization',
|
|
'modulation',
|
|
'standard'
|
|
).get(id=lyngsat_id)
|
|
|
|
# Format date with local timezone
|
|
last_update_str = '-'
|
|
if lyngsat.last_update:
|
|
local_time = timezone.localtime(lyngsat.last_update)
|
|
last_update_str = local_time.strftime("%d.%m.%Y")
|
|
|
|
data = {
|
|
'id': lyngsat.id,
|
|
'satellite': lyngsat.id_satellite.name if lyngsat.id_satellite else '-',
|
|
'frequency': format_frequency(lyngsat.frequency),
|
|
'polarization': lyngsat.polarization.name if lyngsat.polarization else '-',
|
|
'modulation': lyngsat.modulation.name if lyngsat.modulation else '-',
|
|
'standard': lyngsat.standard.name if lyngsat.standard else '-',
|
|
'sym_velocity': format_symbol_rate(lyngsat.sym_velocity),
|
|
'fec': lyngsat.fec or '-',
|
|
'channel_info': lyngsat.channel_info or '-',
|
|
'last_update': last_update_str,
|
|
'url': lyngsat.url or None,
|
|
}
|
|
|
|
return JsonResponse(data)
|
|
except LyngSat.DoesNotExist:
|
|
return JsonResponse({'error': 'Источник LyngSat не найден'}, status=404)
|
|
except Exception as e:
|
|
return JsonResponse({'error': str(e)}, status=500)
|
|
|
|
|
|
class SigmaParameterDataAPIView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting SigmaParameter data."""
|
|
|
|
def get(self, request, parameter_id):
|
|
from ..models import Parameter
|
|
|
|
try:
|
|
parameter = Parameter.objects.select_related(
|
|
'id_satellite',
|
|
'polarization',
|
|
'modulation',
|
|
'standard'
|
|
).prefetch_related(
|
|
'sigma_parameter__mark',
|
|
'sigma_parameter__id_satellite',
|
|
'sigma_parameter__polarization',
|
|
'sigma_parameter__modulation',
|
|
'sigma_parameter__standard'
|
|
).get(id=parameter_id)
|
|
|
|
# Get all related SigmaParameter
|
|
sigma_params = parameter.sigma_parameter.all()
|
|
|
|
sigma_data = []
|
|
for sigma in sigma_params:
|
|
# Get marks
|
|
marks = []
|
|
for mark in sigma.mark.all().order_by('-timestamp'):
|
|
mark_str = '+' if mark.mark else '-'
|
|
date_str = '-'
|
|
if mark.timestamp:
|
|
local_time = timezone.localtime(mark.timestamp)
|
|
date_str = local_time.strftime("%d.%m.%Y %H:%M")
|
|
marks.append({
|
|
'mark': mark_str,
|
|
'date': date_str
|
|
})
|
|
|
|
# Format start and end dates
|
|
datetime_begin_str = '-'
|
|
if sigma.datetime_begin:
|
|
local_time = timezone.localtime(sigma.datetime_begin)
|
|
datetime_begin_str = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
datetime_end_str = '-'
|
|
if sigma.datetime_end:
|
|
local_time = timezone.localtime(sigma.datetime_end)
|
|
datetime_end_str = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
sigma_data.append({
|
|
'id': sigma.id,
|
|
'satellite': sigma.id_satellite.name if sigma.id_satellite else '-',
|
|
'frequency': format_frequency(sigma.frequency),
|
|
'transfer_frequency': format_frequency(sigma.transfer_frequency),
|
|
'freq_range': format_frequency(sigma.freq_range),
|
|
'polarization': sigma.polarization.name if sigma.polarization else '-',
|
|
'modulation': sigma.modulation.name if sigma.modulation else '-',
|
|
'standard': sigma.standard.name if sigma.standard else '-',
|
|
'bod_velocity': format_symbol_rate(sigma.bod_velocity),
|
|
'snr': f"{sigma.snr:.1f}" if sigma.snr is not None else '-',
|
|
'power': f"{sigma.power:.1f}" if sigma.power is not None else '-',
|
|
'status': sigma.status or '-',
|
|
'packets': 'Да' if sigma.packets else 'Нет' if sigma.packets is not None else '-',
|
|
'datetime_begin': datetime_begin_str,
|
|
'datetime_end': datetime_end_str,
|
|
'marks': marks
|
|
})
|
|
|
|
return JsonResponse({
|
|
'parameter_id': parameter.id,
|
|
'sigma_parameters': sigma_data
|
|
})
|
|
except Parameter.DoesNotExist:
|
|
return JsonResponse({'error': 'Parameter не найден'}, status=404)
|
|
except Exception as e:
|
|
return JsonResponse({'error': str(e)}, status=500)
|
|
|
|
|
|
class SourceObjItemsAPIView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting ObjItems related to a Source."""
|
|
|
|
def get(self, request, source_id):
|
|
from datetime import datetime, timedelta
|
|
from ..models import Source
|
|
|
|
try:
|
|
# Get filter parameters from query string
|
|
geo_date_from = request.GET.get("geo_date_from", "").strip()
|
|
geo_date_to = request.GET.get("geo_date_to", "").strip()
|
|
|
|
# Load Source with prefetch_related for ObjItem
|
|
source = Source.objects.prefetch_related(
|
|
'source_objitems',
|
|
'source_objitems__parameter_obj',
|
|
'source_objitems__parameter_obj__id_satellite',
|
|
'source_objitems__parameter_obj__polarization',
|
|
'source_objitems__parameter_obj__modulation',
|
|
'source_objitems__parameter_obj__standard',
|
|
'source_objitems__geo_obj',
|
|
'source_objitems__geo_obj__mirrors',
|
|
'source_objitems__lyngsat_source',
|
|
'source_objitems__transponder',
|
|
'source_objitems__created_by__user',
|
|
'source_objitems__updated_by__user',
|
|
'marks',
|
|
'marks__created_by__user'
|
|
).get(id=source_id)
|
|
|
|
# Get all related ObjItems, sorted by created_at
|
|
objitems = source.source_objitems.all()
|
|
|
|
# Apply Geo timestamp filter if provided
|
|
if geo_date_from:
|
|
try:
|
|
geo_date_from_obj = datetime.strptime(geo_date_from, "%Y-%m-%d")
|
|
objitems = objitems.filter(
|
|
geo_obj__isnull=False,
|
|
geo_obj__timestamp__gte=geo_date_from_obj
|
|
)
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
if geo_date_to:
|
|
try:
|
|
geo_date_to_obj = datetime.strptime(geo_date_to, "%Y-%m-%d")
|
|
# Add one day to include entire end date
|
|
geo_date_to_obj = geo_date_to_obj + timedelta(days=1)
|
|
objitems = objitems.filter(
|
|
geo_obj__isnull=False,
|
|
geo_obj__timestamp__lt=geo_date_to_obj
|
|
)
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
objitems = objitems.order_by('created_at')
|
|
|
|
objitems_data = []
|
|
for objitem in objitems:
|
|
# Get parameter data
|
|
param = getattr(objitem, 'parameter_obj', None)
|
|
satellite_name = '-'
|
|
satellite_id = None
|
|
frequency = '-'
|
|
freq_range = '-'
|
|
polarization = '-'
|
|
bod_velocity = '-'
|
|
modulation = '-'
|
|
standard = '-'
|
|
snr = '-'
|
|
parameter_id = None
|
|
|
|
if param:
|
|
parameter_id = param.id
|
|
if hasattr(param, 'id_satellite') and param.id_satellite:
|
|
satellite_name = param.id_satellite.name
|
|
satellite_id = param.id_satellite.id
|
|
frequency = format_frequency(param.frequency)
|
|
freq_range = format_frequency(param.freq_range)
|
|
if hasattr(param, 'polarization') and param.polarization:
|
|
polarization = param.polarization.name
|
|
bod_velocity = format_symbol_rate(param.bod_velocity)
|
|
if hasattr(param, 'modulation') and param.modulation:
|
|
modulation = param.modulation.name
|
|
if hasattr(param, 'standard') and param.standard:
|
|
standard = param.standard.name
|
|
snr = f"{param.snr:.0f}" if param.snr is not None else '-'
|
|
|
|
# Get geo data
|
|
geo_timestamp = '-'
|
|
geo_location = '-'
|
|
geo_coords = '-'
|
|
|
|
if hasattr(objitem, 'geo_obj') and objitem.geo_obj:
|
|
if objitem.geo_obj.timestamp:
|
|
local_time = timezone.localtime(objitem.geo_obj.timestamp)
|
|
geo_timestamp = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
geo_location = objitem.geo_obj.location or '-'
|
|
|
|
if objitem.geo_obj.coords:
|
|
geo_coords = format_coords_display(objitem.geo_obj.coords)
|
|
|
|
# Get created/updated info
|
|
created_at = '-'
|
|
if objitem.created_at:
|
|
local_time = timezone.localtime(objitem.created_at)
|
|
created_at = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
updated_at = '-'
|
|
if objitem.updated_at:
|
|
local_time = timezone.localtime(objitem.updated_at)
|
|
updated_at = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
created_by = str(objitem.created_by) if objitem.created_by else '-'
|
|
updated_by = str(objitem.updated_by) if objitem.updated_by else '-'
|
|
|
|
# Check for LyngSat
|
|
has_lyngsat = hasattr(objitem, 'lyngsat_source') and objitem.lyngsat_source is not None
|
|
lyngsat_id = objitem.lyngsat_source.id if has_lyngsat else None
|
|
|
|
# Check for Transponder
|
|
has_transponder = hasattr(objitem, 'transponder') and objitem.transponder is not None
|
|
transponder_id = objitem.transponder.id if has_transponder else None
|
|
transponder_info = '-'
|
|
if has_transponder:
|
|
try:
|
|
downlink = objitem.transponder.downlink if objitem.transponder.downlink else '-'
|
|
freq_range_t = objitem.transponder.frequency_range if objitem.transponder.frequency_range else '-'
|
|
transponder_info = f"{downlink}:{freq_range_t}"
|
|
except Exception:
|
|
transponder_info = '-'
|
|
|
|
# Check for Sigma
|
|
has_sigma = False
|
|
sigma_info = '-'
|
|
if param and hasattr(param, 'sigma_parameter'):
|
|
sigma_count = param.sigma_parameter.count()
|
|
if sigma_count > 0:
|
|
has_sigma = True
|
|
sigma_info = f"{sigma_count}"
|
|
|
|
# Get comment, is_average, and mirrors from geo_obj
|
|
comment = '-'
|
|
is_average = '-'
|
|
mirrors = '-'
|
|
if hasattr(objitem, 'geo_obj') and objitem.geo_obj:
|
|
comment = objitem.geo_obj.comment or '-'
|
|
is_average = 'Да' if objitem.geo_obj.is_average else 'Нет'
|
|
# Get mirrors list
|
|
mirrors_list = list(objitem.geo_obj.mirrors.values_list('name', flat=True))
|
|
mirrors = ', '.join(mirrors_list) if mirrors_list else '-'
|
|
|
|
objitems_data.append({
|
|
'id': objitem.id,
|
|
'name': objitem.name or '-',
|
|
'satellite_name': satellite_name,
|
|
'satellite_id': satellite_id,
|
|
'frequency': frequency,
|
|
'freq_range': freq_range,
|
|
'polarization': polarization,
|
|
'bod_velocity': bod_velocity,
|
|
'modulation': modulation,
|
|
'standard': standard,
|
|
'snr': snr,
|
|
'geo_timestamp': geo_timestamp,
|
|
'geo_location': geo_location,
|
|
'geo_coords': geo_coords,
|
|
'created_at': created_at,
|
|
'updated_at': updated_at,
|
|
'created_by': created_by,
|
|
'updated_by': updated_by,
|
|
'comment': comment,
|
|
'is_average': is_average,
|
|
'has_lyngsat': has_lyngsat,
|
|
'lyngsat_id': lyngsat_id,
|
|
'has_transponder': has_transponder,
|
|
'transponder_id': transponder_id,
|
|
'transponder_info': transponder_info,
|
|
'has_sigma': has_sigma,
|
|
'sigma_info': sigma_info,
|
|
'parameter_id': parameter_id,
|
|
'mirrors': mirrors,
|
|
})
|
|
|
|
# Get marks for the source
|
|
marks_data = []
|
|
for mark in source.marks.all().order_by('-timestamp'):
|
|
mark_timestamp = '-'
|
|
if mark.timestamp:
|
|
local_time = timezone.localtime(mark.timestamp)
|
|
mark_timestamp = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
marks_data.append({
|
|
'id': mark.id,
|
|
'mark': mark.mark,
|
|
'timestamp': mark_timestamp,
|
|
'created_by': str(mark.created_by) if mark.created_by else '-',
|
|
})
|
|
|
|
return JsonResponse({
|
|
'source_id': source_id,
|
|
'objitems': objitems_data,
|
|
'marks': marks_data
|
|
})
|
|
except Source.DoesNotExist:
|
|
return JsonResponse({'error': 'Источник не найден'}, status=404)
|
|
except Exception as e:
|
|
return JsonResponse({'error': str(e)}, status=500)
|
|
|
|
|
|
class LyngsatTaskStatusAPIView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting Celery task status."""
|
|
|
|
def get(self, request, task_id):
|
|
from celery.result import AsyncResult
|
|
from django.core.cache import cache
|
|
|
|
task = AsyncResult(task_id)
|
|
|
|
response_data = {
|
|
'task_id': task_id,
|
|
'state': task.state,
|
|
'result': None,
|
|
'error': None
|
|
}
|
|
|
|
if task.state == 'PENDING':
|
|
response_data['status'] = 'Задача в очереди...'
|
|
elif task.state == 'PROGRESS':
|
|
response_data['status'] = task.info.get('status', '')
|
|
response_data['current'] = task.info.get('current', 0)
|
|
response_data['total'] = task.info.get('total', 1)
|
|
response_data['percent'] = int((task.info.get('current', 0) / task.info.get('total', 1)) * 100)
|
|
elif task.state == 'SUCCESS':
|
|
# Get result from cache
|
|
result = cache.get(f'lyngsat_task_{task_id}')
|
|
if result:
|
|
response_data['result'] = result
|
|
response_data['status'] = 'Задача завершена успешно'
|
|
else:
|
|
response_data['result'] = task.result
|
|
response_data['status'] = 'Задача завершена'
|
|
elif task.state == 'FAILURE':
|
|
response_data['status'] = 'Ошибка при выполнении задачи'
|
|
response_data['error'] = str(task.info)
|
|
else:
|
|
response_data['status'] = task.state
|
|
|
|
return JsonResponse(response_data)
|
|
|
|
|
|
class TransponderDataAPIView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting Transponder data."""
|
|
|
|
def get(self, request, transponder_id):
|
|
from mapsapp.models import Transponders
|
|
|
|
try:
|
|
transponder = Transponders.objects.select_related(
|
|
'sat_id',
|
|
'polarization',
|
|
'created_by__user'
|
|
).get(id=transponder_id)
|
|
|
|
# Format created_at date
|
|
created_at_str = '-'
|
|
if transponder.created_at:
|
|
local_time = timezone.localtime(transponder.created_at)
|
|
created_at_str = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
# Get created_by username
|
|
created_by_str = '-'
|
|
if transponder.created_by:
|
|
created_by_str = str(transponder.created_by)
|
|
|
|
data = {
|
|
'id': transponder.id,
|
|
'name': transponder.name or '-',
|
|
'satellite': transponder.sat_id.name if transponder.sat_id else '-',
|
|
'downlink': format_frequency(transponder.downlink),
|
|
'uplink': format_frequency(transponder.uplink) if transponder.uplink else None,
|
|
'frequency_range': format_frequency(transponder.frequency_range),
|
|
'polarization': transponder.polarization.name if transponder.polarization else '-',
|
|
'zone_name': transponder.zone_name or '-',
|
|
'transfer': format_frequency(transponder.transfer) if transponder.transfer else None,
|
|
'snr': f"{transponder.snr:.1f}" if transponder.snr is not None else None,
|
|
'created_at': created_at_str,
|
|
'created_by': created_by_str,
|
|
}
|
|
|
|
return JsonResponse(data)
|
|
except Transponders.DoesNotExist:
|
|
return JsonResponse({'error': 'Транспондер не найден'}, status=404)
|
|
except Exception as e:
|
|
return JsonResponse({'error': str(e)}, status=500)
|
|
|
|
|
|
class SatelliteDataAPIView(LoginRequiredMixin, View):
|
|
"""API endpoint for getting Satellite data."""
|
|
|
|
def get(self, request, satellite_id):
|
|
from ..models import Satellite
|
|
|
|
try:
|
|
satellite = Satellite.objects.prefetch_related(
|
|
'band',
|
|
'created_by__user',
|
|
'updated_by__user'
|
|
).get(id=satellite_id)
|
|
|
|
# Format dates
|
|
created_at_str = '-'
|
|
if satellite.created_at:
|
|
local_time = timezone.localtime(satellite.created_at)
|
|
created_at_str = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
updated_at_str = '-'
|
|
if satellite.updated_at:
|
|
local_time = timezone.localtime(satellite.updated_at)
|
|
updated_at_str = local_time.strftime("%d.%m.%Y %H:%M")
|
|
|
|
launch_date_str = '-'
|
|
if satellite.launch_date:
|
|
launch_date_str = satellite.launch_date.strftime("%d.%m.%Y")
|
|
|
|
# Get bands
|
|
bands_list = list(satellite.band.values_list('name', flat=True))
|
|
bands_str = ', '.join(bands_list) if bands_list else '-'
|
|
|
|
data = {
|
|
'id': satellite.id,
|
|
'name': satellite.name,
|
|
'norad': satellite.norad if satellite.norad else '-',
|
|
'undersat_point': f"{satellite.undersat_point}°" if satellite.undersat_point is not None else '-',
|
|
'bands': bands_str,
|
|
'launch_date': launch_date_str,
|
|
'url': satellite.url or None,
|
|
'comment': satellite.comment or '-',
|
|
'created_at': created_at_str,
|
|
'created_by': str(satellite.created_by) if satellite.created_by else '-',
|
|
'updated_at': updated_at_str,
|
|
'updated_by': str(satellite.updated_by) if satellite.updated_by else '-',
|
|
}
|
|
|
|
return JsonResponse(data)
|
|
except Satellite.DoesNotExist:
|
|
return JsonResponse({'error': 'Спутник не найден'}, status=404)
|
|
except Exception as e:
|
|
return JsonResponse({'error': str(e)}, status=500)
|