You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
488 lines
17 KiB
PHTML
488 lines
17 KiB
PHTML
|
2 months ago
|
<?php
|
||
|
|
namespace App\Http\Controllers\Administracion;
|
||
|
|
|
||
|
|
use App\Http\Controllers\Controller;
|
||
|
|
use App\Models\Academia;
|
||
|
|
use App\Models\User;
|
||
|
|
use App\Models\Examen;
|
||
|
|
use App\Models\Pregunta;
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Support\Facades\Validator;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
use Illuminate\Support\Str;
|
||
|
|
use Carbon\Carbon;
|
||
|
|
|
||
|
|
class ExamenesController extends Controller
|
||
|
|
{
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Obtener exámenes de la academia
|
||
|
|
*/
|
||
|
|
public function getExamenes(Request $request)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$user = auth()->user();
|
||
|
|
|
||
|
|
if (!$user->hasRole('administrador')) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No autorizado'
|
||
|
|
], 403);
|
||
|
|
}
|
||
|
|
|
||
|
|
$academia = Academia::where('admin_academia_id', $user->id)->first();
|
||
|
|
|
||
|
|
if (!$academia) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Academia no encontrada'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$query = $academia->examenes()
|
||
|
|
->withCount(['preguntas', 'intentos' => function($query) {
|
||
|
|
$query->where('estado', 'finalizado');
|
||
|
|
}])
|
||
|
|
->latest();
|
||
|
|
|
||
|
|
// Filtros
|
||
|
|
if ($request->has('search')) {
|
||
|
|
$search = $request->search;
|
||
|
|
$query->where('titulo', 'like', "%{$search}%");
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($request->has('publicado')) {
|
||
|
|
$query->where('publicado', $request->publicado);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($request->has('tipo')) {
|
||
|
|
$query->where('tipo', $request->tipo);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examenes = $query->paginate(15);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => true,
|
||
|
|
'data' => $examenes
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
Log::error('Error obteniendo exámenes', [
|
||
|
|
'error' => $e->getMessage()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Error al cargar los exámenes'
|
||
|
|
], 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Crear nuevo examen
|
||
|
|
*/
|
||
|
|
public function crearExamen(Request $request)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$user = auth()->user();
|
||
|
|
|
||
|
|
if (!$user->hasRole('administrador')) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No autorizado'
|
||
|
|
], 403);
|
||
|
|
}
|
||
|
|
|
||
|
|
$academia = Academia::where('admin_academia_id', $user->id)->first();
|
||
|
|
|
||
|
|
if (!$academia) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Academia no encontrada'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$validator = Validator::make($request->all(), [
|
||
|
|
'titulo' => 'required|string|max:255',
|
||
|
|
'descripcion' => 'nullable|string',
|
||
|
|
'tipo' => 'required|in:practica,simulacro,evaluacion',
|
||
|
|
'dificultad' => 'required|in:facil,medio,dificil,avanzado',
|
||
|
|
|
||
|
|
'duracion_minutos' => 'required|integer|min:1|max:480',
|
||
|
|
'intentos_permitidos' => 'required|integer|min:1|max:10',
|
||
|
|
'puntaje_minimo' => 'required|numeric|min:0|max:100',
|
||
|
|
'preguntas_aleatorias' => 'boolean',
|
||
|
|
'mostrar_resultados' => 'boolean',
|
||
|
|
'mostrar_respuestas' => 'boolean',
|
||
|
|
'publicado' => 'boolean',
|
||
|
|
'fecha_inicio' => 'nullable|date',
|
||
|
|
'fecha_fin' => 'nullable|date|after_or_equal:fecha_inicio',
|
||
|
|
'configuracion' => 'nullable|array'
|
||
|
|
]);
|
||
|
|
|
||
|
|
if ($validator->fails()) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'errors' => $validator->errors()
|
||
|
|
], 422);
|
||
|
|
}
|
||
|
|
|
||
|
|
DB::beginTransaction();
|
||
|
|
|
||
|
|
$examen = Examen::create([
|
||
|
|
'academia_id' => $academia->id,
|
||
|
|
'titulo' => $request->titulo,
|
||
|
|
'descripcion' => $request->descripcion,
|
||
|
|
'tipo' => $request->tipo,
|
||
|
|
'dificultad' => $request->dificultad,
|
||
|
|
'duracion_minutos' => $request->duracion_minutos,
|
||
|
|
'intentos_permitidos' => $request->intentos_permitidos,
|
||
|
|
'puntaje_minimo' => $request->puntaje_minimo,
|
||
|
|
|
||
|
|
// 👇 OJO AQUÍ
|
||
|
|
'preguntas_aleatorias' => $request->preguntas_aleatorias ?? 0,
|
||
|
|
|
||
|
|
'mezclar_opciones' => $request->mezclar_opciones ?? true,
|
||
|
|
'mostrar_resultados' => $request->mostrar_resultados ?? true,
|
||
|
|
'mostrar_respuestas' => $request->mostrar_respuestas ?? false,
|
||
|
|
'mostrar_explicaciones' => $request->mostrar_explicaciones ?? false,
|
||
|
|
|
||
|
|
'activar_timer' => $request->activar_timer ?? true,
|
||
|
|
'permitir_navegacion' => $request->permitir_navegacion ?? true,
|
||
|
|
'permitir_revisar' => $request->permitir_revisar ?? true,
|
||
|
|
|
||
|
|
'publicado' => $request->publicado ?? false,
|
||
|
|
'fecha_inicio' => $request->fecha_inicio,
|
||
|
|
'fecha_fin' => $request->fecha_fin,
|
||
|
|
'orden' => $request->orden ?? 1,
|
||
|
|
|
||
|
|
'configuracion' => $request->configuracion ?? []
|
||
|
|
]);
|
||
|
|
|
||
|
|
DB::commit();
|
||
|
|
|
||
|
|
Log::info('Examen creado por admin', [
|
||
|
|
'academia_id' => $academia->id,
|
||
|
|
'examen_id' => $examen->id,
|
||
|
|
'admin_id' => $user->id
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => true,
|
||
|
|
'message' => 'Examen creado exitosamente',
|
||
|
|
'data' => $examen
|
||
|
|
], 201);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
DB::rollBack();
|
||
|
|
|
||
|
|
Log::error('Error creando examen', [
|
||
|
|
'error' => $e->getMessage()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Error al crear el examen'
|
||
|
|
], 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Obtener detalles de un examen
|
||
|
|
*/
|
||
|
|
public function getExamen($examenId)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$user = auth()->user();
|
||
|
|
|
||
|
|
if (!$user->hasRole('administrador')) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No autorizado'
|
||
|
|
], 403);
|
||
|
|
}
|
||
|
|
|
||
|
|
$academia = Academia::where('admin_academia_id', $user->id)->first();
|
||
|
|
|
||
|
|
if (!$academia) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Academia no encontrada'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examen = Examen::where('academia_id', $academia->id)
|
||
|
|
->with(['preguntas'])
|
||
|
|
->find($examenId);
|
||
|
|
|
||
|
|
if (!$examen) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Examen no encontrado'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Estadísticas del examen
|
||
|
|
$estadisticas = DB::table('intentos_examen')
|
||
|
|
->where('examen_id', $examenId)
|
||
|
|
->where('estado', 'finalizado')
|
||
|
|
->selectRaw('COUNT(*) as total_intentos')
|
||
|
|
->selectRaw('AVG(porcentaje) as promedio')
|
||
|
|
->selectRaw('SUM(CASE WHEN aprobado = 1 THEN 1 ELSE 0 END) as aprobados')
|
||
|
|
->first();
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => true,
|
||
|
|
'data' => [
|
||
|
|
'examen' => $examen,
|
||
|
|
'estadisticas' => $estadisticas
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
Log::error('Error obteniendo examen', [
|
||
|
|
'error' => $e->getMessage()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Error al cargar el examen'
|
||
|
|
], 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Actualizar examen
|
||
|
|
*/
|
||
|
|
public function actualizarExamen(Request $request, $examenId)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$user = auth()->user();
|
||
|
|
|
||
|
|
if (!$user->hasRole('administrador')) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No autorizado'
|
||
|
|
], 403);
|
||
|
|
}
|
||
|
|
|
||
|
|
$academia = Academia::where('admin_academia_id', $user->id)->first();
|
||
|
|
|
||
|
|
if (!$academia) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Academia no encontrada'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examen = Examen::where('academia_id', $academia->id)->find($examenId);
|
||
|
|
|
||
|
|
if (!$examen) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Examen no encontrado'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$validator = Validator::make($request->all(), [
|
||
|
|
'titulo' => 'sometimes|string|max:255',
|
||
|
|
'descripcion' => 'nullable|string',
|
||
|
|
'tipo' => 'sometimes|in:practica,simulacro,evaluacion',
|
||
|
|
'duracion_minutos' => 'sometimes|integer|min:1|max:480',
|
||
|
|
'intentos_permitidos' => 'sometimes|integer|min:1|max:10',
|
||
|
|
'puntaje_minimo' => 'sometimes|numeric|min:0|max:100',
|
||
|
|
'preguntas_aleatorias' => 'boolean',
|
||
|
|
'mostrar_resultados' => 'boolean',
|
||
|
|
'mostrar_respuestas' => 'boolean',
|
||
|
|
'publicado' => 'boolean',
|
||
|
|
'fecha_inicio' => 'nullable|date',
|
||
|
|
'fecha_fin' => 'nullable|date|after_or_equal:fecha_inicio',
|
||
|
|
'configuracion' => 'nullable|array'
|
||
|
|
]);
|
||
|
|
|
||
|
|
if ($validator->fails()) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'errors' => $validator->errors()
|
||
|
|
], 422);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examen->update($request->only([
|
||
|
|
'titulo', 'descripcion', 'tipo', 'duracion_minutos', 'intentos_permitidos',
|
||
|
|
'puntaje_minimo', 'preguntas_aleatorias', 'mostrar_resultados',
|
||
|
|
'mostrar_respuestas', 'publicado', 'fecha_inicio', 'fecha_fin', 'configuracion'
|
||
|
|
]));
|
||
|
|
|
||
|
|
Log::info('Examen actualizado por admin', [
|
||
|
|
'academia_id' => $academia->id,
|
||
|
|
'examen_id' => $examen->id,
|
||
|
|
'admin_id' => $user->id
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => true,
|
||
|
|
'message' => 'Examen actualizado exitosamente',
|
||
|
|
'data' => $examen
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
Log::error('Error actualizando examen', [
|
||
|
|
'error' => $e->getMessage()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Error al actualizar el examen'
|
||
|
|
], 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Eliminar examen
|
||
|
|
*/
|
||
|
|
public function eliminarExamen($examenId)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$user = auth()->user();
|
||
|
|
|
||
|
|
if (!$user->hasRole('administrador')) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No autorizado'
|
||
|
|
], 403);
|
||
|
|
}
|
||
|
|
|
||
|
|
$academia = Academia::where('admin_academia_id', $user->id)->first();
|
||
|
|
|
||
|
|
if (!$academia) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Academia no encontrada'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examen = Examen::where('academia_id', $academia->id)->find($examenId);
|
||
|
|
|
||
|
|
if (!$examen) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Examen no encontrado'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Verificar si hay intentos realizados
|
||
|
|
$tieneIntentos = $examen->intentos()->exists();
|
||
|
|
|
||
|
|
if ($tieneIntentos) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No se puede eliminar un examen con intentos realizados'
|
||
|
|
], 400);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examen->delete();
|
||
|
|
|
||
|
|
Log::info('Examen eliminado por admin', [
|
||
|
|
'academia_id' => $academia->id,
|
||
|
|
'examen_id' => $examenId,
|
||
|
|
'admin_id' => $user->id
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => true,
|
||
|
|
'message' => 'Examen eliminado exitosamente'
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
Log::error('Error eliminando examen', [
|
||
|
|
'error' => $e->getMessage()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Error al eliminar el examen'
|
||
|
|
], 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Obtener resultados de un examen
|
||
|
|
*/
|
||
|
|
public function getResultadosExamen($examenId)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$user = auth()->user();
|
||
|
|
|
||
|
|
if (!$user->hasRole('administrador')) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'No autorizado'
|
||
|
|
], 403);
|
||
|
|
}
|
||
|
|
|
||
|
|
$academia = Academia::where('admin_academia_id', $user->id)->first();
|
||
|
|
|
||
|
|
if (!$academia) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Academia no encontrada'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$examen = Examen::where('academia_id', $academia->id)->find($examenId);
|
||
|
|
|
||
|
|
if (!$examen) {
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Examen no encontrado'
|
||
|
|
], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
$resultados = DB::table('intentos_examen')
|
||
|
|
->join('users', 'intentos_examen.user_id', '=', 'users.id')
|
||
|
|
->where('intentos_examen.examen_id', $examenId)
|
||
|
|
->where('intentos_examen.estado', 'finalizado')
|
||
|
|
->select(
|
||
|
|
'users.id as estudiante_id',
|
||
|
|
'users.name as estudiante_nombre',
|
||
|
|
'users.email as estudiante_email',
|
||
|
|
'intentos_examen.numero_intento',
|
||
|
|
'intentos_examen.porcentaje',
|
||
|
|
'intentos_examen.aprobado',
|
||
|
|
'intentos_examen.tiempo_utilizado',
|
||
|
|
'intentos_examen.finalizado_en'
|
||
|
|
)
|
||
|
|
->orderBy('intentos_examen.porcentaje', 'desc')
|
||
|
|
->get();
|
||
|
|
|
||
|
|
// Estadísticas generales
|
||
|
|
$estadisticas = [
|
||
|
|
'total_estudiantes' => $resultados->groupBy('estudiante_id')->count(),
|
||
|
|
'promedio' => $resultados->avg('porcentaje'),
|
||
|
|
'aprobados' => $resultados->where('aprobado', true)->count(),
|
||
|
|
'reprobados' => $resultados->where('aprobado', false)->count(),
|
||
|
|
'tiempo_promedio' => $resultados->avg('tiempo_utilizado')
|
||
|
|
];
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => true,
|
||
|
|
'data' => [
|
||
|
|
'resultados' => $resultados,
|
||
|
|
'estadisticas' => $estadisticas
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
Log::error('Error obteniendo resultados', [
|
||
|
|
'error' => $e->getMessage()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'success' => false,
|
||
|
|
'message' => 'Error al cargar los resultados'
|
||
|
|
], 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|