Merge branch 'refs/heads/feat-cid'

This commit is contained in:
junleea 2025-03-27 11:19:25 +08:00
commit 2cb9909697
8 changed files with 184 additions and 10 deletions

View File

@ -20,6 +20,7 @@ type CIDRunLog struct {
CID_id int `gorm:"column:cid_id"` CID_id int `gorm:"column:cid_id"`
Auth_id int `form:"column:auth_id"` Auth_id int `form:"column:auth_id"`
Script string `gorm:"column:script"` Script string `gorm:"column:script"`
RunTime float64 `gorm:"column:run_time"`
Log string `gorm:"column:log"` Log string `gorm:"column:log"`
Error string `gorm:"column:error"` Error string `gorm:"column:error"`
} }
@ -75,8 +76,8 @@ func UpdateCIDByID(id, auth_id, time int, name, url, script, token string) bool
} }
// CreateRunLog,添加执行日志 // CreateRunLog,添加执行日志
func CreateRunLog(cid_id, auth_id int, script, log, err string) uint { func CreateRunLog(cid_id, auth_id int, script, log, err string, runtime float64) uint {
cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err, Script: script} cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err, Script: script, RunTime: runtime}
result := DB.Create(&cidRunLog) result := DB.Create(&cidRunLog)
if result != nil { if result != nil {
fmt.Println(err) fmt.Println(err)

View File

@ -8,6 +8,7 @@ import (
"os/exec" "os/exec"
"strconv" "strconv"
"strings" "strings"
"time"
"videoplayer/dao" "videoplayer/dao"
"videoplayer/proto" "videoplayer/proto"
"videoplayer/worker" "videoplayer/worker"
@ -221,6 +222,7 @@ func RunShell(username, url, script string, id, authID int) {
echo "start" echo "start"
` + script + ` ` + script + `
echo "end"` echo "end"`
start := time.Now()
//执行脚本 //执行脚本
cmd := exec.Command("/bin/bash", "-c", scriptContent) cmd := exec.Command("/bin/bash", "-c", scriptContent)
// 使用bytes.Buffer捕获输出 // 使用bytes.Buffer捕获输出
@ -231,8 +233,9 @@ echo "end"`
if err3 != nil { if err3 != nil {
err3_info = err3.Error() err3_info = err3.Error()
} }
elapsed := time.Since(start)
//fmt.Println("bash content:", scriptContent) //fmt.Println("bash content:", scriptContent)
dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info) //添加执行日志 dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info, elapsed.Seconds()) //添加执行日志
} }
// 定时任务处理逻辑 // 定时任务处理逻辑

View File

@ -75,6 +75,15 @@ func SetDeviceStatusV2(c *gin.Context) {
for _, v := range devices { for _, v := range devices {
if v == req.ID { if v == req.ID {
// 继续处理请求 // 继续处理请求
//是否是暂停之后第一次上线,如果是则发送邮件通知
device_status := worker.GetRedis("monitor_" + req.ID)
isExist := worker.IsContainKey("monitor_" + req.ID)
if device_status == "2" || !isExist {
//发送邮件通知
title := "设备上线"
content := "设备上线\n设备:" + req.ID + "\t状态:" + req.Status + "\t时间" + time.Now().String()
go SendMail(title, content)
}
worker.SetRedisWithExpire("monitor_"+req.ID, "1", time.Second*300) worker.SetRedisWithExpire("monitor_"+req.ID, "1", time.Second*300)
c.JSON(200, gin.H{"code": 0, "message": "success"}) c.JSON(200, gin.H{"code": 0, "message": "success"})
return return
@ -322,7 +331,7 @@ func ScanDeviceStatus() {
for _, v := range devices { for _, v := range devices {
c := worker.IsContainKey("monitor_" + v) c := worker.IsContainKey("monitor_" + v)
if c == false { if c == false {
worker.SetRedisWithExpire("monitor_"+v, "1", time.Hour*24) worker.SetRedisWithExpire("monitor_"+v, "2", time.Hour*24)
offline += v + "," offline += v + ","
} }
} }

View File

@ -28,6 +28,7 @@ func SetUpUserGroup(router *gin.Engine) {
userGroup.POST("/update", UpdateUserInfo) userGroup.POST("/update", UpdateUserInfo)
userGroup.POST("/sync", GetSyncUserInfo) userGroup.POST("/sync", GetSyncUserInfo)
userGroup.POST("/delete", DeleteUser) userGroup.POST("/delete", DeleteUser)
userGroup.POST("/reset", ResetPassword)
} }
type RLReq struct { type RLReq struct {
@ -415,3 +416,110 @@ func GetSyncUserInfo(c *gin.Context) {
return 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
}
}

View File

@ -9,7 +9,7 @@ import (
var Config ConfigStruct var Config ConfigStruct
var SigningKey = []byte{} var SigningKey = []byte{}
var Url_map = map[string]bool{"/login": true, "/register": true, "/uuid": true, "/gqr": true, "/cid/callback": true, "/tool/monitor": true, "/user/sync": true, "/tool/file/": true} // 不需要token验证的url var Url_map = map[string]bool{"/login": true, "/register": true, "/uuid": true, "/gqr": true, "/cid/callback": true, "/tool/monitor": true, "/user/sync": true, "/tool/file/": true, "/user/reset": true} // 不需要token验证的url
var Per_menu_map = map[string]int{"/video/": 1, "/device/": 2, "/cid/": 3} var Per_menu_map = map[string]int{"/video/": 1, "/device/": 2, "/cid/": 3}
var File_Type = map[string]int{"im": 1, "avatar": 2, "file": 3, "config": 4} // 文件类型 var File_Type = map[string]int{"im": 1, "avatar": 2, "file": 3, "config": 4} // 文件类型
const ( const (

View File

@ -110,3 +110,10 @@ type UpdateShellRespV2 struct {
ID uint `json:"id" form:"id"` ID uint `json:"id" form:"id"`
Status int `json:"status" form:"status"` Status int `json:"status" form:"status"`
} }
type ResponseOAuth struct {
ID uint `json:"id" form:"id"`
Name string `json:"name" form:"name"`
Email string `json:"email" form:"email"`
Token string `json:"token" form:"token"`
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/golang-jwt/jwt"
"regexp" "regexp"
"strconv" "strconv"
"time" "time"
@ -367,3 +368,35 @@ func ConfirmSyncUserData(device string, data proto.UserSyncConfirm) error {
} }
return err return err
} }
// 生成新的token存入redis返回信息
func CreateTokenAndSave(user dao.User) (string, error) {
var tokenString string
var err error
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 {
return "", err
}
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
}
// 返回令牌
return tokenString, err
}

13
worker/tool.go Normal file
View File

@ -0,0 +1,13 @@
package worker
import "math/rand"
func GetRandomString(l int) string {
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
var result []byte
for i := 0; i < l; i++ {
result = append(result, bytes[rand.Intn(len(bytes))])
}
return string(result)
}