videoplayer/handler/user.go

526 lines
19 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/google/uuid"
"time"
"videoplayer/dao"
"videoplayer/proto"
"videoplayer/service"
"videoplayer/worker"
)
func SetUpUserGroup(router *gin.Engine) {
userGroup := router.Group("/user")
userGroup.POST("/register", registerHandler)
userGroup.POST("/login", loginHandler)
userGroup.POST("/uuid", GetScanUUID)
userGroup.POST("/gqr", GetQRStatus)
userGroup.POST("/sqr", SetQRStatus)
userGroup.POST("/confirm", ConfirmQRLogin)
userGroup.POST("/search", SearchHandler)
userGroup.POST("/info", GetUserInfo)
userGroup.POST("/update", UpdateUserInfo)
userGroup.POST("/sync", GetSyncUserInfo)
userGroup.POST("/delete", DeleteUser)
userGroup.POST("/reset", ResetPassword)
}
type RLReq struct {
User string `json:"username" form:"username"`
Email string `json:"email" form:"email"`
Password string `json:"password" form:"password"`
Age int `json:"age" form:"age"`
Gender string `json:"gender" form:"gender"`
}
type QRReq struct {
UUID string `json:"uuid" form:"uuid"`
Address string `json:"address" form:"address"`
IP string `json:"ip" form:"ip"`
}
type SearchReq struct {
Keyword string `json:"keyword" form:"keyword"`
ID int `json:"id" form:"id"`
}
type GetUserInfoReq struct {
ID int `json:"id" form:"id"`
}
func GetUserInfo(c *gin.Context) {
var req_data GetUserInfoReq
id, _ := c.Get("id")
user_id := int(id.(float64))
if err := c.ShouldBind(&req_data); err == nil {
var user dao.User
if req_data.ID == user_id {
user = dao.FindUserByID2(user_id)
user.Password = "" //不返回密码
} else {
//判断当前用户是否有权限查看
cur_user := dao.FindUserByID2(user_id)
if cur_user.Role == "admin" {
user = dao.FindUserByID2(req_data.ID)
user.Password = "" //不返回密码
} else {
c.JSON(200, gin.H{"code": proto.PermissionDenied, "message": "无权查看", "data": "2"})
return
}
}
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": user})
} else {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
return
}
}
func DeleteUser(c *gin.Context) {
var req GetUserInfoReq
id, _ := c.Get("id")
user_id := int(id.(float64))
if err := c.ShouldBind(&req); err == nil {
res := service.DeleteUserService(req.ID, user_id)
if res != 0 {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
} else {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed", "data": res})
}
} else {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
return
}
}
func UpdateUserInfo(c *gin.Context) {
var req_data proto.UpdateUserInfoReq
id, _ := c.Get("id")
user_id := int(id.(float64))
if err := c.ShouldBind(&req_data); err == nil {
rid, err2 := service.UpdateUser(user_id, req_data)
if err2 != nil {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed", "data": "2"})
return
}
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": rid})
} else {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
return
}
}
func GetScanUUID(c *gin.Context) {
var ReqData QRReq
if err := c.ShouldBind(&ReqData); err != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "2"})
return
}
data := map[string]interface{}{"status": "0", "address": ReqData.Address, "ip": c.ClientIP()}
jsonData, err := json.Marshal(data)
if err != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "2"})
return
}
id := uuid.New()
res := worker.SetRedisWithExpire(id.String(), string(jsonData), time.Minute*30)
if res {
var retrievedData map[string]interface{}
if err2 := json.Unmarshal([]byte(worker.GetRedis(id.String())), &retrievedData); err2 != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
return
}
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": retrievedData, "data": id.String()})
} else {
c.JSON(200, gin.H{"code": proto.RedisSetError, "message": "qr code invalid", "data": "1"})
}
}
func SetQRStatus(c *gin.Context) {
var qrsetReq QRReq
if err := c.ShouldBind(&qrsetReq); err == nil && qrsetReq.UUID != "" {
if worker.IsContainKey(qrsetReq.UUID) == false {
c.JSON(200, gin.H{"code": proto.UUIDNotFound, "message": "uuid not found in server", "data": "0"})
return
}
var retrievedData map[string]interface{}
if err2 := json.Unmarshal([]byte(worker.GetRedis(qrsetReq.UUID)), &retrievedData); err2 != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
return
}
retrievedData["status"] = "1"
jsonData, err2 := json.Marshal(retrievedData)
if err2 != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
return
}
res := worker.SetRedisWithExpire(qrsetReq.UUID, string(jsonData), time.Minute*30)
if res {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": retrievedData})
} else {
c.JSON(200, gin.H{"code": proto.RedisSetError, "message": "qr code invalid", "data": "1"})
}
} else {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "2"})
}
}
// 确认返回token数据
func ConfirmQRLogin(c *gin.Context) {
var qrsetReq QRReq
if err := c.ShouldBind(&qrsetReq); err == nil && qrsetReq.UUID != "" {
//user_id, _ := c.Get("id")
user_name, _ := c.Get("username")
if user_name != "" {
key := "user_" + user_name.(string)
token := worker.GetRedis(key)
if token == "" {
c.JSON(200, gin.H{"code": proto.RedisGetError, "message": "Token不存在", "data": "20"})
}
if worker.IsContainKey(qrsetReq.UUID) == false {
c.JSON(200, gin.H{"code": proto.UUIDNotFound, "message": "uuid not found in server", "data": "0"})
return
}
var retrievedData map[string]interface{}
if err2 := json.Unmarshal([]byte(worker.GetRedis(qrsetReq.UUID)), &retrievedData); err2 != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
return
}
retrievedData["status"] = token
jsonData, err2 := json.Marshal(retrievedData)
if err2 != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
return
}
if worker.SetRedisWithExpire(qrsetReq.UUID, string(jsonData), time.Minute*10) {
c.JSON(200, gin.H{"code": 0, "message": "success", "data": "0"})
} else {
c.JSON(200, gin.H{"code": proto.RedisSetError, "message": "设置Token失败", "data": "8"})
}
} else {
c.JSON(200, gin.H{"code": proto.RedisGetError, "message": "failed", "data": "20"})
}
} else {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "3"})
}
}
func GetQRStatus(c *gin.Context) {
var qrReq QRReq
if err := c.ShouldBind(&qrReq); err == nil {
var retrievedData map[string]interface{}
if err2 := json.Unmarshal([]byte(worker.GetRedis(qrReq.UUID)), &retrievedData); err2 != nil {
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
return
}
str := retrievedData["status"].(string)
switch str {
case "":
c.JSON(200, gin.H{"code": proto.UUIDNotFound, "message": "uuid not found", "data": "0"}) //空值
case "0":
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "0"}) //空值
case "1":
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "1"}) //已扫描待确认
default:
// 解析 JWT 令牌
token, err := jwt.Parse(str, func(token *jwt.Token) (interface{}, error) {
return proto.SigningKey, nil
})
if err != nil {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenParseError, "message": "error"})
return
}
// 返回令牌
data := make(map[string]interface{})
data["id"] = token.Claims.(jwt.MapClaims)["id"]
data["username"] = token.Claims.(jwt.MapClaims)["username"]
data["email"] = token.Claims.(jwt.MapClaims)["email"]
data["token"] = str
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data}) //确认返回token数据
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.DeviceRestartFailed, "message": "error"})
}
}
func SearchHandler(c *gin.Context) {
var req_data SearchReq
if err := c.ShouldBind(&req_data); err == nil {
if req_data.ID != -1 {
user := service.GetUserByID(req_data.ID)
group := service.GetGroupByID(req_data.ID)
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": user, "group": group})
return
} else if req_data.Keyword != "" {
users := service.GetUserByNameLike(req_data.Keyword)
groups := service.GetGroupByNameLike(req_data.Keyword)
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": users, "group": groups})
return
} else {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "无ID 与 关键字"})
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
}
}
func loginHandler(c *gin.Context) {
var req_data RLReq
tokenString := ""
if err := c.ShouldBind(&req_data); err == nil {
if len(req_data.Password) != 32 {
hasher := md5.New()
hasher.Write([]byte(req_data.Password)) // 生成密码的 MD5 散列值
req_data.Password = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
}
user := service.GetUser(req_data.User, req_data.Password, req_data.Password)
if user.ID != 0 {
key := "user_" + user.Name
redis_token := worker.GetRedis(string(key))
if redis_token == "" {
// 生成 JWT 令牌
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"username": user.Name,
"id": user.ID,
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 10小时后过期
})
tokenString, err = token.SignedString(proto.SigningKey)
if err != nil {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenGenerationError, "message": "error"})
return
}
worker.SetRedisWithExpire("user_"+user.Name, tokenString, time.Hour*10) // 将用户信息存入
worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*10) // 设置过期时间为10分钟
data := make(map[string]interface{})
data["id"] = user.ID
data["username"] = user.Name
data["email"] = user.Email
worker.SetHash(tokenString, data) // 将用户信息存入
} else {
tokenString = redis_token
}
// 返回令牌
data := make(map[string]interface{})
data["id"] = user.ID
data["username"] = user.Name
data["email"] = user.Email
data["token"] = tokenString
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
} else {
//用户名或密码错误
c.JSON(200, gin.H{"error": "用户名或密码错误", "code": proto.UsernameOrPasswordError, "message": "error"})
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.DeviceRestartFailed, "message": "error"})
}
}
func registerHandler(c *gin.Context) {
var req_data RLReq
tokenString := ""
var id uint
if err := c.ShouldBind(&req_data); err == nil {
if len(req_data.Password) != 32 {
hasher := md5.New()
hasher.Write([]byte(req_data.Password)) // 生成密码的 MD5 散列值
req_data.Password = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
}
if service.ContainsUser(req_data.User, req_data.Email) == true {
c.JSON(200, gin.H{"error": "user already exists", "code": proto.UsernameExists, "message": "error"})
return
}
id = service.CreateUser(req_data.User, req_data.Password, req_data.Email, req_data.Gender, req_data.Age)
if id == 0 {
c.JSON(200, gin.H{"error": "create user error", "code": proto.OperationFailed, "message": "error"})
return
}
// 生成 JWT 令牌
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"username": req_data.User,
"id": id,
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 1分钟后过期
})
tokenString, err = token.SignedString(proto.SigningKey)
if err != nil {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenGenerationError, "message": "error"})
return
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
return
}
fmt.Println(req_data)
res := worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*10) // 设置过期时间为10分钟
if !res {
c.JSON(200, gin.H{"error": "set token error", "code": proto.RedisSetError, "message": "error"})
return
}
// 返回令牌
data := make(map[string]interface{})
data["id"] = id
data["username"] = req_data.User
data["email"] = req_data.Email
data["token"] = tokenString
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
return
}
func GetSyncUserInfo(c *gin.Context) {
var req_data proto.SyncUserReq
if err := c.ShouldBind(&req_data); err == nil {
if req_data.Token == "" {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "token is empty"})
return
} else {
if worker.IsContainSet("super_permission_tokens", req_data.Token) {
if proto.Config.SERVER_USER_TYPE == "master" {
if req_data.Types == 1 { //1为全量同步
add_users := dao.GetAllUser()
resp := dao.UserSyncResp{}
resp.Add = add_users
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
} else if req_data.Types == 2 { //2为增量同步
if req_data.Device == "" || worker.IsContainSet("sync_devices_ids", req_data.Device) == false {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "device is empty or not exist"})
return
}
res := service.GetUserSyncData(req_data.Device)
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
} else if req_data.Types == 3 { //3为确认同步数据
res := service.ConfirmSyncUserData(req_data.Device, req_data.Confirm)
if res == nil {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
} else {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed:" + res.Error(), "data": "failed"})
}
} else {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "type is error", "data": dao.UserSyncResp{}})
}
} else {
c.JSON(200, gin.H{"code": proto.NoPermission, "message": "no permission,server is not master", "data": proto.UserSync{}})
}
} else {
c.JSON(200, gin.H{"code": proto.NoPermission, "message": "error", "data": "no permission"})
return
}
}
} else {
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
return
}
}
type ResetPasswordReq struct {
Email string `json:"email" form:"email"`
OldPassword string `json:"old_password" form:"old_password"`
NewPassword string `json:"new_password" form:"new_password"`
Type int `json:"type" form:"type"` //0获取验证码,2为邮箱验证码重置密码1为旧密码重置密码
Code string `json:"code" form:"code"` //验证码
}
func ResetPassword(c *gin.Context) {
var req_data ResetPasswordReq
if err := c.ShouldBind(&req_data); err == nil {
if req_data.Type == 0 {
//获取验证码
//查看是否存在该邮箱
user := dao.FindUserByEmail(req_data.Email)
if user.ID == 0 {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
return
}
if worker.IsContainKey("reset_password_" + req_data.Email) {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "验证码已发送请5分钟后再试", "data": "2"})
return
}
//随机字符串验证码大写
code := worker.GetRandomString(6)
worker.SetRedisWithExpire("reset_password_"+req_data.Email, code, time.Minute*5) //设置5分钟过期`
//发送邮件
service.SendEmail(req_data.Email, "大学生学业作品AI生成工具开发重置密码", "验证码:"+code+" ,请在5分钟内使用!")
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "2"})
return
} else if req_data.Type == 1 {
//旧密码重置密码
if len(req_data.OldPassword) != 32 {
hasher := md5.New()
hasher.Write([]byte(req_data.OldPassword)) // 生成密码的 MD5 散列值
req_data.OldPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
}
if len(req_data.NewPassword) != 32 {
hasher := md5.New()
hasher.Write([]byte(req_data.NewPassword)) // 生成密码的 MD5 散列值
req_data.NewPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
}
user := dao.FindUserByEmail(req_data.Email)
if user.ID == 0 {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
return
}
if user.Password != req_data.OldPassword {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "旧密码错误", "data": "2"})
return
}
if user.Password == req_data.NewPassword {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "新旧密码相同", "data": "2"})
return
}
dao.UpdateUserByID(int(user.ID), user.Name, req_data.NewPassword, user.Email)
var resp proto.ResponseOAuth
token, err2 := service.CreateTokenAndSave(user)
if err2 != nil {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "new token error", "data": resp})
return
}
resp.Token = token
resp.ID = user.ID
resp.Name = user.Name
resp.Email = user.Email
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
} else if req_data.Type == 2 {
//邮箱重置密码
if len(req_data.NewPassword) != 32 {
hasher := md5.New()
hasher.Write([]byte(req_data.NewPassword)) // 生成密码的 MD5 散列值
req_data.NewPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
}
user := dao.FindUserByEmail(req_data.Email)
if user.ID == 0 {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
return
}
code := worker.GetRedis("reset_password_" + req_data.Email)
if code != req_data.Code {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "验证码错误", "data": "2"})
return
}
dao.UpdateUserByID(int(user.ID), user.Name, req_data.NewPassword, user.Email)
token, err2 := service.CreateTokenAndSave(user)
if err2 != nil {
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "new token error", "data": "2"})
return
}
var resp proto.ResponseOAuth
resp.Token = token
resp.ID = user.ID
resp.Name = user.Name
resp.Email = user.Email
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
} else {
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "type error", "data": "2"})
return
}
} else {
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
return
}
}