feat(settings): align agents teams payloads

This commit is contained in:
2026-06-05 23:42:21 +08:00
parent f8263a3402
commit dc09036676
10 changed files with 340 additions and 162 deletions
+65 -20
View File
@@ -7,6 +7,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/gochat/gochat/internal/service"
applogger "github.com/gochat/gochat/pkg/logger"
@@ -44,7 +45,8 @@ func (h *AgentHandler) List(c *gin.Context) {
return
}
response.OKWithMeta(c, agents, pg.Page, pg.PerPage, total)
_ = total
c.JSON(http.StatusOK, serializeAgentDetails(agents, accountID))
}
// Get returns a single agent by ID.
@@ -69,7 +71,7 @@ func (h *AgentHandler) Get(c *gin.Context) {
return
}
response.OK(c, agent)
c.JSON(http.StatusOK, serializeAgentDetail(agent, accountID))
}
// Create adds an agent to the account.
@@ -88,15 +90,11 @@ func (h *AgentHandler) Create(c *gin.Context) {
return
}
// Chatwoot: params.require(:agent) → request body must be {"agent": {...}}
var wrapper struct {
Agent service.CreateAgentRequest `json:"agent"`
}
if err := c.ShouldBindJSON(&wrapper); err != nil {
var req service.CreateAgentRequest
if err := bindJSONWrappedOrRaw(c, "agent", &req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
return
}
req := wrapper.Agent
// Chatwoot: validate_limit → can_add_agent? — returns 402 if limit exceeded
canAdd, err := h.svc.CanAddAgent(c.Request.Context(), accountID)
@@ -121,7 +119,7 @@ func (h *AgentHandler) Create(c *gin.Context) {
return
}
response.Created(c, agent)
c.JSON(http.StatusOK, serializeAgentDetail(agent, accountID))
}
// Update modifies agent details (name on User, role/availability on AccountUser).
@@ -140,15 +138,11 @@ func (h *AgentHandler) Update(c *gin.Context) {
return
}
// Chatwoot: params.require(:agent) → request body must be {"agent": {...}}
var wrapper struct {
Agent service.UpdateAgentRequest `json:"agent"`
}
if err := c.ShouldBindJSON(&wrapper); err != nil {
var req service.UpdateAgentRequest
if err := bindJSONWrappedOrRaw(c, "agent", &req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
return
}
req := wrapper.Agent
agent, svcErr := h.svc.Update(c.Request.Context(), uint(id), accountID, req)
if svcErr != nil {
@@ -157,7 +151,7 @@ func (h *AgentHandler) Update(c *gin.Context) {
return
}
response.OK(c, agent)
c.JSON(http.StatusOK, serializeAgentDetail(agent, accountID))
}
// Delete removes an agent from the account.
@@ -183,7 +177,7 @@ func (h *AgentHandler) Delete(c *gin.Context) {
return
}
response.OK(c, gin.H{"message": "agent removed"})
c.Status(http.StatusOK)
}
// BulkCreate adds multiple agents to the account by email.
@@ -220,12 +214,63 @@ func (h *AgentHandler) BulkCreate(c *gin.Context) {
return
}
agents, svcErr := h.svc.BulkCreate(c.Request.Context(), accountID, userID, req)
_, svcErr := h.svc.BulkCreate(c.Request.Context(), accountID, userID, req)
if svcErr != nil {
applogger.L().Errorf("BulkCreate agents for account %d: %v", accountID, svcErr)
handleServiceError(c, svcErr)
return
}
response.OK(c, agents)
}
c.Status(http.StatusOK)
}
func serializeAgentDetails(agents []repository.AgentDetail, accountID uint) []map[string]any {
payload := make([]map[string]any, 0, len(agents))
for i := range agents {
payload = append(payload, serializeAgentDetail(&agents[i], accountID))
}
return payload
}
func serializeAgentDetail(agent *repository.AgentDetail, accountID uint) map[string]any {
if agent == nil {
return map[string]any{}
}
payload := serializeAgentUser(&agent.User, accountID, agent.Role, agent.Availability, agent.AutoOffline, agent.CustomRoleID)
if agent.InvitedBy != 0 {
payload["invited_by"] = agent.InvitedBy
}
if agent.AccountUserID != 0 {
payload["account_user_id"] = agent.AccountUserID
}
return payload
}
func serializeAgentUser(user *model.User, accountID uint, role string, availability string, autoOffline bool, customRoleID uint) map[string]any {
if user == nil {
return map[string]any{}
}
availabilityStatus := nonEmpty(availability, availabilityStatus(user.Available))
payload := map[string]any{
"id": user.ID,
"account_id": accountID,
"availability_status": availabilityStatus,
"auto_offline": autoOffline,
"confirmed": user.ConfirmedAt != nil,
"email": user.Email,
"provider": nonEmpty(user.Provider, "email"),
"available_name": nonEmpty(user.DisplayName, user.Name),
"name": user.Name,
"role": nonEmpty(role, user.Role),
"thumbnail": user.AvatarURL,
}
if attrs := jsonObject(user.CustomAttributes); len(attrs) > 0 {
payload["custom_attributes"] = attrs
}
if customRoleID != 0 {
payload["custom_role_id"] = customRoleID
} else if user.CustomRoleID != nil && *user.CustomRoleID != 0 {
payload["custom_role_id"] = *user.CustomRoleID
}
return payload
}