140 lines
4.8 KiB
Go
140 lines
4.8 KiB
Go
package v1
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/service"
|
|
"github.com/gochat/gochat/pkg/response"
|
|
)
|
|
|
|
// BulkActionHandler handles generic bulk actions for Conversations and Contacts.
|
|
// Reference: Chatwoot app/controllers/api/v1/accounts/bulk_actions_controller.rb
|
|
type BulkActionHandler struct {
|
|
conversationSvc *service.ConversationService
|
|
contactSvc *service.ContactService
|
|
}
|
|
|
|
// NewBulkActionHandler creates a new BulkActionHandler.
|
|
func NewBulkActionHandler(conversationSvc *service.ConversationService, contactSvc *service.ContactService) *BulkActionHandler {
|
|
return &BulkActionHandler{conversationSvc: conversationSvc, contactSvc: contactSvc}
|
|
}
|
|
|
|
// BulkActionRequest is the DTO for generic bulk actions.
|
|
// Reference: Chatwoot bulk_actions_controller#create — params[:type], params[:action_name], params[:ids]
|
|
type BulkActionRequest struct {
|
|
Type string `json:"type" binding:"required"` // "Conversation" or "Contact"
|
|
ActionName string `json:"action_name" binding:"required"` // "resolve", "open", "snooze", "delete", "label_add", "label_remove"
|
|
IDs []uint `json:"ids" binding:"required,min=1"` // target object IDs
|
|
AssigneeID *uint `json:"assignee_id,omitempty"` // for conversation assign
|
|
TeamID *uint `json:"team_id,omitempty"` // for conversation team assign
|
|
SnoozedUntil string `json:"snoozed_until,omitempty"` // for conversation snooze
|
|
Labels []string `json:"labels,omitempty"` // labels to add/update
|
|
}
|
|
|
|
// Create processes a bulk action request.
|
|
// POST /api/v1/accounts/:account_id/bulk_actions
|
|
// Reference: Chatwoot bulk_actions_controller#create — returns 200 OK on success
|
|
func (h *BulkActionHandler) 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 req BulkActionRequest
|
|
if bindErr := c.ShouldBindJSON(&req); bindErr != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, bindErr.Error())
|
|
return
|
|
}
|
|
|
|
switch req.Type {
|
|
case "Conversation":
|
|
h.handleConversationBulk(c, accountID, req)
|
|
case "Contact":
|
|
h.handleContactBulk(c, accountID, req)
|
|
default:
|
|
c.JSON(http.StatusUnprocessableEntity, gin.H{"success": false})
|
|
}
|
|
}
|
|
|
|
// handleConversationBulk processes bulk actions on conversations.
|
|
func (h *BulkActionHandler) handleConversationBulk(c *gin.Context, accountID uint, req BulkActionRequest) {
|
|
successCount := 0
|
|
failCount := 0
|
|
|
|
for _, convID := range req.IDs {
|
|
var svcErr error
|
|
|
|
switch req.ActionName {
|
|
case "resolve":
|
|
_, svcErr = h.conversationSvc.ToggleStatus(c.Request.Context(), accountID, convID, service.ToggleStatusRequest{Status: string(model.ConversationStatusResolved)})
|
|
case "open":
|
|
_, svcErr = h.conversationSvc.ToggleStatus(c.Request.Context(), accountID, convID, service.ToggleStatusRequest{Status: string(model.ConversationStatusOpen)})
|
|
case "snooze":
|
|
_, svcErr = h.conversationSvc.ToggleStatus(c.Request.Context(), accountID, convID, service.ToggleStatusRequest{Status: string(model.ConversationStatusSnoozed)})
|
|
case "assign":
|
|
if req.AssigneeID != nil {
|
|
_, svcErr = h.conversationSvc.AssignAgent(c.Request.Context(), accountID, convID, *req.AssigneeID)
|
|
}
|
|
case "unassign":
|
|
_, svcErr = h.conversationSvc.UnassignAgent(c.Request.Context(), accountID, convID)
|
|
case "assign_team":
|
|
_, svcErr = h.conversationSvc.AssignTeam(c.Request.Context(), accountID, convID, req.AssigneeID, req.TeamID)
|
|
case "delete":
|
|
svcErr = h.conversationSvc.Delete(c.Request.Context(), accountID, convID)
|
|
case "label_add":
|
|
if len(req.Labels) > 0 {
|
|
_, svcErr = h.conversationSvc.UpdateLabels(c.Request.Context(), accountID, convID, req.Labels)
|
|
}
|
|
default:
|
|
failCount++
|
|
continue
|
|
}
|
|
|
|
if svcErr != nil {
|
|
failCount++
|
|
} else {
|
|
successCount++
|
|
}
|
|
}
|
|
|
|
response.OK(c, gin.H{
|
|
"success_count": successCount,
|
|
"fail_count": failCount,
|
|
})
|
|
}
|
|
|
|
// handleContactBulk processes bulk actions on contacts.
|
|
// Reference: Chatwoot only supports "delete" and label operations for contacts in bulk_actions.
|
|
func (h *BulkActionHandler) handleContactBulk(c *gin.Context, accountID uint, req BulkActionRequest) {
|
|
successCount := 0
|
|
failCount := 0
|
|
|
|
for _, contactID := range req.IDs {
|
|
var svcErr error
|
|
|
|
switch req.ActionName {
|
|
case "delete":
|
|
svcErr = h.contactSvc.Delete(c.Request.Context(), accountID, contactID)
|
|
default:
|
|
// Chatwoot: other contact actions (labels) require separate async jobs
|
|
// For now, return error for unsupported actions
|
|
failCount++
|
|
continue
|
|
}
|
|
|
|
if svcErr != nil {
|
|
failCount++
|
|
} else {
|
|
successCount++
|
|
}
|
|
}
|
|
|
|
response.OK(c, gin.H{
|
|
"success_count": successCount,
|
|
"fail_count": failCount,
|
|
})
|
|
} |