package leads import ( "html" "net/http" "strings" "github.com/gin-gonic/gin" ) type Handler struct { store Store } func NewHandler(store Store) *Handler { return &Handler{store: store} } // createRequest : entrée publique (formulaire vitrine). Validation stricte. type createRequest struct { Telegram string `json:"telegram" binding:"required,min=2,max=120"` Message string `json:"message" binding:"max=2000"` } // Create enregistre un lead depuis le formulaire public. // Les entrées sont nettoyées (trim + échappement HTML) avant stockage. func (h *Handler) Create(c *gin.Context) { var req createRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "requête invalide"}) return } lead := Lead{ Telegram: sanitize(req.Telegram), } if msg := sanitize(req.Message); msg != "" { lead.Message = &msg } l, err := h.store.Create(lead) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) return } c.JSON(http.StatusCreated, l) } // List renvoie tous les leads (back-office, protégé). func (h *Handler) List(c *gin.Context) { items, err := h.store.List() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) return } c.JSON(http.StatusOK, gin.H{"items": items}) } type statusRequest struct { Status Status `json:"status" binding:"required"` } // SetStatus met à jour le statut d'un lead (back-office, protégé). func (h *Handler) SetStatus(c *gin.Context) { id := c.Param("id") var req statusRequest if err := c.ShouldBindJSON(&req); err != nil || !req.Status.Valid() { c.JSON(http.StatusBadRequest, gin.H{"error": "statut invalide"}) return } l, ok := h.store.SetStatus(id, req.Status) if !ok { c.JSON(http.StatusNotFound, gin.H{"error": "lead introuvable"}) return } c.JSON(http.StatusOK, l) } // sanitize : trim + échappement HTML pour neutraliser le XSS stocké. func sanitize(s string) string { return html.EscapeString(strings.TrimSpace(s)) }