refactor: 将客服后端重构为宿主可嵌入模块
- 注入数据库、运行时配置、统一响应、文件存储和平台 AI 能力,补充业务读写工具与客户快捷操作契约。 - 移除模块内重复的组织、客户、工单、标签、技能、旧工作流、MCP 和迁移实现,将身份权限与业务主体交由宿主管理。 - 使用 libSQL 重构向量存储,并完善图片消息、访客身份、排队调度、企业微信和支持聊天页面。 - 统一 HTTP、DTO 与 WebSocket 的 snake_case 协议,补齐模块初始化、业务动作和公共载荷等回归测试。
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"code.tczkiot.com/wlw/ai-agent/identity"
|
||||
@@ -75,12 +76,37 @@ func (s *subjectService) CurrentExternal(ctx context.Context) (*openidentity.Ext
|
||||
ExternalSource: enums.ExternalSourceUser,
|
||||
ExternalID: fmt.Sprintf("%s:%d", subject.Type, subject.ID),
|
||||
ExternalName: subject.Name,
|
||||
SubjectType: subject.Type,
|
||||
SubjectID: subject.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ResolveExternal returns a host-authenticated customer when available and
|
||||
// falls back to the opaque browser identifier used by anonymous Web visitors.
|
||||
// The identifier is not a login token and is never accepted for dashboard APIs.
|
||||
func (s *subjectService) ResolveExternal(ctx context.Context, guestID, guestName string) (*openidentity.ExternalUser, error) {
|
||||
external, err := s.CurrentExternal(ctx)
|
||||
if err == nil {
|
||||
return external, nil
|
||||
}
|
||||
guestID = strings.TrimSpace(guestID)
|
||||
if guestID == "" || len(guestID) > 128 {
|
||||
return nil, err
|
||||
}
|
||||
guestName = strings.TrimSpace(guestName)
|
||||
if len(guestName) > 255 {
|
||||
guestName = guestName[:255]
|
||||
}
|
||||
return &openidentity.ExternalUser{
|
||||
ExternalSource: enums.ExternalSourceGuest,
|
||||
ExternalID: guestID,
|
||||
ExternalName: guestName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *subjectService) Get(id int64) *identity.Subject {
|
||||
items, err := s.Query(context.Background(), identity.Query{
|
||||
Types: []identity.SubjectType{identity.SubjectAgent},
|
||||
Types: []identity.SubjectType{identity.SubjectAdmin},
|
||||
IDs: []int64{id},
|
||||
EnabledOnly: true,
|
||||
})
|
||||
@@ -99,7 +125,7 @@ func (s *subjectService) FindByIDs(ids []int64) []identity.Subject {
|
||||
return nil
|
||||
}
|
||||
items, err := s.Query(context.Background(), identity.Query{
|
||||
Types: []identity.SubjectType{identity.SubjectAgent},
|
||||
Types: []identity.SubjectType{identity.SubjectAdmin},
|
||||
IDs: ids,
|
||||
EnabledOnly: true,
|
||||
})
|
||||
@@ -109,3 +135,24 @@ func (s *subjectService) FindByIDs(ids []int64) []identity.Subject {
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (s *subjectService) IsUserReference(subjectType identity.SubjectType, id int64) bool {
|
||||
if id <= 0 {
|
||||
return false
|
||||
}
|
||||
switch subjectType {
|
||||
case identity.SubjectCard, identity.SubjectDevice, identity.SubjectMallUser:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
items, err := s.Query(context.Background(), identity.Query{
|
||||
Types: []identity.SubjectType{subjectType},
|
||||
IDs: []int64{id},
|
||||
EnabledOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
slog.Warn("query external customer subject failed", "type", subjectType, "id", id, "error", err)
|
||||
return false
|
||||
}
|
||||
return len(items) > 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user