Files
pagasis/backend/attendance/views.py
T
Valeria López 9d0d0b6f56 Agrgar SSL
2025-10-21 04:14:58 -06:00

223 lines
8.4 KiB
Python

from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from django_ratelimit.decorators import ratelimit
from authentication.models import UserProfile
from events.models import Event
from .models import Attendance, AttendanceStats
@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
@ratelimit(key='user', rate='60/m', method='POST', block=True)
def register_attendance(request):
"""Registrar asistencia - Solo asistentes: 60 registros por minuto"""
if request.method == 'GET':
return Response({
'message': 'API de registro de asistencia activa',
'methods': ['POST'],
'required_fields': ['event_id', 'account_number']
})
# Verificar que el usuario autenticado sea asistente
try:
registrar_profile = request.user.userprofile
if registrar_profile.user_type != 'assistant':
return Response({
'error': 'Solo los asistentes pueden registrar asistencias'
}, status=status.HTTP_403_FORBIDDEN)
except:
return Response({
'error': 'Usuario sin perfil válido'
}, status=status.HTTP_403_FORBIDDEN)
event_id = request.data.get('event_id')
account_number = request.data.get('account_number')
if not event_id or not account_number:
return Response({
'error': 'Se requiere event_id y account_number'
}, status=status.HTTP_400_BAD_REQUEST)
# Buscar evento
try:
event = Event.objects.get(id=event_id, is_active=True)
except Event.DoesNotExist:
return Response({
'error': 'Evento no encontrado'
}, status=status.HTTP_404_NOT_FOUND)
# Buscar estudiante
try:
student_profile = UserProfile.objects.get(
account_number=account_number,
user_type='student'
)
except UserProfile.DoesNotExist:
return Response({
'error': f'Estudiante con número de cuenta {account_number} no encontrado'
}, status=status.HTTP_404_NOT_FOUND)
# Verificar si ya tiene asistencia
if Attendance.objects.filter(student=student_profile, event=event, is_valid=True).exists():
return Response({
'error': 'El estudiante ya tiene asistencia registrada para este evento'
}, status=status.HTTP_400_BAD_REQUEST)
# Crear asistencia
try:
attendance = Attendance.objects.create(
student=student_profile,
event=event,
registered_by=registrar_profile,
registration_method='manual'
)
return Response({
'message': f'Asistencia registrada para {student_profile.full_name}',
'attendance_id': attendance.id,
'event': event.title,
'registered_by': registrar_profile.full_name
}, status=status.HTTP_201_CREATED)
except Exception as e:
return Response({
'error': f'Error al crear asistencia: {str(e)}'
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
@ratelimit(key='user', rate='30/m', method='GET', block=True)
def get_student_stats(request):
"""Obtener estadísticas de estudiante: 30 consultas por minuto"""
account_number = request.GET.get('account_number')
if not account_number:
return Response({'error': 'Se requiere account_number'}, status=400)
# Verificar permisos: estudiantes solo pueden ver sus propias estadísticas
try:
requester_profile = request.user.userprofile
# Si es estudiante, solo puede consultar sus propias estadísticas
if requester_profile.user_type == 'student':
if requester_profile.account_number != account_number:
return Response({
'error': 'Solo puedes consultar tus propias estadísticas'
}, status=status.HTTP_403_FORBIDDEN)
# Asistentes pueden ver estadísticas de cualquier estudiante
elif requester_profile.user_type != 'assistant':
return Response({
'error': 'No tienes permisos para consultar estadísticas'
}, status=status.HTTP_403_FORBIDDEN)
except:
return Response({
'error': 'Usuario sin perfil válido'
}, status=status.HTTP_403_FORBIDDEN)
try:
student_profile = UserProfile.objects.get(
account_number=account_number,
user_type='student'
)
stats, created = AttendanceStats.objects.get_or_create(
student=student_profile
)
stats.update_stats()
return Response({
'total_events': stats.total_events,
'attended_events': stats.attended_events,
'attendance_percentage': stats.attendance_percentage
})
except UserProfile.DoesNotExist:
return Response({'error': 'Estudiante no encontrado'}, status=404)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
@ratelimit(key='user', rate='60/m', method='GET', block=True)
def get_recent_attendances(request):
"""Obtener asistencias recientes - Solo asistentes: 60 consultas por minuto"""
# Solo asistentes pueden ver asistencias recientes
try:
requester_profile = request.user.userprofile
if requester_profile.user_type != 'assistant':
return Response({
'error': 'Solo los asistentes pueden consultar asistencias recientes'
}, status=status.HTTP_403_FORBIDDEN)
except:
return Response({
'error': 'Usuario sin perfil válido'
}, status=status.HTTP_403_FORBIDDEN)
recent = Attendance.objects.select_related('student', 'event').order_by('-timestamp')[:5]
data = []
for attendance in recent:
data.append({
'attendee_name': attendance.attendee_name,
'event_title': attendance.event.title,
'timestamp': attendance.timestamp.strftime('%H:%M')
})
return Response(data)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
@ratelimit(key='user', rate='60/m', method='GET', block=True)
def get_my_attendances(request):
"""Obtener mis asistencias - Estudiantes pueden ver sus propias asistencias: 60 consultas por minuto"""
account_number = request.GET.get('account_number')
if not account_number:
return Response({'error': 'Se requiere account_number'}, status=400)
# Verificar permisos: estudiantes solo pueden ver sus propias asistencias
try:
requester_profile = request.user.userprofile
# Si es estudiante, solo puede consultar sus propias asistencias
if requester_profile.user_type == 'student':
if requester_profile.account_number != account_number:
return Response({
'error': 'Solo puedes consultar tus propias asistencias'
}, status=status.HTTP_403_FORBIDDEN)
# Asistentes pueden ver asistencias de cualquier estudiante
elif requester_profile.user_type != 'assistant':
return Response({
'error': 'No tienes permisos para consultar asistencias'
}, status=status.HTTP_403_FORBIDDEN)
except:
return Response({
'error': 'Usuario sin perfil válido'
}, status=status.HTTP_403_FORBIDDEN)
try:
student_profile = UserProfile.objects.get(
account_number=account_number,
user_type='student'
)
# Obtener todas las asistencias válidas del estudiante
attendances = Attendance.objects.filter(
student=student_profile,
is_valid=True
).select_related('event').order_by('-timestamp')
data = []
for attendance in attendances:
data.append({
'id': attendance.id,
'event': attendance.event.id,
'event_title': attendance.event.title,
'event_date': attendance.event.date.strftime('%Y-%m-%d'),
'timestamp': attendance.timestamp.strftime('%Y-%m-%d %H:%M:%S')
})
return Response(data)
except UserProfile.DoesNotExist:
return Response({'error': 'Estudiante no encontrado'}, status=404)
# Funciones de usuarios externos eliminadas - Todos los usuarios son ahora estudiantes regulares