2e2c161770
- backed/: Go Fiber backend with cpdaily integration - frondend/: Vue 3 + Vite frontend - Dockerfile: multi-stage build (Node → Go → Alpine) - deploy/docker-compose.yml: production compose file - .woodpecker/build.yml: CI/CD with blue-green zero-downtime deploy - /health endpoint for deployment health checks - Port 8884/8885 blue-green swap via 1Panel OpenResty
89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
package cpdaily
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-resty/resty/v2"
|
|
)
|
|
|
|
// 创建 Resty 客户端
|
|
func newMobileClient() *resty.Client {
|
|
return resty.New().
|
|
SetTimeout(15*time.Second).
|
|
SetDoNotParseResponse(true).
|
|
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
|
|
}
|
|
|
|
// FetchUserProfile 从 cpdaily 获取用户主页信息
|
|
// 使用 wecloud getCurrentUserId API 获取姓名+头像,不再尝试获取手机号
|
|
func FetchUserProfile(cookieMap map[string]string, wecloudUrl string) (*CpdailyUserProfile, error) {
|
|
if wecloudUrl != "" {
|
|
if p, err := fetchFromWecloud(wecloudUrl, cookieMap); err == nil && p.Name != "" {
|
|
return p, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("无法获取用户信息")
|
|
}
|
|
|
|
// fetchFromWecloud 通过 campusphere.net 获取用户基本信息
|
|
func fetchFromWecloud(wecloudUrl string, cookieMap map[string]string) (*CpdailyUserProfile, error) {
|
|
host := strings.TrimSuffix(wecloudUrl, "/")
|
|
cookieStr := cookiesToStr(cookieMap)
|
|
|
|
client := newMobileClient()
|
|
resp, err := client.R().
|
|
SetHeader("User-Agent", "Mozilla/5.0 (Linux; Android 15; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.81 Mobile Safari/537.36 cpdaily/9.9.6 wisedu/9.9.6").
|
|
SetHeader("CpdailyClientType", "CPDAILY").
|
|
SetHeader("Cookie", cookieStr).
|
|
Get(host + "/wec-im-group/group/groupMember/getCurrentUserId")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("请求 wecloud 用户信息失败: %w", err)
|
|
}
|
|
defer resp.RawBody().Close()
|
|
|
|
body, _ := io.ReadAll(resp.RawBody())
|
|
var result struct {
|
|
ErrCode int `json:"errCode"`
|
|
ErrMsg string `json:"errMsg"`
|
|
Data *struct {
|
|
UserName string `json:"userName"`
|
|
AvatarUrl string `json:"avatarUrl"`
|
|
MobilePhone string `json:"mobilePhone"`
|
|
} `json:"data"`
|
|
}
|
|
if err := json.Unmarshal(body, &result); err != nil {
|
|
return nil, fmt.Errorf("解析 wecloud 用户信息失败: %w", err)
|
|
}
|
|
if result.ErrCode != 0 || result.Data == nil {
|
|
return nil, fmt.Errorf("wecloud 用户信息接口错误(%d): %s", result.ErrCode, result.ErrMsg)
|
|
}
|
|
|
|
return &CpdailyUserProfile{
|
|
Name: result.Data.UserName,
|
|
Img: result.Data.AvatarUrl,
|
|
MobilePhone: result.Data.MobilePhone,
|
|
}, nil
|
|
}
|
|
|
|
// cookiesToStr 将 cookie map 转为 cookie 字符串
|
|
func cookiesToStr(cookieMap map[string]string) string {
|
|
var parts []string
|
|
for k, v := range cookieMap {
|
|
parts = append(parts, k+"="+v)
|
|
}
|
|
return strings.Join(parts, "; ")
|
|
}
|
|
|
|
// ParseCookieJSON 将 JSON cookie 字符串解析为 map
|
|
func ParseCookieJSON(cookieJSON string) map[string]string {
|
|
cookieMap := make(map[string]string)
|
|
json.Unmarshal([]byte(cookieJSON), &cookieMap)
|
|
return cookieMap
|
|
}
|