diff --git a/.idea/bug-notify.iml b/.idea/bug-notify.iml index 7ee078d..5e764c4 100644 --- a/.idea/bug-notify.iml +++ b/.idea/bug-notify.iml @@ -1,4 +1,9 @@ - + + + + + + \ No newline at end of file diff --git a/api/dingdingapi.go b/api/dingdingapi.go index 65f59fe..e85b499 100644 --- a/api/dingdingapi.go +++ b/api/dingdingapi.go @@ -27,7 +27,7 @@ func SendMessage(data model.SendMsg) error { } msg["msgtype"] = data.MsgType - if data.MsgType == "markdowny" { + if data.MsgType == "markdown" { msg[data.MsgType] = map[string]interface{}{ "title": "bug", "text": data.Content, @@ -36,7 +36,7 @@ func SendMessage(data model.SendMsg) error { msg[data.MsgType] = map[string]interface{}{ "title": "bug", "text": data.Content, - "singleTitle": "bug地址", + "singleTitle": "问题详情", "singleURL": data.Url, } } diff --git a/bug-notify.log b/bug-notify.log index e7663b8..b4f0dbd 100644 --- a/bug-notify.log +++ b/bug-notify.log @@ -425,3 +425,64 @@ {"level":"INFO","time":"2024-09-09T20:11:45.486+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} {"level":"INFO","time":"2024-09-09T20:13:23.430+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} {"level":"INFO","time":"2024-09-09T20:15:43.275+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:30:20.728+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"ERROR","time":"2024-09-09T20:31:48.536+0800","caller":"handle/notify-handle.go:181","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"ERROR","time":"2024-09-09T20:31:48.750+0800","caller":"handle/notify-handle.go:233","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"ERROR","time":"2024-09-09T20:31:48.954+0800","caller":"handle/notify-handle.go:233","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"ERROR","time":"2024-09-09T20:31:49.137+0800","caller":"handle/notify-handle.go:233","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"ERROR","time":"2024-09-09T20:31:49.323+0800","caller":"handle/notify-handle.go:233","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"ERROR","time":"2024-09-09T20:31:49.548+0800","caller":"handle/notify-handle.go:233","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"ERROR","time":"2024-09-09T20:33:27.025+0800","caller":"handle/notify-handle.go:233","msg":"消息发送失败:","error":"msgtype is null"} +{"level":"INFO","time":"2024-09-09T20:38:50.660+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:40:01.518+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:41:19.819+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:41:25.215+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:41:36.669+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:49:08.124+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:49:44.468+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:51:06.837+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:51:51.779+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T20:55:19.085+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:00:09.301+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:01:30.810+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:49:34.335+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:51:17.466+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:52:06.239+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:53:05.467+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-09T21:53:53.605+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:09:52.775+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:20:38.129+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:33:00.089+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:33:26.627+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:33:34.859+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:34:26.030+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:38:58.590+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:39:30.496+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:44:04.854+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:45:00.407+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T10:58:33.482+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:00:16.315+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:02:57.248+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"ERROR","time":"2024-09-10T11:02:57.471+0800","caller":"handle/notify-handle.go:148","msg":"消息发送失败:","error":"description: 不支持类型 msgType:marksown ;solution:请使用支持的类型;link:请参考本接口对应文档查看支持的消息类型,或者在https://open.dingtalk.com/document/ 搜索对应文档;"} +{"level":"INFO","time":"2024-09-10T11:04:01.229+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:09:38.876+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:09:58.098+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:10:21.970+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:10:47.040+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:11:01.147+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:11:11.236+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:11:28.041+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:11:35.287+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:11:48.014+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:12:06.486+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:12:19.038+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:13:06.896+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:13:20.621+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:13:53.641+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:14:02.886+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:14:14.101+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:14:33.836+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:15:03.411+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:17:33.561+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:18:28.131+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} +{"level":"INFO","time":"2024-09-10T11:29:20.269+0800","caller":"init-tool/logger.go:36","msg":"init logger success"} diff --git a/controller/constant.go b/controller/constant.go new file mode 100644 index 0000000..1d0cc18 --- /dev/null +++ b/controller/constant.go @@ -0,0 +1,24 @@ +package controller + +const ( + CLOSEDSTATUS = iota + 1 //已关闭 + NOTPROCESSED //未处理 + PROCESSING //处理中 + REJECTED //已拒绝 + COMPLETED //已完成 + PENDING //已挂起 + REOPEN //重新打开 +) + +var CreateMap = map[int32]bool{ + PROCESSING: true, + REJECTED: true, + COMPLETED: true, + PENDING: true, +} + +var ProcessorMap = map[int32]bool{ + CLOSEDSTATUS: true, + NOTPROCESSED: true, + REOPEN: true, +} diff --git a/dao/mysql.go b/dao/mysql.go index 858c8d5..5bc69a4 100644 --- a/dao/mysql.go +++ b/dao/mysql.go @@ -5,8 +5,8 @@ import ( "bug-notify/model" ) -func GetPhoneByUserID(id int32) (phone string, err error) { - err = init_tool.DB.Table("custom_values").Where("customized_id = ?", id).Select("value").Find(&phone).Error +func GetPhoneByUserID(id []int32) (phone []string, err error) { + err = init_tool.DB.Table("custom_values").Where("customized_id in ? and customized_type = ?", id, "Principal").Select("value").Find(&phone).Error return } @@ -29,3 +29,9 @@ func GetStatusNumByID(id int) (int64, error) { err := init_tool.DB.Table("issues").Where("status_id = ?", id).Count(&a).Error return a, err } + +func GetWatchUserID(watchid int32, watchtype string) (userid []int32, err error) { + err = init_tool.DB.Table("watchers").Where("watchable_id = ? and watchable_type = ?", watchid, watchtype).Select("user_id").Find(&userid).Error + return + +} diff --git a/handle/notify-handle.go b/handle/notify-handle.go index 077846a..e8276ad 100644 --- a/handle/notify-handle.go +++ b/handle/notify-handle.go @@ -3,9 +3,11 @@ package handle import ( "bufio" "bug-notify/api" + "bug-notify/controller" "bug-notify/dao" init_tool "bug-notify/init-tool" "bug-notify/model" + "bug-notify/utils" "encoding/json" "fmt" "github.com/go-mysql-org/go-mysql/canal" @@ -70,8 +72,8 @@ func (h *MyEventHandler) OnRow(e *canal.RowsEvent) error { olddata, newdata := GetData(e) //对比处理的数据差异 switch action { - case "insert": - InsertHandle(olddata, p) + //case "insert": + // InsertHandle(olddata, p) case "update": UpdateHandle(olddata, newdata, p) } @@ -107,103 +109,137 @@ func NotifyHandle() { c.SetEventHandler(&MyEventHandler{}) - //file, err := os.ReadFile("pos.txt") - //if err != nil { - // zap.L().Error("读文件失败", zap.Error(err)) - // - //} - //var pos model.Potion - //err = json.Unmarshal(file, &pos) - //if err != nil { - // zap.L().Error("反序列化失败:", zap.Error(err)) - //} - //p := mysql.Position{ - // Name: pos.Name, - // Pos: pos.Pos, - //} - //c.RunFrom(p) - masterPos, err := c.GetMasterPos() - c.RunFrom(masterPos) + file, err := os.ReadFile("pos.txt") + if err != nil { + zap.L().Error("读文件失败", zap.Error(err)) + + } + var pos model.Potion + err = json.Unmarshal(file, &pos) + if err != nil { + zap.L().Error("反序列化失败:", zap.Error(err)) + } + p := mysql.Position{ + Name: pos.Name, + Pos: pos.Pos, + } + c.RunFrom(p) + //masterPos, err := c.GetMasterPos() + //c.RunFrom(masterPos) } func Ttttt() { data := model.SendMsg{ + AtMobiles: []string{"17638641623", "15938479072"}, + IsAtAll: false, //AtMobiles: []string{"17638641623"}, //IsAtAll: false, - Content: "bug", + Content: "bug@17638641623@15938479072", + MsgType: "actionCard", + Url: "http://192.168.10.6:3000/issues/16", } //panic("chucuol;") take, _ := dao.GetUserInfoByUserID(12) fmt.Println(take) fmt.Println(data.AtMobiles) - //err := api.SendMessage(data) + err := api.SendMessage(data) + if err != nil { + zap.L().Error("消息发送失败:", zap.Error(err)) + return + } +} + +func InsertHandle(olddata *model.DataChanges, position mysql.Position) { + //对比数据,看有什么变化 + //project, err := dao.GetProject(olddata.ProjectID) + //if err != nil { + // zap.L().Error("获取项目失败:", zap.Error(err)) + // return + //} + //phone, err := dao.GetPhoneByUserID(olddata.AssignedToID) + //if err != nil { + // return + //} + //takeName, createName, err := GetUserName(olddata.AssignedToID, olddata.AuthorID) + //if err != nil { + // return + //} + //data := model.SendMsg{ + // AtMobiles: []string{phone}, + // IsAtAll: false, + // Content: fmt.Sprintf( + // "
温馨提醒
"+ + // "---"+ + // "> **所属项目:%s**"+ + // "---"+ + // "> **bug主题:%s**"+ + // "---"+ + // "> **创建人:%s**"+ + // "---"+ + // "> **处理人:%s**"+ + // "---"+ + // "\n @%s \n", project, olddata.Subject, createName, takeName, phone), + // MsgType: "actionCard", + // Url: "http://192.168.10.6:3000/issues/" + strconv.Itoa(int(olddata.ID)), + //} + //file, err := os.ReadFile("pos.txt") + //if err != nil { + // zap.L().Error("读文件失败", zap.Error(err)) + //} + //var pos model.Potion + //json.Unmarshal(file, pos) + //err = api.SendMessage(data) //if err != nil { // zap.L().Error("消息发送失败:", zap.Error(err)) // return //} + //if pos.Pos != 0 { + // //存储文件 + // marshal, err := json.Marshal(position) + // if err != nil { + // zap.L().Error("转换失败:", zap.Error(err)) + // return + // } + // err = StroageFile(string(marshal)) + // if err != nil { + // zap.L().Error("文件写入失败:", zap.Error(err)) + // return + // } + //} } -func InsertHandle(olddata *model.DataChanges, position mysql.Position) { +func UpdateHandle(olddata, newdata *model.DataChanges, position mysql.Position) { //对比数据,看有什么变化 - project, err := dao.GetProject(olddata.ProjectID) + project, err := dao.GetProject(newdata.ProjectID) if err != nil { zap.L().Error("获取项目失败:", zap.Error(err)) return } - phone, err := dao.GetPhoneByUserID(olddata.AssignedToID) + //根据bugid获取到bug的关注者,然后根据bug不同的状态通知给不同的人 + userids, err := dao.GetWatchUserID(newdata.ID, "Issue") if err != nil { + zap.L().Error("获取关注用户失败:", zap.Error(err)) return } - takeName, createName, err := GetUserName(olddata.AssignedToID, olddata.AuthorID) - if err != nil { - return - } - data := model.SendMsg{ - AtMobiles: []string{phone}, - IsAtAll: false, - Content: fmt.Sprintf("### 温馨提醒\n"+ - "\n**所属项目**:%s "+ - "\n**bug主题**:%s "+ - "\n**创建人**:%s"+ - "\n**处理人**:%s"+ - "\n @%s", project, olddata.Subject, createName, takeName, phone), - } - file, err := os.ReadFile("pos.txt") - if err != nil { - zap.L().Error("读文件失败", zap.Error(err)) - } - var pos model.Potion - json.Unmarshal(file, pos) - err = api.SendMessage(data) + //发消息的时候根据bug状态通知到作者或处理者 + status, err := dao.GetStatusByID(newdata.StatusID) if err != nil { - zap.L().Error("消息发送失败:", zap.Error(err)) + zap.L().Error("获取bug状态失败:", zap.Error(err)) return } - if pos.Pos != 0 { - //存储文件 - marshal, err := json.Marshal(position) - if err != nil { - zap.L().Error("转换失败:", zap.Error(err)) - return - } - err = StroageFile(string(marshal)) - if err != nil { - zap.L().Error("文件写入失败:", zap.Error(err)) - return - } - } -} -func UpdateHandle(olddata, newdata *model.DataChanges, position mysql.Position) { - //对比数据,看有什么变化 - project, err := dao.GetProject(newdata.ProjectID) - if err != nil { - zap.L().Error("获取项目失败:", zap.Error(err)) - return + //发消息的时候根据bug状态通知到作者或处理者 + //3、4、5、6通知创建者 + //1、2、7 通知处理者 + if controller.CreateMap[newdata.StatusID] { + userids = append(userids, newdata.AuthorID) + } else if controller.ProcessorMap[newdata.StatusID] { + userids = append(userids, newdata.AssignedToID) } - phone, err := dao.GetPhoneByUserID(newdata.AssignedToID) + + phones, err := dao.GetPhoneByUserID(userids) if err != nil { zap.L().Error("获取手机号失败:", zap.Error(err)) return @@ -212,22 +248,32 @@ func UpdateHandle(olddata, newdata *model.DataChanges, position mysql.Position) if err != nil { return } + splicingString := utils.SplicingString(phones, "@") data := model.SendMsg{ - AtMobiles: []string{phone}, + AtMobiles: phones, IsAtAll: false, - Content: fmt.Sprintf("## Bug\n"+ - "\n**所属项目**:%s "+ - "\n**bug主题**:%s "+ - "\n**创建人**:%s \n"+ - "\n**处理人**:%s \n"+ - "\n @%s \n", project, olddata.Subject, createName, takeName, phone), + Content: fmt.Sprintf("
温馨提醒
\n"+ + "\n--- \n"+ + "\n> **所属项目:%s**\n"+ + "\n--- \n"+ + "\n> **bug主题:%s**\n"+ + "\n--- \n"+ + "\n> **bug状态:%s**\n"+ + "\n--- \n"+ + "\n> **创建人:%s** \n"+ + "\n--- \n"+ + "\n> **处理人:%s** \n"+ + "\n--- \n"+ + "\n @%s \n", project, newdata.Subject, status, createName, takeName, splicingString), + MsgType: "actionCard", + Url: "http://192.168.10.6:3000/issues/" + strconv.Itoa(int(newdata.ID)), } file, err := os.ReadFile("pos.txt") if err != nil { zap.L().Error("读文件失败", zap.Error(err)) } - var pos mysql.Position - json.Unmarshal(file, pos) + var pos model.Potion + json.Unmarshal(file, &pos) err = api.SendMessage(data) if err != nil { zap.L().Error("消息发送失败:", zap.Error(err)) @@ -251,6 +297,7 @@ func UpdateHandle(olddata, newdata *model.DataChanges, position mysql.Position) func GetData(e *canal.RowsEvent) (*model.DataChanges, *model.DataChanges) { oldData := new(model.DataChanges) + oldData.ID = e.Rows[0][0].(int32) oldData.ProjectID = e.Rows[0][2].(int32) oldData.Subject = e.Rows[0][3].(string) oldData.StatusID = e.Rows[0][7].(int32) @@ -262,13 +309,15 @@ func GetData(e *canal.RowsEvent) (*model.DataChanges, *model.DataChanges) { oldData.AuthorID = e.Rows[0][11].(int32) newData := new(model.DataChanges) if e.Action == "update" { + newData.ID = e.Rows[1][0].(int32) newData.ProjectID = e.Rows[1][2].(int32) newData.Subject = e.Rows[1][3].(string) newData.StatusID = e.Rows[1][7].(int32) - if e.Rows[1][8] != nil { - oldData.AssignedToID = e.Rows[1][8].(int32) + if e.Rows[1][8] == nil { + newData.AssignedToID = 0 } else { - oldData.AssignedToID = 0 + fmt.Println("走着路", e.Rows) + newData.AssignedToID = e.Rows[1][8].(int32) } newData.AuthorID = e.Rows[1][11].(int32) } diff --git a/model/DataModel.go b/model/DataModel.go index 2b21280..bccada5 100644 --- a/model/DataModel.go +++ b/model/DataModel.go @@ -1,6 +1,7 @@ package model type DataChanges struct { + ID int32 `json:"id"` ProjectID int32 `json:"project_id"` //项目ID Subject string `json:"subject"` //标题 Description string `json:"description"` //问题描述 @@ -18,9 +19,8 @@ type SendMsg struct { AtMobiles []string `json:"at_mobiles"` MsgType string `json:"msgtype"` Url string `json:"url"` - //AtUserID string `json:"at_user_id"` - Content string `json:"content"` - IsAtAll bool `json:"is_at_all"` + Content string `json:"content"` + IsAtAll bool `json:"is_at_all"` } type Potion struct { Name string `json:"Name"` diff --git a/pos.txt b/pos.txt index 21f218d..7d60d04 100644 --- a/pos.txt +++ b/pos.txt @@ -1 +1 @@ -{"Name":"binlog.000021","Pos":29302} \ No newline at end of file +{"Name":"binlog.000021","Pos":76619} \ No newline at end of file diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..114aab4 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,8 @@ +package utils + +import "strings" + +func SplicingString(str []string, s string) (newstr string) { + newstr = strings.Join(str, s) + return +}