sync: soul-api 接口逻辑 | 原因: 后端接口逻辑修改
This commit is contained in:
185
soul-api/internal/handler/admin_shensheshou.go
Normal file
185
soul-api/internal/handler/admin_shensheshou.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var sssHTTPClient = &http.Client{Timeout: 15 * time.Second}
|
||||
|
||||
func sssBaseURL() string {
|
||||
u := os.Getenv("SHENSHESHOU_BASE_URL")
|
||||
if u == "" {
|
||||
u = "https://your-domain.com/api/shensheshou"
|
||||
}
|
||||
return strings.TrimRight(u, "/")
|
||||
}
|
||||
|
||||
func sssAPIKey() string {
|
||||
return os.Getenv("SHENSHESHOU_API_KEY")
|
||||
}
|
||||
|
||||
func sssDoRequest(method, url string, body interface{}) (map[string]interface{}, error) {
|
||||
var reqBody io.Reader
|
||||
if body != nil {
|
||||
b, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqBody = bytes.NewReader(b)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+sssAPIKey())
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := sssHTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
raw, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(raw, &result); err != nil {
|
||||
return nil, fmt.Errorf("响应解析失败: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AdminShensheShouQuery GET /api/admin/shensheshou/query?phone=xxx&openId=xxx
|
||||
func AdminShensheShouQuery(c *gin.Context) {
|
||||
if sssAPIKey() == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "神射手 API Key 未配置,请在 .env 中设置 SHENSHESHOU_API_KEY"})
|
||||
return
|
||||
}
|
||||
|
||||
phone := strings.TrimSpace(c.Query("phone"))
|
||||
openID := strings.TrimSpace(c.Query("openId"))
|
||||
|
||||
if phone == "" && openID == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "需要 phone 或 openId 参数"})
|
||||
return
|
||||
}
|
||||
|
||||
queryURL := sssBaseURL() + "?endpoint=user"
|
||||
if phone != "" {
|
||||
queryURL += "&phone=" + phone
|
||||
}
|
||||
|
||||
result, err := sssDoRequest(http.MethodGet, queryURL, nil)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if success, ok := result["success"].(bool); ok && !success {
|
||||
errMsg := "查询失败"
|
||||
if e, ok := result["error"].(string); ok {
|
||||
errMsg = e
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": errMsg})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": result["data"]})
|
||||
}
|
||||
|
||||
// AdminShensheShouIngest POST /api/admin/shensheshou/ingest — 推送用户数据到神射手
|
||||
func AdminShensheShouIngest(c *gin.Context) {
|
||||
if sssAPIKey() == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "神射手 API Key 未配置"})
|
||||
return
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Users []map[string]interface{} `json:"users" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"endpoint": "ingest",
|
||||
"source": "cunkebao",
|
||||
"users": body.Users,
|
||||
}
|
||||
|
||||
result, err := sssDoRequest(http.MethodPost, sssBaseURL(), payload)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if success, ok := result["success"].(bool); ok && !success {
|
||||
errMsg := "推送失败"
|
||||
if e, ok := result["error"].(string); ok {
|
||||
errMsg = e
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": errMsg})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": result["data"]})
|
||||
}
|
||||
|
||||
// AdminShensheShouBatchQuery POST /api/admin/shensheshou/batch — 批量查询
|
||||
func AdminShensheShouBatchQuery(c *gin.Context) {
|
||||
if sssAPIKey() == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": "神射手 API Key 未配置"})
|
||||
return
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Phones []string `json:"phones"`
|
||||
Fields []string `json:"fields"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
if len(body.Phones) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "phones 不能为空"})
|
||||
return
|
||||
}
|
||||
if len(body.Phones) > 100 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "单次最多 100 个"})
|
||||
return
|
||||
}
|
||||
|
||||
fields := body.Fields
|
||||
if len(fields) == 0 {
|
||||
fields = []string{"rfm_score", "user_level", "tags"}
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"endpoint": "users/batch",
|
||||
"phones": body.Phones,
|
||||
"fields": fields,
|
||||
}
|
||||
|
||||
result, err := sssDoRequest(http.MethodPost, sssBaseURL(), payload)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": result["data"]})
|
||||
}
|
||||
Reference in New Issue
Block a user