package v1 import ( "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/gochat/gochat/internal/automation" "github.com/gochat/gochat/pkg/response" ) // AutomationRuleHandler handles automation rule API endpoints. // Reference: Chatwoot AutomationRulesController — CRUD + clone type AutomationRuleHandler struct { svc *automation.AutomationRuleService } // NewAutomationRuleHandler creates a new AutomationRuleHandler. func NewAutomationRuleHandler(svc *automation.AutomationRuleService) *AutomationRuleHandler { return &AutomationRuleHandler{svc: svc} } // List retrieves all automation rules for an account. // GET /api/v1/accounts/:account_id/automation_rules func (h *AutomationRuleHandler) List(c *gin.Context) { accountID, err := parseUintParam(c, "account_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } rules, svcErr := h.svc.ListByAccount(c.Request.Context(), accountID) if svcErr != nil { handleServiceError(c, svcErr) return } c.JSON(http.StatusOK, gin.H{ "automation_rules": rules, "meta": gin.H{"count": len(rules)}, }) } // Get retrieves a single automation rule by ID. // GET /api/v1/accounts/:account_id/automation_rules/:id func (h *AutomationRuleHandler) Get(c *gin.Context) { if _, err := parseUintParam(c, "account_id"); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } automationID, err := parseUintParam(c, "automation_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id") return } rule, svcErr := h.svc.GetByID(c.Request.Context(), automationID) if svcErr != nil { handleServiceError(c, svcErr) return } response.OK(c, rule) } // Create creates a new automation rule. // POST /api/v1/accounts/:account_id/automation_rules func (h *AutomationRuleHandler) Create(c *gin.Context) { accountID, err := parseUintParam(c, "account_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } var rule automation.AutomationRule if err := c.ShouldBindJSON(&rule); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error()) return } if rule.Name == "" || rule.EventName == "" { response.AbortWithStatusError(c, http.StatusUnprocessableEntity, response.ErrValidation, "name and event_name are required") return } rule.AccountID = accountID if svcErr := h.svc.Create(c.Request.Context(), &rule); svcErr != nil { handleServiceError(c, svcErr) return } response.Created(c, rule) } // Update updates an existing automation rule. // PUT /api/v1/accounts/:account_id/automation_rules/:id func (h *AutomationRuleHandler) Update(c *gin.Context) { if _, err := parseUintParam(c, "account_id"); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } automationID, err := parseUintParam(c, "automation_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id") return } var rule automation.AutomationRule if err := c.ShouldBindJSON(&rule); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error()) return } if rule.Name == "" || rule.EventName == "" { response.AbortWithStatusError(c, http.StatusUnprocessableEntity, response.ErrValidation, "name and event_name are required") return } rule.ID = automationID if svcErr := h.svc.Update(c.Request.Context(), &rule); svcErr != nil { handleServiceError(c, svcErr) return } response.OK(c, rule) } // Delete soft-deletes an automation rule. // DELETE /api/v1/accounts/:account_id/automation_rules/:id func (h *AutomationRuleHandler) Delete(c *gin.Context) { if _, err := parseUintParam(c, "account_id"); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } automationID, err := parseUintParam(c, "automation_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id") return } if svcErr := h.svc.Delete(c.Request.Context(), automationID); svcErr != nil { handleServiceError(c, svcErr) return } c.JSON(http.StatusOK, gin.H{ "id": strconv.FormatUint(uint64(automationID), 10), "deleted": true, }) } // Clone duplicates an automation rule. // POST /api/v1/accounts/:account_id/automation_rules/:id/clone func (h *AutomationRuleHandler) Clone(c *gin.Context) { if _, err := parseUintParam(c, "account_id"); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } automationID, err := parseUintParam(c, "automation_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id") return } cloned, svcErr := h.svc.Clone(c.Request.Context(), automationID) if svcErr != nil { handleServiceError(c, svcErr) return } response.Created(c, cloned) } // ToggleActive toggles the active state of an automation rule. // POST /api/v1/accounts/:account_id/automation_rules/:id/toggle_active // Reference: Chatwoot does not have a toggle_active endpoint; gochat adds this per M6 requirements. func (h *AutomationRuleHandler) ToggleActive(c *gin.Context) { if _, err := parseUintParam(c, "account_id"); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } automationID, err := parseUintParam(c, "automation_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id") return } var req struct { Active *bool `json:"active"` } if err := c.ShouldBindJSON(&req); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, "active field is required") return } if req.Active == nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, "active field is required") return } if svcErr := h.svc.ToggleActive(c.Request.Context(), automationID, *req.Active); svcErr != nil { handleServiceError(c, svcErr) return } c.JSON(http.StatusOK, gin.H{ "id": strconv.FormatUint(uint64(automationID), 10), "active": *req.Active, }) }