From cf47b1241a2f97291fbe41c82b975aa13f969ea2 Mon Sep 17 00:00:00 2001 From: chenyifan01 Date: Thu, 21 Jul 2022 11:51:50 +0800 Subject: [PATCH] #2479 add wechat template msg --- modules/auth/wechat/client.go | 50 +++++++++++++++ modules/auth/wechat/template.go | 110 ++++++++++++++++++++++++++++++++ modules/setting/setting.go | 4 ++ routers/repo/cloudbrain.go | 2 +- 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 modules/auth/wechat/template.go diff --git a/modules/auth/wechat/client.go b/modules/auth/wechat/client.go index 9ed4b543f..e137c123f 100644 --- a/modules/auth/wechat/client.go +++ b/modules/auth/wechat/client.go @@ -4,6 +4,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "encoding/json" + "errors" "fmt" "github.com/go-resty/resty/v2" "strconv" @@ -19,6 +20,7 @@ const ( ACCESS_TOKEN_PATH = "/cgi-bin/token" QR_CODE_PATH = "/cgi-bin/qrcode/create" GET_MATERIAL_PATH = "/cgi-bin/material/batchget_material" + SEND_TEMPLATE_PATH = "/cgi-bin/message/template/send" ACTION_QR_STR_SCENE = "QR_STR_SCENE" ERR_CODE_ACCESSTOKEN_EXPIRE = 42001 @@ -41,12 +43,33 @@ type QRCodeRequest struct { Action_info ActionInfo `json:"action_info"` Expire_seconds int `json:"expire_seconds"` } + type MaterialRequest struct { Type string `json:"type"` Offset int `json:"offset"` Count int `json:"count"` } +type TemplateMsgRequest struct { + ToUser string `json:"touser"` + TemplateId string `json:"template_id"` + Url string `json:"url"` + ClientMsgId string `json:"client_msg_id"` + Data interface{} `json:"data"` +} +type TemplateValue struct { + Value string `json:"value"` + Color string `json:"color"` +} + +type CloudbrainTaskData struct { + First TemplateValue `json:"first"` + Keyword1 TemplateValue `json:"keyword1"` + Keyword2 TemplateValue `json:"keyword2"` + Keyword3 TemplateValue `json:"keyword3"` + Remark TemplateValue `json:"remark"` +} + type ActionInfo struct { Scene Scene `json:"scene"` } @@ -161,3 +184,30 @@ func getErrorCodeFromResponse(r *resty.Response) int { c, _ := strconv.Atoi(fmt.Sprint(code)) return c } + +func sendTemplateMsg(req TemplateMsgRequest) (error, bool) { + client := getWechatRestyClient() + + bodyJson, _ := json.Marshal(req) + r, err := client.R(). + SetHeader("Content-Type", "application/json"). + SetQueryParam("access_token", GetWechatAccessToken()). + SetBody(bodyJson). + Post(setting.WechatApiHost + SEND_TEMPLATE_PATH) + if err != nil { + log.Error("sendTemplateMsg,e=%v", err) + return nil, false + } + a := r.Body() + resultMap := make(map[string]interface{}, 0) + json.Unmarshal(a, &resultMap) + errcode := resultMap["errcode"] + log.Info("sendTemplateMsg,%v", r) + if errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_EXPIRE) || errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_INVALID) { + return nil, true + } + if errcode != "" { + return errors.New(fmt.Sprintf("sendTemplateMsg error[%s]", errcode)), false + } + return nil, false +} diff --git a/modules/auth/wechat/template.go b/modules/auth/wechat/template.go new file mode 100644 index 000000000..157f0d92f --- /dev/null +++ b/modules/auth/wechat/template.go @@ -0,0 +1,110 @@ +package wechat + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "errors" + "fmt" + "time" +) + +type JobOperateType string + +const ( + JobOperateTypeStart JobOperateType = "start" + JobOperateTypeStop JobOperateType = "stop" + JobOperateTypeFailed JobOperateType = "failed" +) + +func SendCloudbrainTemplateMsg(operateType JobOperateType, cloudbrain models.Cloudbrain, date time.Time) error { + openId := models.GetUserWechatOpenId(cloudbrain.UserID) + if openId == "" { + return errors.New("Wechat openId not exist") + } + data := CloudbrainTaskData{ + First: TemplateValue{Value: getCloudbrainTemplateTitle(operateType)}, + Keyword1: TemplateValue{Value: cloudbrain.DisplayJobName}, + Keyword2: TemplateValue{Value: getJobTypeDisplayName(cloudbrain.JobType)}, + Keyword3: TemplateValue{Value: date.Format("2006-01-02 15:04:05")}, + Remark: TemplateValue{Value: cloudbrain.DisplayJobName}, + } + req := TemplateMsgRequest{ + ToUser: openId, + TemplateId: setting.CloudbrainTemplateId, + Url: getCloudbrainTemplateUrl(cloudbrain), + ClientMsgId: string(operateType) + "_" + fmt.Sprint(cloudbrain.ID), + Data: data, + } + err, retryFlag := sendTemplateMsg(req) + if retryFlag { + log.Info("retrySendCloudbrainTemplateMsg calling") + refreshAccessToken() + err, _ = sendTemplateMsg(req) + if err != nil { + log.Error("SendCloudbrainTemplateMsg err. %v", err) + return err + } + return nil + } + if err != nil { + log.Error("SendCloudbrainTemplateMsg err. %v", err) + return err + } + return nil +} + +func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain) string { + url := setting.AppURL + + switch cloudbrain.JobType { + case string(models.JobTypeDebug): + if cloudbrain.ComputeResource == "CPU/GPU" { + url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID) + } else { + url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID) + } + case string(models.JobTypeBenchmark): + url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID) + case string(models.JobTypeTrain): + if cloudbrain.Type == models.TypeCloudBrainOne { + url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID) + } else if cloudbrain.Type == models.TypeCloudBrainTwo { + url += "/modelarts/train-job" + fmt.Sprint(cloudbrain.JobID) + } else if cloudbrain.Type == models.TypeC2Net { + url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID) + } + case string(models.JobTypeInference): + url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID) + } + return url +} + +func getCloudbrainTemplateTitle(operateType JobOperateType) string { + var title string + switch operateType { + case JobOperateTypeStart: + title = "您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。" + case JobOperateTypeFailed: + title = "您好,您提交的任务启动失败,您可以通过日志查看失败原因。" + case JobOperateTypeStop: + title = "您好,您提交的任务已运行结束。" + } + + return title + +} + +func getJobTypeDisplayName(jobType string) string { + switch jobType { + case string(models.JobTypeDebug): + return "调试任务" + case string(models.JobTypeBenchmark): + return "评测任务" + case string(models.JobTypeTrain): + return "训练任务" + case string(models.JobTypeInference): + return "推理任务" + } + return "" +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6ec54fdff..c0c5c715f 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -582,6 +582,9 @@ var ( TreePathOfAutoMsgReply string TreePathOfSubscribe string + //wechat template msg config + CloudbrainTemplateId string + //nginx proxy PROXYURL string RadarMap = struct { @@ -1440,6 +1443,7 @@ func NewContext() { RefNameOfWechatReply = sec.Key("AUTO_REPLY_REF_NAME").MustString("master") TreePathOfAutoMsgReply = sec.Key("AUTO_REPLY_TREE_PATH").MustString("wechat/auto_reply.json") TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json") + CloudbrainTemplateId = sec.Key("CLOUDBRAIN_TEMPLATE_ID").MustString("4qtOaImiFnzIrzLxxP99lYc12EYxvtAE1fNqd7fcihw") SetRadarMapConfig() diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index bee70965d..59ee08278 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -373,7 +373,6 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { } } - func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBrainInferencForm) { ctx.Data["PageIsCloudBrain"] = true displayJobName := form.DisplayJobName @@ -494,6 +493,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/inference-job") } + /** 检查用户传输的参数是否符合专属资源池 */