package handler import ( "StuAcaWorksAI/dao" "StuAcaWorksAI/proto" "StuAcaWorksAI/service" "StuAcaWorksAI/service/spark" "StuAcaWorksAI/worker" "encoding/base64" "encoding/json" "fmt" "github.com/gin-gonic/gin" "io" "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) toolGroup.GET("/qq_auth", GetQQAuthUrl) toolGroup.GET("/github_auth", GetGithubAuthUrl) toolGroup.GET("/get_auth_url", GetThirdPartyAuthUrl) toolGroup.GET("/github_callback", handleGithubCallback) toolGroup.GET("/gitee_callback", handleGiteeCallback) toolGroup.GET("/third_party_callback", handleThirdPartyCallback) //统一处理第三方登录回调 toolGroup.POST("/loginRedirect", LoginRedirect) //发送邮件 toolGroup.POST("/send_mail", SendMailTool) toolGroup.POST("/dashboard", DashBoardStatistics) toolGroup.POST("/spark_ppt_theme_list", GetSparkPPTThemeList) toolGroup.POST("/spark_create_outline", CreateSparkPPTSOutline) toolGroup.POST("/spark_create_ppt", CreateSparkPPT) 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"` } func GetQQAuthUrl(c *gin.Context) { //query uuid := c.Query("uuid") hType := c.Query("type") var resp proto.GenerateResp if uuid == "" || hType == "" { resp.Code = proto.ParameterError 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) params.Add("state", "saw_"+hType+"_"+uuid) str := fmt.Sprintf("%s", params.Encode()) loginURL := fmt.Sprintf("%s?%s", "https://graph.qq.com/oauth2.0/authorize", str) //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"}) } } 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) } } } c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp}) return } func GetSparkPPTThemeList(c *gin.Context) { //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 //获取主题列表 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() } else { themeList, err = spark.SparkPPTThemeList(&modelParam, req) themeListStr, _ := json.Marshal(themeList) worker.SetRedis("spark_ppt_theme_list", string(themeListStr)) //调试阶段不设置过期 } if err != nil { 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) { 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 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) { 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} base.SessionID = req.SessionID pptresp, err2 := spark.SparkDoCreatePPTByOutline(&req, &base) if err2 != nil { 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 } } func GetSparkCreatePPTStatus(c *gin.Context) { id, _ := c.Get("id") userID := int(id.(float64)) 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) if status == "" { c.JSON(http.StatusOK, gin.H{"code": proto.GetSparkCreatePPTStatusFailed, "message": "status is null", "data": nil}) 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 } } 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) 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) } 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 { 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) } } } resp.Code = 0 resp.Message = "success" c.JSON(http.StatusOK, resp) c.Redirect(http.StatusFound, "https://sv.ljsea.top/") //重定向到登录页面 } func GetGithubAuthUrl(c *gin.Context) { uuid := c.Query("uuid") hType := c.Query("type") //操作类型add,login var resp proto.GenerateResp if uuid == "" || hType == "" { resp.Code = proto.ParameterError resp.Message = "uuid or type is empty" c.JSON(http.StatusOK, resp) 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) } } 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") if token == "" { token = c.Query("token") } if token == "" { resp.Code = proto.ParameterError resp.Message = "token is empty" c.JSON(http.StatusOK, resp) return } userID, err := service.DecodeJWTToken(token) if err != nil { resp.Code = proto.ParameterError resp.Message = err.Error() 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()) 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) params.Add("redirect_uri", "https://pm.ljsea.top/tool/gitee_callback") baseUri := proto.GiteeAuthorizeBaseUrl respUrl = fmt.Sprintf("%s?%s", baseUri, params.Encode()) case "google": params := url.Values{} params.Add("client_id", worker.GoogleClientID) params.Add("response_type", "code") params.Add("redirect_uri", "https://pm.ljsea.top/tool/third_party_callback") params.Add("scope", "https://www.googleapis.com/auth/drive.metadata.readonly+https://www.googleapis.com/auth/calendar.readonly") params.Add("state", stateBase64Str) } resp.Message = "success" resp.Code = proto.SuccessCode resp.Data = respUrl 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 } 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) } else { service.DoThirdPartyCallBack(&state, code) } } 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 { 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) }