From b22afcc38267514553d617a02c0ac2419a5f2e84 Mon Sep 17 00:00:00 2001 From: Zhao Xiaojie Date: Sun, 17 Feb 2019 10:59:45 +0800 Subject: [PATCH] Add notification to gitter support --- .gitignore | 3 + Makefile | 6 +- pkg/reply/github_bind.go | 194 ++++++++++++++++++++++++++++++++++ pkg/reply/github_bind_test.go | 53 ++++++++++ pkg/reply/gitter.go | 88 +++++++++++++++ pkg/reply/gitter_test.go | 7 ++ 6 files changed, 348 insertions(+), 3 deletions(-) create mode 100644 pkg/reply/github_bind.go create mode 100644 pkg/reply/github_bind_test.go create mode 100644 pkg/reply/gitter.go create mode 100644 pkg/reply/gitter_test.go diff --git a/.gitignore b/.gitignore index 7326468..9817981 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ # Build stuffs bin/ wechat-backend + +# test data files +pkg/reply/*.yaml \ No newline at end of file diff --git a/Makefile b/Makefile index af0c086..d1e360c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -TAG=dev-$(shell cat .version)-$(shell git config --get user.email | sed -e "s/@/-/") +TAG=dev-$(shell git rev-parse HEAD | cut -c 1-8) build: CGO_ENABLED=0 GOOS=linux go build -ldflags "-w -s" -a -installsuffix cgo -o bin/wechat-backend @@ -12,13 +12,13 @@ image: build docker build -t surenpi/jenkins-wechat:${TAG} . image-alauda: build - docker build -t index.alauda.cn/alaudak8s/jenkins-wechat . + docker build -t index.alauda.cn/alaudak8s/jenkins-wechat:${TAG} . push-image: image docker push surenpi/jenkins-wechat:${TAG} push-image-alauda: image-alauda - docker push index.alauda.cn/alaudak8s/jenkins-wechat + docker push index.alauda.cn/alaudak8s/jenkins-wechat:${TAG} image-ubuntu: build docker build -t surenpi/jenkins-wechat:ubuntu . -f Dockerfile.ubuntu diff --git a/pkg/reply/github_bind.go b/pkg/reply/github_bind.go new file mode 100644 index 0000000..7a1a28c --- /dev/null +++ b/pkg/reply/github_bind.go @@ -0,0 +1,194 @@ +package reply + +import ( + "fmt" + "os" + "strings" + + "io/ioutil" + + core "github.com/linuxsuren/wechat-backend/pkg" + yaml "gopkg.in/yaml.v2" +) + +// GitHubBindAutoReply only reply for match +type GitHubBindAutoReply struct { + Request *core.TextRequestBody + GitHubBind GitHubBind + Event string + Keyword string +} + +var _ AutoReply = &GitHubBindAutoReply{} + +const ( + GitHubEventRegister = "注册" + GitHubEventUnregister = "注销" +) + +// Name indicate reply's name +func (m *GitHubBindAutoReply) Name() string { + return "GitHubBindAutoReply" +} + +// Weight weight for order +func (m *GitHubBindAutoReply) Weight() int { + return 0 +} + +// Accept consider if it will accept the request +func (m *GitHubBindAutoReply) Accept(request *core.TextRequestBody) bool { + m.Request = request + m.Keyword = request.Content + + if "text" != request.MsgType { + return false + } + + if strings.HasPrefix(request.Content, GitHubEventRegister) { + m.Event = GitHubEventRegister + m.Keyword = strings.TrimLeft(m.Keyword, fmt.Sprintf("%s ", GitHubEventRegister)) + } else if strings.HasPrefix(request.Content, GitHubEventUnregister) { + m.Event = GitHubEventUnregister + m.Keyword = strings.TrimLeft(m.Keyword, fmt.Sprintf("%s ", GitHubEventUnregister)) + } else { + return false + } + + return true +} + +// Handle hanlde the request then return data +func (m *GitHubBindAutoReply) Handle() (string, error) { + from := m.Request.ToUserName + to := m.Request.FromUserName + var reply string + + if m.Keyword != "" { + switch m.Event { + case GitHubEventRegister: + m.GitHubBind.Add(GitHubBindData{ + WeChatID: to, + GitHubID: m.Keyword, + }) + reply = "register success" + case GitHubEventUnregister: + m.GitHubBind.Remove(to) + reply = "unregister success" + default: + reply = "unknow event" + } + } else { + reply = "need your github id" + } + + var err error + var data []byte + data, err = makeTextResponseBody(from, to, reply) + if err != nil { + err = fmt.Errorf("Wechat Service: makeTextResponseBody error: %v", err) + } + return string(data), err +} + +type GitHubBind interface { + Add(GitHubBindData) error + Update(GitHubBindData) error + Remove(string) + Exists(string) bool + Find(string) *GitHubBindData + Count() int +} + +type GitHubBindData struct { + WeChatID string + GitHubID string +} + +type GitHubBindDataList []GitHubBindData + +type GitHubBinder struct { + File string + DataList GitHubBindDataList +} + +func (g *GitHubBinder) Read() (err error) { + if _, err = os.Stat(g.File); os.IsNotExist(err) { + g.DataList = GitHubBindDataList{} + return nil + } + + var content []byte + if content, err = ioutil.ReadFile(g.File); err != nil { + return + } + + g.DataList = GitHubBindDataList{} + err = yaml.Unmarshal(content, &g.DataList) + return +} + +func (g *GitHubBinder) Add(bindData GitHubBindData) (err error) { + g.Read() + + if g.Exists(bindData.WeChatID) { + return + } + + g.DataList = append(g.DataList, bindData) + var data []byte + if data, err = yaml.Marshal(g.DataList); err == nil { + err = ioutil.WriteFile(g.File, data, 0644) + } + return +} + +func (g *GitHubBinder) Update(bindData GitHubBindData) (err error) { + return +} + +func (g *GitHubBinder) Remove(wechatID string) { +} + +func (g *GitHubBinder) Exists(wechatID string) bool { + g.Read() + if g.DataList == nil { + return false + } + + for _, item := range g.DataList { + if item.WeChatID == wechatID { + return true + } + } + return false +} + +func (g *GitHubBinder) Find(wechatID string) *GitHubBindData { + g.Read() + if g.DataList == nil { + return nil + } + + for _, item := range g.DataList { + if item.WeChatID == wechatID { + return &item + } + } + return nil +} + +func (g *GitHubBinder) Count() int { + g.Read() + return len(g.DataList) +} + +func init() { + Register(func() AutoReply { + return &GitHubBindAutoReply{ + GitHubBind: &GitHubBinder{ + File: "config/github_bind.yaml", + }, + } + }) +} diff --git a/pkg/reply/github_bind_test.go b/pkg/reply/github_bind_test.go new file mode 100644 index 0000000..5017f0d --- /dev/null +++ b/pkg/reply/github_bind_test.go @@ -0,0 +1,53 @@ +package reply + +import ( + "testing" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestGitHubBind(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Unknown keywords") +} + +var _ = Describe("github bind", func() { + var ( + binder GitHubBind + data GitHubBindData + ctrl *gomock.Controller + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + binder = &GitHubBinder{ + File: "github_bind.yaml", + } + data = GitHubBindData{ + WeChatID: "WeChatID", + GitHubID: "GitHubID", + } + }) + + It("should not error", func() { + Expect(binder.Exists("none")).To(Equal(false)) + + Expect(binder.Add(data)).To(BeNil()) + + Expect(binder.Exists("WeChatID")).To(Equal(true)) + + Expect(binder.Find("WeChatID").GitHubID).To(Equal("GitHubID")) + }) + + It("non-repetitive", func() { + Expect(binder.Add(data)).To(BeNil()) + + Expect(binder.Count()).To(Equal(1)) + }) + + AfterEach(func() { + ctrl.Finish() + }) +}) diff --git a/pkg/reply/gitter.go b/pkg/reply/gitter.go new file mode 100644 index 0000000..9a2798f --- /dev/null +++ b/pkg/reply/gitter.go @@ -0,0 +1,88 @@ +package reply + +import ( + "fmt" + "net/http" + "net/url" + "strings" + + core "github.com/linuxsuren/wechat-backend/pkg" +) + +// GitterAutoReply only reply for match +type GitterAutoReply struct { + Request *core.TextRequestBody + Keyword string + Callback string +} + +var _ AutoReply = &GitterAutoReply{} + +// Name indicate reply's name +func (m *GitterAutoReply) Name() string { + return "GitterAutoReply" +} + +// Weight weight for order +func (m *GitterAutoReply) Weight() int { + return 0 +} + +// Accept consider if it will accept the request +func (m *GitterAutoReply) Accept(request *core.TextRequestBody) (ok bool) { + m.Request = request + m.Keyword = request.Content + m.Keyword = strings.TrimLeft(m.Keyword, "问 ") + m.Keyword = strings.TrimLeft(m.Keyword, "q ") + + if "text" != request.MsgType { + return false + } + + return strings.HasPrefix(request.Content, "问") || + strings.HasPrefix(request.Content, "q") +} + +// Handle hanlde the request then return data +func (m *GitterAutoReply) Handle() (string, error) { + from := m.Request.ToUserName + to := m.Request.FromUserName + var err error + var data []byte + + binder := &GitHubBinder{ + File: "config/github_bind.yaml", + } + + var sender string + gitHubBindData := binder.Find(to) + if gitHubBindData == nil { + sender = "anonymous" + } else { + sender = gitHubBindData.GitHubID + } + + sendMsg(m.Callback, fmt.Sprintf("@%s %s", sender, m.Keyword)) + data, err = makeTextResponseBody(from, to, "sent") + if err != nil { + err = fmt.Errorf("Wechat Service: makeTextResponseBody error: %v", err) + } + return string(data), err +} + +func init() { + Register(func() AutoReply { + return &GitterAutoReply{ + Callback: "https://webhooks.gitter.im/e/911738f12cb4ca5d3c41", + } + }) +} + +// SendMsg send message to server +func sendMsg(server, message string) { + value := url.Values{ + "message": {message}, + } + + http.PostForm(server, value) +} diff --git a/pkg/reply/gitter_test.go b/pkg/reply/gitter_test.go new file mode 100644 index 0000000..c935b31 --- /dev/null +++ b/pkg/reply/gitter_test.go @@ -0,0 +1,7 @@ +package reply + +import "testing" + +func TestGitter(t *testing.T) { + // SendMsg("https://webhooks.gitter.im/e/392bac9a454b919ef965", "sdf") +} -- GitLab