- 广告获取改走 versionUrl /api/stat/advitise/v2/get(appId=12),移除 adcenter(Jt) 调用;新增 /api/app/ads/click 异步上报点击;proto.AdvitiseData 别名为 proxy.AdvitiseData,AList/BList 字段改名 AppInfoAList/AppInfoBList。 - web 后台登录取消谷歌验证码(srv_mwacc.AccLogin 去掉 code 参数),密码正确即 发放 token。 - app 端取消注册/登录/找回密码/游客登录接口及密码、token 相关代码;鉴权中间件 不再校验 token,按 X-User-Agent 中的 devID 识别用户,首次访问自动建号, Redis 缓存 10 分钟;修改资料不再支持改密码。 - app m3u8 ticket 校验失败不再降级到 fallback 路径,仍按原 m3u8Name 返回。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
178 lines
6.3 KiB
Go
178 lines
6.3 KiB
Go
package authser
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
"videoweb/pub/common/log"
|
|
"videoweb/pub/common/srvdef"
|
|
"videoweb/pub/common/useragent"
|
|
"videoweb/pub/common/utils"
|
|
"videoweb/pub/models/usermod"
|
|
"videoweb/pub/pubdef"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
)
|
|
|
|
var defaultAvatars = []string{
|
|
"v3/image/bo/ty/1016/girl1.jpeg",
|
|
"v3/image/re/9y/1016/girl2.jpeg",
|
|
"v3/image/5f/k4/1016/girl3.jpeg",
|
|
"v3/image/ej/ss/1016/girl4.jpeg",
|
|
"v3/image/yq/ys/1016/girl5.jpeg",
|
|
"v3/image/9e/d3/1016/girl6.jpeg",
|
|
}
|
|
|
|
func randomAvatar() string {
|
|
return defaultAvatars[time.Now().UnixNano()%int64(len(defaultAvatars))]
|
|
}
|
|
|
|
// generateUniqueInviteCode 生成 8 位唯一邀请码(纯大写字母),最多重试 10 次
|
|
func generateUniqueInviteCode(ctx context.Context) string {
|
|
for i := 0; i < 10; i++ {
|
|
code := strings.ToUpper(utils.GetRandomLetters(8))
|
|
exist, _ := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.InviteCode: code})
|
|
if exist == nil {
|
|
return code
|
|
}
|
|
log.Warn("authser:generateUniqueInviteCode collision, retrying", log.Any("code", code))
|
|
}
|
|
// 极小概率走到这里:用更长的随机串兜底
|
|
return strings.ToUpper(utils.GetRandomLetters(12))
|
|
}
|
|
|
|
// LoginResp 用户信息
|
|
type LoginResp struct {
|
|
UserId int64 `json:"userId"`
|
|
AccountNo string `json:"accountNo"`
|
|
Email string `json:"email"`
|
|
NickName string `json:"nickName"`
|
|
Introduction string `json:"introduction"` // 简介
|
|
VipType pubdef.VipType `json:"vipType"`
|
|
CurrentVipExpire time.Time `json:"currentVipExpire"` // VIP 过期时间,客户端需结合 vipType 判断是否真正有效
|
|
ShowCardId int64 `json:"showCardId"` // 最新会员卡id
|
|
ShowCardName string `json:"showCardName"` // 最新会员卡名称
|
|
Status pubdef.UserStatus `json:"status"`
|
|
Avatar string `json:"avatar"` // 头像
|
|
InviteCode string `json:"inviteCode"` // 邀请码
|
|
Type pubdef.UserType `json:"type"` // 身份类型:0游客 1普通用户
|
|
LoginType pubdef.LoginType `json:"loginType"` // 登陆方式
|
|
IsRegister bool `json:"isRegister"` // 是否已注册
|
|
PrivacyMode bool `json:"privacyMode"` // 隐私模式
|
|
HasPassword bool `json:"hasPassword"` // 是否已设置密码
|
|
Score int64 `json:"score"` // 积分
|
|
Recharge int64 `json:"recharge"` // 金币余额
|
|
}
|
|
|
|
// CrawlerLoginResp 爬虫虚拟游客资料,不对应任何数据库用户。
|
|
func CrawlerLoginResp() *LoginResp {
|
|
return &LoginResp{
|
|
UserId: pubdef.CrawlerUserId,
|
|
NickName: "游客",
|
|
Status: pubdef.UserStatusNormal,
|
|
Type: pubdef.UserTypeGuest,
|
|
LoginType: pubdef.LoginTypeDevice,
|
|
IsRegister: false,
|
|
}
|
|
}
|
|
|
|
// GetInfo 获取当前用户的最新信息
|
|
func GetInfo(ctx context.Context, userId int64, ua useragent.UA) (*LoginResp, *srvdef.SrvErr) {
|
|
if pubdef.IsCrawlerUser(userId) {
|
|
return CrawlerLoginResp(), nil
|
|
}
|
|
user, _ := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: userId})
|
|
if user == nil {
|
|
return nil, srvdef.New(srvdef.ErrUserNotExsit, srvdef.ErrUserNotExsit.Msg(), "")
|
|
}
|
|
now := time.Now()
|
|
setDoc := bson.M{}
|
|
if v := strings.TrimSpace(ua.DevID); v != "" && v != user.DevID {
|
|
setDoc[usermod.FN.User.DevID] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.DevType); v != "" && v != user.Device {
|
|
setDoc[usermod.FN.User.Device] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.SysType); v != "" && v != user.SysType {
|
|
setDoc[usermod.FN.User.SysType] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.Ver); v != "" && v != user.AppVer {
|
|
setDoc[usermod.FN.User.AppVer] = v
|
|
}
|
|
if strings.TrimSpace(user.AccountNo) != "" && user.Type != pubdef.UserTypeNormal {
|
|
setDoc[usermod.FN.User.Type] = pubdef.UserTypeNormal
|
|
setDoc[usermod.FN.User.IsRegister] = true
|
|
user.Type = pubdef.UserTypeNormal
|
|
user.IsRegister = true
|
|
}
|
|
mergeUAExtFieldsToSet(setDoc, user, ua)
|
|
if len(setDoc) > 0 {
|
|
setDoc[usermod.FN.User.UpdatedAt] = now
|
|
_ = usermod.UpdateOneUser(ctx, bson.M{usermod.FN.User.Id: user.Id}, bson.M{"$set": setDoc})
|
|
}
|
|
return toLoginResp(ctx, user, true), nil
|
|
}
|
|
|
|
func mergeUAExtFieldsToSet(setDoc bson.M, user *usermod.User, ua useragent.UA) {
|
|
if user == nil {
|
|
return
|
|
}
|
|
if v := strings.TrimSpace(ua.SessionID); v != "" && v != user.SessionID {
|
|
setDoc[usermod.FN.User.SessionID] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.DeviceBrand); v != "" && v != user.DeviceBrand {
|
|
setDoc[usermod.FN.User.DeviceBrand] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.DeviceModel); v != "" && v != user.DeviceModel {
|
|
setDoc[usermod.FN.User.DeviceModel] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.SystemName); v != "" && v != user.SystemName {
|
|
setDoc[usermod.FN.User.SystemName] = v
|
|
}
|
|
if v := strings.TrimSpace(ua.SystemVersion); v != "" && v != user.SystemVersion {
|
|
setDoc[usermod.FN.User.SystemVersion] = v
|
|
}
|
|
}
|
|
|
|
// UpdateProfileReq 修改用户资料的参数(所有字段均为可选)
|
|
type UpdateProfileReq struct {
|
|
UserId int64 // 用户ID(按设备ID识别)
|
|
NickName *string // 新昵称(可选)
|
|
Avatar *string // 新头像 URL(可选)
|
|
Introduction *string // 简介(可选)
|
|
PrivacyMode *bool // 隐私模式:true-开启,false-关闭(可选)
|
|
}
|
|
|
|
// UpdateProfile 修改用户资料:支持修改昵称、头像、简介、隐私模式,或组合修改
|
|
func UpdateProfile(ctx context.Context, req *UpdateProfileReq) *srvdef.SrvErr {
|
|
user, _ := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: req.UserId})
|
|
if user == nil {
|
|
return srvdef.New(srvdef.ErrUserNotExsit, srvdef.ErrUserNotExsit.Msg(), "")
|
|
}
|
|
|
|
setDoc := bson.M{usermod.FN.User.UpdatedAt: time.Now()}
|
|
|
|
if req.NickName != nil && *req.NickName != "" {
|
|
setDoc[usermod.FN.User.NickName] = *req.NickName
|
|
}
|
|
if req.Avatar != nil && *req.Avatar != "" {
|
|
setDoc[usermod.FN.User.Avatar] = *req.Avatar
|
|
}
|
|
if req.Introduction != nil {
|
|
setDoc[usermod.FN.User.Introduction] = strings.TrimSpace(*req.Introduction)
|
|
}
|
|
if req.PrivacyMode != nil {
|
|
setDoc[usermod.FN.User.PrivacyMode] = *req.PrivacyMode
|
|
}
|
|
|
|
// 没有任何需要更新的字段
|
|
if len(setDoc) == 1 {
|
|
return srvdef.New(srvdef.ErrParamError, "至少需要修改一项资料", "")
|
|
}
|
|
|
|
return usermod.UpdateOneUser(ctx,
|
|
bson.M{usermod.FN.User.Id: user.Id},
|
|
bson.M{"$set": setDoc},
|
|
)
|
|
}
|