diff --git a/README.md b/README.md index 482ec1d..f90a3f8 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,16 @@ path. Do it like: opensaps -config /path/to/opensaps.yaml ``` +# About hooks and parsers + +While configuring a webhook in your application, please, set username +exactly same as one of parsers in ``parsers`` directory! Otherwise parser +"default" will be used, which will just concatenate text and attachments +into one message! + +Also note - that nickname will be ignored while sending message to +pushers. + ---- # IMPORTANT NOTICE diff --git a/context/context.go b/context/context.go index 2226580..86f4040 100644 --- a/context/context.go +++ b/context/context.go @@ -20,9 +20,11 @@ package context import ( // stdlib "os" + "strings" // local "lab.pztrn.name/pztrn/opensaps/config/interface" + "lab.pztrn.name/pztrn/opensaps/parsers/interface" "lab.pztrn.name/pztrn/opensaps/pushers/interface" "lab.pztrn.name/pztrn/opensaps/slack/apiserverinterface" "lab.pztrn.name/pztrn/opensaps/slack/message" @@ -36,11 +38,13 @@ type Context struct { Config configurationinterface.ConfigurationInterface Flagger *flagger.Flagger Log *mogrus.LoggerHandler + Parsers map[string]parserinterface.ParserInterface Pushers map[string]pusherinterface.PusherInterface SlackAPIServer slackapiserverinterface.SlackAPIServerInterface } func (c *Context) Initialize() { + c.Parsers = make(map[string]parserinterface.ParserInterface) c.Pushers = make(map[string]pusherinterface.PusherInterface) l := mogrus.New() @@ -58,6 +62,12 @@ func (c *Context) RegisterConfigurationInterface(ci configurationinterface.Confi c.Config.Initialize() } +// Registers parser interface. +func (c *Context) RegisterParserInterface(name string, iface parserinterface.ParserInterface) { + c.Parsers[name] = iface + c.Parsers[name].Initialize() +} + // Registers Pusher interface. func (c *Context) RegisterPusherInterface(name string, iface pusherinterface.PusherInterface) { c.Pushers[name] = iface @@ -71,6 +81,16 @@ func (c *Context) RegisterSlackAPIServerInterface(sasi slackapiserverinterface.S c.SlackAPIServer.Initialize() } +func (c *Context) SendToParser(name string, message slackmessage.SlackMessage) string { + parser, found := c.Parsers[strings.ToLower(name)] + if !found { + c.Log.Errorf("Parser '%s' not found, will use default one!", name) + return c.Parsers["default"].ParseMessage(message) + } + + return parser.ParseMessage(message) +} + func (c *Context) SendToPusher(protocol string, connection string, data slackmessage.SlackMessage) { pusher, ok := c.Pushers[protocol] if !ok { diff --git a/opensaps.go b/opensaps.go index d1bc6be..83eaa89 100644 --- a/opensaps.go +++ b/opensaps.go @@ -26,6 +26,8 @@ import ( // local "lab.pztrn.name/pztrn/opensaps/config" "lab.pztrn.name/pztrn/opensaps/context" + "lab.pztrn.name/pztrn/opensaps/parsers/default" + "lab.pztrn.name/pztrn/opensaps/parsers/gitea" "lab.pztrn.name/pztrn/opensaps/pushers/matrix" "lab.pztrn.name/pztrn/opensaps/slack" ) @@ -44,6 +46,10 @@ func main() { slack.New(c) + // Initialize parsers. + defaultparser.New(c) + giteaparser.New(c) + // Initialize pushers. matrixpusher.New(c) diff --git a/parsers/default/defaultparser.go b/parsers/default/defaultparser.go new file mode 100644 index 0000000..e125ac7 --- /dev/null +++ b/parsers/default/defaultparser.go @@ -0,0 +1,34 @@ +// OpenSAPS - Open Slack API server for everyone. +// +// Copyright (c) 2017, Stanislav N. aka pztrn. +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package defaultparser + +import ( + // local + "lab.pztrn.name/pztrn/opensaps/slack/message" +) + +type DefaultParser struct {} + +func (dp DefaultParser) Initialize() { + c.Log.Infoln("Initializing default parser...") +} + +func (dp DefaultParser) ParseMessage(message slackmessage.SlackMessage) string { + c.Log.Debugln("Parsing default message...") + return message.Text +} diff --git a/parsers/default/exported.go b/parsers/default/exported.go new file mode 100644 index 0000000..34607ea --- /dev/null +++ b/parsers/default/exported.go @@ -0,0 +1,34 @@ +// OpenSAPS - Open Slack API server for everyone. +// +// Copyright (c) 2017, Stanislav N. aka pztrn. +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package defaultparser + +import ( + // local + "lab.pztrn.name/pztrn/opensaps/context" + "lab.pztrn.name/pztrn/opensaps/parsers/interface" +) + +var ( + c *context.Context +) + +func New(cc *context.Context) { + c = cc + dp := DefaultParser{} + c.RegisterParserInterface("default", parserinterface.ParserInterface(dp)) +} diff --git a/parsers/gitea/exported.go b/parsers/gitea/exported.go new file mode 100644 index 0000000..949a6f9 --- /dev/null +++ b/parsers/gitea/exported.go @@ -0,0 +1,34 @@ +// OpenSAPS - Open Slack API server for everyone. +// +// Copyright (c) 2017, Stanislav N. aka pztrn. +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package giteaparser + +import ( + // local + "lab.pztrn.name/pztrn/opensaps/context" + "lab.pztrn.name/pztrn/opensaps/parsers/interface" +) + +var ( + c *context.Context +) + +func New(cc *context.Context) { + c = cc + gp := GiteaParser{} + c.RegisterParserInterface("gitea", parserinterface.ParserInterface(gp)) +} diff --git a/parsers/gitea/giteaparser.go b/parsers/gitea/giteaparser.go new file mode 100644 index 0000000..be07c0a --- /dev/null +++ b/parsers/gitea/giteaparser.go @@ -0,0 +1,109 @@ +// OpenSAPS - Open Slack API server for everyone. +// +// Copyright (c) 2017, Stanislav N. aka pztrn. +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package giteaparser + +import ( + // stdlib + "fmt" + "regexp" + "strings" + + // local + "lab.pztrn.name/pztrn/opensaps/slack/message" +) + +type GiteaParser struct {} + +func (gp GiteaParser) Initialize() { + c.Log.Infoln("Initializing Gitea parser...") +} + +func (gp GiteaParser) cutCommitLink(data string) [][]string { + var links [][]string + c.Log.Debugln("Passed:", data) + + r := regexp.MustCompile("(http[?s]://[a-zA-Z1-9./-]+)|([a-zA-Z1-9]+)>") + + found := r.FindAllStringSubmatch(data, -1) + + var result []string + for i := range found { + if i%2 == 0 { + result = make([]string, 0, 2) + result = append(result, found[i][1]) + } else { + result = append(result, found[i][2]) + links = append(links, result) + } + } + + c.Log.Debugln("Links cutted:", links) + return links +} + +func (gp GiteaParser) cutHeaderLinks(data string) [][]string { + var links [][]string + c.Log.Debugln("Passed:", data) + + r := regexp.MustCompile("<(http[?s]://[a-zA-Z1-9./-]+)|([a-zA-Z1-9_-]+)>") + + found := r.FindAllStringSubmatch(data, -1) + + var result []string + for i := range found { + if i%2 == 0 { + result = make([]string, 0, 2) + result = append(result, found[i][1]) + } else { + result = append(result, found[i][2]) + links = append(links, result) + } + } + + c.Log.Debugln("Links cutted:", links) + return links +} + +func (gp GiteaParser) ParseMessage(message slackmessage.SlackMessage) string { + c.Log.Debugln("Parsing Gitea message...") + + var msg string = "" + + // Parse header. + // [0] is repo, [1] is branch. + header_data := gp.cutHeaderLinks(message.Text) + + msg += fmt.Sprintf("[Repo: %s | Branch: %s] ", header_data[0][0], header_data[0][1], header_data[1][0], header_data[1][1]) + + header_msg := strings.Split(message.Text, "] ")[1] + msg += header_msg + "
" + + // Parse commits. + for i := range message.Attachments { + // Commit link. + attachment_link := gp.cutCommitLink(message.Attachments[i].Text) + msg += fmt.Sprintf("%s: ", attachment_link[0][0], attachment_link[0][1]) + // Commit author and message. + authormsg := strings.Split(message.Attachments[i].Text, ">: ")[1] + msg += authormsg + "
" + } + + c.Log.Debugln("Message:", msg) + + return msg +} diff --git a/parsers/interface/parserinterface.go b/parsers/interface/parserinterface.go new file mode 100644 index 0000000..29143e8 --- /dev/null +++ b/parsers/interface/parserinterface.go @@ -0,0 +1,28 @@ +// OpenSAPS - Open Slack API server for everyone. +// +// Copyright (c) 2017, Stanislav N. aka pztrn. +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package parserinterface + +import ( + // local + "lab.pztrn.name/pztrn/opensaps/slack/message" +) + +type ParserInterface interface { + Initialize() + ParseMessage(message slackmessage.SlackMessage) string +} diff --git a/pushers/matrix/matrixconnection.go b/pushers/matrix/matrixconnection.go index 0edd15b..9f91dac 100644 --- a/pushers/matrix/matrixconnection.go +++ b/pushers/matrix/matrixconnection.go @@ -184,9 +184,7 @@ func (mxc *MatrixConnection) Initialize(conn_name string, api_root string, user // It will prepare a message which will be passed to mxc.SendMessage(). func (mxc *MatrixConnection) ProcessMessage(message slackmessage.SlackMessage) { // Prepare message body. - message_body := message.Text - - // ToDo: attachments handling. + message_body := c.SendToParser(message.Username, message) // Send message. mxc.SendMessage(message_body) @@ -199,7 +197,7 @@ func (mxc *MatrixConnection) SendMessage(message string) { // We should send notices as it is preferred behaviour for bots and // appservices. //msgStr := fmt.Sprintf(`{"msgtype": "m.text", "body": "%s", "format": "org.matrix.custom.html", "formatted_body": "%s"}`, message, message) - msgStr := fmt.Sprintf(`{"msgtype": "m.notice", "body": "%s"}`, message) + msgStr := fmt.Sprintf(`{"msgtype": "m.notice", "body": "%s", "format": "org.matrix.custom.html", "formatted_body": "%s"}`, message, message) reply, err := mxc.doPutRequest("/rooms/" + mxc.room_id + "/send/m.room.message/" + mxc.generateTnxId(), msgStr) if err != nil { c.Log.Fatalf("Failed to send message to room '%s' (conn: '%s'): %s", mxc.room_id, mxc.conn_name, err.Error())