diff --git a/server/initialize/router.go b/server/initialize/router.go index d04ced5b..3b856420 100644 --- a/server/initialize/router.go +++ b/server/initialize/router.go @@ -1,6 +1,12 @@ package initialize import ( + + //email "github.com/flipped-aurora/gva-plug-email" // 在线仓库模式 + "github.com/flipped-aurora/gin-vue-admin/server/plugin/email" // 本地插件仓库地址模式 + "github.com/flipped-aurora/gin-vue-admin/server/plugin/example_plugin" + "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify" + "net/http" _ "github.com/flipped-aurora/gin-vue-admin/server/docs" @@ -58,8 +64,27 @@ func Routers() *gin.Engine { // Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT. } + + // 添加开放权限的插件 示例 + PluginInit(PublicGroup, example_plugin.ExamplePlugin) + + // 钉钉通知,暂时开放权限 + PluginInit(PublicGroup, notify.CreateDDPlug()) + + // 添加跟角色挂钩权限的插件 示例 本地示例模式于在线仓库模式注意上方的import 可以自行切换 效果相同 + PluginInit(PrivateGroup, email.CreateEmailPlug( + global.GVA_CONFIG.Email.To, + global.GVA_CONFIG.Email.From, + global.GVA_CONFIG.Email.Host, + global.GVA_CONFIG.Email.Secret, + global.GVA_CONFIG.Email.Nickname, + global.GVA_CONFIG.Email.Port, + global.GVA_CONFIG.Email.IsSSL, + )) + InstallPlugin(PublicGroup, PrivateGroup) // 安装插件 + global.GVA_LOG.Info("router register success") return Router } diff --git a/server/plugin/notify/README.MD b/server/plugin/notify/README.MD new file mode 100644 index 00000000..b0b5cc19 --- /dev/null +++ b/server/plugin/notify/README.MD @@ -0,0 +1,38 @@ +## GVA 钉钉群通知插件 + +本插件用于向钉钉群推送消息 + +### 1. 使用场景 + +- 当服务运行异常时,可以向钉钉推送异常信息,便于及时发现解决问题 +- 推送一些关键业务的运行日志等 + +### 2. 配置说明 + +钉钉 token 等相关信息的获取,请参考 [钉钉官网](https://developers.dingtalk.com/document/robots/custom-robot-access?spm=ding_open_doc.document.0.0.7f8710afbfzduV#topic-2026027) + +在`plugin/notify/global/global.go` 文件中配置钉钉通知的URL ,Token 等 + +```go +var GlobalConfig_ = &config.DingDing{ + Url: "https://oapi.dingtalk.com/robot/send", + Token: "xxx", + Secret: "xxx", +} +``` +### 3. 使用说明 + +在代码中调用 `SendTextMessage` 方法即可 +```go +func NotifyController(c *gin.Context) { + if err := service.ServiceGroupApp.SendTextMessage("test"); err != nil { + global.GVA_LOG.Error("发送失败!", zap.Any("err", err)) + response.FailWithMessage("发送失败", c) + } else { + response.OkWithData("发送成功", c) + } +} + +``` +### 方法API + diff --git a/server/plugin/notify/api/api.go b/server/plugin/notify/api/api.go new file mode 100644 index 00000000..4874a814 --- /dev/null +++ b/server/plugin/notify/api/api.go @@ -0,0 +1,21 @@ +package api + +import ( + "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" + "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/service" + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type Api struct { +} + +func (s *Api) NotifyController(c *gin.Context) { + if err := service.ServiceGroupApp.SendTextMessage("test"); err != nil { + global.GVA_LOG.Error("发送失败!", zap.Any("err", err)) + response.FailWithMessage("发送失败", c) + } else { + response.OkWithData("发送成功", c) + } +} diff --git a/server/plugin/notify/api/enter.go b/server/plugin/notify/api/enter.go new file mode 100644 index 00000000..5fe286c1 --- /dev/null +++ b/server/plugin/notify/api/enter.go @@ -0,0 +1,7 @@ +package api + +type ApiGroup struct { + Api +} + +var ApiGroupApp = new(ApiGroup) diff --git a/server/plugin/notify/config/dingding.go b/server/plugin/notify/config/dingding.go new file mode 100644 index 00000000..9cf0d24d --- /dev/null +++ b/server/plugin/notify/config/dingding.go @@ -0,0 +1,7 @@ +package config + +type DingDing struct { + Url string `mapstructure:"url" json:"url" yaml:"url"` // Url + Token string `mapstructure:"token" json:"token" yaml:"token"` // Token + Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 +} diff --git a/server/plugin/notify/global/global.go b/server/plugin/notify/global/global.go new file mode 100644 index 00000000..376f7ef8 --- /dev/null +++ b/server/plugin/notify/global/global.go @@ -0,0 +1,9 @@ +package global + +import "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/config" + +var GlobalConfig_ = &config.DingDing{ + Url: "https://oapi.dingtalk.com/robot/send", + Token: "77d18293e221b3b7bdae7330d19a213c3cbb20fa07de5f4c273c0363ae475c34", + Secret: "SEC38425b7bd57c6bca9ce20611c41b437994ed65e0ddbd42e840ffa7a8c7da2106", +} diff --git a/server/plugin/notify/main.go b/server/plugin/notify/main.go new file mode 100644 index 00000000..5813b6ce --- /dev/null +++ b/server/plugin/notify/main.go @@ -0,0 +1,24 @@ +package notify + +import ( + "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/router" + "github.com/gin-gonic/gin" +) + +type ddPlugin struct { + Secret string + Token string + Url string +} + +func CreateDDPlug() *ddPlugin { + return &ddPlugin{} +} + +func (*ddPlugin) Register(group *gin.RouterGroup) { + router.RouterGroupApp.InitRouter(group) +} + +func (*ddPlugin) RouterPath() string { + return "notify" +} diff --git a/server/plugin/notify/router/enter.go b/server/plugin/notify/router/enter.go new file mode 100644 index 00000000..30aca42c --- /dev/null +++ b/server/plugin/notify/router/enter.go @@ -0,0 +1,7 @@ +package router + +type RouterGroup struct { + NotifyRouter +} + +var RouterGroupApp = new(RouterGroup) diff --git a/server/plugin/notify/router/router.go b/server/plugin/notify/router/router.go new file mode 100644 index 00000000..61842b5e --- /dev/null +++ b/server/plugin/notify/router/router.go @@ -0,0 +1,18 @@ +package router + +import ( + "github.com/flipped-aurora/gin-vue-admin/server/middleware" + "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/api" + "github.com/gin-gonic/gin" +) + +type NotifyRouter struct { +} + +func (s *NotifyRouter) InitRouter(Router *gin.RouterGroup) { + router := Router.Use(middleware.OperationRecord()) + var Controller = api.ApiGroupApp.Api.NotifyController + { + router.POST("dingding", Controller) + } +} diff --git a/server/plugin/notify/service/enter.go b/server/plugin/notify/service/enter.go new file mode 100644 index 00000000..0eb00088 --- /dev/null +++ b/server/plugin/notify/service/enter.go @@ -0,0 +1,7 @@ +package service + +type ServiceGroup struct { + NotifyService +} + +var ServiceGroupApp = new(ServiceGroup) diff --git a/server/plugin/notify/service/notify.go b/server/plugin/notify/service/notify.go new file mode 100644 index 00000000..e21508d1 --- /dev/null +++ b/server/plugin/notify/service/notify.go @@ -0,0 +1,106 @@ +package service + +import ( + "bytes" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/global" + "io/ioutil" + "net/http" + "net/url" + "time" +) + +type NotifyService struct { +} + +//@author: [Espoir](https://github.com/nightsimon) +//@function: NotifyController +//@description: 钉钉通知测试 +//@return: err error + +func (e *NotifyService) SendTextMessage(content string) (err error) { + msg := map[string]interface{}{ + "msgtype": "text", + "text": map[string]string{ + "content": content, + }, + //"at": map[string]interface{}{ + // "atMobiles": atMobiles, + // "isAtAll": isAtAll, + //}, + } + return SendMessage(msg) +} + +func SendMessage(msg interface{}) error { + body := bytes.NewBuffer(nil) + err := json.NewEncoder(body).Encode(msg) + if err != nil { + return fmt.Errorf("msg json failed, msg: %v, err: %v", msg, err.Error()) + } + + value := url.Values{} + value.Set("access_token", global.GlobalConfig_.Token) + if global.GlobalConfig_.Secret != "" { + t := time.Now().UnixNano() / 1e6 + value.Set("timestamp", fmt.Sprintf("%d", t)) + value.Set("sign", sign(t, global.GlobalConfig_.Secret)) + } + + request, err := http.NewRequest(http.MethodPost, global.GlobalConfig_.Url, body) + if err != nil { + return fmt.Errorf("error request: %v", err.Error()) + } + request.URL.RawQuery = value.Encode() + request.Header.Add("Content-Type", "application/json") + res, err := (&http.Client{}).Do(request) + if err != nil { + return fmt.Errorf("send dingTalk message failed, error: %v", err.Error()) + } + defer func() { _ = res.Body.Close() }() + result, err := ioutil.ReadAll(res.Body) + + if res.StatusCode != 200 { + return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, "http code is not 200")) + } + if err != nil { + return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, err.Error())) + } + + type response struct { + ErrCode int `json:"errcode"` + } + var ret response + + if err := json.Unmarshal(result, &ret); err != nil { + return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, err.Error())) + } + + if ret.ErrCode != 0 { + return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, "errcode is not 0")) + } + + return nil +} + +func httpError(request *http.Request, response *http.Response, body []byte, error string) string { + return fmt.Sprintf( + "http request failure, error: %s, status code: %d, %s %s, body:\n%s", + error, + response.StatusCode, + request.Method, + request.URL.String(), + string(body), + ) +} +func sign(t int64, secret string) string { + strToHash := fmt.Sprintf("%d\n%s", t, secret) + hmac256 := hmac.New(sha256.New, []byte(secret)) + hmac256.Write([]byte(strToHash)) + data := hmac256.Sum(nil) + return base64.StdEncoding.EncodeToString(data) +} diff --git a/server/plugin/notify/utils/utils.go b/server/plugin/notify/utils/utils.go new file mode 100644 index 00000000..d4b585bf --- /dev/null +++ b/server/plugin/notify/utils/utils.go @@ -0,0 +1 @@ +package utils