refactor: rename ExternalInfo to ExternalUser and update related functions for consistency

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
mlogclub
2026-04-28 11:10:47 +08:00
parent 0ad2ef83df
commit cf63b75590
15 changed files with 81 additions and 111 deletions
+4 -4
View File
@@ -28,9 +28,9 @@ func NewServer() (*iris.Application, error) {
app := iris.New() app := iris.New()
corsHandler := cors.New(). corsHandler := cors.New().
AllowOrigin("*"). AllowOrigin("*").
AllowHeaders("Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With", "X-Guest-Id", "X-Channel-Id", "X-External-Source", "X-External-Id", "X-External-Name"). AllowHeaders("Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With", "X-Guest-Id", "X-Channel-Id", "X-External-Id", "X-External-Name").
MaxAge(600). MaxAge(600).
ExposeHeaders("Content-Length", "Content-Type", "Authorization", "X-Guest-Id", "X-Channel-Id", "X-External-Source", "X-External-Id", "X-External-Name"). ExposeHeaders("Content-Length", "Content-Type", "Authorization", "X-Guest-Id", "X-Channel-Id", "X-External-Id", "X-External-Name").
Handler() Handler()
app.UseRouter(func(ctx iris.Context) { app.UseRouter(func(ctx iris.Context) {
// WebSocket upgrade is validated by the upgrader's origin policy. // WebSocket upgrade is validated by the upgrader's origin policy.
@@ -95,8 +95,8 @@ func addRouter(app *iris.Application) {
mvc.Configure(app.Party("/api"), func(m *mvc.Application) { mvc.Configure(app.Party("/api"), func(m *mvc.Application) {
m.Party("/auth").Handle(new(api.AuthController)) m.Party("/auth").Handle(new(api.AuthController))
m.Party("/channel").Handle(new(api.ChannelController)) m.Party("/channel").Handle(new(api.ChannelController))
m.Party("/conversation", middleware.ExternalInfoMiddleware).Handle(new(api.ConversationController)) m.Party("/conversation", middleware.ExternalUserMiddleware).Handle(new(api.ConversationController))
m.Party("/message", middleware.ExternalInfoMiddleware).Handle(new(api.MessageController)) m.Party("/message", middleware.ExternalUserMiddleware).Handle(new(api.MessageController))
}) })
mvc.Configure(app.Party("/api/ws"), func(m *mvc.Application) { mvc.Configure(app.Party("/api/ws"), func(m *mvc.Application) {
@@ -20,7 +20,7 @@ func (c *ConversationController) GetBy(id int64) *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -45,7 +45,7 @@ func (c *ConversationController) PostCreate_or_match() *web.JsonResult {
if channel == nil { if channel == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -61,7 +61,7 @@ func (c *ConversationController) PostClose() *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -23,7 +23,7 @@ func (c *MessageController) AnyList() *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -57,7 +57,7 @@ func (c *MessageController) PostSend() *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -78,7 +78,7 @@ func (c *MessageController) PostRead() *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -97,7 +97,7 @@ func (c *MessageController) PostUpload_image() *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
@@ -142,7 +142,7 @@ func (c *MessageController) PostUpload_attachment() *web.JsonResult {
if services.ChannelService.GetEnabledChannel(c.Ctx) == nil { if services.ChannelService.GetEnabledChannel(c.Ctx) == nil {
return web.JsonErrorMsg("接入渠道未初始化") return web.JsonErrorMsg("接入渠道未初始化")
} }
external := irisx.GetExternalInfo(c.Ctx) external := irisx.GetExternalUser(c.Ctx)
if external == nil { if external == nil {
return web.JsonErrorMsg("外部身份未初始化") return web.JsonErrorMsg("外部身份未初始化")
} }
+3 -3
View File
@@ -9,7 +9,7 @@ import (
"github.com/mlogclub/simple/web" "github.com/mlogclub/simple/web"
) )
func ExternalInfoMiddleware(ctx iris.Context) { func ExternalUserMiddleware(ctx iris.Context) {
channel := services.ChannelService.GetEnabledChannel(ctx) channel := services.ChannelService.GetEnabledChannel(ctx)
if channel == nil { if channel == nil {
ctx.StopExecution() ctx.StopExecution()
@@ -17,12 +17,12 @@ func ExternalInfoMiddleware(ctx iris.Context) {
return return
} }
secret := services.ChannelService.GetUserTokenSecret(channel) secret := services.ChannelService.GetUserTokenSecret(channel)
ext, err := openidentity.GetExternalInfo(ctx, secret) ext, err := openidentity.GetExternalUser(ctx, secret)
if err != nil { if err != nil {
ctx.StopExecution() ctx.StopExecution()
_ = ctx.JSON(web.JsonError(err)) _ = ctx.JSON(web.JsonError(err))
return return
} }
irisx.SetExternalInfo(ctx, ext) irisx.SetExternalUser(ctx, ext)
ctx.Next() ctx.Next()
} }
-10
View File
@@ -23,13 +23,3 @@ func GetExternalSourceLabel(v ExternalSource) string {
} }
return string(v) return string(v)
} }
// IsAllowedOpenImExternalSource 开放 IM 入口允许的外部来源(闭集校验)。
func IsAllowedOpenImExternalSource(s ExternalSource) bool {
switch s {
case ExternalSourceGuest, ExternalSourceUser:
return true
default:
return false
}
}
+6 -6
View File
@@ -9,16 +9,16 @@ import (
) )
const ( const (
ctxKeyExternalInfo = "externalInfo" ctxKeyExternalUser = "externalUser"
) )
func SetExternalInfo(ctx iris.Context, ext *openidentity.ExternalInfo) { func SetExternalUser(ctx iris.Context, ext *openidentity.ExternalUser) {
ctx.Values().Set(ctxKeyExternalInfo, ext) ctx.Values().Set(ctxKeyExternalUser, ext)
} }
func GetExternalInfo(ctx iris.Context) *openidentity.ExternalInfo { func GetExternalUser(ctx iris.Context) *openidentity.ExternalUser {
v := ctx.Values().Get(ctxKeyExternalInfo) v := ctx.Values().Get(ctxKeyExternalUser)
ext, _ := v.(*openidentity.ExternalInfo) ext, _ := v.(*openidentity.ExternalUser)
return ext return ext
} }
+20 -40
View File
@@ -1,4 +1,3 @@
// Package openidentity 解析开放 IM 场景下的外部访客身份(HTTP Header / Query),与 JSON 请求体 DTO 解耦。
package openidentity package openidentity
import ( import (
@@ -14,8 +13,8 @@ import (
"github.com/mlogclub/simple/web/params" "github.com/mlogclub/simple/web/params"
) )
// ExternalInfo 外部访客身份(IM 客户),与站内 AuthPrincipal 区分。 // ExternalUser 外部访客身份(IM 客户),与站内 AuthPrincipal 区分。
type ExternalInfo struct { type ExternalUser struct {
ExternalSource enums.ExternalSource `json:"externalSource"` ExternalSource enums.ExternalSource `json:"externalSource"`
ExternalID string `json:"externalId"` ExternalID string `json:"externalId"`
ExternalName string `json:"externalName"` ExternalName string `json:"externalName"`
@@ -27,37 +26,19 @@ type UserTokenClaims struct {
jwt.RegisteredClaims jwt.RegisteredClaims
} }
func GetExternalInfo(ctx iris.Context, secret string) (*ExternalInfo, error) { func GetExternalUser(ctx iris.Context, secret string) (*ExternalUser, error) {
if userToken := getUserToken(ctx); strs.IsNotBlank(userToken) { if userToken := getUserToken(ctx); strs.IsNotBlank(userToken) {
claims, err := verifyUserToken(userToken, secret) claims, err := verifyUserToken(userToken, secret)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ExternalInfo{ return &ExternalUser{
ExternalSource: enums.ExternalSourceUser, ExternalSource: enums.ExternalSourceUser,
ExternalID: claims.UserID, ExternalID: claims.UserID,
ExternalName: claims.Name, ExternalName: claims.Name,
}, nil }, nil
} }
externalSource, err := getExternalSource(ctx) return getGuestUser(ctx)
if err != nil {
return nil, err
}
if !enums.IsAllowedOpenImExternalSource(externalSource) {
return nil, errorsx.InvalidParam("不支持的外部来源")
}
if externalSource == enums.ExternalSourceUser {
return nil, errorsx.Unauthorized("用户身份不能为空")
}
externalID, err := getExternalID(ctx)
if err != nil {
return nil, err
}
return &ExternalInfo{
ExternalSource: externalSource,
ExternalID: externalID,
ExternalName: getExternalName(ctx),
}, nil
} }
func verifyUserToken(userToken, secret string) (*UserTokenClaims, error) { func verifyUserToken(userToken, secret string) (*UserTokenClaims, error) {
@@ -113,26 +94,24 @@ func getUserToken(ctx iris.Context) string {
return strings.TrimSpace(userToken) return strings.TrimSpace(userToken)
} }
func getExternalSource(ctx iris.Context) (enums.ExternalSource, error) { func getGuestUser(ctx iris.Context) (*ExternalUser, error) {
externalSource := ctx.GetHeader("X-External-Source") externalID := getExternalID(ctx)
if strs.IsBlank(externalSource) { if strs.IsBlank(externalID) {
externalSource, _ = params.Get(ctx, "externalSource") return nil, errorsx.Unauthorized("用户标识不能为空")
} }
if strs.IsBlank(externalSource) { return &ExternalUser{
return "", errorsx.Unauthorized("用户来源不能为空") ExternalSource: enums.ExternalSourceGuest,
} ExternalID: externalID,
return enums.ExternalSource(strings.TrimSpace(externalSource)), nil ExternalName: getExternalName(ctx),
}, nil
} }
func getExternalID(ctx iris.Context) (string, error) { func getExternalID(ctx iris.Context) string {
externalID := ctx.GetHeader("X-External-Id") externalID := ctx.GetHeader("X-External-Id")
if strs.IsBlank(externalID) { if strs.IsBlank(externalID) {
externalID, _ = params.Get(ctx, "externalId") externalID, _ = params.Get(ctx, "externalId")
} }
if strs.IsBlank(externalID) { return externalID
return "", errorsx.Unauthorized("用户标识不能为空")
}
return strings.TrimSpace(externalID), nil
} }
func getExternalName(ctx iris.Context) string { func getExternalName(ctx iris.Context) string {
@@ -140,11 +119,12 @@ func getExternalName(ctx iris.Context) string {
if strs.IsBlank(externalName) { if strs.IsBlank(externalName) {
externalName, _ = params.Get(ctx, "externalName") externalName, _ = params.Get(ctx, "externalName")
} }
return decodeExternalDisplayName(externalName) if strs.IsNotBlank(externalName) {
externalName, _ = url.QueryUnescape(externalName)
}
return externalName
} }
// decodeExternalDisplayName 将客户端对 X-External-Name / externalName 做的 encodeURIComponent 还原为 UTF-8。
// 无百分号编码时 QueryUnescape 原样返回,解码失败则保留原串(兼容异常或旧客户端明文)。
func decodeExternalDisplayName(s string) string { func decodeExternalDisplayName(s string) string {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if s == "" { if s == "" {
@@ -69,12 +69,12 @@ func (s *conversationParticipantService) Delete(id int64) {
repositories.ConversationParticipantRepository.Delete(sqls.DB(), id) repositories.ConversationParticipantRepository.Delete(sqls.DB(), id)
} }
func (s *conversationParticipantService) CreateCustomerParticipant(ctx *sqls.TxContext, conversationID int64, externalInfo openidentity.ExternalInfo) error { func (s *conversationParticipantService) CreateCustomerParticipant(ctx *sqls.TxContext, conversationID int64, externalUser openidentity.ExternalUser) error {
return repositories.ConversationParticipantRepository.Create(ctx.Tx, &models.ConversationParticipant{ return repositories.ConversationParticipantRepository.Create(ctx.Tx, &models.ConversationParticipant{
ConversationID: conversationID, ConversationID: conversationID,
ParticipantType: string(enums.IMParticipantTypeCustomer), ParticipantType: string(enums.IMParticipantTypeCustomer),
ParticipantID: 0, ParticipantID: 0,
ExternalParticipantID: externalInfo.ExternalID, ExternalParticipantID: externalUser.ExternalID,
JoinedAt: new(time.Now()), JoinedAt: new(time.Now()),
Status: enums.StatusOk, Status: enums.StatusOk,
AuditFields: utils.BuildAuditFields(nil), AuditFields: utils.BuildAuditFields(nil),
@@ -47,7 +47,7 @@ func agentReaderCursor(operator *dto.AuthPrincipal) (readerCursor, error) {
}, nil }, nil
} }
func customerReaderCursor(external *openidentity.ExternalInfo) (readerCursor, error) { func customerReaderCursor(external *openidentity.ExternalUser) (readerCursor, error) {
if external == nil || strings.TrimSpace(external.ExternalID) == "" { if external == nil || strings.TrimSpace(external.ExternalID) == "" {
return readerCursor{}, errorsx.Unauthorized("外部用户标识不能为空") return readerCursor{}, errorsx.Unauthorized("外部用户标识不能为空")
} }
@@ -126,7 +126,7 @@ func (s *conversationReadStateService) GetByAgentReader(conversationID int64, op
} }
// GetByCustomerReader 查询 IM 客户侧已读游标(按 ExternalID)。 // GetByCustomerReader 查询 IM 客户侧已读游标(按 ExternalID)。
func (s *conversationReadStateService) GetByCustomerReader(conversationID int64, external *openidentity.ExternalInfo) *models.ConversationReadState { func (s *conversationReadStateService) GetByCustomerReader(conversationID int64, external *openidentity.ExternalUser) *models.ConversationReadState {
if external == nil || strings.TrimSpace(external.ExternalID) == "" { if external == nil || strings.TrimSpace(external.ExternalID) == "" {
return nil return nil
} }
@@ -181,7 +181,7 @@ func (s *conversationReadStateService) MarkAgentRead(ctx *sqls.TxContext, conver
} }
// MarkCustomerRead 在事务内更新/创建 IM 客户已读游标。 // MarkCustomerRead 在事务内更新/创建 IM 客户已读游标。
func (s *conversationReadStateService) MarkCustomerRead(ctx *sqls.TxContext, conversation *models.Conversation, external *openidentity.ExternalInfo, message *models.Message, now time.Time) (*models.ConversationReadState, error) { func (s *conversationReadStateService) MarkCustomerRead(ctx *sqls.TxContext, conversation *models.Conversation, external *openidentity.ExternalUser, message *models.Message, now time.Time) (*models.ConversationReadState, error) {
c, err := customerReaderCursor(external) c, err := customerReaderCursor(external)
if err != nil { if err != nil {
return nil, err return nil, err
+12 -12
View File
@@ -100,7 +100,7 @@ func (s *conversationService) getLatestNotFinishedByCustomerID(db *gorm.DB, cust
return repositories.ConversationRepository.FindOne(db, cnd) return repositories.ConversationRepository.FindOne(db, cnd)
} }
func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, channelID, aiAgentID int64) (*models.Conversation, error) { func (s *conversationService) Create(externalUser openidentity.ExternalUser, channelID, aiAgentID int64) (*models.Conversation, error) {
aiAgent := AIAgentService.Get(aiAgentID) aiAgent := AIAgentService.Get(aiAgentID)
if aiAgent == nil || aiAgent.Status != enums.StatusOk { if aiAgent == nil || aiAgent.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("AI Agent not found") return nil, errorsx.InvalidParam("AI Agent not found")
@@ -109,7 +109,7 @@ func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, cha
var conversation *models.Conversation var conversation *models.Conversation
created := false created := false
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
customerID, err := CustomerService.EnsureExternalCustomer(ctx.Tx, externalInfo) customerID, err := CustomerService.EnsureExternalCustomer(ctx.Tx, externalUser)
if err != nil { if err != nil {
return err return err
} }
@@ -146,7 +146,7 @@ func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, cha
if err := ctx.Tx.Create(conversation).Error; err != nil { if err := ctx.Tx.Create(conversation).Error; err != nil {
return err return err
} }
if err := ConversationParticipantService.CreateCustomerParticipant(ctx, conversation.ID, externalInfo); err != nil { if err := ConversationParticipantService.CreateCustomerParticipant(ctx, conversation.ID, externalUser); err != nil {
return err return err
} }
return ConversationEventLogService.CreateEvent(ctx, conversation.ID, enums.IMEventTypeCreate, enums.IMSenderTypeCustomer, 0, "用户创建会话", "") return ConversationEventLogService.CreateEvent(ctx, conversation.ID, enums.IMEventTypeCreate, enums.IMSenderTypeCustomer, 0, "用户创建会话", "")
@@ -378,12 +378,12 @@ func (s *conversationService) CloseConversation(conversationID int64, closeReaso
return s.closeConversation(conversationID, enums.IMSenderTypeAgent, closeReason, operator) return s.closeConversation(conversationID, enums.IMSenderTypeAgent, closeReason, operator)
} }
func (s *conversationService) CloseCustomerConversation(conversationID int64, externalInfo openidentity.ExternalInfo) error { func (s *conversationService) CloseCustomerConversation(conversationID int64, externalUser openidentity.ExternalUser) error {
conversation := s.Get(conversationID) conversation := s.Get(conversationID)
if conversation == nil { if conversation == nil {
return errorsx.InvalidParam("会话不存在") return errorsx.InvalidParam("会话不存在")
} }
if !s.IsCustomerConversationOwner(conversation, externalInfo) { if !s.IsCustomerConversationOwner(conversation, externalUser) {
return errorsx.Forbidden("无权访问该会话") return errorsx.Forbidden("无权访问该会话")
} }
return s.closeConversation(conversationID, enums.IMSenderTypeCustomer, "", nil) return s.closeConversation(conversationID, enums.IMSenderTypeCustomer, "", nil)
@@ -477,7 +477,7 @@ func (s *conversationService) MarkAgentConversationReadToMessage(conversationID,
} }
// MarkCustomerConversationReadToMessage IM 客户将会话已读推进到指定消息(需为会话归属外部身份)。 // MarkCustomerConversationReadToMessage IM 客户将会话已读推进到指定消息(需为会话归属外部身份)。
func (s *conversationService) MarkCustomerConversationReadToMessage(conversationID, messageID int64, external *openidentity.ExternalInfo) error { func (s *conversationService) MarkCustomerConversationReadToMessage(conversationID, messageID int64, external *openidentity.ExternalUser) error {
if external == nil || strings.TrimSpace(external.ExternalID) == "" { if external == nil || strings.TrimSpace(external.ExternalID) == "" {
return errorsx.Unauthorized("外部用户标识不能为空") return errorsx.Unauthorized("外部用户标识不能为空")
} }
@@ -500,7 +500,7 @@ func (s *conversationService) MarkCustomerConversationReadToMessage(conversation
return nil return nil
} }
func displayExternalName(ext *openidentity.ExternalInfo) string { func displayExternalName(ext *openidentity.ExternalUser) string {
if ext == nil { if ext == nil {
return "" return ""
} }
@@ -541,7 +541,7 @@ func (a agentConversationReadActor) conversationUpdateAudit() (int64, string) {
} }
type customerConversationReadActor struct { type customerConversationReadActor struct {
external *openidentity.ExternalInfo external *openidentity.ExternalUser
} }
func (a customerConversationReadActor) isAgentSide() bool { return false } func (a customerConversationReadActor) isAgentSide() bool { return false }
@@ -651,15 +651,15 @@ func (s *conversationService) countUnreadByState(ctx *sqls.TxContext, conversati
return int(count), err return int(count), err
} }
func (s *conversationService) IsCustomerConversationOwner(conversation *models.Conversation, externalInfo openidentity.ExternalInfo) bool { func (s *conversationService) IsCustomerConversationOwner(conversation *models.Conversation, externalUser openidentity.ExternalUser) bool {
if conversation == nil { if conversation == nil {
return false return false
} }
extID := strings.TrimSpace(externalInfo.ExternalID) extID := strings.TrimSpace(externalUser.ExternalID)
if extID == "" || strings.TrimSpace(string(externalInfo.ExternalSource)) == "" || conversation.CustomerID <= 0 { if extID == "" || strings.TrimSpace(string(externalUser.ExternalSource)) == "" || conversation.CustomerID <= 0 {
return false return false
} }
identity := repositories.CustomerIdentityRepository.GetBy(sqls.DB(), externalInfo.ExternalSource, extID) identity := repositories.CustomerIdentityRepository.GetBy(sqls.DB(), externalUser.ExternalSource, extID)
if identity == nil { if identity == nil {
return false return false
} }
+8 -8
View File
@@ -113,9 +113,9 @@ func (s *customerService) CountByCompanyIDs(companyIDs []int64) map[int64]int64
return repositories.CustomerRepository.CountByCompanyIDs(sqls.DB(), companyIDs, int(enums.StatusDeleted)) return repositories.CustomerRepository.CountByCompanyIDs(sqls.DB(), companyIDs, int(enums.StatusDeleted))
} }
func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalInfo openidentity.ExternalInfo) (int64, error) { func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openidentity.ExternalUser) (int64, error) {
externalSource := externalInfo.ExternalSource externalSource := externalUser.ExternalSource
externalID := strings.TrimSpace(externalInfo.ExternalID) externalID := strings.TrimSpace(externalUser.ExternalID)
if strings.TrimSpace(string(externalSource)) == "" || externalID == "" { if strings.TrimSpace(string(externalSource)) == "" || externalID == "" {
return 0, errorsx.Unauthorized("外部用户标识不能为空") return 0, errorsx.Unauthorized("外部用户标识不能为空")
} }
@@ -129,7 +129,7 @@ func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalInfo openi
} }
customer := &models.Customer{ customer := &models.Customer{
Name: buildExternalCustomerName(externalInfo), Name: buildExternalCustomerName(externalUser),
LastActiveAt: &now, LastActiveAt: &now,
Status: enums.StatusOk, Status: enums.StatusOk,
AuditFields: utils.BuildAuditFields(nil), AuditFields: utils.BuildAuditFields(nil),
@@ -149,11 +149,11 @@ func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalInfo openi
return customer.ID, nil return customer.ID, nil
} }
func buildExternalCustomerName(externalInfo openidentity.ExternalInfo) string { func buildExternalCustomerName(externalUser openidentity.ExternalUser) string {
if strs.IsNotBlank(externalInfo.ExternalName) { if strs.IsNotBlank(externalUser.ExternalName) {
return externalInfo.ExternalName return externalUser.ExternalName
} }
return "访客" + hashUUID(externalInfo.ExternalID) return "访客" + hashUUID(externalUser.ExternalID)
} }
func hashUUID(uuid string) string { func hashUUID(uuid string) string {
+4 -4
View File
@@ -127,7 +127,7 @@ func (s *messageService) GetConversationReadTarget(conversationID, messageID int
return s.FindOne(sqls.NewCnd().Eq("conversation_id", conversationID).Desc("seq_no").Desc("id")), nil return s.FindOne(sqls.NewCnd().Eq("conversation_id", conversationID).Desc("seq_no").Desc("id")), nil
} }
func (s *messageService) SendMessage(conversationID int64, senderType enums.IMSenderType, reqSenderID int64, clientMsgID string, messageType enums.IMMessageType, content, payload string, operator *dto.AuthPrincipal, external *openidentity.ExternalInfo) (*models.Message, error) { func (s *messageService) SendMessage(conversationID int64, senderType enums.IMSenderType, reqSenderID int64, clientMsgID string, messageType enums.IMMessageType, content, payload string, operator *dto.AuthPrincipal, external *openidentity.ExternalUser) (*models.Message, error) {
switch senderType { switch senderType {
case enums.IMSenderTypeAgent: case enums.IMSenderTypeAgent:
return s.sendMessage(conversationID, enums.IMSenderTypeAgent, reqSenderID, clientMsgID, messageType, content, payload, operator, nil) return s.sendMessage(conversationID, enums.IMSenderTypeAgent, reqSenderID, clientMsgID, messageType, content, payload, operator, nil)
@@ -243,13 +243,13 @@ func (s *messageService) SendAIMessage(conversationID int64, aiAgentID int64, cl
return s.sendMessage(conversationID, enums.IMSenderTypeAI, aiAgentID, clientMsgID, messageType, content, payload, operator, nil) return s.sendMessage(conversationID, enums.IMSenderTypeAI, aiAgentID, clientMsgID, messageType, content, payload, operator, nil)
} }
func (s *messageService) SendCustomerMessage(conversationID int64, clientMsgID string, messageType enums.IMMessageType, content, payload string, external openidentity.ExternalInfo) (*models.Message, error) { func (s *messageService) SendCustomerMessage(conversationID int64, clientMsgID string, messageType enums.IMMessageType, content, payload string, external openidentity.ExternalUser) (*models.Message, error) {
ext := external ext := external
return s.sendMessage(conversationID, enums.IMSenderTypeCustomer, 0, clientMsgID, messageType, content, payload, nil, &ext) return s.sendMessage(conversationID, enums.IMSenderTypeCustomer, 0, clientMsgID, messageType, content, payload, nil, &ext)
} }
func (s *messageService) sendMessage(conversationID int64, senderType enums.IMSenderType, reqSenderID int64, clientMsgID string, func (s *messageService) sendMessage(conversationID int64, senderType enums.IMSenderType, reqSenderID int64, clientMsgID string,
messageType enums.IMMessageType, content, payload string, operator *dto.AuthPrincipal, external *openidentity.ExternalInfo) (*models.Message, error) { messageType enums.IMMessageType, content, payload string, operator *dto.AuthPrincipal, external *openidentity.ExternalUser) (*models.Message, error) {
if senderType == enums.IMSenderTypeCustomer { if senderType == enums.IMSenderTypeCustomer {
if external == nil || strings.TrimSpace(external.ExternalID) == "" { if external == nil || strings.TrimSpace(external.ExternalID) == "" {
@@ -493,7 +493,7 @@ func (s *messageService) normalizeMessageContent(conversationID int64, messageTy
} }
} }
func (s *messageService) ValidateConversationSender(conversationID int64, senderType enums.IMSenderType, operator *dto.AuthPrincipal, external *openidentity.ExternalInfo) (*models.Conversation, error) { func (s *messageService) ValidateConversationSender(conversationID int64, senderType enums.IMSenderType, operator *dto.AuthPrincipal, external *openidentity.ExternalUser) (*models.Conversation, error) {
conversation := ConversationService.Get(conversationID) conversation := ConversationService.Get(conversationID)
if conversation == nil { if conversation == nil {
return nil, errorsx.InvalidParam("会话不存在") return nil, errorsx.InvalidParam("会话不存在")
+1 -1
View File
@@ -229,7 +229,7 @@ type ClientSession struct {
ID string ID string
Conn *websocket.Conn Conn *websocket.Conn
Principal *dto.AuthPrincipal Principal *dto.AuthPrincipal
External *openidentity.ExternalInfo External *openidentity.ExternalUser
Role string Role string
TerminalType string TerminalType string
Topics map[string]struct{} Topics map[string]struct{}
+3 -3
View File
@@ -63,10 +63,10 @@ func (s *wsService) HandleOpenWS(ctx iris.Context) {
var ( var (
principal = AuthService.GetAuthPrincipal(ctx) principal = AuthService.GetAuthPrincipal(ctx)
external *openidentity.ExternalInfo external *openidentity.ExternalUser
) )
if principal == nil { if principal == nil {
ext, err := openidentity.GetExternalInfoWithUserTokenSecret(ctx, ChannelService.GetUserTokenSecret(channel)) ext, err := openidentity.GetExternalUser(ctx, ChannelService.GetUserTokenSecret(channel))
if err != nil { if err != nil {
_ = ctx.StopWithJSON(iris.StatusUnauthorized, web.JsonError(err)) _ = ctx.StopWithJSON(iris.StatusUnauthorized, web.JsonError(err))
return return
@@ -80,7 +80,7 @@ func (s *wsService) HandleOpenWS(ctx iris.Context) {
} }
} }
func (s *wsService) upgradeConnection(ctx iris.Context, principal *dto.AuthPrincipal, external *openidentity.ExternalInfo, role string) error { func (s *wsService) upgradeConnection(ctx iris.Context, principal *dto.AuthPrincipal, external *openidentity.ExternalUser, role string) error {
conn, err := s.upgrader.Upgrade(ctx.ResponseWriter().Naive(), ctx.Request(), nil) conn, err := s.upgrader.Upgrade(ctx.ResponseWriter().Naive(), ctx.Request(), nil)
if err != nil { if err != nil {
return err return err
@@ -119,7 +119,7 @@ func (s *wxWorkKFInboundService) handleTextMessage(item syncmsg.Message) error {
enums.IMMessageTypeText, enums.IMMessageTypeText,
strings.TrimSpace(payload.Text.Content), strings.TrimSpace(payload.Text.Content),
"", "",
s.buildExternalInfo(payload.ExternalUserID), s.buildExternalUser(payload.ExternalUserID),
) )
if err != nil { if err != nil {
return err return err
@@ -149,7 +149,7 @@ func (s *wxWorkKFInboundService) handleImageMessage(item syncmsg.Message) error
enums.IMMessageTypeImage, enums.IMMessageTypeImage,
content, content,
canonicalPayload, canonicalPayload,
s.buildExternalInfo(payload.ExternalUserID), s.buildExternalUser(payload.ExternalUserID),
) )
if err != nil { if err != nil {
return err return err
@@ -179,7 +179,7 @@ func (s *wxWorkKFInboundService) handleFileMessage(item syncmsg.Message) error {
enums.IMMessageTypeAttachment, enums.IMMessageTypeAttachment,
content, content,
canonicalPayload, canonicalPayload,
s.buildExternalInfo(payload.ExternalUserID), s.buildExternalUser(payload.ExternalUserID),
) )
if err != nil { if err != nil {
return err return err
@@ -203,7 +203,7 @@ func (s *wxWorkKFInboundService) handleUnsupportedMessage(item syncmsg.Message)
enums.IMMessageTypeText, enums.IMMessageTypeText,
content, content,
string(item.OriginData), string(item.OriginData),
s.buildExternalInfo(base.ExternalUserID), s.buildExternalUser(base.ExternalUserID),
) )
if err != nil { if err != nil {
return err return err
@@ -376,7 +376,7 @@ func (s *wxWorkKFInboundService) ensureConversation(base syncmsg.BaseMessage, pr
return nil, err return nil, err
} }
external := s.buildExternalInfo(externalID) external := s.buildExternalUser(externalID)
conversation, err := ConversationService.Create(external, channel.ID, channel.AIAgentID) conversation, err := ConversationService.Create(external, channel.ID, channel.AIAgentID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -558,8 +558,8 @@ func (s *wxWorkKFInboundService) getChannelByOpenKfID(openKfID string) (*models.
return channel, nil return channel, nil
} }
func (s *wxWorkKFInboundService) buildExternalInfo(externalUserID string) openidentity.ExternalInfo { func (s *wxWorkKFInboundService) buildExternalUser(externalUserID string) openidentity.ExternalUser {
return openidentity.ExternalInfo{ return openidentity.ExternalUser{
ExternalSource: enums.ExternalSourceWxWorkKF, ExternalSource: enums.ExternalSourceWxWorkKF,
ExternalID: strings.TrimSpace(externalUserID), ExternalID: strings.TrimSpace(externalUserID),
ExternalName: strings.TrimSpace(externalUserID), ExternalName: strings.TrimSpace(externalUserID),