package v1 import ( "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/gochat/gochat/internal/service" "github.com/gochat/gochat/pkg/response" ) // AssignableAgentHandler handles endpoints for finding agents assignable to conversations. // Reference: Chatwoot app/controllers/api/v1/accounts/assignable_agents_controller.rb // Two routes: // 1. GET /api/v1/accounts/:account_id/assignable_agents (with inbox_ids[] query param) // 2. GET /api/v1/accounts/:account_id/inboxes/:inbox_id/assignable_agents (single inbox) type AssignableAgentHandler struct { svc *service.AssignableAgentService } // NewAssignableAgentHandler creates a new AssignableAgentHandler. func NewAssignableAgentHandler(svc *service.AssignableAgentService) *AssignableAgentHandler { return &AssignableAgentHandler{svc: svc} } // List returns agents that can be assigned to conversations in the specified inbox(es). // Supports two modes: // 1. Standalone resource: GET /api/v1/accounts/:account_id/assignable_agents?inbox_ids[]=1&inbox_ids[]=2 // (Ref: Chatwoot resources :assignable_agents, only: [:index] — takes inbox_ids[] query param) // 2. Inbox member action: GET /api/v1/accounts/:account_id/inboxes/:inbox_id/assignable_agents // (Ref: Chatwoot get :assignable_agents, on: :member on inboxes) // // 返回带workload信息的agent列表,按workload升序排序(最少conversations优先)。 func (h *AssignableAgentHandler) List(c *gin.Context) { if h.svc == nil { response.AbortWithStatusError(c, http.StatusUnprocessableEntity, response.ErrInternal, "assignable agent service unavailable") return } accountID := getAccountID(c) if accountID == 0 { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } // Determine inbox IDs from either path param or query param inboxIDs := []uint{} // Mode 2: inbox_id from URL path (GET /accounts/:account_id/inboxes/:inbox_id/assignable_agents) if inboxIDStr := c.Param("inbox_id"); inboxIDStr != "" { inboxID, parseErr := strconv.ParseUint(inboxIDStr, 10, 32) if parseErr != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid inbox_id") return } inboxIDs = append(inboxIDs, uint(inboxID)) } // Mode 1 & 2: additional inbox IDs from query param inbox_ids[] if queryInboxIDs, exists := c.GetQueryArray("inbox_ids[]"); exists { for _, qid := range queryInboxIDs { id, parseErr := strconv.ParseUint(qid, 10, 32) if parseErr == nil { // Avoid duplicate if path inbox_id matches query inbox_id isDup := false if len(inboxIDs) > 0 && uint(id) == inboxIDs[0] { isDup = true } if !isDup { inboxIDs = append(inboxIDs, uint(id)) } } } } agents, svcErr := h.svc.GetAssignableAgents(c.Request.Context(), accountID, inboxIDs) if svcErr != nil { response.AbortWithStatusError(c, http.StatusUnprocessableEntity, response.ErrInternal, "failed to list assignable agents") return } response.OK(c, agents) }