feat: add and delete amende and point by admin

This commit is contained in:
2026-04-22 14:00:43 +02:00
parent 8f617e04d1
commit 7605fce9f4
5 changed files with 323 additions and 2 deletions
+166
View File
@@ -0,0 +1,166 @@
package handlers
import (
"gestion/db"
"gestion/utils"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
// SetClientParrainAdmin — POST /api/v2/admin/protected/client/:username/parrain/set (admin)
// Assigne un parrain à un client. Le parrain reçoit settings.ReferralAmount sur son solde.
func SetClientParrainAdmin(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
targetUsername := c.Param("username")
var req struct {
Parrain string `json:"parrain" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Champ parrain requis"})
return
}
if req.Parrain == targetUsername {
c.JSON(http.StatusBadRequest, gin.H{"error": "Un client ne peut pas être son propre parrain"})
return
}
// Vérifier que le parrain existe
parrain, err := database.GetClientByUsername(req.Parrain)
if err != nil || parrain == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Parrain introuvable"})
return
}
// Vérifier que le client n'a pas déjà un parrain
existing, err := database.GetClientParrain(targetUsername)
if err != nil {
utils.ServerErr(c, "Erreur vérification parrain", err)
return
}
if existing != "" {
c.JSON(http.StatusConflict, gin.H{"error": "Ce client a déjà un parrain", "parrain": existing})
return
}
if err := database.SetClientParrain(targetUsername, req.Parrain); err != nil {
utils.ServerErr(c, "Erreur enregistrement parrain", err)
return
}
settings, _ := database.GetSettings()
if settings.ReferralEnabled && settings.ReferralAmount > 0 {
if err := database.CreditClientReferral(req.Parrain, settings.ReferralAmount); err != nil {
log.Printf("⚠️ [PARRAIN] Impossible de créditer %s: %v", req.Parrain, err)
} else {
log.Printf("✅ [PARRAIN] %s parrainé par %s → +%.2f€ crédité", targetUsername, req.Parrain, settings.ReferralAmount)
}
}
c.JSON(http.StatusOK, gin.H{
"message": "Parrain enregistré",
"client": targetUsername,
"parrain": req.Parrain,
"amount_credited": settings.ReferralAmount,
})
}
// GetMyParrainInfo — GET /api/v1/parrain (client authentifié)
// Retourne le parrain du client + ses filleuls + son solde parrainage.
func GetMyParrainInfo(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
username, exists := c.Get("username")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Utilisateur non authentifié"})
return
}
clientUsername := username.(string)
settings, _ := database.GetSettings()
parrain, err := database.GetClientParrain(clientUsername)
if err != nil {
utils.ServerErr(c, "Erreur récupération parrain", err)
return
}
filleuls, err := database.GetClientsByParrain(clientUsername)
if err != nil {
utils.ServerErr(c, "Erreur récupération filleuls", err)
return
}
balance, err := database.GetClientReferralBalance(clientUsername)
if err != nil {
balance = 0
}
filleulNames := make([]string, 0, len(filleuls))
for _, f := range filleuls {
filleulNames = append(filleulNames, f.Username)
}
c.JSON(http.StatusOK, gin.H{
"parrain": parrain,
"filleuls": filleulNames,
"filleul_count": len(filleulNames),
"referral_balance": balance,
"referral_enabled": settings.ReferralEnabled,
"referral_amount": settings.ReferralAmount,
})
}
// GetClientParrainAdmin — GET /api/v2/admin/protected/client/:username/parrain (admin)
// Retourne les infos parrainage d'un client spécifique.
func GetClientParrainAdmin(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
targetUsername := c.Param("username")
parrain, err := database.GetClientParrain(targetUsername)
if err != nil {
utils.ServerErr(c, "Erreur récupération parrain", err)
return
}
filleuls, err := database.GetClientsByParrain(targetUsername)
if err != nil {
utils.ServerErr(c, "Erreur récupération filleuls", err)
return
}
balance, _ := database.GetClientReferralBalance(targetUsername)
filleulNames := make([]string, 0, len(filleuls))
for _, f := range filleuls {
filleulNames = append(filleulNames, f.Username)
}
c.JSON(http.StatusOK, gin.H{
"username": targetUsername,
"parrain": parrain,
"filleuls": filleulNames,
"filleul_count": len(filleulNames),
"referral_balance": balance,
})
}
// GetParrainStatsAdmin — GET /api/v2/admin/protected/parrain/stats (admin)
// Retourne la liste de tous les parrains avec leur nombre de filleuls et leur solde.
func GetParrainStatsAdmin(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
stats, err := database.GetParrainStats()
if err != nil {
utils.ServerErr(c, "Erreur récupération stats parrainage", err)
return
}
c.JSON(http.StatusOK, gin.H{
"parrains": stats,
"total": len(stats),
})
}
@@ -975,6 +975,86 @@ func ResetClientPenaltiesAdmin(c *gin.Context) {
})
}
// AddClientPointsAdmin ajoute des points à un client dans un pool donné (Admin/Cabine)
// POST /api/v2/admin/protected/client/:username/points/add
// Body: {"pool_key": "pool_0", "points": 10}
func AddClientPointsAdmin(c *gin.Context) {
userRole := c.GetString("role")
if userRole != "admin" && userRole != "cabine" {
c.JSON(http.StatusForbidden, gin.H{"error": "Accès refusé"})
return
}
username := c.Param("username")
if username == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Username requis"})
return
}
var req struct {
PoolKey string `json:"pool_key" binding:"required"`
Points int `json:"points" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Données invalides"})
return
}
if req.Points <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Le nombre de points doit être positif"})
return
}
database := c.MustGet("database").(*db.Database)
// Vérifier que le pool_key existe dans les settings
settings, err := database.GetSettings()
if err != nil {
utils.ServerErr(c, "Erreur récupération paramètres", err)
return
}
poolExists := false
for _, pool := range settings.PointsPools {
if pool.Key == req.PoolKey {
poolExists = true
break
}
}
if !poolExists {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Pool de points invalide",
"pools_valides": func() []string {
keys := make([]string, 0, len(settings.PointsPools))
for _, p := range settings.PointsPools {
keys = append(keys, p.Key)
}
return keys
}(),
})
return
}
if err := database.AddClientPointsByCategory(username, req.Points, req.PoolKey); err != nil {
if strings.Contains(err.Error(), "non trouvé") {
c.JSON(http.StatusNotFound, gin.H{"error": "Client non trouvé"})
} else {
utils.ServerErr(c, "Erreur ajout de points", err)
}
return
}
log.Printf("✅ [ADD_POINTS] %d points (pool=%s) ajoutés à %s par %s",
req.Points, req.PoolKey, username, c.GetString("username"))
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Points ajoutés avec succès",
"username": username,
"pool_key": req.PoolKey,
"points": req.Points,
})
}
// ============================================
// STATISTIQUES TEMPS RÉEL
// ============================================