Ahora si :)))))))))))))))))

This commit is contained in:
Laucha1312
2026-06-04 15:10:18 -03:00
parent 47408d49fc
commit 1a8c01ae45
167 changed files with 15870 additions and 0 deletions
+211
View File
@@ -0,0 +1,211 @@
<?php
namespace App\Services;
use App\Models\Notificacion;
use App\Models\PushSubscription;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;
class NotificacionService
{
/**
* Enviar una notificación in-app a un usuario (jugador o aficionado).
*/
public function enviar(
string $tipo_dest,
string|int $id_dest,
string $tipo,
string $titulo,
string $mensaje,
?string $url = null
): Notificacion {
$notif = Notificacion::create([
'tipo_destinatario' => $tipo_dest,
'id_destinatario' => (string) $id_dest,
'tipo' => $tipo,
'titulo' => $titulo,
'mensaje' => $mensaje,
'url_accion' => $url,
'leida' => false,
'enviada_email' => false,
'creada_en' => now(),
]);
// Intentar envío Push
$this->enviarPush([['tipo' => $tipo_dest, 'id' => $id_dest]], $titulo, $mensaje, $url);
return $notif;
}
/**
* Enviar la misma notificación a múltiples destinatarios.
* $destinatarios = [['tipo' => 'jugador', 'id' => 'XXX'], ...]
*/
public function enviarMasivo(array $destinatarios, string $tipo, string $titulo, string $mensaje, ?string $url = null): int
{
$rows = [];
$ahora = now()->toDateTimeString();
foreach ($destinatarios as $dest) {
$rows[] = [
'tipo_destinatario' => $dest['tipo'],
'id_destinatario' => (string) $dest['id'],
'tipo' => $tipo,
'titulo' => $titulo,
'mensaje' => $mensaje,
'url_accion' => $url,
'leida' => false,
'enviada_email' => false,
'creada_en' => $ahora,
];
}
if (empty($rows)) return 0;
// Insert en chunks para no sobrecargar
foreach (array_chunk($rows, 500) as $chunk) {
Notificacion::insert($chunk);
}
// Intentar envío Push masivo
$this->enviarPush($destinatarios, $titulo, $mensaje, $url);
return count($rows);
}
/**
* Lógica centralizada para enviar Web Push Notifications
*/
private function enviarPush(array $destinatarios, string $titulo, string $mensaje, ?string $url = null): void
{
$vPublic = env('VAPID_PUBLIC_KEY');
$vPrivate = env('VAPID_PRIVATE_KEY');
if (!$vPublic || !$vPrivate) return;
// Buscar todas las suscripciones de estos usuarios
$subsFound = PushSubscription::where(function($query) use ($destinatarios) {
foreach ($destinatarios as $d) {
$query->orWhere(function($q) use ($d) {
$q->where('tipo_usuario', $d['tipo'])
->where('id_usuario', (string)$d['id']);
});
}
})->get();
if ($subsFound->isEmpty()) return;
try {
$auth = [
'VAPID' => [
'subject' => env('APP_URL', 'http://localhost'),
'publicKey' => $vPublic,
'privateKey' => $vPrivate,
],
];
$webPush = new WebPush($auth);
$payload = json_encode([
'title' => $titulo,
'body' => $mensaje,
'url' => $url ?: '/',
]);
foreach ($subsFound as $sub) {
$webPush->queueNotification(
Subscription::create([
'endpoint' => $sub->endpoint,
'publicKey' => $sub->p256dh,
'authToken' => $sub->auth,
]),
$payload
);
}
foreach ($webPush->flush() as $report) {
if (!$report->isSuccess()) {
// Si falló (ej: suscripción expirada), la borramos para no reintentar
if ($report->isSubscriptionExpired()) {
$endpoint = $report->getEndpoint();
PushSubscription::where('endpoint', $endpoint)->delete();
}
}
}
} catch (\Exception $e) {
Log::error("Error enviando Web Push: " . $e->getMessage());
}
}
/**
* Obtener notificaciones no leídas de un usuario.
*/
public function obtenerNoLeidas(string $tipo, string|int $id): Collection
{
return Notificacion::paraUsuario($tipo, $id)
->noLeidas()
->orderByDesc('creada_en')
->limit(50)
->get();
}
/**
* Obtener todas las notificaciones de un usuario (paginadas).
*/
public function obtenerTodas(string $tipo, string|int $id, int $perPage = 20)
{
return Notificacion::paraUsuario($tipo, $id)
->orderByDesc('creada_en')
->paginate($perPage);
}
/**
* Contar notificaciones no leídas.
*/
public function contarNoLeidas(string $tipo, string|int $id): int
{
return Notificacion::paraUsuario($tipo, $id)->noLeidas()->count();
}
/**
* Marcar una notificación como leída (verificando pertenencia).
*/
public function marcarLeida(int $id_notif, string $tipo, string|int $id_dest): bool
{
return (bool) Notificacion::paraUsuario($tipo, $id_dest)
->where('id', $id_notif)
->update(['leida' => true]);
}
/**
* Marcar todas como leídas para un usuario.
*/
public function marcarTodasLeidas(string $tipo, string|int $id_dest): int
{
return Notificacion::paraUsuario($tipo, $id_dest)
->noLeidas()
->update(['leida' => true]);
}
/**
* Eliminar una notificación (verificando pertenencia).
*/
public function eliminar(int $id_notif, string $tipo, string|int $id_dest): bool
{
return (bool) Notificacion::paraUsuario($tipo, $id_dest)
->where('id', $id_notif)
->delete();
}
/**
* Eliminar todas las notificaciones de un usuario.
*/
public function eliminarTodas(string $tipo, string|int $id_dest): int
{
return Notificacion::paraUsuario($tipo, $id_dest)->delete();
}
}