package demos import ( "errors" "net/http" "github.com/gin-gonic/gin" "github.com/omnex/control-plane/api/internal/auth" ) type Handler struct{ svc *Service } func NewHandler(svc *Service) *Handler { return &Handler{svc: svc} } type createRequest struct { LeadID string `json:"lead_id" binding:"omitempty,uuid4"` Username string `json:"username" binding:"omitempty,min=3,max=64,alphanum"` } // Create : POST /demos — provisionne une démo (202 Accepted, worker asynchrone). 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 } d, err := h.svc.Create(req.LeadID, req.Username) if err != nil { if errors.Is(err, ErrCapacityReached) { c.JSON(http.StatusConflict, gin.H{"error": "capacité maximale de démos atteinte"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) return } c.JSON(http.StatusAccepted, d) } // List : GET /demos. func (h *Handler) List(c *gin.Context) { items, err := h.svc.List() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) return } c.JSON(http.StatusOK, gin.H{"items": items}) } // ListMine : GET /demos/mine — démos rattachées au client authentifié. func (h *Handler) ListMine(c *gin.Context) { p := auth.PrincipalFrom(c) if p == nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "non authentifié"}) return } items, err := h.svc.ListForUser(p.Username) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) return } c.JSON(http.StatusOK, gin.H{"items": items}) } // Get : GET /demos/:id. func (h *Handler) Get(c *gin.Context) { d, err := h.svc.Get(c.Param("id")) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "démo introuvable"}) return } c.JSON(http.StatusOK, d) } // Delete : DELETE /demos/:id — teardown + libération du pool. func (h *Handler) Delete(c *gin.Context) { d, err := h.svc.Delete(c.Param("id")) if err != nil { if errors.Is(err, ErrNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "démo introuvable"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) return } c.JSON(http.StatusOK, d) } // Extend : POST /demos/:id/extend — prolonge de 30 jours. func (h *Handler) Extend(c *gin.Context) { d, err := h.svc.Extend(c.Param("id")) if err != nil { switch { case errors.Is(err, ErrNotFound): c.JSON(http.StatusNotFound, gin.H{"error": "démo introuvable"}) case errors.Is(err, ErrNotExtendable): c.JSON(http.StatusConflict, gin.H{"error": "démo non prolongeable"}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) } return } c.JSON(http.StatusOK, d) }