package projects import ( "errors" "net/http" "github.com/gin-gonic/gin" ) type Handler struct{ svc *Service } func NewHandler(svc *Service) *Handler { return &Handler{svc: svc} } type createRequest struct { ClientName string `json:"client_name" binding:"required,min=1,max=64"` // Months : durée souscrite, 1 à 12. Months int `json:"months" binding:"required,min=1,max=12"` AdminUsername string `json:"admin_username" binding:"required,min=3,max=64,alphanum"` AdminPassword string `json:"admin_password" binding:"required,min=12"` // AdminNumber : nombre maximum de comptes admin (ADMIN_NUMBER), 1 par défaut. AdminNumber int `json:"admin_number" binding:"omitempty,min=1,max=20"` } type extendRequest struct { Months int `json:"months" binding:"required,min=1,max=12"` } func (h *Handler) writeError(c *gin.Context, err error) { switch { case errors.Is(err, ErrNotFound): c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) case errors.Is(err, ErrNotExtendable): c.JSON(http.StatusConflict, gin.H{"error": err.Error()}) case errors.Is(err, ErrInvalidMonths), errors.Is(err, ErrInvalidClient), errors.Is(err, ErrInvalidAdmin), errors.Is(err, ErrWeakAdminPass), errors.Is(err, ErrInvalidAdminSize): c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur serveur"}) } } // Create : POST /projects — déploie un projet pour la durée souscrite // (202 Accepted, déploiement 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 } p, err := h.svc.Create(CreateInput{ ClientName: req.ClientName, Months: req.Months, AdminUsername: req.AdminUsername, AdminPassword: req.AdminPassword, AdminNumber: req.AdminNumber, }) if err != nil { h.writeError(c, err) return } c.JSON(http.StatusAccepted, p) } // List : GET /projects. func (h *Handler) List(c *gin.Context) { items, err := h.svc.List() if err != nil { h.writeError(c, err) return } c.JSON(http.StatusOK, gin.H{"items": items}) } // Get : GET /projects/:id. func (h *Handler) Get(c *gin.Context) { p, err := h.svc.Get(c.Param("id")) if err != nil { h.writeError(c, err) return } c.JSON(http.StatusOK, p) } // Extend : POST /projects/:id/extend {"months": 1..12} — renouvelle // l'abonnement (relance un projet suspendu). func (h *Handler) Extend(c *gin.Context) { var req extendRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": ErrInvalidMonths.Error()}) return } p, err := h.svc.Extend(c.Param("id"), req.Months) if err != nil { h.writeError(c, err) return } c.JSON(http.StatusOK, p) } // Delete : DELETE /projects/:id — suppression immédiate (namespace, données, // sauvegardes). func (h *Handler) Delete(c *gin.Context) { p, err := h.svc.Delete(c.Param("id")) if err != nil { h.writeError(c, err) return } c.JSON(http.StatusOK, p) }