Skip to content

Commit

Permalink
tickets/zendesk: service search or create user on open ticket
Browse files Browse the repository at this point in the history
  • Loading branch information
rasoro committed Aug 2, 2023
1 parent 33cd420 commit 0b6197d
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 28 deletions.
23 changes: 16 additions & 7 deletions services/tickets/zendesk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,19 +312,20 @@ func encodeIds(ids []int64) string {
// User see https://developer.zendesk.com/api-reference/ticketing/users/users/#json-format
type User struct {
ID int64 `json:"id,omitempty"`
Name string `json:"name"`
Name string `json:"name,omitempty"`
Organization struct {
Name string `json:"name"`
} `json:"organization"`
ExternalID string `json:"external_id"`
} `json:"organization,omitempty"`
ExternalID string `json:"external_id,omitempty"`
Identities []struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"identities,omitempty"`
Verified bool `json:"verified"`
Role string `json:"role"`
Verified bool `json:"verified,omitempty"`
Role string `json:"role,omitempty"`
}

// CreateUser creates a new user in zendesk
func (c *RESTClient) CreateUser(user *User) (*User, *httpx.Trace, error) {
payload := struct {
User *User `json:"user"`
Expand All @@ -342,12 +343,20 @@ func (c *RESTClient) CreateUser(user *User) (*User, *httpx.Trace, error) {
return response.User, trace, nil
}

type SearchUserResponse struct {
Users []User `json:"users"`
}

// SearchUser returns the user with the given external ID or nil if it doesn't exist
func (c *RESTClient) SearchUser(externalID string) (*User, *httpx.Trace, error) {
endpoint := fmt.Sprintf("users/search?external_id=%s", externalID)
var response map[string][]User
var response SearchUserResponse
trace, err := c.get(endpoint, nil, &response)
if err != nil {
return nil, trace, err
}
return &response["users"][0], trace, nil
if len(response.Users) == 0 {
return nil, trace, nil
}
return &response.Users[0], trace, nil
}
16 changes: 7 additions & 9 deletions services/tickets/zendesk/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,14 +316,8 @@ func TestSearchUser(t *testing.T) {
fmt.Sprintf("https://mocked_subdomain.zendesk.com/api/v2/users/search?external_id=%s", userUUID): {
httpx.MockConnectionError,
httpx.NewMockResponse(400, nil, `{"description": "Something went wrong", "error": "Unknown"}`),
httpx.NewMockResponse(201, nil, `{
"users": [
{
"id": 35436,
"name": "Dummy User"
}
]
}`),
httpx.NewMockResponse(200, nil, `{"users": []}`),
httpx.NewMockResponse(200, nil, `{"users": [{"id": 35436,"name": "Dummy User"}]}`),
},
}))

Expand All @@ -335,8 +329,12 @@ func TestSearchUser(t *testing.T) {
_, _, err = client.SearchUser(userUUID)
assert.EqualError(t, err, "Something went wrong")

user, _, err := client.SearchUser(userUUID)
assert.NoError(t, err)
assert.Nil(t, user)

user, trace, err := client.SearchUser(userUUID)
assert.NoError(t, err)
assert.Equal(t, "Dummy User", user.Name)
assert.Equal(t, "HTTP/1.0 201 Created\r\nContent-Length: 87\r\n\r\n", string(trace.ResponseTrace))
assert.Equal(t, "HTTP/1.0 200 OK\r\nContent-Length: 47\r\n\r\n", string(trace.ResponseTrace))
}
26 changes: 25 additions & 1 deletion services/tickets/zendesk/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,37 @@ func NewService(rtCfg *runtime.Config, httpClient *http.Client, httpRetries *htt
func (s *service) Open(session flows.Session, topic *flows.Topic, body string, assignee *flows.User, logHTTP flows.HTTPLogCallback) (*flows.Ticket, error) {
ticket := flows.OpenTicket(s.ticketer, topic, body, assignee)
contactDisplay := session.Contact().Format(session.Environment())
contactUUID := string(session.Contact().UUID())

user, trace, err := s.restClient.SearchUser(contactUUID)
if trace != nil {
logHTTP(flows.NewHTTPLog(trace, flows.HTTPStatusFromCode, s.redactor))
}
if err != nil && trace.Response.StatusCode != http.StatusNotFound {
return nil, err
}
if trace.Response.StatusCode == http.StatusNotFound || user == nil {
user := &User{
Name: contactDisplay,
ExternalID: contactUUID,
Verified: true,
Role: "end-user",
}
_, trace, err = s.restClient.CreateUser(user)
if trace != nil {
logHTTP(flows.NewHTTPLog(trace, flows.HTTPStatusFromCode, s.redactor))
}
if err != nil {
return nil, err
}
}

msg := &ExternalResource{
ExternalID: string(ticket.UUID()), // there's no local msg so use ticket UUID instead
ThreadID: string(ticket.UUID()),
CreatedAt: dates.Now(),
Author: Author{
ExternalID: string(session.Contact().UUID()),
ExternalID: contactUUID,
Name: contactDisplay,
},
AllowChannelback: true,
Expand Down
9 changes: 7 additions & 2 deletions services/tickets/zendesk/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ func TestOpenAndForward(t *testing.T) {
uuids.SetGenerator(uuids.NewSeededGenerator(12345))
dates.SetNowSource(dates.NewSequentialNowSource(time.Date(2019, 10, 7, 15, 21, 30, 0, time.UTC)))
httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{
"https://nyaruka.zendesk.com/api/v2/users/search?external_id=5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f": {
httpx.NewMockResponse(200, nil, `{"users": [{"id": 35241, "name": "Dummy User"}], "count": 1, "next_page": "https://nyaruka.zendesk.com/api/v2/users.json?page=2"}`),
httpx.NewMockResponse(200, nil, `{"users": [{"id": 35241, "name": "Dummy User"}], "count": 1, "next_page": "https://nyaruka.zendesk.com/api/v2/users.json?page=2"}`),
httpx.NewMockResponse(200, nil, `{"users": [{"id": 35241, "name": "Dummy User"}], "count": 1, "next_page": "https://nyaruka.zendesk.com/api/v2/users.json?page=2"}`),
},
"https://nyaruka.zendesk.com/api/v2/any_channel/push.json": {
httpx.MockConnectionError,
httpx.NewMockResponse(201, nil, `{
Expand Down Expand Up @@ -123,7 +128,7 @@ func TestOpenAndForward(t *testing.T) {
assert.Equal(t, "General", ticket.Topic().Name())
assert.Equal(t, fieldTicket, ticket.Body())
assert.Equal(t, "", ticket.ExternalID())
assert.Equal(t, 1, len(logger.Logs))
assert.Equal(t, 2, len(logger.Logs))
test.AssertSnapshot(t, "open_ticket", logger.Logs[0].Request)

dbTicket := models.NewTicket(ticket.UUID(), testdata.Org1.ID, testdata.Cathy.ID, testdata.Zendesk.ID, "", testdata.DefaultTopic.ID, "Where are my cookies?", models.NilUserID, map[string]interface{}{
Expand All @@ -147,7 +152,7 @@ func TestOpenAndForward(t *testing.T) {
logger = &flows.HTTPLogger{}
_, err = svc.Open(session, defaultTopic, fieldTicket1, nil, logger.Log)
assert.NoError(t, err)
assert.Equal(t, 1, len(logger.Logs))
assert.Equal(t, 2, len(logger.Logs))
test.AssertSnapshot(t, "open", logger.Logs[0].Request)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Authorization: Bearer ****************
Content-Type: application/json
Accept-Encoding: gzip

{"instance_push_id":"1234-abcd","request_id":"sesame:1570461700000000000","external_resources":[{"external_id":"ca5607f0-cba8-4c94-9cd5-c4fbc24aa767","message":"It's urgent","thread_id":"59d74b86-3e2f-4a93-aece-b05d2fdcde0c","created_at":"2019-10-07T15:21:39Z","author":{"external_id":"6393abc0-283d-4c9b-a1b3-641a035c34bf","name":"Cathy"},"allow_channelback":true,"file_urls":["https:///api/v2/file/0123/attachment1.jpg"]}]}
{"instance_push_id":"1234-abcd","request_id":"sesame:1570461704000000000","external_resources":[{"external_id":"ca5607f0-cba8-4c94-9cd5-c4fbc24aa767","message":"It's urgent","thread_id":"59d74b86-3e2f-4a93-aece-b05d2fdcde0c","created_at":"2019-10-07T15:21:43Z","author":{"external_id":"6393abc0-283d-4c9b-a1b3-641a035c34bf","name":"Cathy"},"allow_channelback":true,"file_urls":["https:///api/v2/file/0123/attachment1.jpg"]}]}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
PUT /api/v2/tickets/update_many.json?ids=10 HTTP/1.1
GET /api/v2/users/search?external_id=5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f HTTP/1.1
Host: nyaruka.zendesk.com
User-Agent: Go-http-client/1.1
Content-Length: 28
Authorization: Bearer ****************
Content-Type: application/json
Accept-Encoding: gzip

{"ticket":{"status":"open"}}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
POST /api/v2/any_channel/push.json HTTP/1.1
GET /api/v2/users/search?external_id=5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f HTTP/1.1
Host: nyaruka.zendesk.com
User-Agent: Go-http-client/1.1
Content-Length: 708
Authorization: Bearer ****************
Content-Type: application/json
Accept-Encoding: gzip

{"instance_push_id":"1234-abcd","request_id":"sesame:1570461696000000000","external_resources":[{"external_id":"59d74b86-3e2f-4a93-aece-b05d2fdcde0c","message":"Cookies","thread_id":"59d74b86-3e2f-4a93-aece-b05d2fdcde0c","created_at":"2019-10-07T15:21:35Z","author":{"external_id":"5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f","name":"Ryan Lewis"},"allow_channelback":true,"fields":[{"id":"message","value":"Cookies"},{"id":"priority","value":"high"},{"id":"subject","value":"Where are my cookies?"},{"id":"description","value":"I want to know where is my cookie."},{"id":"21938362","value":"hd_3000"},{"id":"tags","value":["TAG_01","TAG_02"]},{"id":"external_id","value":"59d74b86-3e2f-4a93-aece-b05d2fdcde0c"}]}]}

0 comments on commit 0b6197d

Please sign in to comment.