Files
gochat/internal/handler/api/v1/platform_account_user_handler.go
T

152 lines
5.4 KiB
Go

package v1
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/gochat/gochat/pkg/response"
)
// PlatformAccountUserHandler handles Platform API account_user endpoints (AccessToken auth).
// Reference: Chatwoot Platform::Api::V1::AccountUsersController — AccessToken authenticated
//
// Manages the association between users and accounts from the Platform API context.
// Both the account and the user must be within the PlatformApp's permissible scope.
type PlatformAccountUserHandler struct {
accountRepo *repository.AccountRepo
userRepo *repository.UserRepo
permissibleRepo *repository.PermissibleRepo
}
// NewPlatformAccountUserHandler creates a new PlatformAccountUser handler.
func NewPlatformAccountUserHandler(
accountRepo *repository.AccountRepo,
userRepo *repository.UserRepo,
permissibleRepo *repository.PermissibleRepo,
) *PlatformAccountUserHandler {
return &PlatformAccountUserHandler{
accountRepo: accountRepo,
userRepo: userRepo,
permissibleRepo: permissibleRepo,
}
}
// Index lists account_users for a specific account.
// GET /platform/api/v1/accounts/:account_id/account_users
// Reference: Chatwoot Platform::Api::V1::AccountUsersController#index
// Requires: Account must be within PlatformApp's permissible scope.
func (h *PlatformAccountUserHandler) Index(c *gin.Context) {
accountID, err := parseUintAnyParam(c, "account_id", "id")
if err != nil || accountID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account ID")
return
}
platformAppID := getPlatformAppID(c)
// Verify PlatformApp has permissible access to this account
perm, err := h.permissibleRepo.FindByPlatformAppAndResource(c.Request.Context(), platformAppID, model.PermissibleTypeAccount, accountID)
if err != nil || perm == nil {
response.AbortWithStatusError(c, http.StatusForbidden, response.ErrForbidden, "non permissible resource")
return
}
accountUsers, _, err := h.accountRepo.FindAgentsByAccount(c.Request.Context(), accountID, 0, 100)
if err != nil {
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, err.Error())
return
}
c.JSON(http.StatusOK, accountUsers)
}
// Create adds a user to an account.
// POST /platform/api/v1/accounts/:account_id/account_users
// Reference: Chatwoot Platform::Api::V1::AccountUsersController#create
// Requires: Both account and user must be within PlatformApp's permissible scope.
func (h *PlatformAccountUserHandler) Create(c *gin.Context) {
accountID, err := parseUintAnyParam(c, "account_id", "id")
if err != nil || accountID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account ID")
return
}
platformAppID := getPlatformAppID(c)
// Verify PlatformApp has permissible access to this account
perm, err := h.permissibleRepo.FindByPlatformAppAndResource(c.Request.Context(), platformAppID, model.PermissibleTypeAccount, accountID)
if err != nil || perm == nil {
response.AbortWithStatusError(c, http.StatusForbidden, response.ErrForbidden, "non permissible resource")
return
}
var req struct {
UserID uint `json:"user_id" form:"user_id" binding:"required"`
Role *string `json:"role,omitempty" form:"role"`
}
if err := c.ShouldBind(&req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
return
}
acctUser, err := h.accountRepo.UpsertAccountUser(c.Request.Context(), accountID, req.UserID, req.Role)
if err != nil {
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, err.Error())
return
}
c.JSON(http.StatusOK, acctUser)
}
// Destroy removes a user from an account.
// DELETE /platform/api/v1/accounts/:account_id/account_users/:id
// Reference: Chatwoot Platform::Api::V1::AccountUsersController#destroy
// Requires: Account must be within PlatformApp's permissible scope.
func (h *PlatformAccountUserHandler) Destroy(c *gin.Context) {
accountID, err := parseUintAnyParam(c, "account_id", "id")
if err != nil || accountID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account ID")
return
}
userID, err := platformAccountUserID(c)
if err != nil || userID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid user ID")
return
}
platformAppID := getPlatformAppID(c)
// Verify PlatformApp has permissible access to this account
perm, err := h.permissibleRepo.FindByPlatformAppAndResource(c.Request.Context(), platformAppID, model.PermissibleTypeAccount, accountID)
if err != nil || perm == nil {
response.AbortWithStatusError(c, http.StatusForbidden, response.ErrForbidden, "non permissible resource")
return
}
if err := h.accountRepo.RemoveUserFromAccount(c.Request.Context(), accountID, userID); err != nil {
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, err.Error())
return
}
c.Status(http.StatusOK)
}
func platformAccountUserID(c *gin.Context) (uint, error) {
if raw := c.Param("user_id"); raw != "" {
id, err := strconv.ParseUint(raw, 10, 32)
return uint(id), err
}
var req struct {
UserID uint `json:"user_id" form:"user_id"`
}
if err := c.ShouldBind(&req); err != nil {
return 0, err
}
return req.UserID, nil
}