All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 48s
- Crear composable useNotifications con gestión por localStorage - Almacenamiento separado por usuario usando UID de Authentik - Auto-limpieza de notificaciones mayores a 30 días - Sincronización automática entre pestañas - Filtrado por tipo, búsqueda y gestión completa - Crear wrapper useToast para guardar toasts automáticamente - Intercepta todos los toasts de la aplicación - Guarda historial sin afectar funcionalidad existente - Implementar endpoints de API para notificaciones del backend - POST /api/notifications/send para enviar notificaciones - GET /api/notifications/list para obtener pendientes - Actualizar página de notificaciones con funcionalidad real - Búsqueda y filtros por tipo (info, warning, success, error) - Eliminar individual o todas las notificaciones - Marcar como leídas individual o todas - Badges de origen (toast, backend, manual) - Estados vacíos con mensajes informativos - Actualizar badge del sidebar con contador dinámico - Muestra número real de notificaciones no leídas - Se oculta cuando no hay notificaciones - Inicializar sistema en app.vue - Auto-inicialización al montar la app - Limpieza automática de notificaciones antiguas
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
/**
|
|
* Endpoint para enviar notificaciones a usuarios específicos desde el backend
|
|
*
|
|
* Esta API permite crear notificaciones que se entregarán directamente
|
|
* al cliente para ser guardadas en su localStorage.
|
|
*
|
|
* Casos de uso:
|
|
* - Notificaciones del sistema
|
|
* - Alertas generadas por procesos del backend
|
|
* - Notificaciones administrativas
|
|
*/
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
try {
|
|
// Leer el body de la petición
|
|
const body = await readBody(event)
|
|
|
|
// Validar campos requeridos
|
|
if (!body.targetUserId || !body.title) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Faltan campos requeridos: targetUserId y title'
|
|
})
|
|
}
|
|
|
|
// Validar tipo de notificación
|
|
const validTypes = ['info', 'warning', 'success', 'error']
|
|
const type = body.type || 'info'
|
|
if (!validTypes.includes(type)) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: `Tipo inválido. Debe ser uno de: ${validTypes.join(', ')}`
|
|
})
|
|
}
|
|
|
|
// Leer el usuario actual de los headers de Authentik
|
|
const headers = getHeaders(event)
|
|
const currentUserId = headers['x-authentik-uid']
|
|
const currentUsername = headers['x-authentik-username']
|
|
|
|
// Verificar que el usuario esté autenticado
|
|
if (!currentUserId) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Usuario no autenticado'
|
|
})
|
|
}
|
|
|
|
// Opcional: verificar permisos (por ejemplo, solo admins pueden enviar notificaciones)
|
|
// const groups = headers['x-authentik-groups']?.split('|') || []
|
|
// if (!groups.includes('admins')) {
|
|
// throw createError({
|
|
// statusCode: 403,
|
|
// statusMessage: 'No tienes permisos para enviar notificaciones'
|
|
// })
|
|
// }
|
|
|
|
// Construir la notificación
|
|
const notification = {
|
|
targetUserId: body.targetUserId,
|
|
type: type as 'info' | 'warning' | 'success' | 'error',
|
|
title: body.title,
|
|
message: body.message || '',
|
|
origin: 'backend' as const,
|
|
metadata: {
|
|
sentBy: currentUsername,
|
|
sentAt: new Date().toISOString(),
|
|
...body.metadata
|
|
}
|
|
}
|
|
|
|
// Nota: Como usamos localStorage en el cliente, no guardamos en BD
|
|
// En su lugar, retornamos la notificación para que el cliente la guarde
|
|
// El cliente debe hacer polling o usar SSE/WebSocket para obtener notificaciones
|
|
|
|
return {
|
|
success: true,
|
|
notification,
|
|
message: 'Notificación creada correctamente'
|
|
}
|
|
} catch (error: any) {
|
|
console.error('Error al enviar notificación:', error)
|
|
|
|
// Si ya es un error de H3, relanzarlo
|
|
if (error.statusCode) {
|
|
throw error
|
|
}
|
|
|
|
// Error genérico
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: 'Error al procesar la notificación'
|
|
})
|
|
}
|
|
})
|