Files
soft_usite/pkg/models/notif_config.go
T
2026-05-21 23:49:37 -05:00

189 lines
7.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package models
import (
"time"
"github.com/sujit-baniya/fiber-boilerplate/app"
"gorm.io/gorm"
)
// ─── NotifEventoConfig ────────────────────────────────────────────────────────
// Define qué canales activar para cada combinación evento × destinatario.
//
// Eventos disponibles (extensibles):
// ticket_nuevo → admin recibe cuando el cliente abre un ticket
// ticket_respuesta_cliente → admin recibe cuando el cliente responde
// ticket_respuesta_admin → portal_user recibe cuando admin responde
// factura_emitida → portal_user recibe cuando se emite factura
// avance_publicado → portal_user recibe cuando se publica avance
//
// Destinatarios: "admin" | "portal_user"
type NotifEventoConfig struct {
gorm.Model
Evento string `json:"evento" gorm:"column:evento;uniqueIndex:uidx_notif_ev_dest"`
Destinatario string `json:"destinatario" gorm:"column:destinatario;uniqueIndex:uidx_notif_ev_dest"`
CanalEmail bool `json:"canal_email" gorm:"column:canal_email;default:true"`
CanalTelegram bool `json:"canal_telegram" gorm:"column:canal_telegram;default:false"`
CanalSistema bool `json:"canal_sistema" gorm:"column:canal_sistema;default:true"`
Descripcion string `json:"descripcion" gorm:"column:descripcion"`
}
func (NotifEventoConfig) TableName() string { return "notif_evento_configs" }
// ─── SistemaNotificacion ──────────────────────────────────────────────────────
// Notificaciones in-app visibles en el badge del header.
// tipo_usuario = "admin" → visible para todos los admins (usuario_id = 0)
// tipo_usuario = "portal_user" → visible solo para ese portal user
type SistemaNotificacion struct {
gorm.Model
TipoUsuario string `json:"tipo_usuario" gorm:"column:tipo_usuario;index"`
UsuarioID uint `json:"usuario_id" gorm:"column:usuario_id;index"`
Titulo string `json:"titulo" gorm:"column:titulo"`
Cuerpo string `json:"cuerpo" gorm:"column:cuerpo;type:text"`
Leida bool `json:"leida" gorm:"column:leida;default:false"`
Url string `json:"url" gorm:"column:url"`
Icono string `json:"icono" gorm:"column:icono"` // emoji: 🎫 🧾 📦
}
func (SistemaNotificacion) TableName() string { return "sistema_notificaciones" }
// ─── CRUD NotifEventoConfig ───────────────────────────────────────────────────
func GetAllNotifConfigs() ([]NotifEventoConfig, error) {
var items []NotifEventoConfig
err := app.Http.Database.DB.Order("evento, destinatario").Find(&items).Error
return items, err
}
func GetNotifConfig(evento, destinatario string) *NotifEventoConfig {
var item NotifEventoConfig
if err := app.Http.Database.DB.
Where("evento = ? AND destinatario = ?", evento, destinatario).
First(&item).Error; err != nil {
return nil
}
return &item
}
// UpsertNotifConfig inserta o actualiza los canales para un evento × destinatario.
func UpsertNotifConfig(cfg *NotifEventoConfig) error {
db := app.Http.Database.DB
result := db.Model(&NotifEventoConfig{}).
Where("evento = ? AND destinatario = ?", cfg.Evento, cfg.Destinatario).
Updates(map[string]interface{}{
"canal_email": cfg.CanalEmail,
"canal_telegram": cfg.CanalTelegram,
"canal_sistema": cfg.CanalSistema,
})
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return db.Create(cfg).Error
}
return nil
}
// ─── CRUD SistemaNotificacion ─────────────────────────────────────────────────
func CreateSistemaNotif(n *SistemaNotificacion) error {
return app.Http.Database.DB.Create(n).Error
}
func GetSistemaNotifs(tipoUsuario string, usuarioID uint, soloNoLeidas bool) ([]SistemaNotificacion, error) {
var items []SistemaNotificacion
db := app.Http.Database.DB.Where("tipo_usuario = ? AND (usuario_id = ? OR usuario_id = 0)", tipoUsuario, usuarioID)
if soloNoLeidas {
db = db.Where("leida = false")
}
err := db.Order("created_at DESC").Limit(50).Find(&items).Error
return items, err
}
func CountUnreadNotifs(tipoUsuario string, usuarioID uint) int64 {
var count int64
app.Http.Database.DB.Model(&SistemaNotificacion{}).
Where("tipo_usuario = ? AND (usuario_id = ? OR usuario_id = 0) AND leida = false", tipoUsuario, usuarioID).
Count(&count)
return count
}
func MarcarNotifLeida(id uint) error {
return app.Http.Database.DB.Model(&SistemaNotificacion{}).
Where("id = ?", id).Update("leida", true).Error
}
func MarcarTodasLeidas(tipoUsuario string, usuarioID uint) error {
return app.Http.Database.DB.Model(&SistemaNotificacion{}).
Where("tipo_usuario = ? AND (usuario_id = ? OR usuario_id = 0)", tipoUsuario, usuarioID).
Update("leida", true).Error
}
func CountUnreadFacturaNotifs(usuarioID uint) int64 {
var count int64
app.Http.Database.DB.Model(&SistemaNotificacion{}).
Where("tipo_usuario = 'portal_user' AND usuario_id = ? AND icono = '🧾' AND leida = false", usuarioID).
Count(&count)
return count
}
func MarcarNotifsFacturasLeidas(usuarioID uint) error {
return app.Http.Database.DB.Model(&SistemaNotificacion{}).
Where("tipo_usuario = 'portal_user' AND usuario_id = ? AND icono = '🧾'", usuarioID).
Update("leida", true).Error
}
// ─── ServidorAlertaUmbral ─────────────────────────────────────────────────────
// Configuración global de umbrales para alertas de servidores.
// Solo existe un registro (singleton, ID = 1).
type ServidorAlertaUmbral struct {
gorm.Model
Activo bool `json:"activo" gorm:"column:activo;default:true"`
MinutosSinPing int `json:"minutos_sin_ping" gorm:"column:minutos_sin_ping;default:10"`
UmbralCPU int `json:"umbral_cpu" gorm:"column:umbral_cpu;default:90"`
UmbralRAM int `json:"umbral_ram" gorm:"column:umbral_ram;default:90"`
UmbralDisco int `json:"umbral_disco" gorm:"column:umbral_disco;default:90"`
DiasAnteVencimiento int `json:"dias_ante_vencimiento" gorm:"column:dias_ante_vencimiento;default:7"`
}
func (ServidorAlertaUmbral) TableName() string { return "servidor_alerta_umbral" }
// GetServidorAlertaUmbral obtiene el singleton de umbrales; crea uno con defaults si no existe.
func GetServidorAlertaUmbral() *ServidorAlertaUmbral {
var cfg ServidorAlertaUmbral
db := app.Http.Database.DB
if err := db.First(&cfg).Error; err != nil {
cfg = ServidorAlertaUmbral{Activo: true, MinutosSinPing: 10, UmbralCPU: 90, UmbralRAM: 90, UmbralDisco: 90, DiasAnteVencimiento: 7}
db.Create(&cfg)
}
return &cfg
}
// SaveServidorAlertaUmbral guarda el singleton.
func SaveServidorAlertaUmbral(cfg *ServidorAlertaUmbral) error {
db := app.Http.Database.DB
var existing ServidorAlertaUmbral
if err := db.First(&existing).Error; err != nil {
return db.Create(cfg).Error
}
return db.Model(&existing).Updates(map[string]interface{}{
"activo": cfg.Activo,
"minutos_sin_ping": cfg.MinutosSinPing,
"umbral_cpu": cfg.UmbralCPU,
"umbral_ram": cfg.UmbralRAM,
"umbral_disco": cfg.UmbralDisco,
"dias_ante_vencimiento": cfg.DiasAnteVencimiento,
}).Error
}
// YaExisteAlertaServidor evita spam: true si ya se creó una notificación con el
// mismo título para este servidor en las últimas `horas` horas.
func YaExisteAlertaServidor(titulo string, horas int) bool {
var count int64
app.Http.Database.DB.Model(&SistemaNotificacion{}).
Where("titulo = ? AND created_at > ?", titulo, time.Now().Add(-time.Duration(horas)*time.Hour)).
Count(&count)
return count > 0
}