Skip to content

Commit

Permalink
Revert "Remove rocketchat as ticketer"
Browse files Browse the repository at this point in the history
This reverts commit e67f87c.
  • Loading branch information
rowanseymour committed Nov 11, 2022
1 parent ee38a8c commit 7268a1e
Show file tree
Hide file tree
Showing 12 changed files with 936 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/mailroom/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
_ "github.com/nyaruka/mailroom/services/ivr/vonage"
_ "github.com/nyaruka/mailroom/services/tickets/intern"
_ "github.com/nyaruka/mailroom/services/tickets/mailgun"
_ "github.com/nyaruka/mailroom/services/tickets/rocketchat"
_ "github.com/nyaruka/mailroom/services/tickets/zendesk"
_ "github.com/nyaruka/mailroom/web/contact"
_ "github.com/nyaruka/mailroom/web/docs"
Expand Down
146 changes: 146 additions & 0 deletions services/tickets/rocketchat/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package rocketchat

import (
"bytes"
"fmt"
"github.com/nyaruka/gocommon/httpx"
"github.com/nyaruka/gocommon/jsonx"
"github.com/pkg/errors"
"io"
"net/http"
)

// Client is a basic RocketChat app client
type Client struct {
httpClient *http.Client
httpRetries *httpx.RetryConfig
baseURL string
secret string
}

// NewClient creates a new RocketChat app client
func NewClient(httpClient *http.Client, httpRetries *httpx.RetryConfig, baseURL, secret string) *Client {
return &Client{
httpClient: httpClient,
httpRetries: httpRetries,
baseURL: baseURL,
secret: secret,
}
}

type errorResponse struct {
Error string `json:"error"`
}

func (c *Client) request(method, endpoint string, payload interface{}, response interface{}) (*httpx.Trace, error) {
url := fmt.Sprintf("%s/%s", c.baseURL, endpoint)
headers := map[string]string{
"Authorization": fmt.Sprintf("Token %s", c.secret),
"Content-Type": "application/json",
}
var body io.Reader

if payload != nil {
data, err := jsonx.Marshal(payload)
if err != nil {
return nil, err
}
body = bytes.NewReader(data)
}

req, err := httpx.NewRequest(method, url, body, headers)
if err != nil {
return nil, err
}

trace, err := httpx.DoTrace(c.httpClient, req, c.httpRetries, nil, -1)
if err != nil {
return trace, err
}

if trace.Response.StatusCode >= 400 {
response := &errorResponse{}
err := jsonx.Unmarshal(trace.ResponseBody, response)
if err != nil {
return trace, err
}
return trace, errors.New(response.Error)
}

if response != nil {
return trace, jsonx.Unmarshal(trace.ResponseBody, response)
}
return trace, nil
}

func (c *Client) get(endpoint string, payload interface{}, response interface{}) (*httpx.Trace, error) {
return c.request("GET", endpoint, payload, response)
}

func (c *Client) post(endpoint string, payload interface{}, response interface{}) (*httpx.Trace, error) {
return c.request("POST", endpoint, payload, response)
}

type Visitor struct {
Token string `json:"token"`
ContactUUID string `json:"contactUUID,omitempty"`
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
}

type Room struct {
Visitor Visitor `json:"visitor"`
TicketID string `json:"ticketID"`
}

// CreateRoom creates a new room and returns the ID
func (c *Client) CreateRoom(room *Room) (string, *httpx.Trace, error) {
response := &struct {
ID string `json:"id"`
}{}

trace, err := c.get("room", room, response)
if err != nil {
return "", trace, err
}

return response.ID, trace, nil
}

func (c *Client) CloseRoom(visitor *Visitor) (*httpx.Trace, error) {
payload := struct {
Visitor *Visitor `json:"visitor"`
}{Visitor: visitor}

trace, err := c.get("room.close", payload, nil)
if err != nil {
return trace, err
}

return trace, nil
}

type Attachment struct {
Type string `json:"type"`
URL string `json:"url"`
}

type VisitorMsg struct {
Visitor Visitor `json:"visitor"`
Text string `json:"text,omitempty"`
Attachments []Attachment `json:"attachments,omitempty"`
}

func (c *Client) SendMessage(msg *VisitorMsg) (string, *httpx.Trace, error) {
response := &struct {
ID string `json:"id"`
}{}

trace, err := c.post("visitor-message", msg, response)
if err != nil {
return "", trace, err
}

return response.ID, trace, nil
}
109 changes: 109 additions & 0 deletions services/tickets/rocketchat/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package rocketchat_test

