276 lines
8.3 KiB
Go
276 lines
8.3 KiB
Go
package v1
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/gochat/gochat/internal/service"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
"github.com/gochat/gochat/pkg/pagination"
|
|
"github.com/gochat/gochat/pkg/response"
|
|
)
|
|
|
|
// TeamHandler handles Team CRUD + members.
|
|
// Reference: Chatwoot app/controllers/api/v1/teams_controller.rb
|
|
type TeamHandler struct {
|
|
svc *service.TeamService
|
|
}
|
|
|
|
// NewTeamHandler creates a new Team handler.
|
|
func NewTeamHandler(svc *service.TeamService) *TeamHandler {
|
|
return &TeamHandler{svc: svc}
|
|
}
|
|
|
|
// List returns all teams for an account.
|
|
// GET /api/v1/accounts/:account_id/teams
|
|
func (h *TeamHandler) List(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
pg := pagination.Parse(c)
|
|
teams, total, err := h.svc.List(c.Request.Context(), accountID, pg.Offset, pg.PerPage)
|
|
if err != nil {
|
|
applogger.L().Errorf("List teams for account %d: %v", accountID, err)
|
|
handleServiceError(c, err)
|
|
return
|
|
}
|
|
|
|
response.OKWithMeta(c, teams, pg.Page, pg.PerPage, total)
|
|
}
|
|
|
|
// Get returns a single team by ID.
|
|
// GET /api/v1/accounts/:account_id/teams/:id
|
|
func (h *TeamHandler) Get(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
|
|
return
|
|
}
|
|
|
|
team, svcErr := h.svc.Get(c.Request.Context(), uint(id), accountID)
|
|
if svcErr != nil {
|
|
applogger.L().Errorf("Get team %d for account %d: %v", id, accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.OK(c, team)
|
|
}
|
|
|
|
// Create creates a new team within an account.
|
|
// POST /api/v1/accounts/:account_id/teams
|
|
func (h *TeamHandler) Create(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
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 {
|
|
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 {
|
|
applogger.L().Errorf("Create team for account %d: %v", accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.Created(c, team)
|
|
}
|
|
|
|
// Update updates an existing team.
|
|
// PUT /api/v1/accounts/:account_id/teams/:id
|
|
func (h *TeamHandler) Update(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
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 {
|
|
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 {
|
|
applogger.L().Errorf("Update team %d for account %d: %v", id, accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.OK(c, team)
|
|
}
|
|
|
|
// Delete soft-deletes a team.
|
|
// DELETE /api/v1/accounts/:account_id/teams/:id
|
|
func (h *TeamHandler) Delete(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
|
|
return
|
|
}
|
|
|
|
if svcErr := h.svc.Delete(c.Request.Context(), uint(id), accountID); svcErr != nil {
|
|
applogger.L().Errorf("Delete team %d for account %d: %v", id, accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.NoContent(c)
|
|
}
|
|
|
|
// AddMembers adds users to a team.
|
|
// POST /api/v1/accounts/:account_id/teams/:id/members
|
|
func (h *TeamHandler) AddMembers(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
|
|
return
|
|
}
|
|
|
|
var req service.TeamMemberRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
members, 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
|
|
}
|
|
|
|
response.OK(c, members)
|
|
}
|
|
|
|
// RemoveMembers removes a user from a team.
|
|
// DELETE /api/v1/accounts/:account_id/teams/:id/members/:user_id
|
|
func (h *TeamHandler) RemoveMembers(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
|
|
return
|
|
}
|
|
|
|
userID, err := strconv.ParseUint(c.Param("user_id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid user ID")
|
|
return
|
|
}
|
|
|
|
if svcErr := h.svc.RemoveMember(c.Request.Context(), uint(id), uint(userID), accountID); svcErr != nil {
|
|
applogger.L().Errorf("Remove member %d from team %d for account %d: %v", userID, id, accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.NoContent(c)
|
|
}
|
|
|
|
// ListMembers retrieves all members of a team.
|
|
// GET /api/v1/accounts/:account_id/teams/:id/members
|
|
func (h *TeamHandler) ListMembers(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
|
|
return
|
|
}
|
|
|
|
members, svcErr := h.svc.ListMembers(c.Request.Context(), uint(id), accountID)
|
|
if svcErr != nil {
|
|
applogger.L().Errorf("List members for team %d for account %d: %v", id, accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.OK(c, members)
|
|
}
|
|
|
|
// UpdateMembers adds/removes members to match the provided user_ids list.
|
|
// PATCH /api/v1/accounts/:account_id/teams/:team_id/team_members
|
|
// Reference: Chatwoot team_members#update — calculates add/remove diffs from user_ids
|
|
func (h *TeamHandler) UpdateMembers(c *gin.Context) {
|
|
accountID := getAccountID(c)
|
|
if accountID == 0 {
|
|
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
|
|
return
|
|
}
|
|
|
|
teamID, err := strconv.ParseUint(c.Param("team_id"), 10, 32)
|
|
if err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid team ID")
|
|
return
|
|
}
|
|
|
|
var req service.TeamMemberRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
|
|
return
|
|
}
|
|
|
|
members, svcErr := h.svc.UpdateMembers(c.Request.Context(), uint(teamID), accountID, req.UserIDs)
|
|
if svcErr != nil {
|
|
applogger.L().Errorf("Update members for team %d for account %d: %v", teamID, accountID, svcErr)
|
|
handleServiceError(c, svcErr)
|
|
return
|
|
}
|
|
|
|
response.OK(c, members)
|
|
}
|