Skip to content

Commit

Permalink
feat: add Rocket.chat support (#64)
Browse files Browse the repository at this point in the history
* feat: add Rocket.chat support

* fix: copy/paste errors and unnecessary comments fixed, Rocket.chat integration documentation added

* fix: revert go.mod changes

* fix: Rocket.chat doc link fixed

Co-authored-by: nils måsén <[email protected]>

Co-authored-by: Dmitry Kovalev <[email protected]>
Co-authored-by: nils måsén <[email protected]>
  • Loading branch information
3 people authored Oct 8, 2020
1 parent 9c522a1 commit e68669d
Show file tree
Hide file tree
Showing 12 changed files with 381 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/services/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ Click on the service for a more thorough explanation.
| [Hangouts Chat](./hangouts.md) | *hangouts://chat.googleapis.com/v1/spaces/FOO/messages?key=bar&token=baz* |
| [Zulip Chat](./zulip.md) | *zulip://__`bot-mail`__:__`bot-key`__@__`zulip-domain`__/?stream=__`name-or-id`__&topic=__`name`__* |
| [Join](./not-documented.md) | *join://shoutrrr:__`api-key`__@join/?devices=__`device1`__[,__`device2`__, ...][&icon=__`icon`__][&title=__`title`__]* |
| [Rocketchat](./rocketchat.md) | *rocketchat://[__`username`__@]__`rocketchat-host`__/__`token`__[/__`channel`&#124;`@recipient`__]* |
61 changes: 61 additions & 0 deletions docs/services/rocketchat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Rocket.chat

## URL Format

## Creating a Webhook in Rocket.chat

1. Open up the chat Administration by clicking on *Administration* menu
![Screenshot 1](rocketchat/1.png)

2. Open *Integrations* and then click *New*
![Screenshot 2](rocketchat/2.png)

3. Fill in the information for the webhook and click *Save*. Please don't forget to Enable your integration.
![Screenshot 3](rocketchat/3.png)

5. If you did everything correctly, Rocket.chat will give you the *URL* and *Token* to your newly created webhook.
![Screenshot 4](rocketchat/4.png)

6. Format the service URL
```
rocketchat://your-domain.com/8eGdRzc9r4YYNyvge/2XYQcX9NBwJBKfQnphpebPcnXZcPEi32Nt4NKJfrnbhsbRfX
└────────────────────────────────────────────────────────────────┘
token
```

## Additional URL configuration

Rocket.chat provides functionality to post as another user or to another channel / user, compared to the webhook configuration.
<br/>
To do this, you can add a *sender* and/or *channel* / *receiver* to the service URL.

```
rocketchat://[email protected]/8eGdRzc9r4YYNyvge/2XYQcX9NBwJBKfQnphpebPcnXZcPEi32Nt4NKJfrnbhsbRfX/shoutrrrChannel
└──────────┘ └────────────────────────────────────────────────────────────────┘ └─────────────┘
sender token channel
rocketchat://[email protected]/8eGdRzc9r4YYNyvge/2XYQcX9NBwJBKfQnphpebPcnXZcPEi32Nt4NKJfrnbhsbRfX/@shoutrrrReceiver
└──────────┘ └────────────────────────────────────────────────────────────────┘ └───────────────┘
sender token receiver
```

## Passing parameters via code

If you want to, you also have the possibility to pass parameters to the `send` function.
<br/>
The following example contains all parameters that are currently supported.

```gotemplate
params := (*types.Params)(
&map[string]string{
"username": "overwriteUserName",
"channel": "overwriteChannel",
},
)
service.Send("this is a message", params)
```

This will overwrite any options, that you passed via URL.

For more Rocket.chat Webhooks options see [official guide](https://docs.rocket.chat/guides/administrator-guides/integrations).
Binary file added docs/services/rocketchat/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/services/rocketchat/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/services/rocketchat/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/services/rocketchat/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
Expand Down Expand Up @@ -81,8 +79,6 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
Expand Down
2 changes: 2 additions & 0 deletions pkg/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package router

import (
"fmt"
"github.com/containrrr/shoutrrr/pkg/services/rocketchat"
"log"
"net/url"
"strings"
Expand Down Expand Up @@ -148,6 +149,7 @@ var serviceMap = map[string]func() t.Service{
"hangouts": func() t.Service { return &hangouts.Service{} },
"zulip": func() t.Service { return &zulip.Service{} },
"join": func() t.Service { return &join.Service{} },
"rocketchat": func() t.Service { return &rocketchat.Service{} },
}

func (router *ServiceRouter) initService(rawURL string) (t.Service, error) {
Expand Down
47 changes: 47 additions & 0 deletions pkg/services/rocketchat/rocketchat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package rocketchat

import (
"bytes"
"fmt"
"log"
"net/http"
"net/url"

"github.com/containrrr/shoutrrr/pkg/services/standard"
"github.com/containrrr/shoutrrr/pkg/types"
)

// Service sends notifications to a pre-configured channel or user
type Service struct {
standard.Standard
config *Config
}

// Initialize loads ServiceConfig from configURL and sets logger for this Service
func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error {
service.Logger.SetLogger(logger)
service.config = &Config{}
if err := service.config.SetURL(configURL); err != nil {
return err
}

return nil
}

// Send a notification message to Rocket.chat
func (service *Service) Send(message string, params *types.Params) error {
config := service.config
apiURL := buildURL(config)
json, _ := CreateJSONPayload(config, message, params)
res, err := http.Post(apiURL, "application/json", bytes.NewReader(json))

if res.StatusCode != http.StatusOK {
return fmt.Errorf("failed to send notification to service, response status code %s", res.Status)
}
return err
}

func buildURL(config *Config) string {
return fmt.Sprintf("https://%s/hooks/%s/%s", config.Host, config.TokenA, config.TokenB)
}

70 changes: 70 additions & 0 deletions pkg/services/rocketchat/rocketchat_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package rocketchat

import (
"errors"
"fmt"
"github.com/containrrr/shoutrrr/pkg/services/standard"
"net/url"
"strings"
)

// Config for the rocket.chat service
type Config struct {
standard.QuerylessConfig
standard.EnumlessConfig
UserName string
Host string
TokenA string
Channel string
TokenB string
}

// GetURL returns a URL representation of it's current field values
func (config *Config) GetURL() *url.URL {
return &url.URL{
Host: config.Host,
Path: fmt.Sprintf("hooks/%s/%s", config.TokenA, config.TokenB),
Scheme: Scheme,
ForceQuery: false,
}
}

// SetURL updates a ServiceConfig from a URL representation of it's field values
func (config *Config) SetURL(serviceURL *url.URL) error {

UserName := serviceURL.User.Username()
host := serviceURL.Hostname()

path := strings.Split(serviceURL.Path, "/")

if len(path) < 3 {
return errors.New(NotEnoughArguments)
}

config.UserName = UserName
config.Host = host
config.TokenA = path[1]
config.TokenB = path[2]
if len(path) > 3 {
if path[3][0:1] != "@" {
config.Channel = "#" + path[3]
} else {
config.Channel = path[3]
}
}
return nil
}

const (
// Scheme is the identifying part of this service's configuration URL
Scheme = "rocketchat"
// NotEnoughArguments provided in the service URL
NotEnoughArguments = "the apiURL does not include enough arguments"
)

// CreateConfigFromURL to use within the rocket.chat service
func CreateConfigFromURL(serviceURL *url.URL) (*Config, error) {
config := Config{}
err := config.SetURL(serviceURL)
return &config, err
}
34 changes: 34 additions & 0 deletions pkg/services/rocketchat/rocketchat_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package rocketchat

import (
"encoding/json"

"github.com/containrrr/shoutrrr/pkg/types"
)

// JSON used within the Rocket.chat service
type JSON struct {
Text string `json:"text"`
UserName string `json:"username,omitempty"`
Channel string `json:"channel,omitempty"`
}

// CreateJSONPayload compatible with the rocket.chat webhook api
func CreateJSONPayload(config *Config, message string, params *types.Params) ([]byte, error) {
payload := JSON{
Text: message,
UserName: config.UserName,
Channel: config.Channel,
}

if params != nil {
if value, found := (*params)["username"]; found {
payload.UserName = value
}
if value, found := (*params)["channel"]; found {
payload.Channel = value
}
}
return json.Marshal(payload)
}

Loading

0 comments on commit e68669d

Please sign in to comment.