Files
aerbim-ht-monitor/backend/api/account/views/alert_views.py
2025-10-29 11:00:29 +03:00

179 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from rest_framework import status
from rest_framework.viewsets import ViewSet
from rest_framework.permissions import IsAuthenticated
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample, inline_serializer, OpenApiParameter
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response
from django.http import HttpResponse
from django.db.models import Case, When, IntegerField
from api.account.serializers.alert_serializers import AlertSerializer
from sitemanagement.models import Alert
from api.utils.decorators import handle_exceptions
from api.utils.error_serializer import ErrorResponseSerializer
from api.utils.report_generators import generate_csv_report, generate_pdf_report
from django.utils import timezone
@extend_schema(tags=['Алерты'])
class AlertView(ViewSet):
# permission_classes = [IsAuthenticated]
@extend_schema(
summary="Получение списка алертов",
description="Возвращает список алертов в системе с фильтрацией по уровню тревоги. Алерты сортируются: сначала warning, затем critical",
parameters=[
OpenApiParameter(
name='severity',
description='Фильтр по уровню тревоги',
required=False,
type=str,
enum=['warning', 'critical']
)
],
responses={
200: OpenApiResponse(response=AlertSerializer(many=True), description="Список алертов успешно получен",
examples=[OpenApiExample(
'Успешный ответ',
value=[{
"id": 1,
"name": "Датчик 1",
"object": "Объект 1",
"metric_value": "12.5 °C",
"sensor_type_name": "Инклинометр",
"message": "alert message",
"severity": "warning",
"created_at": "2025-10-06T15:53:11.759725+03:00",
"resolved": False
}]
)])
})
@action(detail=False, methods=['get'])
@handle_exceptions
def get_alerts(self, request):
alerts = Alert.objects.all()
# фильтрация по severity
severity = request.query_params.get('severity')
if severity and severity in ['warning', 'critical']:
alerts = alerts.filter(severity=severity)
# сортировка: warning первыми, потом critical
alerts = alerts.annotate(
severity_order=Case(
When(severity='critical', then=1),
When(severity='warning', then=2),
default=3,
output_field=IntegerField()
)
).order_by('severity_order', '-created_at')
serializer = AlertSerializer(alerts, many=True)
return Response(serializer.data)
@extend_schema(
summary="Изменение статуса алерта",
description="Изменяет статус обработки алерта на противоположный",
responses={
200: OpenApiResponse(response=AlertSerializer, description="Статус алерта успешно изменен",
examples=[OpenApiExample(
'Успешный ответ',
value={
"message": "Статус алерта успешно изменен"
}
)]),
404: OpenApiResponse(
response=ErrorResponseSerializer,
description="Алерт не найден",
examples=[
OpenApiExample(
'Алерт не найден',
value={"error": "Алерт не найден"},
status_codes=['404']
)
]
)
})
@action(detail=True, methods=['patch'])
@handle_exceptions
def change_alert_status(self, request, pk=None):
try:
alert = Alert.objects.get(pk=pk)
alert.resolved = not alert.resolved
alert.save()
return Response({"message": "Статус алерта успешно изменен"}, status=status.HTTP_200_OK)
except Alert.DoesNotExist:
return Response(
{"error": "Алерт не найден"},
status=status.HTTP_404_NOT_FOUND)
@extend_schema(tags=['Репорты'])
class ReportView(ViewSet):
permission_classes = [IsAuthenticated]
@extend_schema(
summary="Генерация отчета",
description="Генерирует отчет в выбранном формате (PDF или CSV)",
request={'application/json': {'type': 'object', 'properties': {'report_format': {'type': 'string', 'enum': ['pdf', 'csv']}}}},
methods=['POST'],
responses={
200: OpenApiResponse(
response=inline_serializer(
name='BinaryFile',
fields={
'file': serializers.FileField()
}
),
description="Файл отчета для скачивания в формате PDF или CSV"
),
400: OpenApiResponse(
response=ErrorResponseSerializer,
description="Неверный формат",
examples=[OpenApiExample(
'Неверный формат',
value={"error": "Неверный формат"},
status_codes=['400']
)]
)
})
@action(detail=False, methods=['post'])
@handle_exceptions
def get_reports(self, request):
"""Генерация отчета в выбранном формате"""
report_format = request.data.get('report_format', '').lower()
if not report_format:
report_format = request.query_params.get('format', '').lower()
if report_format not in ["pdf", "csv"]:
return Response(
{"error": "Неверный формат. Допустимые значения: pdf, csv"},
status=status.HTTP_400_BAD_REQUEST
)
alerts = Alert.objects.select_related(
'sensor',
'sensor__signal_format',
'sensor_type',
'metric'
).prefetch_related(
'sensor__zones',
'sensor__zones__object'
).all()
# текущая дата для имени файла
timestamp = timezone.now().strftime("%Y%m%d_%H%M%S")
if report_format == "csv":
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = f'attachment; filename="alerts_report_{timestamp}.csv"'
response.write(generate_csv_report(alerts))
return response
else: # pdf
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="alerts_report_{timestamp}.pdf"'
response.write(generate_pdf_report(alerts))
return response