package db import ( "encoding/json" "fmt" "gestion/models" "gestion/services" "log" "time" ) // sendTelegramNotif envoie via le bot principal, puis lbtelegram (BOT1/BOT2) en fallback. func sendTelegramNotif(chatID int64, text string) { if err := services.TelegramBot.SendMessage(chatID, text); err != nil { log.Printf("⚠️ [NOTIF] bot principal échoué: %v — fallback lbtelegram", err) if services.LBTelegram != nil && services.LBTelegram.IsConfigured() { if err2 := services.LBTelegram.SendNotification(chatID, text); err2 != nil { log.Printf("⚠️ [NOTIF] lbtelegram aussi échoué: %v", err2) } } } } func (d *Database) NotifyClient(username string, commandID int, notifType, message string) error { notifKey := fmt.Sprintf("notifications:%s", username) notification := map[string]any{ "command_id": commandID, "type": notifType, "message": message, "created_at": time.Now().Format(time.RFC3339), "read": false, } notifJSON, _ := json.Marshal(notification) pipe := Redis.Pipeline() pipe.LPush(RedisCtx, notifKey, notifJSON) pipe.LTrim(RedisCtx, notifKey, 0, 199) pipe.Expire(RedisCtx, notifKey, time.Hour) pipe.Exec(RedisCtx) //nolint if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { if chatID, ok, err := d.GetClientTelegramChatID(username); err == nil && ok { dedupKey := fmt.Sprintf("notif:dedup:%d:%s", commandID, notifType) if set, _ := Redis.SetNX(RedisCtx, dedupKey, "1", 5*time.Minute).Result(); set { go sendTelegramNotif(chatID, fmt.Sprintf("🔔 Notification\n\n%s", message)) } else { log.Printf("⚠️ [NOTIF] Doublon détecté (cmd=%d, type=%s) — Telegram ignoré", commandID, notifType) } } } log.Printf("📬 Notification envoyée à %s: %s", username, message) return nil } func (d *Database) NotifyLivreur(username string, commandID int, notifType, message string) error { notifKey := fmt.Sprintf("notifications:%s", username) notification := map[string]any{ "command_id": commandID, "type": notifType, "message": message, "created_at": time.Now().Format(time.RFC3339), "read": false, } notifJSON, _ := json.Marshal(notification) pipe2 := Redis.Pipeline() pipe2.LPush(RedisCtx, notifKey, notifJSON) pipe2.LTrim(RedisCtx, notifKey, 0, 199) pipe2.Expire(RedisCtx, notifKey, time.Hour) pipe2.Exec(RedisCtx) //nolint if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { if chatID, ok, err := d.GetUserTelegramChatID(username); err == nil && ok { dedupKey := fmt.Sprintf("notif:dedup:livreur:%d:%s", commandID, notifType) if set, _ := Redis.SetNX(RedisCtx, dedupKey, "1", 5*time.Minute).Result(); set { go sendTelegramNotif(chatID, fmt.Sprintf("🔔 Notification\n\n%s", message)) } else { log.Printf("⚠️ [NOTIF] Doublon livreur détecté (cmd=%d, type=%s) — Telegram ignoré", commandID, notifType) } } } log.Printf("📬 [LIVREUR_NOTIF] Notification envoyée à %s: %s", username, message) return nil } func (d *Database) NotifyAllAdminCabine(commandID int, clientUsername, deliveryAddr string) { var users []struct { Username string `gorm:"column:username"` } if err := d.GDB.Model(&models.User{}).Select("username").Where("role IN ?", []string{"admin", "cabine"}).Scan(&users).Error; err != nil { log.Printf("❌ [ADMIN_NOTIF] Erreur lecture users admin/cabine: %v", err) return } msg := fmt.Sprintf("Nouvelle commande #%d de %s — %s", commandID, clientUsername, deliveryAddr) notification := map[string]any{ "command_id": commandID, "type": "new_order", "message": msg, "created_at": time.Now().Format(time.RFC3339), "read": false, } notifJSON, _ := json.Marshal(notification) pipe := Redis.Pipeline() for _, u := range users { notifKey := fmt.Sprintf("notifications:%s", u.Username) pipe.LPush(RedisCtx, notifKey, notifJSON) pipe.LTrim(RedisCtx, notifKey, 0, 199) pipe.Expire(RedisCtx, notifKey, time.Hour) } pipe.Exec(RedisCtx) //nolint count := len(users) if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { for _, u := range users { if chatID, ok, err := d.GetUserTelegramChatID(u.Username); err == nil && ok { capturedChatID := chatID go sendTelegramNotif(capturedChatID, fmt.Sprintf("🔔 Nouvelle commande\n\n%s", msg)) } } } log.Printf("📬 [ADMIN_NOTIF] Notif Redis (%d users) pour commande #%d", count, commandID) } func (d *Database) NotifyAllAdminCabineAlert(alertID int, livreurUsername, alertMessage string) { var users []struct { Username string `gorm:"column:username"` } if err := d.GDB.Model(&models.User{}).Select("username").Where("role IN ?", []string{"admin", "cabine"}).Scan(&users).Error; err != nil { log.Printf("❌ [ALERT_NOTIF] Erreur lecture users admin/cabine: %v", err) return } body := fmt.Sprintf("%s — livreur : %s", alertMessage, livreurUsername) notification := map[string]any{ "alert_id": alertID, "type": "alert", "message": body, "created_at": time.Now().Format(time.RFC3339), "read": false, } notifJSON, _ := json.Marshal(notification) pipe := Redis.Pipeline() for _, u := range users { notifKey := fmt.Sprintf("notifications:%s", u.Username) pipe.LPush(RedisCtx, notifKey, notifJSON) pipe.LTrim(RedisCtx, notifKey, 0, 199) pipe.Expire(RedisCtx, notifKey, time.Hour) } pipe.Exec(RedisCtx) //nolint count := len(users) if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { for _, u := range users { if chatID, ok, err := d.GetUserTelegramChatID(u.Username); err == nil && ok { capturedChatID := chatID go sendTelegramNotif(capturedChatID, fmt.Sprintf("🚨 Alerte livreur\n\n%s", body)) } } } log.Printf("🚨 [ALERT_NOTIF] Notif Redis (%d users) pour alerte #%d de %s", count, alertID, livreurUsername) }