diff --git a/docs/services/webex.md b/docs/services/webex.md index c2feb3b1..9b790c39 100644 --- a/docs/services/webex.md +++ b/docs/services/webex.md @@ -5,9 +5,13 @@ Adds Webex service functionality !!! info "Your bot must be in the room" Your bot must be invited to the room before a message can be sent by it. -## Examples +## URL Format -!!! example "General" +The URL format requires the `@webex?` to be present. This is to handle the URL +being parsed properly and is ignored. + +!!! info "" ```uri - webex://your-bot-token@your-room-id - ``` \ No newline at end of file + webex://__`token`__@webex?rooms=__`room-1`__[,__`room-2`__,...] + +--8<-- "docs/services/webex/config.md" \ No newline at end of file diff --git a/pkg/services/webex/webex.go b/pkg/services/webex/webex.go index 3b6c0cfa..63fcbd10 100644 --- a/pkg/services/webex/webex.go +++ b/pkg/services/webex/webex.go @@ -57,28 +57,36 @@ func (service *Service) Initialize(configURL *url.URL, logger types.StdLogger) e } func doSend(message string, config *Config) error { - req, err := BuildRequestFromPayloadAndConfig(message, config) - if err != nil { - return err - } + var firstErr error - res, err := http.DefaultClient.Do(req) + for _, room := range config.Rooms { + req, firstErr := BuildRequestFromPayloadAndConfig(message, room, config) + if firstErr != nil { + return firstErr + } - if res == nil && err == nil { - err = fmt.Errorf("unknown error") - } + res, firstErr := http.DefaultClient.Do(req) + + if res == nil && firstErr == nil { + firstErr = fmt.Errorf("unknown error") + } + + if firstErr == nil && res.StatusCode != http.StatusOK { + firstErr = fmt.Errorf("response status code %s", res.Status) + } - if err == nil && res.StatusCode != http.StatusOK { - err = fmt.Errorf("response status code %s", res.Status) + if firstErr != nil { + return firstErr + } } - return err + return firstErr } -func BuildRequestFromPayloadAndConfig(message string, config *Config) (*http.Request, error) { +func BuildRequestFromPayloadAndConfig(message string, room string, config *Config) (*http.Request, error) { var err error payload := MessagePayload{ - RoomID: config.RoomID, + RoomID: room, Markdown: message, } diff --git a/pkg/services/webex/webex_config.go b/pkg/services/webex/webex_config.go index 268d5664..8c2c9c04 100644 --- a/pkg/services/webex/webex_config.go +++ b/pkg/services/webex/webex_config.go @@ -12,8 +12,8 @@ import ( // Config is the configuration needed to send webex notifications type Config struct { standard.EnumlessConfig - RoomID string `url:"host"` - BotToken string `url:"user"` + BotToken string `url:"user"` + Rooms []string `key:"rooms"` } // GetURL returns a URL representation of it's current field values @@ -31,10 +31,10 @@ func (config *Config) SetURL(url *url.URL) error { func (config *Config) getURL(resolver types.ConfigQueryResolver) (u *url.URL) { u = &url.URL{ User: url.User(config.BotToken), - Host: config.RoomID, + Host: Scheme, Scheme: Scheme, RawQuery: format.BuildQuery(resolver), - ForceQuery: false, + ForceQuery: true, } return u @@ -42,8 +42,6 @@ func (config *Config) getURL(resolver types.ConfigQueryResolver) (u *url.URL) { // SetURL updates a ServiceConfig from a URL representation of it's field values func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) error { - - config.RoomID = url.Host config.BotToken = url.User.Username() if len(url.Path) > 0 { @@ -54,8 +52,14 @@ func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) e } } - if config.RoomID == "" { - return errors.New("room ID missing from config URL") + for key, vals := range url.Query() { + if err := resolver.Set(key, vals[0]); err != nil { + return err + } + } + + if len(config.Rooms) < 1 { + return errors.New("no rooms defined in config URL") } if len(config.BotToken) < 1 { diff --git a/pkg/services/webex/webex_test.go b/pkg/services/webex/webex_test.go index 0283b29c..be5bbebf 100644 --- a/pkg/services/webex/webex_test.go +++ b/pkg/services/webex/webex_test.go @@ -78,7 +78,7 @@ var _ = Describe("the webex service", func() { }) When("parsing the configuration URL", func() { It("should be identical after de-/serialization", func() { - testURL := "webex://token@room" + testURL := "webex://token@webex?rooms=room" url, err := url.Parse(testURL) Expect(err).NotTo(HaveOccurred(), "parsing") @@ -97,9 +97,10 @@ var _ = Describe("the webex service", func() { Describe("sending the payload", func() { var dummyConfig = Config{ - RoomID: "1", BotToken: "dummyToken", + Rooms: []string{"1", "2"}, } + var service Service BeforeEach(func() { httpmock.Activate() @@ -108,32 +109,38 @@ var _ = Describe("the webex service", func() { panic(fmt.Errorf("service initialization failed: %w", err)) } }) + AfterEach(func() { httpmock.DeactivateAndReset() }) + It("should not report an error if the server accepts the payload", func() { setupResponder(&dummyConfig, 200, "") Expect(service.Send("Message", nil)).To(Succeed()) }) + It("should report an error if the server response is not OK", func() { setupResponder(&dummyConfig, 400, "") Expect(service.Initialize(dummyConfig.GetURL(), logger)).To(Succeed()) Expect(service.Send("Message", nil)).NotTo(Succeed()) }) + It("should report an error if the message is empty", func() { setupResponder(&dummyConfig, 400, "") Expect(service.Initialize(dummyConfig.GetURL(), logger)).To(Succeed()) Expect(service.Send("", nil)).NotTo(Succeed()) }) }) + Describe("doing request", func() { dummyConfig := &Config{ BotToken: "dummyToken", + Rooms: []string{"1"}, } It("should add authorization header", func() { - request, err := BuildRequestFromPayloadAndConfig("", dummyConfig) + request, err := BuildRequestFromPayloadAndConfig("", dummyConfig.Rooms[0], dummyConfig) Expect(err).To(BeNil()) Expect(request.Header.Get("Authorization")).To(Equal("Bearer dummyToken")) @@ -141,7 +148,7 @@ var _ = Describe("the webex service", func() { // webex API rejects messages which do not define Content-Type It("should add content type header", func() { - request, err := BuildRequestFromPayloadAndConfig("", dummyConfig) + request, err := BuildRequestFromPayloadAndConfig("", dummyConfig.Rooms[0], dummyConfig) Expect(err).To(BeNil()) Expect(request.Header.Get("Content-Type")).To(Equal("application/json"))