import (
"net/http"
"testing"

"github.com/nyaruka/gocommon/httpx"
"github.com/nyaruka/mailroom/services/tickets/rocketchat"
"github.com/stretchr/testify/assert"
)

const (
baseURL = "https://my.rocket.chat/api/apps/public/684202ed-1461-4983-9ea7-fde74b15026c"
secret = "123456789"
)

func TestCreateRoom(t *testing.T) {
defer httpx.SetRequestor(httpx.DefaultRequestor)

httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{
baseURL + "/room": {
httpx.MockConnectionError,
httpx.NewMockResponse(400, nil, []byte(`{ "error": "There's no agents online" }`)),
httpx.NewMockResponse(201, nil, []byte(`{ "id": "uiF7ybjsv7PSJGSw6" }`)),
},
}))

client := rocketchat.NewClient(http.DefaultClient, nil, baseURL, secret)
room := &rocketchat.Room{
Visitor: rocketchat.Visitor{
Token: "1234",
ContactUUID: "88ff1e41-c1f8-4637-af8e-d56acbde9171",
Name: "Bob",
Email: "bob@acme.com",
Phone: "+16055741111",
},
TicketID: "88ff1e41-c1f8-4637-af8e-d56acbde9171",
}

_, _, err := client.CreateRoom(room)
assert.EqualError(t, err, "unable to connect to server")

_, _, err = client.CreateRoom(room)
assert.EqualError(t, err, "There's no agents online")

id, trace, err := client.CreateRoom(room)
assert.NoError(t, err)
assert.Equal(t, id, "uiF7ybjsv7PSJGSw6")
assert.Equal(t, "HTTP/1.0 201 Created\r\nContent-Length: 29\r\n\r\n", string(trace.ResponseTrace))
}

func TestCloseRoom(t *testing.T) {
defer httpx.SetRequestor(httpx.DefaultRequestor)

httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{
baseURL + "/room.close": {
httpx.MockConnectionError,
httpx.NewMockResponse(400, nil, []byte(`{ "error": "Could not find a room for visitor token: 1234" }`)),
httpx.NewMockResponse(204, nil, nil),
},
}))

client := rocketchat.NewClient(http.DefaultClient, nil, baseURL, secret)
visitor := &rocketchat.Visitor{Token: "1234"}

_, err := client.CloseRoom(visitor)
assert.EqualError(t, err, "unable to connect to server")

_, err = client.CloseRoom(visitor)
assert.EqualError(t, err, "Could not find a room for visitor token: 1234")

trace, err := client.CloseRoom(visitor)
assert.NoError(t, err)
assert.Equal(t, "HTTP/1.0 204 No Content\r\n\r\n", string(trace.ResponseTrace))
}

func TestSendMessage(t *testing.T) {
defer httpx.SetRequestor(httpx.DefaultRequestor)

httpx.SetRequestor(httpx.NewMockRequestor(map[string][]*httpx.MockResponse{
baseURL + "/visitor-message": {
httpx.MockConnectionError,
httpx.NewMockResponse(400, nil, []byte(`{ "error": "Could not find a room for visitor token: 1234" }`)),
httpx.NewMockResponse(201, nil, []byte(`{ "id": "tyLrD97j8TFZmT3Y6" }`)),
},
}))

client := rocketchat.NewClient(http.DefaultClient, nil, baseURL, secret)
msg := &rocketchat.VisitorMsg{
Visitor: rocketchat.Visitor{Token: "1234"},
Text: "Can you help me?",
Attachments: []rocketchat.Attachment{
{Type: "image/jpg", URL: "https://link.to/image.jpg"},
{Type: "video/mp4", URL: "https://link.to/video.mp4"},
{Type: "audio/ogg", URL: "https://link.to/audio.ogg"},
},
}

_, _, err := client.SendMessage(msg)
assert.EqualError(t, err, "unable to connect to server")

_, _, err = client.SendMessage(msg)
assert.EqualError(t, err, "Could not find a room for visitor token: 1234")

id, trace, err := client.SendMessage(msg)
assert.NoError(t, err)
assert.Equal(t, id, "tyLrD97j8TFZmT3Y6")
assert.Equal(t, "HTTP/1.0 201 Created\r\nContent-Length: 29\r\n\r\n", string(trace.ResponseTrace))
}
Loading

0 comments on commit 7268a1e

Please # to comment.