saw-go/handler/tool.go

875 lines
27 KiB
Go
Raw Normal View History

package handler
import (
"StuAcaWorksAI/dao"
"StuAcaWorksAI/proto"
"StuAcaWorksAI/service"
2025-04-03 13:35:48 +08:00
"StuAcaWorksAI/service/spark"
"StuAcaWorksAI/worker"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io"
2025-04-05 13:24:39 +08:00
"log"
"net/http"
"net/url"
"os"
"strconv"
"time"
)
type SetRedisReq struct {
Option string `json:"option" form:"option"`
Key string `json:"key" form:"key"`
Value string `json:"value" form:"value"`
Expire int `json:"expire" form:"expire"`
}
type SetDeviceStatusReq struct {
ID string `json:"id" form:"id"` //设备编码
Status string `json:"status" form:"status"` //设备状态
}
type GetFileListReq struct {
Type string `json:"type" form:"type"` //请求类型1按md5查询2按文件名查询;3:查询待删除文件
Md5 string `json:"md5" form:"md5"`
}
type SendMailReq struct {
Title string `json:"title" form:"title"`
Content string `json:"content" form:"content"`
To string `json:"to" form:"to"`
}
func SetUpToolGroup(router *gin.Engine) {
toolGroup := router.Group("/tool")
toolGroup.POST("/set_redis", SetRedis)
toolGroup.POST("/get_redis", GetRedis)
//文件上传、下载
toolGroup.POST("/upload", UploadFile)
toolGroup.GET("/download", DownloadFile)
toolGroup.GET("/file/:filename", GetFile)
toolGroup.POST("/file_list", GetFileList)
//文件管理
toolGroup.POST("/file_del", DelFile)
//服务器、设备状态接口
toolGroup.POST("/monitor", SetDeviceStatusV2)
toolGroup.POST("/qq_callback", handleQQCallback)
2025-04-26 11:14:30 +08:00
toolGroup.GET("/qq_auth", GetQQAuthUrl)
toolGroup.GET("/github_auth", GetGithubAuthUrl)
toolGroup.GET("/get_auth_url", GetThirdPartyAuthUrl)
toolGroup.GET("/github_callback", handleGithubCallback)
2025-04-28 13:14:51 +08:00
toolGroup.GET("/gitee_callback", handleGiteeCallback)
2025-04-28 14:32:51 +08:00
toolGroup.GET("/third_party_callback", handleThirdPartyCallback) //统一处理第三方登录回调
2025-04-26 11:40:19 +08:00
toolGroup.POST("/loginRedirect", LoginRedirect)
//发送邮件
toolGroup.POST("/send_mail", SendMailTool)
2025-03-31 15:36:34 +08:00
toolGroup.POST("/dashboard", DashBoardStatistics)
toolGroup.POST("/spark_ppt_theme_list", GetSparkPPTThemeList)
toolGroup.POST("/spark_create_outline", CreateSparkPPTSOutline)
toolGroup.POST("/spark_create_ppt", CreateSparkPPT)
2025-04-03 16:25:18 +08:00
toolGroup.POST("/spark_ppt_create_status", GetSparkCreatePPTStatus)
//国外服务器处理请求
toolGroup.POST("/online_server_request", HandleOnlineServerRequest)
}
func SetDeviceStatusV2(c *gin.Context) {
// TODO
var req SetDeviceStatusReq
if err := c.ShouldBind(&req); err != nil {
c.JSON(200, gin.H{"code": 400, "message": "参数错误"})
return
} else {
token := c.Request.Header.Get("token")
if token == "" {
c.JSON(200, gin.H{"code": 401, "message": "token为空"})
return
}
devices := worker.GetRedisSetMembers(token)
if len(devices) == 0 {
c.JSON(200, gin.H{"code": 402, "message": "设备为空"})
return
}
for _, v := range devices {
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)
c.JSON(200, gin.H{"code": 0, "message": "success"})
return
}
}
c.JSON(200, gin.H{"code": 402, "message": "设备不存在"})
}
}
type QQCallbackReq struct {
Code string `json:"code" form:"code"`
State string `json:"state" form:"state"`
}
2025-04-26 11:03:34 +08:00
func GetQQAuthUrl(c *gin.Context) {
//query
uuid := c.Query("uuid")
2025-04-26 11:24:46 +08:00
hType := c.Query("type")
2025-04-26 11:03:34 +08:00
var resp proto.GenerateResp
2025-04-26 11:24:46 +08:00
if uuid == "" || hType == "" {
resp.Code = proto.ParameterError
2025-04-26 11:24:46 +08:00
resp.Message = "uuid or hType is empty"
c.JSON(http.StatusOK, resp)
return
}
params := url.Values{}
params.Add("response_type", "code")
params.Add("client_id", worker.AppId)
2025-04-26 11:24:46 +08:00
params.Add("state", "saw_"+hType+"_"+uuid)
2025-04-26 11:40:19 +08:00
str := fmt.Sprintf("%s", params.Encode())
loginURL := fmt.Sprintf("%s?%s", "https://graph.qq.com/oauth2.0/authorize", str)
2025-04-26 11:03:34 +08:00
//c.Redirect(http.StatusFound, loginURL) //重定向到QQ登录页面
resp.Message = "success"
resp.Code = proto.SuccessCode
resp.Data = loginURL
c.JSON(http.StatusOK, resp)
}
func handleQQCallback(c *gin.Context) {
var resp proto.GenerateResp
resp.Code = 0
var req QQCallbackReq
//query参数
if err := c.ShouldBindQuery(&req); err != nil {
resp.Code = 1
resp.Message = "参数错误"
c.JSON(http.StatusOK, resp)
return
} else {
}
c.JSON(http.StatusOK, resp)
}
func GetFileList(c *gin.Context) {
//解析请求参数
var req GetFileListReq
if err := c.ShouldBind(&req); err == nil {
if req.Type == "1" {
//按md5查询
if req.Md5 == "" {
c.JSON(http.StatusOK, gin.H{"error": "md5 is empty", "code": proto.ParameterError, "message": "failed"})
return
}
file := dao.FindFileByMd5(req.Md5)
if file.ID == 0 {
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
return
}
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file})
}
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
func DelFile(c *gin.Context) {
//先查看是否有权限
id, _ := c.Get("id")
id1 := int(id.(float64))
file_id, _ := strconv.Atoi(c.PostForm("id"))
file_ := dao.FindFileByID(file_id, id1)
if file_.ID == 0 {
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
return
}
//删除文件
err := os.Remove(file_.FilePath + "/" + file_.FileStoreName)
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": "delete file failed", "code": proto.DeleteFileFailed, "message": "failed"})
return
}
//删除文件信息
if res := dao.DeleteFileById(file_id); !res {
c.JSON(http.StatusOK, gin.H{"error": "delete file info failed", "code": proto.DeleteFileInfoFailed, "message": "failed"})
return
}
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
}
func GetFile(c *gin.Context) {
//先查看是否有权限
filename := c.Param("filename")
if filename == "" {
c.JSON(http.StatusOK, gin.H{"error": "filename is empty", "code": proto.ParameterError, "message": "failed"})
return
}
//查询文件信息
file := dao.FindFileByName(filename)
if file.ID == 0 {
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
return
}
//下载文件
if file.NeedAuth == false {
c.File(file.FilePath + "/" + file.FileStoreName)
} else {
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "file must auth", "data": "file must auth"})
}
}
func UploadFile(c *gin.Context) {
//先查看是否有权限
id, _ := c.Get("id")
id1 := int(id.(float64))
//从请求头获取upload_type
uploadType := c.PostForm("upload_type")
authType := c.PostForm("auth_type")
md5_ := c.PostForm("md5")
if uploadType == "" {
c.JSON(http.StatusOK, gin.H{"error": "upload_type is empty", "code": proto.ParameterError, "message": "failed"})
return
}
user := dao.FindUserByUserID(id1)
if user.Upload == false {
c.JSON(http.StatusOK, gin.H{"error": "no upload Permissions", "code": proto.NoUploadPermissions, "message": "failed"})
return
}
//上传文件
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": "upload file failed", "code": proto.UploadFileFailed, "message": "failed"})
return
}
//计算文件md5值
if md5_ == "" {
file_, _ := file.Open()
md5_ = service.CalculateFileMd5(file_)
if md5_ == "" {
c.JSON(http.StatusOK, gin.H{"error": "计算文件MD5值失败", "code": proto.UploadFileFailed, "message": "failed"})
return
}
}
//查询文件是否已存在
fileExist := dao.FindFileByMd5(md5_)
if fileExist.ID != 0 {
fileExist.FilePath = ""
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileExist})
return
}
//保存文件
filePath, fileStoreName, err := service.SaveFile(c, file, uploadType)
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": "save file failed", "code": proto.SaveFileFailed, "message": "failed"})
return
}
//保存文件信息
fileSize := int(file.Size)
fileName := file.Filename
fileType := file.Header.Get("file_type")
var auth_type_ bool
if authType == "public" || authType == "" {
auth_type_ = false
} else if authType == "private" {
auth_type_ = true
}
file_record := dao.CreateFile(fileStoreName, fileName, fileType, filePath, md5_, fileSize, id1, auth_type_)
if file_record.ID == 0 {
c.JSON(http.StatusOK, gin.H{"error": "save file info failed", "code": proto.SaveFileInfoFailed, "message": "failed"})
return
}
file_record.FilePath = ""
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file_record})
}
func DownloadFile(c *gin.Context) {
//参数
//filename := c.Param("filename")
file_id, _ := strconv.Atoi(c.Query("id"))
id, _ := c.Get("id")
//查询文件信息
//file := dao.FindFileByNames(file_id, int(id.(float64)))
file_ := dao.FindFileByID(file_id, int(id.(float64)))
if file_.ID == 0 {
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
return
}
//下载文件
// 打开文件
file, err := os.Open(file_.FilePath + "/" + file_.FileStoreName)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error", "message": "Failed to open file"})
return
}
defer file.Close()
// 设置响应头
c.Writer.Header().Set("Content-Type", "application/octet-stream")
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", file_.FileName))
// 发送文件内容
_, err = io.Copy(c.Writer, file)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error", "message": "Failed to send file"})
return
}
c.Status(http.StatusOK)
}
func SetRedis(c *gin.Context) {
//先查看是否有权限
id, _ := c.Get("id")
id1 := int(id.(float64))
user := dao.FindUserByUserID(id1)
if user.Redis == false {
c.JSON(http.StatusOK, gin.H{"error": "no redis Permissions", "code": proto.NoRedisPermissions, "message": "failed"})
return
}
//解析请求参数
var req SetRedisReq
if err := c.ShouldBind(&req); err == nil {
var code int
var message string
if req.Option == "list" {
code, message = service.SetToolRedisList(req.Key, req.Value, req.Expire)
} else if req.Option == "set" {
code, message = service.SetToolRedisSet(req.Key, req.Value, req.Expire)
} else if req.Option == "kv" {
code, message = service.SetToolRedisKV(req.Key, req.Value, req.Expire)
}
c.JSON(http.StatusOK, gin.H{"code": code, "message": message})
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
func GetRedis(c *gin.Context) {
//先查看是否有权限
id, _ := c.Get("id")
id1 := int(id.(float64))
user := dao.FindUserByUserID(id1)
if user.Redis == false {
c.JSON(http.StatusOK, gin.H{"error": "no redis Permissions", "code": proto.NoRedisPermissions, "message": "failed"})
return
}
//解析请求参数
var req SetRedisReq
if err := c.ShouldBind(&req); err == nil {
if req.Option == "one" {
code, message := service.GetToolRedis(req.Key)
req.Value = message
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": req})
} else if req.Option == "all" {
code, message, data := service.GetAllRedis()
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": data})
}
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
// 服务器、设备状态扫描
func ScanDeviceStatus() {
// TODO
// 检查设备状态
// 如果设备状态异常, 则发送邮件通知
devices := worker.GetRedisSetMembers("627gyf3488h")
offline := ""
for _, v := range devices {
c := worker.IsContainKey("monitor_" + v)
if c == false {
worker.SetRedisWithExpire("monitor_"+v, "2", time.Hour*24)
offline += v + ","
}
}
if offline != "" {
title := "设备状态异常"
content := "设备状态异常\n设备: " + offline + "\t时间" + time.Now().String()
go SendMail(title, content)
}
}
func SendMail(title, content string) {
//捕获异常
defer func() {
if err := recover(); err != nil {
fmt.Errorf("tool send mail error: %s", err)
}
}()
// TODO
// 发送邮件
// 邮件内容
// 邮件标题
// 收件人
// 发送邮件
// 发送邮件通知
// 发送邮件通知
var em worker.MyEmail
em.SmtpPassword = "nihzazdkmucnbhid"
em.SmtpHost = "pop.qq.com:587"
em.SmtpUserName = "354425203@qq.com"
em.SmtpPort = 587
em.ImapPort = 993
err := em.Send(title, content, []string{"3236990479@qq.com", "lijun@ljsea.top"})
if err != nil {
fmt.Println(err)
}
}
func SendMailTool(c *gin.Context) {
id, _ := c.Get("id")
id1 := int(id.(float64))
var req SendMailReq
if err := c.ShouldBind(&req); err == nil {
user := dao.FindUserByUserID(id1)
if user.ID == 0 {
c.JSON(http.StatusOK, gin.H{"error": "user not found", "code": proto.ParameterError, "message": "failed"})
return
}
//目标邮箱地址是否合法
if !service.CheckEmail(req.To) {
c.JSON(http.StatusOK, gin.H{"error": "email address is invalid", "code": proto.ParameterError, "message": "failed"})
return
}
if req.Title == "" || req.Content == "" {
c.JSON(http.StatusOK, gin.H{"error": "title or content is empty", "code": proto.ParameterError, "message": "failed"})
return
}
//发送邮件
if user.Role == "admin" {
go service.SendEmail(req.To, req.Title, req.Content)
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": "mail will be sent"})
} else {
c.JSON(http.StatusOK, gin.H{"error": "no send mail permission", "code": proto.PermissionDenied, "message": "failed"})
}
} else {
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
}
}
2025-03-31 15:36:34 +08:00
func DashBoardStatistics(c *gin.Context) {
//用户统计信息
var resp proto.DashBoardStatisticsResp
key := "dashboard_statistics_info"
if worker.IsContainKey(key) {
//从redis获取
dashboardStatisticsInfo := worker.GetRedis(key)
if dashboardStatisticsInfo != "" {
err := json.Unmarshal([]byte(dashboardStatisticsInfo), &resp)
if err != nil {
log.Println("get redis dashboard statistics info error:", err)
}
}
} else {
service.SetDashboardInfoToRedis() //统计dashboard信息保存在redis中
dashboardStatisticsInfo := worker.GetRedis(key)
if dashboardStatisticsInfo != "" {
err := json.Unmarshal([]byte(dashboardStatisticsInfo), &resp)
if err != nil {
log.Println("get redis dashboard statistics info error:", err)
}
}
}
2025-03-31 15:36:34 +08:00
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
return
}
func GetSparkPPTThemeList(c *gin.Context) {
2025-04-05 13:33:23 +08:00
//id, _ := c.Get("id")
//userID := int(id.(float64))
var req proto.GetSparkPPTThemeReq
if err := c.ShouldBind(&req); err == nil {
if req.Style == "" || req.Color == "" || req.Industry == "" {
c.JSON(http.StatusOK, gin.H{"error": "parameter error,request parameter is null", "code": proto.ParameterError, "message": "failed"})
return
}
var modelParam proto.ModelParam
//获取模型
models, funcs, mferr := service.FindFuncModelListByFunctionV2(req.Function)
if mferr != nil {
c.JSON(http.StatusOK, gin.H{"error": "function not exist", "code": proto.ParameterError, "message": "failed"})
return
}
if len(funcs) == 0 || len(models) == 0 {
c.JSON(http.StatusOK, gin.H{"error": "function or model not exist", "code": proto.ParameterError, "message": "failed"})
return
}
model := models[0]
err = json.Unmarshal([]byte(model.Parameter), &modelParam)
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": "model parameter decode error", "code": proto.ParameterError, "message": "failed"})
return
}
modelParam.Url = model.Url
modelParam.System = funcs[0].Info //系统功能
var themeList proto.SparkPPTThemeListResponse
//获取主题列表
2025-04-03 19:50:39 +08:00
if worker.IsContainKey("spark_ppt_theme_list") {
//themeListStr := worker.GetRedis("spark_ppt_theme_list")
//if themeListStr != "" {
// err = json.Unmarshal([]byte(themeListStr), &themeList)
// if err != nil {
// log.Println("get redis spark ppt theme list error:", err)
// }
//}
themeList = spark.TestPPTTHemeList()
2025-04-03 19:50:39 +08:00
} else {
themeList, err = spark.SparkPPTThemeList(&modelParam, req)
themeListStr, _ := json.Marshal(themeList)
worker.SetRedis("spark_ppt_theme_list", string(themeListStr)) //调试阶段不设置过期
}
if err != nil {
2025-04-03 13:35:48 +08:00
c.JSON(http.StatusOK, gin.H{"error": "get spark ppt theme list error", "code": proto.ParameterError, "message": "failed"})
return
}
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": themeList})
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
func CreateSparkPPTSOutline(c *gin.Context) {
2025-04-05 13:33:23 +08:00
id, _ := c.Get("id")
userID := int(id.(float64))
var req proto.SparkCreateOutlineRequest
if err := c.ShouldBind(&req); err == nil {
if req.Function == "" || req.Query == "" {
c.JSON(http.StatusOK, gin.H{"error": "function or query is empty", "code": proto.ParameterError, "message": "failed"})
return
}
if req.FileUrl != "" && req.FileName == "" {
c.JSON(http.StatusOK, gin.H{"error": "file name is empty", "code": proto.ParameterError, "message": "failed"})
return
}
err3 := service.CheckUserCreatePPTSessionPermission(userID)
if err3 != nil {
c.JSON(http.StatusOK, gin.H{"error": "user create ppt session permission error", "code": proto.ParameterError, "message": err3.Error()})
return
}
var base proto.SparkCreatePPTBaseInfo
base.UserID = userID
2025-04-05 13:24:39 +08:00
log.Println("create outline user id:", userID)
outlineResp, err2 := spark.SparkDoCreateOutline(&req, &base)
if err2 != nil {
c.JSON(http.StatusOK, gin.H{"error": "create outline error", "code": proto.ParameterError, "message": "failed"})
return
}
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": outlineResp, "base": base})
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
func CreateSparkPPT(c *gin.Context) {
2025-04-05 13:33:23 +08:00
id, _ := c.Get("id")
userID := int(id.(float64))
var req proto.SparkCreatePPTByOutlineUserRequest
if err := c.ShouldBind(&req); err == nil {
if req.Function == "" || req.Query == "" {
c.JSON(http.StatusOK, gin.H{"error": "function or query is empty", "code": proto.ParameterError, "message": "failed"})
return
}
base := proto.SparkCreatePPTBaseInfo{UserID: userID}
2025-04-04 18:35:01 +08:00
base.SessionID = req.SessionID
pptresp, err2 := spark.SparkDoCreatePPTByOutline(&req, &base)
if err2 != nil {
2025-04-04 18:36:34 +08:00
c.JSON(http.StatusOK, gin.H{"error": "create ppt error:" + err2.Error(), "code": proto.ParameterError, "message": "failed"})
return
} else {
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": pptresp})
return
}
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
2025-04-03 16:25:18 +08:00
func GetSparkCreatePPTStatus(c *gin.Context) {
2025-04-05 13:33:23 +08:00
id, _ := c.Get("id")
userID := int(id.(float64))
2025-04-03 16:25:18 +08:00
var req proto.GetSparkCreatePPTStatusReq
if err := c.ShouldBind(&req); err == nil {
//查看该会话是否属于该用户
session := dao.FindSessionByID(req.SessionID)
if session.ID == 0 || session.UserID != userID {
c.JSON(http.StatusOK, gin.H{"error": "session not found or session is not the user", "code": proto.ParameterError, "message": "failed"})
return
}
//从redis获取
key := fmt.Sprintf("user-%d-session-%d-create-pptx", userID, req.SessionID)
status := worker.GetRedis(key)
log.Println("get redis key:", key, "\t,status:", status)
2025-04-03 16:25:18 +08:00
if status == "" {
c.JSON(http.StatusOK, gin.H{"code": proto.GetSparkCreatePPTStatusFailed, "message": "status is null", "data": nil})
2025-04-03 16:25:18 +08:00
return
}
var resp proto.SparkCreatePPTByOutlineResponse
err2 := json.Unmarshal([]byte(status), &resp)
if err2 != nil {
c.JSON(http.StatusOK, gin.H{"error": "get redis error", "code": proto.ParameterError, "message": "failed"})
return
}
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
} else {
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
return
}
}
2025-04-26 10:40:08 +08:00
func handleGithubCallback(c *gin.Context) {
var resp proto.GenerateResp
code := c.Query("code") //code
stateBase64Str := c.Query("state") //state
//解析base64
decodedBytes, err := base64.StdEncoding.DecodeString(stateBase64Str)
if err != nil {
fmt.Println("Decoding error:", err)
} else {
decodedStr := string(decodedBytes)
//json解析
var state proto.ThirdPartyLoginState
err = json.Unmarshal([]byte(decodedStr), &state)
2025-04-27 10:00:19 +08:00
log.Println("handle github callback state:", decodedStr, "\tcode:", code)
if err != nil {
log.Println("json unmarshal error:", err)
}
service.DoGithubCallBack(&state, code)
}
resp.Code = 0
resp.Message = "success"
c.JSON(http.StatusOK, resp)
2025-04-26 10:40:08 +08:00
}
2025-04-28 13:14:51 +08:00
func handleGiteeCallback(c *gin.Context) {
var resp proto.GenerateResp
code := c.Query("code") //code
stateBase64Str := c.Query("state") //state
//解析base64
decodedBytes, err := base64.StdEncoding.DecodeString(stateBase64Str)
if err != nil {
fmt.Println("Decoding error:", err)
} else {
2025-04-28 18:31:21 +08:00
if code == "" || stateBase64Str == "" {
log.Println("code or state is empty")
} else {
decodedStr := string(decodedBytes)
//json解析
var state proto.ThirdPartyLoginState
err = json.Unmarshal([]byte(decodedStr), &state)
if err != nil {
log.Println("json unmarshal error:", err)
} else {
log.Println("handle github callback state:", decodedStr, "\tcode:", code)
service.DoGiteeCallBack(&state, code)
}
2025-04-28 13:14:51 +08:00
}
}
resp.Code = 0
resp.Message = "success"
c.JSON(http.StatusOK, resp)
2025-04-28 18:31:21 +08:00
c.Redirect(http.StatusFound, "https://sv.ljsea.top/") //重定向到登录页面
2025-04-28 13:14:51 +08:00
}
func GetGithubAuthUrl(c *gin.Context) {
2025-04-26 10:40:08 +08:00
uuid := c.Query("uuid")
2025-04-26 11:24:46 +08:00
hType := c.Query("type") //操作类型add,login
2025-04-26 11:03:34 +08:00
var resp proto.GenerateResp
2025-04-26 11:24:46 +08:00
if uuid == "" || hType == "" {
2025-04-26 11:03:34 +08:00
resp.Code = proto.ParameterError
2025-04-26 11:24:46 +08:00
resp.Message = "uuid or type is empty"
2025-04-26 11:03:34 +08:00
c.JSON(http.StatusOK, resp)
2025-04-26 10:40:08 +08:00
return
} else {
var state proto.ThirdPartyLoginState
state.UUID = uuid
state.Type = hType
state.Platform = "github"
state.Project = "saw"
stateStr, _ := json.Marshal(state)
//base64编码
stateBase64Str := base64.StdEncoding.EncodeToString(stateStr)
params := url.Values{}
params.Add("client_id", proto.Config.GITHUB_CLIENT_ID)
params.Add("login", uuid)
params.Add("state", stateBase64Str)
baseUri := "https://github.com/login/oauth/authorize"
redirectUrl := fmt.Sprintf("%s?%s", baseUri, params.Encode())
//c.Redirect(http.StatusFound, redirectUrl)
resp.Message = "success"
resp.Code = proto.SuccessCode
resp.Data = redirectUrl
c.JSON(http.StatusOK, resp)
2025-04-26 10:40:08 +08:00
}
2025-04-26 11:03:34 +08:00
2025-04-26 10:40:08 +08:00
}
2025-04-26 11:40:19 +08:00
func LoginRedirect(c *gin.Context) {
c.Redirect(http.StatusFound, "https://sv.ljsea.top/") //重定向到登录页面
}
func GetThirdPartyAuthUrl(c *gin.Context) {
platform := c.Query("platform")
uuid := c.Query("uuid")
hType := c.Query("type") //操作类型add,login
var resp proto.GenerateResp
if platform == "" || uuid == "" || hType == "" {
resp.Code = proto.ParameterError
resp.Message = "platform or uuid is empty"
c.JSON(http.StatusOK, resp)
return
}
var state proto.ThirdPartyLoginState
state.UUID = uuid
state.Type = hType
state.Platform = platform
state.Project = "SAW"
if hType == "add" {
//查看是否已经绑定
token := c.Request.Header.Get("token")
2025-04-27 10:57:54 +08:00
if token == "" {
token = c.Query("token")
}
if token == "" {
resp.Code = proto.ParameterError
resp.Message = "token is empty"
2025-04-27 10:57:54 +08:00
c.JSON(http.StatusOK, resp)
return
}
userID, err := service.DecodeJWTToken(token)
if err != nil {
resp.Code = proto.ParameterError
resp.Message = err.Error()
2025-04-27 10:57:54 +08:00
c.JSON(http.StatusOK, resp)
return
}
//需要将uuid绑定在该用户上
worker.SetRedisWithExpire("user_add_platform_"+uuid, strconv.Itoa(userID), time.Minute*9)
state.UserID = userID
}
stateStr, _ := json.Marshal(state)
var respUrl string
//base64编码
stateBase64Str := base64.StdEncoding.EncodeToString(stateStr)
switch platform {
case "qq":
params := url.Values{}
params.Add("response_type", "code")
params.Add("client_id", worker.AppId)
params.Add("state", stateBase64Str)
str := fmt.Sprintf("%s", params.Encode())
respUrl = fmt.Sprintf("%s?%s", proto.QQAuthorizeBaseUrl, str)
case "github":
params := url.Values{}
params.Add("client_id", proto.Config.GITHUB_CLIENT_ID)
params.Add("login", uuid)
params.Add("state", stateBase64Str)
baseUri := proto.GitHuAuthorizeBaseUrl
respUrl = fmt.Sprintf("%s?%s", baseUri, params.Encode())
2025-04-28 13:14:51 +08:00
case "gitee":
params := url.Values{}
params.Add("client_id", proto.Config.GITEE_CLIENT_ID)
//response_type=code
params.Add("response_type", "code")
params.Add("state", stateBase64Str)
2025-04-28 13:19:53 +08:00
params.Add("redirect_uri", "https://pm.ljsea.top/tool/gitee_callback")
2025-04-28 13:14:51 +08:00
baseUri := proto.GiteeAuthorizeBaseUrl
respUrl = fmt.Sprintf("%s?%s", baseUri, params.Encode())
2025-04-28 21:16:35 +08:00
case "google":
params := url.Values{}
params.Add("client_id", worker.GoogleClientID)
2025-04-30 14:37:36 +08:00
params.Add("response_type", "token") //直接返回token
2025-04-28 21:16:35 +08:00
params.Add("redirect_uri", "https://pm.ljsea.top/tool/third_party_callback")
2025-04-30 14:37:36 +08:00
params.Add("scope", "https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+openid")
2025-04-28 21:16:35 +08:00
params.Add("state", stateBase64Str)
}
resp.Message = "success"
resp.Code = proto.SuccessCode
resp.Data = respUrl
2025-04-27 10:14:21 +08:00
c.JSON(http.StatusOK, resp)
}
type GetThirdPartyAddAuthUrlReq struct {
Platform string `json:"platform" form:"platform"`
Uuid string `json:"uuid" form:"uuid"`
HType string `json:"type" form:"type"` //操作类型add,login
//Platform string `json:"platform" form:"platform"` //操作类型add,login
}
2025-04-28 14:32:51 +08:00
func handleThirdPartyCallback(c *gin.Context) {
var resp proto.GenerateResp
code := c.Query("code") //code
stateBase64Str := c.Query("state") //state
//解析base64
decodedBytes, err := base64.StdEncoding.DecodeString(stateBase64Str)
if err != nil {
fmt.Println("Decoding error:", err)
} else {
decodedStr := string(decodedBytes)
//json解析
var state proto.ThirdPartyLoginState
err = json.Unmarshal([]byte(decodedStr), &state)
log.Println("handle github callback state:", decodedStr, "\tcode:", code)
if err != nil {
log.Println("json unmarshal error:", err)
2025-04-28 21:16:35 +08:00
} else {
2025-04-30 14:37:36 +08:00
service.DoThirdPartyCallBack(c, &state, code)
2025-04-28 14:32:51 +08:00
}
}
resp.Code = 0
resp.Message = "success"
c.JSON(http.StatusOK, resp)
}
func HandleOnlineServerRequest(c *gin.Context) {
var req proto.OnlineServerReq
var resp proto.GenerateResp
if err := c.ShouldBind(&req); err == nil {
2025-04-29 11:35:43 +08:00
log.Println("handle online server request:", req)
respData, err2 := service.DoRequestToForeignServer(&req)
if err2 != nil {
resp.Code = proto.OperationFailed
resp.Message = err2.Error()
} else {
resp.Code = proto.SuccessCode
resp.Message = "success"
resp.Data = respData
}
} else {
resp.Code = proto.ParameterError
resp.Message = "参数错误"
}
c.JSON(http.StatusOK, resp)
}