chore: add new features

This commit is contained in:
2026-03-05 19:09:16 +01:00
parent 532584edb2
commit 5ca480ea0b
23 changed files with 695 additions and 284 deletions
+9 -9
View File
@@ -80,7 +80,7 @@ type ProfileResponse struct {
var (
clientTokenDuration = 5 * time.Hour
adminTokenDuration = 2 * time.Hour
adminTokenDuration = 10 * time.Hour
userJWTSecret = []byte(os.Getenv("USER_JWT_SECRET")) // ✅ Pour clients
adminJWTSecret = []byte(os.Getenv("ADMIN_JWT_SECRET")) // ✅ Pour admin/cabine/livreur
)
@@ -287,7 +287,7 @@ func LoginClient(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
client, err := database.GetClientByUsername(req.Username)
if err != nil {
if err != nil || client == nil {
log.Printf("❌ [LOGIN_CLIENT] Client non trouvé: %s", req.Username)
c.JSON(http.StatusUnauthorized, gin.H{"error": "Identifiants invalides"})
return
@@ -327,13 +327,13 @@ func LoginClient(c *gin.Context) {
TokenType: "Bearer",
ExpiresIn: int(clientTokenDuration.Seconds()),
User: gin.H{
"id": client.ID,
"username": client.Username,
"nom": client.Nom,
"prenom": client.Prenom,
"telephone": client.Telephone,
"role": "client",
"session_id": sessionID,
"id": client.ID,
"username": client.Username,
"nom": client.Nom,
"prenom": client.Prenom,
"telephone": client.Telephone,
"role": "client",
"session_id": sessionID,
"must_change_password": client.MustChangePassword,
},
})
+79 -22
View File
@@ -305,6 +305,51 @@ func ApproveDelivery(c *gin.Context) {
})
}
// ============================================
// CONFIRMATION RÉCEPTION PAR STAFF (ADMIN / CABINE)
// ============================================
func StaffApproveDelivery(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
role := c.GetString("role")
if role != "admin" && role != "cabine" {
c.JSON(http.StatusForbidden, gin.H{"error": "Accès réservé aux admins et à la cabine"})
return
}
staffUsername, err := safeGetUsername(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentification requise"})
return
}
commandID, err := strconv.Atoi(c.Param("id"))
if err != nil || commandID <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID invalide"})
return
}
log.Printf("✅ [STAFF_APPROVE] %s (%s) confirme réception cmd %d", staffUsername, role, commandID)
totalPoints, clientUsername, err := database.ApproveDeliveryAtomicByStaff(commandID, staffUsername)
if err != nil {
log.Printf("❌ [STAFF_APPROVE] Erreur: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "Impossible de confirmer la réception: " + err.Error()})
return
}
log.Printf("✅ [STAFF_APPROVE] %d points attribués au client %s", totalPoints, clientUsername)
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Réception confirmée",
"command_id": commandID,
"client_username": clientUsername,
"points_earned": totalPoints,
})
}
// ============================================
// APPROBATION PAR ADMIN
// ============================================
@@ -464,37 +509,49 @@ func GetAvailableDeliveryPersons(c *gin.Context) {
}
// AssignDeliveryPerson assigne manuellement un livreur à une commande
// POST /api/v1/admin/commands/:id/assign
// Admin: POST /api/v2/admin/protected/delivery-persons/:username/assign/:command_id
// Cabine: POST /api/v1/cabine/commands/:id/assign (body: {"livreur_username": "..."})
func AssignDeliveryPerson(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
// ✅ SÉCURITÉ: Admin seulement
if c.GetString("role") != "admin" {
// ✅ SÉCURITÉ: Admin ou Cabine
role := c.GetString("role")
if role != "admin" && role != "cabine" {
c.JSON(http.StatusForbidden, gin.H{"error": "Accès refusé"})
return
}
commandID, err := strconv.Atoi(c.Param("id"))
if err != nil {
// Support deux formats de route: :command_id (admin) ou :id (cabine)
commandIDStr := c.Param("command_id")
if commandIDStr == "" {
commandIDStr = c.Param("id")
}
commandID, err := strconv.Atoi(commandIDStr)
if err != nil || commandID == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID de commande invalide"})
return
}
var req struct {
LivreurUsername string `json:"livreur_username" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Données invalides",
"details": err.Error(),
})
return
// Livreur depuis URL param (admin) ou body JSON (cabine)
livreurUsername := c.Param("username")
if livreurUsername == "" {
var req struct {
LivreurUsername string `json:"livreur_username" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Données invalides",
"details": err.Error(),
})
return
}
livreurUsername = req.LivreurUsername
}
log.Printf("👤 [ASSIGN] Assignation cmd %d à livreur %s", commandID, req.LivreurUsername)
log.Printf("👤 [ASSIGN] Assignation cmd %d à livreur %s", commandID, livreurUsername)
adminUsername, _ := c.Get("username")
if err := database.AssignDeliveryPerson(commandID, req.LivreurUsername); err != nil {
staffUsername, _ := c.Get("username")
if err := database.AssignDeliveryPerson(commandID, livreurUsername); err != nil {
log.Printf("❌ [ASSIGN] Erreur: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Erreur assignation livreur",
@@ -504,17 +561,17 @@ func AssignDeliveryPerson(c *gin.Context) {
}
database.AddCommandLog(commandID, "support",
fmt.Sprintf("Livreur '%s' assigné manuellement par %s", req.LivreurUsername, adminUsername),
adminUsername.(string))
fmt.Sprintf("Livreur '%s' assigné manuellement par %s", livreurUsername, staffUsername),
staffUsername.(string))
log.Printf("✅ [ASSIGN] Commande %d assignée à %s", commandID, req.LivreurUsername)
log.Printf("✅ [ASSIGN] Commande %d assignée à %s", commandID, livreurUsername)
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Livreur assigné avec succès",
"command_id": commandID,
"livreur": req.LivreurUsername,
"assigned_by": adminUsername,
"livreur": livreurUsername,
"assigned_by": staffUsername,
})
}