Initial commit

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
fish03
2026-09-23 14:43:16 +07:00
co-authored by Claude Opus 5.5
commit bef9f8b4ed
663 changed files with 81305 additions and 0 deletions
+548
View File
@@ -0,0 +1,548 @@
package web
import (
"net/http"
"strings"
"videoweb/app/service/authser"
"videoweb/pub/common/log"
"videoweb/pub/common/useragent"
"github.com/gin-gonic/gin"
)
type registerBody struct {
AccountNo string `json:"accountNo"`
Email string `json:"email"`
Password string `json:"password"`
AgentInviteCode string `json:"agentInviteCode"`
DevID string `json:"devID"`
Channel string `json:"channel"`
}
type loginBody struct {
Account string `json:"account"`
Password string `json:"password"`
DevID string `json:"devID"`
Channel string `json:"channel"`
}
type resetPasswordBody struct {
AccountNo string `json:"accountNo"`
Email string `json:"email"`
NewPassword string `json:"newPassword"`
}
type updateProfileBody struct {
Avatar string `json:"avatar"`
Introduction string `json:"introduction"`
NickName string `json:"nickName"`
OldPassword string `json:"oldPassword"`
NewPassword string `json:"newPassword"`
PrivacyMode *bool `json:"privacyMode"`
}
// Register 代理上游注册,成功后写入登录 cookie。
func Register(c *gin.Context) {
var body registerBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "参数错误",
"data": nil,
})
return
}
body.AccountNo = strings.TrimSpace(body.AccountNo)
body.Email = strings.TrimSpace(body.Email)
body.AgentInviteCode = strings.TrimSpace(body.AgentInviteCode)
body.DevID = strings.TrimSpace(body.DevID)
body.Channel = strings.TrimSpace(body.Channel)
if body.AccountNo == "" || body.Password == "" {
c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "请填写账号和密码",
"data": nil,
})
return
}
// 上游 registerReq 仍要求 email;前端已去掉邮箱输入时,用账号生成唯一占位邮箱。
if body.Email == "" {
body.Email = body.AccountNo + "@qmdj.local"
}
env, user, err := authser.Register(c, authser.RegisterReq{
AccountNo: body.AccountNo,
Email: body.Email,
Password: body.Password,
AgentInviteCode: body.AgentInviteCode,
DevID: body.DevID,
Channel: body.Channel,
})
if err != nil {
log.Error("register upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "register failed",
"tip": "注册失败,请稍后重试",
"data": nil,
})
return
}
if env.Code != 200 || user == nil {
tip := strings.TrimSpace(env.Tip)
if tip == "" {
tip = strings.TrimSpace(env.Msg)
}
if tip == "" {
tip = "注册失败"
}
c.JSON(http.StatusOK, gin.H{
"code": env.Code,
"msg": env.Msg,
"tip": tip,
"data": nil,
})
return
}
authser.SetAuthCookies(c, user)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": env.Msg,
"tip": firstNonEmpty(env.Tip, "注册成功"),
"data": user,
})
}
// Login 代理上游登录,成功后写入登录 cookie。
func Login(c *gin.Context) {
var body loginBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "参数错误",
"data": nil,
})
return
}
body.Account = strings.TrimSpace(body.Account)
body.DevID = strings.TrimSpace(body.DevID)
body.Channel = strings.TrimSpace(body.Channel)
if body.Account == "" || body.Password == "" {
c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "请填写账号和密码",
"data": nil,
})
return
}
env, user, err := authser.Login(c, authser.LoginReq{
Account: body.Account,
Password: body.Password,
DevID: body.DevID,
Channel: body.Channel,
})
if err != nil {
log.Error("login upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "login failed",
"tip": "登录失败,请稍后重试",
"data": nil,
})
return
}
if env.Code != 200 || user == nil {
tip := strings.TrimSpace(env.Tip)
if tip == "" {
tip = strings.TrimSpace(env.Msg)
}
if tip == "" {
tip = "登录失败"
}
c.JSON(http.StatusOK, gin.H{
"code": env.Code,
"msg": env.Msg,
"tip": tip,
"data": nil,
})
return
}
authser.SetAuthCookies(c, user)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": env.Msg,
"tip": firstNonEmpty(env.Tip, "登录成功"),
"data": user,
})
}
// ResetPassword 代理上游找回密码接口。
func ResetPassword(c *gin.Context) {
var body resetPasswordBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 1001, "msg": "参数错误", "tip": "参数错误", "data": nil})
return
}
body.AccountNo = strings.TrimSpace(body.AccountNo)
body.Email = strings.TrimSpace(body.Email)
if body.AccountNo == "" || body.Email == "" || body.NewPassword == "" {
c.JSON(http.StatusOK, gin.H{"code": 1001, "msg": "参数错误", "tip": "请填写账号、邮箱和新密码", "data": nil})
return
}
env, err := authser.ResetPassword(c, authser.ResetPasswordReq{
AccountNo: body.AccountNo,
Email: body.Email,
NewPassword: body.NewPassword,
})
if err != nil {
log.Error("reset password upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{"code": 500, "msg": "reset password failed", "tip": "重置密码失败,请稍后重试", "data": nil})
return
}
tip := firstNonEmpty(env.Tip, env.Msg)
if env.Code == 200 {
tip = firstNonEmpty(tip, "密码重置成功")
} else {
tip = firstNonEmpty(tip, "密码重置失败")
}
c.JSON(http.StatusOK, gin.H{"code": env.Code, "msg": env.Msg, "tip": tip, "data": env.Data})
}
// Guest 代理上游游客登录,成功后写入登录 cookie。
// 对应 POST /api/app/auth/guest;需传 devID,上游要求 X-User-Agent(由 BFF 组装)。
func Guest(c *gin.Context) {
var body struct {
DevID string `json:"devID"`
DeviceID string `json:"deviceId"`
Mac string `json:"mac"`
Channel string `json:"channel"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "参数错误",
"data": nil,
})
return
}
body.DevID = strings.TrimSpace(body.DevID)
body.DeviceID = strings.TrimSpace(body.DeviceID)
body.Mac = strings.TrimSpace(body.Mac)
body.Channel = strings.TrimSpace(body.Channel)
if body.DevID == "" {
c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "缺少设备标识",
"data": nil,
})
return
}
if body.DeviceID == "" {
body.DeviceID = body.DevID
}
env, user, err := authser.GuestLogin(c, authser.GuestLoginReq{
DevID: body.DevID,
DeviceID: body.DeviceID,
Mac: body.Mac,
Channel: body.Channel,
})
if err != nil {
log.Error("guest login upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "guest login failed",
"tip": "游客登录失败,请稍后重试",
"data": nil,
})
return
}
if env.Code != 200 || user == nil {
tip := strings.TrimSpace(env.Tip)
if tip == "" {
tip = strings.TrimSpace(env.Msg)
}
if tip == "" {
tip = "游客登录失败"
}
c.JSON(http.StatusOK, gin.H{
"code": env.Code,
"msg": env.Msg,
"tip": tip,
"data": nil,
})
return
}
authser.SetAuthCookies(c, user)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": firstNonEmpty(env.Msg, "success"),
"tip": firstNonEmpty(env.Tip, "游客登录成功"),
"data": user,
})
}
// UpdateProfile 代理上游修改资料,成功后刷新 getInfo 并写 cookie。
func UpdateProfile(c *gin.Context) {
var body updateProfileBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "参数错误",
"data": nil,
})
return
}
body.Avatar = strings.TrimSpace(body.Avatar)
body.Introduction = strings.TrimSpace(body.Introduction)
body.NickName = strings.TrimSpace(body.NickName)
body.OldPassword = strings.TrimSpace(body.OldPassword)
body.NewPassword = strings.TrimSpace(body.NewPassword)
req := authser.UpdateProfileReq{
Avatar: body.Avatar,
Introduction: body.Introduction,
NickName: body.NickName,
OldPassword: body.OldPassword,
NewPassword: body.NewPassword,
PrivacyMode: body.PrivacyMode,
}
if req.Avatar == "" && req.Introduction == "" && req.NickName == "" && req.OldPassword == "" && req.NewPassword == "" && req.PrivacyMode == nil {
c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "请至少修改一项资料",
"data": nil,
})
return
}
if (req.OldPassword == "") != (req.NewPassword == "") {
c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "修改密码需同时填写旧密码和新密码",
"data": nil,
})
return
}
env, err := authser.UpdateProfile(c, req)
if err != nil {
log.Error("update profile upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "update profile failed",
"tip": "保存失败,请稍后重试",
"data": nil,
})
return
}
if env != nil && TryJSONSessionRecover(c, env.Code) {
env, err = authser.UpdateProfile(c, req)
if err != nil {
log.Error("update profile retry failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "update profile failed",
"tip": "保存失败,请稍后重试",
"data": nil,
})
return
}
}
if env == nil || env.Code != 200 {
tip := "保存失败"
msg := ""
code := 500
if env != nil {
code = env.Code
msg = env.Msg
tip = firstNonEmpty(env.Tip, env.Msg, tip)
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": msg,
"tip": tip,
"data": nil,
})
return
}
// 上游成功后拉最新资料写 cookie
_, user, infoErr := authser.GetInfo(c)
if infoErr != nil || user == nil {
log.Error("update profile getInfo failed", log.E(infoErr))
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": env.Msg,
"tip": firstNonEmpty(env.Tip, "保存成功"),
"data": nil,
})
return
}
authser.SetAuthCookies(c, user)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": env.Msg,
"tip": firstNonEmpty(env.Tip, "保存成功"),
"data": user,
})
}
// UploadImage 代理上游图片上传(头像不加 watermark)。
func UploadImage(c *gin.Context) {
fileHeader, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": "参数错误",
"tip": "请选择图片文件",
"data": nil,
})
return
}
f, err := fileHeader.Open()
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "open file failed",
"tip": "读取图片失败",
"data": nil,
})
return
}
defer f.Close()
resp, err := authser.UploadImage(c, fileHeader.Filename, f)
if err != nil {
log.Error("upload image upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "upload failed",
"tip": "上传失败,请稍后重试",
"data": nil,
})
return
}
if resp == nil || resp.Code != 200 || resp.Data == nil || strings.TrimSpace(resp.Data.SourceNameFs) == "" {
tip := "上传失败"
msg := ""
code := 500
if resp != nil {
code = resp.Code
msg = resp.Msg
tip = firstNonEmpty(resp.Tip, resp.Msg, tip)
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": msg,
"tip": tip,
"data": nil,
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": firstNonEmpty(resp.Msg, "success"),
"tip": firstNonEmpty(resp.Tip, "上传成功"),
"data": gin.H{
"id": resp.Data.ID,
"sourceNameFs": resp.Data.SourceNameFs,
"url": resp.Data.SourceNameFs,
},
})
}
// GetUserInfo 代理上游 GET /api/app/auth/getInfo。
func GetUserInfo(c *gin.Context) {
if useragent.TokenFromRequest(c.Request) == "" {
c.JSON(http.StatusOK, gin.H{
"code": 401,
"msg": "unauthorized",
"tip": "请先登录",
"data": nil,
})
return
}
env, user, err := authser.GetInfo(c)
if err != nil {
log.Error("getInfo upstream failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "getInfo failed",
"tip": "获取用户信息失败,请稍后重试",
"data": nil,
})
return
}
if env != nil && TryJSONSessionRecover(c, env.Code) {
env, user, err = authser.GetInfo(c)
if err != nil {
log.Error("getInfo retry failed", log.E(err))
c.JSON(http.StatusOK, gin.H{
"code": 500,
"msg": "getInfo failed",
"tip": "获取用户信息失败,请稍后重试",
"data": nil,
})
return
}
}
if env == nil || env.Code != 200 || user == nil {
tip := "获取用户信息失败"
msg := ""
code := 500
if env != nil {
code = env.Code
msg = env.Msg
tip = firstNonEmpty(env.Tip, env.Msg, tip)
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": msg,
"tip": tip,
"data": nil,
})
return
}
authser.SetAuthCookies(c, user)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": firstNonEmpty(env.Msg, "success"),
"tip": firstNonEmpty(env.Tip, "成功"),
"data": user,
})
}
func firstNonEmpty(values ...string) string {
for _, v := range values {
if strings.TrimSpace(v) != "" {
return v
}
}
return ""
}