Skip to content

Commit

Permalink
fix(gotify): use pkr for fields to make them settable from url (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
piksel committed Jan 12, 2021
1 parent 163ff52 commit 91cd790
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 51 deletions.
40 changes: 16 additions & 24 deletions pkg/services/gotify/gotify.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/containrrr/shoutrrr/pkg/format"
"log"
"net/http"
"net/url"
"strconv"
"strings"

"github.com/containrrr/shoutrrr/pkg/services/standard"
Expand All @@ -18,12 +18,16 @@ import (
type Service struct {
standard.Standard
config *Config
pkr format.PropKeyResolver
}

// 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{}
service.config = &Config{
Title: "Shoutrrr notification",
}
service.pkr = format.NewPropKeyResolver(service.config)
err := service.config.SetURL(configURL)
return err
}
Expand Down Expand Up @@ -55,27 +59,11 @@ func buildURL(config *Config) (string, error) {
if !isTokenValid(token) {
return "", fmt.Errorf("invalid gotify token \"%s\"", token)
}
return fmt.Sprintf("https://%s/message?token=%s", config.Host, token), nil
}

func getPriority(params map[string]string) int {
priorityStr, ok := params["priority"]
if !ok {
priorityStr = "0"
}
priority, err := strconv.Atoi(priorityStr)
if err != nil {
priority = 0
}
return priority
}

func getTitle(params map[string]string) string {
title, ok := params["title"]
if !ok {
title = "Shoutrrr notification"
scheme := "https"
if config.DisableTLS {
scheme = scheme[:4]
}
return title
return fmt.Sprintf("%s://%s/message?token=%s", scheme, config.Host, token), nil
}

// Send a notification message to Gotify
Expand All @@ -84,14 +72,18 @@ func (service *Service) Send(message string, params *types.Params) error {
params = &types.Params{}
}
config := service.config
if err := service.pkr.UpdateConfigFromParams(config, params); err != nil {
service.Logf("Failed to update params: %v", err)
}

postURL, err := buildURL(config)
if err != nil {
return err
}
jsonBody, err := json.Marshal(JSON{
Message: message,
Title: getTitle(*params),
Priority: getPriority(*params),
Title: config.Title,
Priority: config.Priority,
})
if err != nil {
return err
Expand Down
33 changes: 27 additions & 6 deletions pkg/services/gotify/gotify_config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package gotify

import (
"github.com/containrrr/shoutrrr/pkg/format"
"github.com/containrrr/shoutrrr/pkg/types"
"net/url"

"github.com/containrrr/shoutrrr/pkg/services/standard"
Expand All @@ -9,25 +11,44 @@ import (
// Config for use within the gotify plugin
type Config struct {
standard.EnumlessConfig
Token string
Host string
Prority int
Token string
Host string
Priority int `key:"priority" default:"0"`
Title string `key:"title" default:"Shoutrrr notification"`
DisableTLS bool `key:"disabletls" default:"No"`
}

// GetURL returns a URL representation of it's current field values
func (config *Config) GetURL() *url.URL {
resolver := format.NewPropKeyResolver(config)
return config.getURL(&resolver)
}

// SetURL updates a ServiceConfig from a URL representation of it's field values
func (config *Config) SetURL(url *url.URL) error {
resolver := format.NewPropKeyResolver(config)
return config.setURL(&resolver, url)
}

func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL {
return &url.URL{
Host: config.Host,
Scheme: Scheme,
ForceQuery: false,
Path: config.Token,
RawQuery: format.BuildQuery(resolver),
}
}

// SetURL updates a ServiceConfig from a URL representation of it's field values
func (config *Config) SetURL(url *url.URL) error {
config.Host = url.Hostname()
func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) error {
config.Host = url.Host
config.Token = url.Path

for key, vals := range url.Query() {
if err := resolver.Set(key, vals[0]); err != nil {
return err
}
}
return nil
}

Expand Down
93 changes: 72 additions & 21 deletions pkg/services/gotify/gotify_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package gotify

import (
"errors"
"github.com/jarcoal/httpmock"
"log"
"net/url"
"testing"

. "github.com/onsi/ginkgo"
Expand All @@ -12,6 +16,8 @@ func TestGotify(t *testing.T) {
RunSpecs(t, "Shoutrrr Gotify Suite")
}

var logger *log.Logger

var _ = Describe("the Gotify plugin URL building and token validation functions", func() {
It("should build a valid gotify URL", func() {
config := Config{
Expand All @@ -23,29 +29,21 @@ var _ = Describe("the Gotify plugin URL building and token validation functions"
expectedURL := "https://my.gotify.tld/message?token=Aaa.bbb.ccc.ddd"
Expect(url).To(Equal(expectedURL))
})
When("provided empty params", func() {
It("should return 0", func() {
params := make(map[string]string)
priority := getPriority(params)
Expect(priority).To(Equal(0))
})
})
When("provided invalid params", func() {
It("should return 0", func() {
params := make(map[string]string)
params["priority"] = "not an integer"
priority := getPriority(params)
Expect(priority).To(Equal(0))
})
})
When("provided 42", func() {
It("should return 42", func() {
params := make(map[string]string)
params["priority"] = "42"
priority := getPriority(params)
Expect(priority).To(Equal(42))

When("TLS is disabled", func() {
It("should use http schema", func() {
config := Config{
Token: "Aaa.bbb.ccc.ddd",
Host: "my.gotify.tld",
DisableTLS: true,
}
url, err := buildURL(&config)
Expect(err).To(BeNil())
expectedURL := "http://my.gotify.tld/message?token=Aaa.bbb.ccc.ddd"
Expect(url).To(Equal(expectedURL))
})
})

When("provided a valid token", func() {
It("should return true", func() {
token := "Ahwbsdyhwwgarxd"
Expand All @@ -64,4 +62,57 @@ var _ = Describe("the Gotify plugin URL building and token validation functions"
Expect(isTokenValid(token)).To(BeFalse())
})
})
Describe("creating a config", func() {
When("parsing the configuration URL", func() {
It("should be identical after de-/serialization", func() {
testURL := "gotify://my.gotify.tld/Aaa.bbb.ccc.ddd?disabletls=No&priority=1&title=Test title"

url, err := url.Parse(testURL)
Expect(err).NotTo(HaveOccurred(), "parsing")

config := &Config{}
err = config.SetURL(url)
Expect(err).NotTo(HaveOccurred(), "verifying")

outputURL := config.GetURL()

Expect(outputURL.String()).To(Equal(testURL))

})
})
})

Describe("sending the payload", func() {
var err error
var service Service
BeforeEach(func() {
httpmock.Activate()
})
AfterEach(func() {
httpmock.DeactivateAndReset()
})
It("should not report an error if the server accepts the payload", func() {
serviceURL, _ := url.Parse("gotify://my.gotify.tld/Aaa.bbb.ccc.ddd")
err = service.Initialize(serviceURL, logger)
Expect(err).NotTo(HaveOccurred())

targetURL := "https://my.gotify.tld/message?token=Aaa.bbb.ccc.ddd"
httpmock.RegisterResponder("POST", targetURL, httpmock.NewStringResponder(200, ""))

err = service.Send("Message", nil)
Expect(err).NotTo(HaveOccurred())
})
It("should not panic if an error occurs when sending the payload", func() {
serviceURL, _ := url.Parse("gotify://my.gotify.tld/Aaa.bbb.ccc.ddd")
err = service.Initialize(serviceURL, logger)
Expect(err).NotTo(HaveOccurred())

targetURL := "https://my.gotify.tld/message?token=Aaa.bbb.ccc.ddd"
httpmock.RegisterResponder("POST", targetURL, httpmock.NewErrorResponder(errors.New("dummy error")))

err = service.Send("Message", nil)
Expect(err).To(HaveOccurred())
})

})
})

0 comments on commit 91cd790

Please sign in to comment.