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
+74 -29
View File
@@ -6,6 +6,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/service"
applogger "github.com/gochat/gochat/pkg/logger"
"github.com/gochat/gochat/pkg/pagination"
@@ -40,7 +41,8 @@ func (h *TeamHandler) List(c *gin.Context) {
return
}
response.OKWithMeta(c, teams, pg.Page, pg.PerPage, total)
_ = total
c.JSON(http.StatusOK, serializeTeams(c, h.svc, teams))
}
// Get returns a single team by ID.
@@ -52,7 +54,7 @@ func (h *TeamHandler) Get(c *gin.Context) {
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
id, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
@@ -65,7 +67,7 @@ func (h *TeamHandler) Get(c *gin.Context) {
return
}
response.OK(c, team)
c.JSON(http.StatusOK, serializeTeamForAccount(c, h.svc, team))
}
// Create creates a new team within an account.
@@ -77,15 +79,11 @@ func (h *TeamHandler) Create(c *gin.Context) {
return
}
// Chatwoot: params.require(:team) → request body must be {"team": {...}}
var wrapper struct {
Team service.CreateTeamRequest `json:"team"`
}
if err := c.ShouldBindJSON(&wrapper); err != nil {
var req service.CreateTeamRequest
if err := bindJSONWrappedOrRaw(c, "team", &req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
return
}
req := wrapper.Team
team, svcErr := h.svc.Create(c.Request.Context(), accountID, req)
if svcErr != nil {
@@ -94,7 +92,7 @@ func (h *TeamHandler) Create(c *gin.Context) {
return
}
response.Created(c, team)
c.JSON(http.StatusOK, serializeTeamForAccount(c, h.svc, team))
}
// Update updates an existing team.
@@ -106,21 +104,17 @@ func (h *TeamHandler) Update(c *gin.Context) {
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
id, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
}
// Chatwoot: params.require(:team) → request body must be {"team": {...}}
var wrapper struct {
Team service.UpdateTeamRequest `json:"team"`
}
if err := c.ShouldBindJSON(&wrapper); err != nil {
var req service.UpdateTeamRequest
if err := bindJSONWrappedOrRaw(c, "team", &req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
return
}
req := wrapper.Team
team, svcErr := h.svc.Update(c.Request.Context(), uint(id), accountID, req)
if svcErr != nil {
@@ -129,7 +123,7 @@ func (h *TeamHandler) Update(c *gin.Context) {
return
}
response.OK(c, team)
c.JSON(http.StatusOK, serializeTeamForAccount(c, h.svc, team))
}
// Delete soft-deletes a team.
@@ -141,7 +135,7 @@ func (h *TeamHandler) Delete(c *gin.Context) {
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
id, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
@@ -153,7 +147,7 @@ func (h *TeamHandler) Delete(c *gin.Context) {
return
}
response.NoContent(c)
c.Status(http.StatusOK)
}
// AddMembers adds users to a team.
@@ -165,7 +159,7 @@ func (h *TeamHandler) AddMembers(c *gin.Context) {
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
id, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
@@ -177,14 +171,19 @@ func (h *TeamHandler) AddMembers(c *gin.Context) {
return
}
members, svcErr := h.svc.AddMembers(c.Request.Context(), uint(id), accountID, req.UserIDs)
_, svcErr := h.svc.AddMembers(c.Request.Context(), uint(id), accountID, req.UserIDs)
if svcErr != nil {
applogger.L().Errorf("Add members to team %d for account %d: %v", id, accountID, svcErr)
handleServiceError(c, svcErr)
return
}
members, svcErr := h.svc.ListMembers(c.Request.Context(), uint(id), accountID)
if svcErr != nil {
handleServiceError(c, svcErr)
return
}
response.OK(c, members)
c.JSON(http.StatusOK, serializeTeamMemberAgents(accountID, members))
}
// RemoveMembers removes a user from a team.
@@ -196,7 +195,7 @@ func (h *TeamHandler) RemoveMembers(c *gin.Context) {
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
id, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
@@ -214,7 +213,7 @@ func (h *TeamHandler) RemoveMembers(c *gin.Context) {
return
}
response.NoContent(c)
c.Status(http.StatusOK)
}
// ListMembers retrieves all members of a team.
@@ -226,7 +225,7 @@ func (h *TeamHandler) ListMembers(c *gin.Context) {
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
id, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
@@ -239,7 +238,7 @@ func (h *TeamHandler) ListMembers(c *gin.Context) {
return
}
response.OK(c, members)
c.JSON(http.StatusOK, serializeTeamMemberAgents(accountID, members))
}
// UpdateMembers adds/removes members to match the provided user_ids list.
@@ -252,7 +251,7 @@ func (h *TeamHandler) UpdateMembers(c *gin.Context) {
return
}
teamID, err := strconv.ParseUint(c.Param("team_id"), 10, 32)
teamID, err := parseTeamIDParam(c)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
return
@@ -271,5 +270,51 @@ func (h *TeamHandler) UpdateMembers(c *gin.Context) {
return
}
response.OK(c, members)
c.JSON(http.StatusOK, serializeTeamMemberAgents(accountID, members))
}
func parseTeamIDParam(c *gin.Context) (uint64, error) {
value := c.Param("team_id")
if value == "" {
value = c.Param("id")
}
return strconv.ParseUint(value, 10, 32)
}
func serializeTeams(c *gin.Context, svc *service.TeamService, teams []model.Team) []map[string]any {
payload := make([]map[string]any, 0, len(teams))
for i := range teams {
payload = append(payload, serializeTeamForAccount(c, svc, &teams[i]))
}
return payload
}
func serializeTeamForAccount(c *gin.Context, svc *service.TeamService, team *model.Team) map[string]any {
if team == nil {
return map[string]any{}
}
payload := map[string]any{
"id": team.ID,
"name": team.Name,
"description": team.Description,
"allow_auto_assign": team.AllowAutoAssignment,
"account_id": team.AccountID,
"is_member": false,
}
userID := getUserID(c)
if userID != 0 && svc != nil && svc.DB() != nil {
var count int64
svc.DB().WithContext(c.Request.Context()).Model(&model.TeamMember{}).Where("team_id = ? AND user_id = ?", team.ID, userID).Count(&count)
payload["is_member"] = count > 0
}
return payload
}
func serializeTeamMemberAgents(accountID uint, members []model.TeamMember) []map[string]any {
payload := make([]map[string]any, 0, len(members))
for i := range members {
member := members[i]
payload = append(payload, serializeAgentUser(&member.User, accountID, "", member.AvailabilityStatus, false, 0))
}
return payload
}