second commit
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gochat/gochat/internal/automation"
|
||||
"github.com/gochat/gochat/pkg/response"
|
||||
)
|
||||
|
||||
// MacroHandler handles macro API endpoints.
|
||||
// Reference: Chatwoot MacrosController — CRUD + execute
|
||||
type MacroHandler struct {
|
||||
svc *automation.MacroService
|
||||
}
|
||||
|
||||
// NewMacroHandler creates a new MacroHandler.
|
||||
func NewMacroHandler(svc *automation.MacroService) *MacroHandler {
|
||||
return &MacroHandler{svc: svc}
|
||||
}
|
||||
|
||||
// List retrieves all macros for an account, respecting visibility.
|
||||
// GET /api/v1/accounts/:account_id/macros
|
||||
func (h *MacroHandler) List(c *gin.Context) {
|
||||
accountID, err := parseUintParam(c, "account_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id")
|
||||
return
|
||||
}
|
||||
|
||||
userID := getUserID(c)
|
||||
|
||||
macros, svcErr := h.svc.ListByAccount(c.Request.Context(), accountID, userID)
|
||||
if svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"payload": macros,
|
||||
})
|
||||
}
|
||||
|
||||
// Get retrieves a single macro by ID.
|
||||
// GET /api/v1/accounts/:account_id/macros/:id
|
||||
func (h *MacroHandler) Get(c *gin.Context) {
|
||||
macroID, err := parseUintParam(c, "macro_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
|
||||
macro, svcErr := h.svc.GetByID(c.Request.Context(), macroID)
|
||||
if svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, macro)
|
||||
}
|
||||
|
||||
// Create creates a new macro.
|
||||
// POST /api/v1/accounts/:account_id/macros
|
||||
func (h *MacroHandler) 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 macro automation.Macro
|
||||
if err := c.ShouldBindJSON(¯o); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
macro.AccountID = accountID
|
||||
macro.CreatedByID = getUserID(c)
|
||||
macro.UpdatedByID = getUserID(c)
|
||||
|
||||
// set_visibility: Chatwoot forces visibility=personal if user role is agent
|
||||
// Reference: Chatwoot macro.rb set_visibility — self.visibility = :personal if user.agent?
|
||||
role := getRole(c)
|
||||
if role == "agent" {
|
||||
macro.Visibility = automation.MacroVisibilityPersonal
|
||||
}
|
||||
|
||||
if svcErr := h.svc.Create(c.Request.Context(), ¯o); svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, macro)
|
||||
}
|
||||
|
||||
// Update updates an existing macro.
|
||||
// PUT /api/v1/accounts/:account_id/macros/:id
|
||||
func (h *MacroHandler) Update(c *gin.Context) {
|
||||
macroID, err := parseUintParam(c, "macro_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
|
||||
var macro automation.Macro
|
||||
if err := c.ShouldBindJSON(¯o); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
macro.ID = macroID
|
||||
macro.UpdatedByID = getUserID(c)
|
||||
|
||||
if svcErr := h.svc.Update(c.Request.Context(), ¯o); svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, macro)
|
||||
}
|
||||
|
||||
// Delete soft-deletes a macro.
|
||||
// DELETE /api/v1/accounts/:account_id/macros/:id
|
||||
func (h *MacroHandler) Delete(c *gin.Context) {
|
||||
macroID, err := parseUintParam(c, "macro_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
|
||||
if svcErr := h.svc.Delete(c.Request.Context(), macroID); svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"id": strconv.FormatUint(uint64(macroID), 10),
|
||||
"deleted": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Execute runs a macro on a conversation.
|
||||
// POST /api/v1/accounts/:account_id/macros/:id/execute
|
||||
// Reference: Chatwoot MacrosController#execute — MacroService.Execute returns error only
|
||||
func (h *MacroHandler) Execute(c *gin.Context) {
|
||||
macroID, err := parseUintParam(c, "id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid macro id")
|
||||
return
|
||||
}
|
||||
|
||||
accountID, err := parseUintParam(c, "account_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id")
|
||||
return
|
||||
}
|
||||
|
||||
var body struct {
|
||||
ConversationID uint `json:"conversation_id"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, "conversation_id is required")
|
||||
return
|
||||
}
|
||||
|
||||
userID := getUserID(c)
|
||||
|
||||
if svcErr := h.svc.Execute(c.Request.Context(), accountID, body.ConversationID, macroID, userID); svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"macro_id": strconv.FormatUint(uint64(macroID), 10),
|
||||
"conversation_id": strconv.FormatUint(uint64(body.ConversationID), 10),
|
||||
})
|
||||
}
|
||||
|
||||
// Clone duplicates a macro.
|
||||
// POST /api/v1/accounts/:account_id/macros/:id/clone
|
||||
// Reference: Chatwoot MacrosController does not have clone, but AutomationRulesController does.
|
||||
// gochat adds clone for macros per M6 requirements.
|
||||
func (h *MacroHandler) Clone(c *gin.Context) {
|
||||
accountID, err := parseUintParam(c, "account_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id")
|
||||
return
|
||||
}
|
||||
|
||||
macroID, err := parseUintParam(c, "macro_id")
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
|
||||
_ = accountID // validated but not used — authorization enforced by middleware
|
||||
|
||||
cloned, svcErr := h.svc.Clone(c.Request.Context(), macroID)
|
||||
if svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, cloned)
|
||||
}
|
||||
|
||||
// ToggleActive toggles the active state of a macro.
|
||||
// POST /api/v1/accounts/:account_id/macros/:id/toggle_active
|
||||
// Reference: Chatwoot does not have toggle_active for macros; gochat adds this per M6 requirements.
|
||||
func (h *MacroHandler) ToggleActive(c *gin.Context) {
|
||||
macroID, err := parseUintParam(c, "macro_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 svcErr := h.svc.ToggleActive(c.Request.Context(), macroID, req.Active); svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"id": strconv.FormatUint(uint64(macroID), 10),
|
||||
"active": req.Active,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user