feat(platform): align user payloads
This commit is contained in:
@@ -2,9 +2,11 @@ package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
"github.com/gochat/gochat/internal/service"
|
||||
"github.com/gochat/gochat/pkg/pagination"
|
||||
"github.com/gochat/gochat/pkg/response"
|
||||
@@ -37,13 +39,13 @@ func (h *PlatformUserHandler) Show(c *gin.Context) {
|
||||
|
||||
platformAppID := getPlatformAppID(c)
|
||||
|
||||
user, err := h.svc.GetUser(c.Request.Context(), platformAppID, userID)
|
||||
user, err := h.svc.GetUserResponse(c.Request.Context(), platformAppID, userID)
|
||||
if err != nil {
|
||||
handlePlatformError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, user)
|
||||
c.JSON(http.StatusOK, serializePlatformUser(user))
|
||||
}
|
||||
|
||||
// Create creates a new user and auto-creates Permissible record.
|
||||
@@ -53,27 +55,27 @@ func (h *PlatformUserHandler) Show(c *gin.Context) {
|
||||
func (h *PlatformUserHandler) Create(c *gin.Context) {
|
||||
platformAppID := getPlatformAppID(c)
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
var req service.PlatformUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if req.Email == "" {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "email is required")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.svc.CreateUser(c.Request.Context(), platformAppID, req.Name, req.Email, req.Password)
|
||||
user, err := h.svc.CreateUser(c.Request.Context(), platformAppID, req)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, user)
|
||||
c.JSON(http.StatusOK, serializePlatformUser(user))
|
||||
}
|
||||
|
||||
// Login generates an SSO login link for a user.
|
||||
// POST /platform/api/v1/users/:id/login
|
||||
// GET /platform/api/v1/users/:id/login
|
||||
// Reference: Chatwoot Platform::Api::V1::UsersController#login
|
||||
// Returns: { url: sso_redirect_url }
|
||||
func (h *PlatformUserHandler) Login(c *gin.Context) {
|
||||
@@ -85,18 +87,17 @@ func (h *PlatformUserHandler) Login(c *gin.Context) {
|
||||
|
||||
platformAppID := getPlatformAppID(c)
|
||||
|
||||
// Verify Permissible access first
|
||||
if err := h.svc.ValidatePermissible(c.Request.Context(), platformAppID, userID); err != nil {
|
||||
user, err := h.svc.GetUserResponse(c.Request.Context(), platformAppID, userID)
|
||||
if err != nil {
|
||||
handlePlatformError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// SSO link generation — requires full SSO implementation (HMAC/JWT token, user lookup).
|
||||
// Production note: When SSO middleware is wired, this endpoint will generate
|
||||
// a signed redirect URL based on the user record and SSO configuration.
|
||||
response.OK(c, gin.H{
|
||||
"url": "", // Would be populated with SSO redirect URL
|
||||
"id": userID,
|
||||
query := url.Values{}
|
||||
query.Set("email", user.User.Email)
|
||||
query.Set("sso_auth_token", user.AccessToken)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"url": "/app/login?" + query.Encode(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -119,15 +120,22 @@ func (h *PlatformUserHandler) Token(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.svc.GetUser(c.Request.Context(), platformAppID, userID)
|
||||
user, err := h.svc.TokenResponse(c.Request.Context(), platformAppID, userID)
|
||||
if err != nil {
|
||||
handlePlatformError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, gin.H{
|
||||
"id": user.ID,
|
||||
"sso_auth_token": "", // Would be populated with SSO token
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"access_token": user.AccessToken,
|
||||
"expiry": nil,
|
||||
"user": gin.H{
|
||||
"id": user.User.ID,
|
||||
"name": user.User.Name,
|
||||
"display_name": user.User.DisplayName,
|
||||
"email": user.User.Email,
|
||||
"pubsub_token": user.User.PubsubToken,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -144,22 +152,19 @@ func (h *PlatformUserHandler) Update(c *gin.Context) {
|
||||
|
||||
platformAppID := getPlatformAppID(c)
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
}
|
||||
var req service.PlatformUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.svc.UpdateUser(c.Request.Context(), platformAppID, userID, req.Name, req.Email)
|
||||
user, err := h.svc.UpdateUser(c.Request.Context(), platformAppID, userID, req)
|
||||
if err != nil {
|
||||
handlePlatformError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, user)
|
||||
c.JSON(http.StatusOK, serializePlatformUser(user))
|
||||
}
|
||||
|
||||
// Destroy deletes a user.
|
||||
@@ -180,7 +185,63 @@ func (h *PlatformUserHandler) Destroy(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
response.NoContent(c)
|
||||
c.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
func serializePlatformUser(payload *service.PlatformUserResponse) gin.H {
|
||||
if payload == nil {
|
||||
return gin.H{}
|
||||
}
|
||||
user := payload.User
|
||||
out := gin.H{
|
||||
"access_token": payload.AccessToken,
|
||||
"account_id": activeAccountID(payload.AccountUsers),
|
||||
"available_name": nonEmpty(user.DisplayName, user.Name),
|
||||
"avatar_url": user.AvatarURL,
|
||||
"confirmed": user.ConfirmedAt != nil,
|
||||
"display_name": user.DisplayName,
|
||||
"message_signature": user.MessageSignature,
|
||||
"email": user.Email,
|
||||
"id": user.ID,
|
||||
"name": user.Name,
|
||||
"provider": nonEmpty(user.Provider, "email"),
|
||||
"pubsub_token": user.PubsubToken,
|
||||
"role": activeAccountRole(payload.AccountUsers),
|
||||
"ui_settings": jsonObject(user.UISettings),
|
||||
"uid": user.UID,
|
||||
"accounts": serializePlatformUserAccounts(payload.AccountUsers),
|
||||
}
|
||||
if attrs := jsonObject(user.CustomAttributes); len(attrs) > 0 {
|
||||
out["custom_attributes"] = attrs
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func serializePlatformUserAccounts(accountUsers []model.AccountUser) []gin.H {
|
||||
accounts := make([]gin.H, 0, len(accountUsers))
|
||||
for _, au := range accountUsers {
|
||||
accounts = append(accounts, gin.H{
|
||||
"id": au.AccountID,
|
||||
"name": au.Account.Name,
|
||||
"active_at": au.ActiveAt,
|
||||
"role": au.Role,
|
||||
})
|
||||
}
|
||||
return accounts
|
||||
}
|
||||
|
||||
func activeAccountID(accountUsers []model.AccountUser) any {
|
||||
if len(accountUsers) == 0 {
|
||||
return nil
|
||||
}
|
||||
return accountUsers[0].AccountID
|
||||
}
|
||||
|
||||
func activeAccountRole(accountUsers []model.AccountUser) any {
|
||||
if len(accountUsers) == 0 {
|
||||
return nil
|
||||
}
|
||||
return accountUsers[0].Role
|
||||
}
|
||||
|
||||
// --- Helper functions for Platform API handlers ---
|
||||
@@ -235,4 +296,4 @@ func (h *PlatformUserHandler) List(c *gin.Context) {
|
||||
}
|
||||
|
||||
response.OKWithMeta(c, users[start:end], page.Page, page.PerPage, total)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user