Files
projet_gestion_commande/backend/gestion/db/db_notifications.go
T
2026-03-19 19:56:51 +01:00

232 lines
7.3 KiB
Go

package db
import (
"bytes"
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
)
func (d *Database) NotifyClient(username string, commandID int, notifType, message string) error {
// Sauvegarder la notification dans Redis
notifKey := fmt.Sprintf("notifications:%s", username)
notification := map[string]interface{}{
"command_id": commandID,
"type": notifType,
"message": message,
"created_at": time.Now().Format(time.RFC3339),
"read": false,
}
notifJSON, _ := json.Marshal(notification)
Redis.LPush(RedisCtx, notifKey, notifJSON)
Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour)
// Envoyer push notification si le client a un token enregistré
pushToken, err := d.GetClientPushToken(username)
if err == nil && pushToken != "" {
go sendExpoPush(pushToken, "Uber Stup", message, commandID, notifType)
}
log.Printf("📬 Notification envoyée à %s: %s", username, message)
return nil
}
func sendExpoPush(token, title, body string, commandID int, notifType string) {
sendExpoPushWithChannel(token, title, body, commandID, notifType, "orders")
}
func sendExpoPushWithChannel(token, title, body string, commandID int, notifType, channelID string) {
payload := map[string]interface{}{
"to": token,
"title": title,
"body": body,
"channelId": channelID,
"data": map[string]interface{}{
"command_id": commandID,
"type": notifType,
},
"sound": "default",
}
jsonBody, err := json.Marshal(payload)
if err != nil {
log.Printf("❌ [EXPO_PUSH] Erreur marshal: %v", err)
return
}
req, err := http.NewRequest("POST", "https://exp.host/--/api/v2/push/send", bytes.NewBuffer(jsonBody))
if err != nil {
log.Printf("❌ [EXPO_PUSH] Erreur création requête: %v", err)
return
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.Header.Set("Accept-Encoding", "gzip, deflate")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
log.Printf("❌ [EXPO_PUSH] Erreur envoi: %v", err)
return
}
defer resp.Body.Close()
log.Printf("✅ [EXPO_PUSH] Push envoyé à %s (channel: %s, status: %d)", token, channelID, resp.StatusCode)
}
// ============================================
// PUSH TOKEN - LIVREURS (table users)
// ============================================
// SaveUserPushToken sauvegarde le token push d'un livreur dans la table users
func (d *Database) SaveUserPushToken(username, token string) error {
_, err := d.Exec(`UPDATE users SET push_token = $1 WHERE username = $2`, token, username)
return err
}
// GetUserPushToken récupère le token push d'un livreur depuis la table users
func (d *Database) GetUserPushToken(username string) (string, error) {
var token sql.NullString
err := d.QueryRow(`SELECT push_token FROM users WHERE username = $1`, username).Scan(&token)
if err != nil || !token.Valid {
return "", err
}
return token.String, nil
}
// DeleteUserPushToken supprime le token push d'un livreur
func (d *Database) DeleteUserPushToken(username string) error {
_, err := d.Exec(`UPDATE users SET push_token = NULL WHERE username = $1`, username)
return err
}
// NotifyLivreur envoie une notification in-app (Redis) + push Expo à un livreur
func (d *Database) NotifyLivreur(username string, commandID int, notifType, message string) error {
notifKey := fmt.Sprintf("notifications:%s", username)
notification := map[string]interface{}{
"command_id": commandID,
"type": notifType,
"message": message,
"created_at": time.Now().Format(time.RFC3339),
"read": false,
}
notifJSON, _ := json.Marshal(notification)
Redis.LPush(RedisCtx, notifKey, notifJSON)
Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour)
// Push notification si le livreur a un token enregistré
pushToken, err := d.GetUserPushToken(username)
if err == nil && pushToken != "" {
go sendExpoPushWithChannel(pushToken, "Nouvelle commande assignée", message, commandID, notifType, "deliveries")
}
log.Printf("📬 [LIVREUR_NOTIF] Notification envoyée à %s: %s", username, message)
return nil
}
// NotifyAllAdminCabine stocke une notification Redis pour tous les admins/cabines
// et envoie un push aux ceux qui ont un token. Appelé dès qu'une nouvelle commande est créée.
func (d *Database) NotifyAllAdminCabine(commandID int, clientUsername, deliveryAddr string) {
rows, err := d.Query(
`SELECT username, COALESCE(push_token, '') FROM users WHERE role IN ('admin','cabine')`,
)
if err != nil {
log.Printf("❌ [ADMIN_NOTIF] Erreur lecture users admin/cabine: %v", err)
return
}
defer rows.Close()
msg := fmt.Sprintf("Nouvelle commande #%d de %s — %s", commandID, clientUsername, deliveryAddr)
notification := map[string]interface{}{
"command_id": commandID,
"type": "new_order",
"message": msg,
"created_at": time.Now().Format(time.RFC3339),
"read": false,
}
notifJSON, _ := json.Marshal(notification)
sent := 0
for rows.Next() {
var username, token string
if err := rows.Scan(&username, &token); err != nil {
continue
}
notifKey := fmt.Sprintf("notifications:%s", username)
Redis.LPush(RedisCtx, notifKey, notifJSON)
Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour)
if token != "" {
go sendExpoPushWithChannel(token, "Nouvelle commande", msg, commandID, "new_order", "orders")
sent++
}
}
log.Printf("📬 [ADMIN_NOTIF] Notif Redis + push (%d tokens) pour commande #%d", sent, commandID)
}
// NotifyAllAdminCabineAlert envoie une notification Redis + push à tous les admins/cabines
// lors du déclenchement d'une alerte par un livreur.
func (d *Database) NotifyAllAdminCabineAlert(alertID int, livreurUsername, alertMessage string) {
rows, err := d.Query(
`SELECT username, COALESCE(push_token, '') FROM users WHERE role IN ('admin','cabine')`,
)
if err != nil {
log.Printf("❌ [ALERT_NOTIF] Erreur lecture users admin/cabine: %v", err)
return
}
defer rows.Close()
title := "🚨 Alerte livreur"
body := fmt.Sprintf("%s — livreur : %s", alertMessage, livreurUsername)
notification := map[string]interface{}{
"alert_id": alertID,
"type": "alert",
"message": body,
"created_at": time.Now().Format(time.RFC3339),
"read": false,
}
notifJSON, _ := json.Marshal(notification)
sent := 0
for rows.Next() {
var username, token string
if err := rows.Scan(&username, &token); err != nil {
continue
}
notifKey := fmt.Sprintf("notifications:%s", username)
Redis.LPush(RedisCtx, notifKey, notifJSON)
Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour)
if token != "" {
go sendExpoPushWithChannel(token, title, body, alertID, "alert", "orders")
sent++
}
}
log.Printf("🚨 [ALERT_NOTIF] Notif Redis + push (%d tokens) pour alerte #%d de %s", sent, alertID, livreurUsername)
}
// AddDeliveryRating ajoute une note pour un livreur
func (d *Database) AddDeliveryRating(livreurUsername string, commandID, rating int, comment string) error {
query := `
INSERT INTO delivery_ratings (livreur_username, command_id, rating, comment, created_at)
VALUES (?, ?, ?, ?, NOW())
`
_, err := d.Exec(query, livreurUsername, commandID, rating, comment)
if err != nil {
log.Printf("⚠️ Erreur sauvegarde note livreur: %v", err)
return err
}
log.Printf("⭐ Note %d/5 ajoutée pour livreur %s (commande %d)", rating, livreurUsername, commandID)
return nil
}