refactor(server): 会话/访客/设置业务逻辑下沉 internal/service 层,handler 瘦身
- handler 只保留请求绑定、权限检查与响应映射;业务校验顺序、状态码与文案逐字保留 - 新增 service.Error 语义错误,由 handler 统一映射 HTTP 响应 - session 875→361 行、widget 745→321 行、settings 540→73 行 - 自动分配/租户设置(工作时间、欢迎语)/消息校验/黑名单检查/联系方式提取随迁 service 包 - 相关单元测试随迁 service 包,go test ./... 全部通过
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -12,6 +10,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kefu-cloud/server/internal/middleware"
|
||||
"kefu-cloud/server/internal/model"
|
||||
"kefu-cloud/server/internal/service"
|
||||
"kefu-cloud/server/internal/ws"
|
||||
)
|
||||
|
||||
@@ -19,53 +18,6 @@ type BlacklistHandler struct{}
|
||||
|
||||
func NewBlacklistHandler() *BlacklistHandler { return &BlacklistHandler{} }
|
||||
|
||||
// normalizeDeviceKey 规范化设备指纹:优先客户端 device_id;否则用 UA 摘要哈希兜底。
|
||||
func normalizeDeviceKey(deviceID, userAgent string) string {
|
||||
id := strings.TrimSpace(deviceID)
|
||||
if id != "" {
|
||||
if utf8.RuneCountInString(id) > 64 {
|
||||
id = string([]rune(id)[:64])
|
||||
}
|
||||
return id
|
||||
}
|
||||
ua := strings.TrimSpace(userAgent)
|
||||
if ua == "" {
|
||||
return ""
|
||||
}
|
||||
sum := sha256.Sum256([]byte(strings.ToLower(ua)))
|
||||
return hex.EncodeToString(sum[:])[:32]
|
||||
}
|
||||
|
||||
// isBlacklisted 检查租户下 IP/设备是否在有效黑名单中。
|
||||
func isBlacklisted(tenantID uint, kind, value string) (bool, *model.BlacklistEntry) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" || (kind != "ip" && kind != "device") {
|
||||
return false, nil
|
||||
}
|
||||
now := time.Now()
|
||||
var entry model.BlacklistEntry
|
||||
err := model.DB.
|
||||
Where("tenant_id = ? AND kind = ? AND value = ?", tenantID, kind, value).
|
||||
Where("expires_at IS NULL OR expires_at > ?", now).
|
||||
Order("id desc").
|
||||
First(&entry).Error
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, &entry
|
||||
}
|
||||
|
||||
// checkVisitorBlacklist 同时检查 IP 与设备。
|
||||
func checkVisitorBlacklist(tenantID uint, ip, deviceKey string) (blocked bool, kind string, reason string) {
|
||||
if ok, e := isBlacklisted(tenantID, "ip", ip); ok {
|
||||
return true, "ip", e.Reason
|
||||
}
|
||||
if ok, e := isBlacklisted(tenantID, "device", deviceKey); ok {
|
||||
return true, "device", e.Reason
|
||||
}
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
type CreateBlacklistReq struct {
|
||||
// SessionID 从会话一键拉黑时必填(自动带出 IP/设备)
|
||||
SessionID *uint `json:"session_id"`
|
||||
@@ -163,8 +115,9 @@ func (h *BlacklistHandler) Create(c *gin.Context) {
|
||||
var customerID *uint
|
||||
|
||||
if req.SessionID != nil && *req.SessionID > 0 {
|
||||
s, ok := loadTenantSession(c, fmt.Sprintf("%d", *req.SessionID))
|
||||
if !ok {
|
||||
s, err := service.LoadTenantSession(fmt.Sprintf("%d", *req.SessionID), middleware.GetTenantID(c))
|
||||
if err != nil {
|
||||
respondServiceError(c, err)
|
||||
return
|
||||
}
|
||||
session = s
|
||||
@@ -182,7 +135,7 @@ func (h *BlacklistHandler) Create(c *gin.Context) {
|
||||
value = strings.TrimSpace(s.DeviceKey)
|
||||
if value == "" {
|
||||
// 旧会话兜底:用 UA 哈希
|
||||
value = normalizeDeviceKey("", s.UserAgent)
|
||||
value = service.NormalizeDeviceKey("", s.UserAgent)
|
||||
}
|
||||
if value == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "该会话无设备标识,无法按设备拉黑"})
|
||||
@@ -250,7 +203,7 @@ func (h *BlacklistHandler) Create(c *gin.Context) {
|
||||
if kind == "device" {
|
||||
kindLabel = "设备"
|
||||
}
|
||||
detail := userDisplayName(operatorID) + " 拉黑" + kindLabel + " " + maskBlacklistValue(kind, value) +
|
||||
detail := service.UserDisplayName(operatorID) + " 拉黑" + kindLabel + " " + maskBlacklistValue(kind, value) +
|
||||
"(" + durationLabel(req.Duration) + "):" + reason
|
||||
model.DB.Create(&model.SessionEvent{
|
||||
SessionID: session.ID,
|
||||
@@ -274,12 +227,12 @@ func (h *BlacklistHandler) Create(c *gin.Context) {
|
||||
Action: "end",
|
||||
Detail: "结束会话: 拉黑访客",
|
||||
})
|
||||
broadcastSessionUpdate(session)
|
||||
service.BroadcastSessionUpdate(session)
|
||||
if payload, err := ws.NewEvent("session_updated", session.ID, session); err == nil {
|
||||
ws.DefaultHub.BroadcastToSession(session.TenantID, session.ID, session.AgentID, payload)
|
||||
}
|
||||
} else {
|
||||
broadcastSessionUpdate(session)
|
||||
service.BroadcastSessionUpdate(session)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user