diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 298ef5e..a5e76b0 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -1,49 +1,80 @@ getMessage()); + + // Captura excepciones personalizadas y envíalas a Discord if ($this->shouldReport($exception)) { - try { - $this->notifyDiscord($exception); - } catch (Throwable $e) { - // Evitar que fallos en la notificación rompan el flujo - logger()->error("Error al enviar notificación a Discord: " . $e->getMessage()); - } + DiscordNotifier::notifyException($exception); // Notificar a Discord } - parent::report($exception); + // Captura errores HTTP (como 404, 500, etc.) y envíalos a Discord + if ($exception instanceof HttpException) { + // Aquí puedes poner un log adicional o realizar otra acción si es necesario. + Log::info("Capturado error HTTP: " . $exception->getStatusCode()); + DiscordNotifier::notifyEvent("HTTP Error: " . $exception->getStatusCode(), [ + 'Status Code' => $exception->getStatusCode(), + 'Error Message' => $exception->getMessage(), + 'URL' => request()->url(), + 'Timestamp' => now()->toDateTimeString(), + ]); + } } - protected function notifyDiscord(Throwable $exception) -{ - $details = [ - 'message' => $exception->getMessage(), - 'file' => "{$exception->getFile()}:{$exception->getLine()}", - 'trace' => substr($exception->getTraceAsString(), 0, 1800), - ]; - - // Logea el error antes de enviarlo a Discord - logger()->error('Excepción capturada', $details); - - // Envía la notificación a Discord - DiscordNotifier::notifyEvent( - 'Excepción en el sistema 🚨', - $details, - asset('images/logo.png') - ); -} + /** + * Determine if the exception should be reported. + * + * @param \Throwable $exception + * @return bool + */ + public function shouldReport(Throwable $exception) + { + // Reportar todos los errores HTTP, incluyendo 404 y 500 + if ($exception instanceof HttpException) { + return true; // Se reporta cualquier error HTTP (404, 500, etc.) + } + + // Puedes agregar más excepciones personalizadas aquí si es necesario + return parent::shouldReport($exception); + } + + /** + * Render the exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @param \Throwable $exception + * @return \Illuminate\Http\Response + */ + public function render($request, Throwable $exception) + { + // Renderizar errores HTTP (como 404, 500) de forma personalizada + if ($exception instanceof HttpException) { + return response()->json([ + 'message' => 'Error HTTP detectado.', + 'error' => $exception->getMessage(), + ], $exception->getStatusCode()); + } + + return parent::render($request, $exception); + } } diff --git a/app/Helpers/DiscordNotifier.php b/app/Helpers/DiscordNotifier.php index 5a01cb0..bd4c749 100644 --- a/app/Helpers/DiscordNotifier.php +++ b/app/Helpers/DiscordNotifier.php @@ -3,56 +3,93 @@ namespace App\Helpers; use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Log; +use Throwable; class DiscordNotifier { public static function send($message, $embed = []) { $webhookUrl = env('DISCORD_WEBHOOK_URL'); - + if ($webhookUrl) { $payload = [ 'content' => $message, + 'embeds' => $embed ? [$embed] : [], ]; - - if (!empty($embed)) { - $payload['embeds'] = [$embed]; + + try { + $response = Http::post($webhookUrl, $payload); + + if ($response->successful()) { + Log::info('Notificación enviada a Discord correctamente.'); + } else { + Log::error('Error al enviar notificación a Discord. Código de error: ' . $response->status()); + } + } catch (\Exception $e) { + Log::error('Error al intentar enviar la solicitud a Discord: ' . $e->getMessage()); } - - Http::post($webhookUrl, $payload); + } else { + Log::error('La URL del Webhook de Discord no está configurada.'); } } + + + - public static function notifyException(\Throwable $exception) + public static function notifyException(Throwable $exception) { - $trace = substr($exception->getTraceAsString(), 0, 1800); // Discord tiene límites. - $message = "**🚨 Exception Alert**\n" - . "**Mensaje:** {$exception->getMessage()}\n" - . "**Archivo:** {$exception->getFile()}:{$exception->getLine()}\n" - . "**Trace:** ```{$trace}```"; - - self::send($message); + $webhookUrl = env('DISCORD_WEBHOOK_URL'); + + if ($webhookUrl) { + // Construir el mensaje de la excepción + $message = "**🚨 Excepción Crítica**\n" + . "**Mensaje:** {$exception->getMessage()}\n" + . "**Archivo:** {$exception->getFile()}:{$exception->getLine()}\n" + . "**Trace:** ```" . substr($exception->getTraceAsString(), 0, 1800) . "```"; + + // Crear el embed para Discord + $embed = [ + 'title' => '🚨 Error Crítico del Sistema', + 'description' => $message, + 'color' => 16711680, // Rojo para alertas + 'footer' => [ + 'text' => 'Notificaciones de Excepciones', + 'icon_url' => asset('images/logo.png'), // Asegúrate de que esta URL sea válida + ], + 'timestamp' => now()->toIso8601String(), + ]; + + // Enviar el embed a Discord + self::send('', $embed); + } } - + + + + + public static function notifyEvent($eventType, $details = [], $imageUrl = null) { $webhookUrl = env('DISCORD_WEBHOOK_URL'); - + if ($webhookUrl) { - $logoUrl = $imageUrl ?? asset('logo.png'); // Imagen por defecto + $logoUrl = $imageUrl ?? asset('https://gananza.crudzaso.com/assets/media/auth/agency-dark.png'); // Imagen por defecto $embed = [ - 'title' => '🔔 Notificación del Sistema', - 'description' => "Se ha detectado un evento: **{$eventType}**.", - 'color' => 7506394, // Color (hex: #72A0C1) + 'title' => "🔔 {$eventType}", + 'description' => "Un nuevo evento ha sido detectado: **{$eventType}**.", + 'color' => 7506394, 'fields' => [], 'footer' => [ - 'text' => 'Notificaciones del Sistema', + 'text' => 'Sistema de Notificaciones', 'icon_url' => $logoUrl, ], 'timestamp' => now()->toIso8601String(), + 'thumbnail' => [ + 'url' => $logoUrl, + ], ]; - - // Agregar detalles al mensaje. + foreach ($details as $key => $value) { $embed['fields'][] = [ 'name' => ucfirst($key), @@ -61,7 +98,11 @@ public static function notifyEvent($eventType, $details = [], $imageUrl = null) ]; } + + + // Enviar el mensaje a Discord self::send('', $embed); } } + } diff --git a/app/Http/Middleware/HandleExceptions.php b/app/Http/Middleware/HandleExceptions.php index 70bae6e..5e9a19b 100644 --- a/app/Http/Middleware/HandleExceptions.php +++ b/app/Http/Middleware/HandleExceptions.php @@ -5,6 +5,7 @@ use Closure; use Throwable; use App\Helpers\DiscordNotifier; +use Illuminate\Support\Facades\Log; class HandleExceptions { @@ -14,17 +15,20 @@ public function handle($request, Closure $next) return $next($request); } catch (Throwable $e) { $this->reportToDiscord($e); // Enviar notificación a Discord - throw $e; // Rethrow para permitir que el sistema maneje la excepción + throw $e; // Volver a lanzar la excepción para que el sistema maneje la excepción } } protected function reportToDiscord(Throwable $exception) { + + Log::info('Enviando excepción a Discord: ' . $exception->getMessage()); + $message = "**🚨 Excepción Crítica**\n" . "**Mensaje:** {$exception->getMessage()}\n" . "**Archivo:** {$exception->getFile()}:{$exception->getLine()}\n" . "**Trace:** ```" . substr($exception->getTraceAsString(), 0, 1800) . "```"; - DiscordNotifier::send($message); + DiscordNotifier::send($message); // Enviar a Discord } } diff --git a/app/Listeners/SendLoginNotification.php b/app/Listeners/SendLoginNotification.php index c47e933..310588b 100644 --- a/app/Listeners/SendLoginNotification.php +++ b/app/Listeners/SendLoginNotification.php @@ -4,20 +4,32 @@ use Illuminate\Auth\Events\Login; use App\Helpers\DiscordNotifier; +use Illuminate\Auth\Events\Logout; class SendLoginNotification { /** * Handle the event. * - * @param Login $event + * @param mixed $event * @return void */ - public function handle(Login $event) + public function handle($event) { - DiscordNotifier::notifyEvent('User Logged In', [ - 'user_id' => $event->user->id, - 'email' => $event->user->email, - ]); + if ($event instanceof Login) { + DiscordNotifier::notifyEvent('User Logged In', [ + 'User ID' => $event->user->id, + 'Email' => $event->user->email, + 'Login Time' => now()->toDateTimeString(), + ], 'https://cdn0.iconfinder.com/data/icons/very-basic-android-l-lollipop-icon-pack/24/key-256.png'); + } + + if ($event instanceof Logout) { + DiscordNotifier::notifyEvent('User Logged Out', [ + 'User ID' => $event->user->id, + 'Email' => $event->user->email, + 'Logout Time' => now()->toDateTimeString(), + ], 'https://cdn3.iconfinder.com/data/icons/remixicon-system/24/login-box-line-256.png'); + } } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 5751a31..4a53752 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,9 +2,12 @@ namespace App\Providers; +use App\Listeners\SendHttpErrorNotification; use Illuminate\Auth\Events\Login; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use App\Listeners\SendLoginNotification; +use Illuminate\Auth\Events\Logout; +use Symfony\Component\HttpKernel\Exception\HttpException; class EventServiceProvider extends ServiceProvider { @@ -17,8 +20,12 @@ class EventServiceProvider extends ServiceProvider Login::class => [ SendLoginNotification::class, ], + Logout::class => [ + SendLoginNotification::class, + ], ]; + /** * Register any events for your application. * diff --git a/bootstrap/app.php b/bootstrap/app.php index c10fa31..dc48127 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,8 +1,10 @@ withRouting( @@ -27,5 +29,9 @@ ]); }) ->withExceptions(function (Exceptions $exceptions) { - // - })->create(); + // Captura todas las excepciones reportables y envíalas a Discord + $exceptions->report(function (Throwable $exception) { + Log::info('Excepción reportada: ' . $exception->getMessage()); // Log de depuración + DiscordNotifier::notifyException($exception); // Reportar la excepción a Discord + }); + })->create(); \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 4f96746..9af8533 100644 --- a/routes/web.php +++ b/routes/web.php @@ -97,3 +97,10 @@ Route::post('/verify-payment', [PaymentVerificationController::class, 'verifyPayment']); +Route::get('/test-404', function () { + abort(404); +}); + +Route::get('/test-500', function () { + abort(500); +}); \ No newline at end of file