Class: ZendeskApiService

Inherits:
Object
  • Object
show all
Includes:
ActionView::Helpers::SanitizeHelper
Defined in:
app/services/zendesk_api_service.rb

Overview

ZendeskApiService provides methods to interact with the Zendesk API.

erp_user_id = ErpUser.all.sample.id

local_user = ErpUser.find(erp_user_id)
company = local_user.companies.first

zendesk_service = ZendeskApiService.new(company: company)
organization = zendesk_service.organization

user = zendesk_service.user(local_user)
users = zendesk_service.users
suspended_user = zendesk_service.suspend_user(local_user)

organization_membership = zendesk_service.organization_membership(local_user)

created_ticket = zendesk_service.create_ticket(
   local_user: local_user,
   subject: 'Hello',
   description: 'Need help',
   uploads: []
)
ticket_id = created_ticket['id']
tickets = zendesk_service.tickets(page: 1, per_page: 50)

created_ticket_comment = zendesk_service.create_ticket_comment(
   ticket_id: ticket_id, local_user: local_user, html: '<p>Hi</p>', uploads: []
)
ticket = zendesk_service.ticket(ticket_id)

populated_tickets = zendesk_service.populated_tickets(page: 1, per_page: 50)
ticket_with_requester = zendesk_service.ticket_with_requester(ticket_id)

Constant Summary collapse

ZENDESK_BASE_URL =
Rails.application.credentials.zendesk_base_url
ZENDESK_API_KEY =
Rails.application.credentials.zendesk_api_key
ZENDESK_USER =
Rails.application.credentials.zendesk_user
PER_PAGE =
100
RESOURCE_TYPES =
{
  USER: 'user',
  ORGANIZATION: 'organization',
  TICKET: 'ticket',
  ORGANIZATION_MEMBERSHIPS: 'organization_membership'
}.freeze
EXTERNAL_ID_PREFIXES =
{
  USER: 'paiehub_user_id',
  ORGANIZATION: 'paiehub_company_id'
}.freeze
DEFAULT_TICKET_PRIORITY =
'normal'
DEFAULT_TICKET_TYPE =
'question'
DEFAULT_TICKET_STATUS =
'open'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(company:) ⇒ ZendeskApiService

Initializes a new instance of ZendeskApiService.

Parameters:

  • company (Company)

    the company object



65
66
67
# File 'app/services/zendesk_api_service.rb', line 65

def initialize(company:)
  @company = company
end

Instance Attribute Details

#companyObject (readonly)

Returns the value of attribute company.



60
61
62
# File 'app/services/zendesk_api_service.rb', line 60

def company
  @company
end

Class Method Details

.connFaraday::Connection

Returns the Faraday connection.

Returns:

  • (Faraday::Connection)

    the Faraday connection



635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
# File 'app/services/zendesk_api_service.rb', line 635

def conn
  @conn ||= Faraday.new(url: "#{ZENDESK_BASE_URL}/api/v2/") do |faraday|
    faraday.request :json
    faraday.response :json
    faraday.response :raise_error
    faraday.use FaradayCustomErrorMiddleware
    faraday.use RateLimitAdapter,
                rate_limit_key: 'zendesk_api_limit',
                max_requests: 200,
                duration: 30,
                max_wait_time: 5
    faraday.headers['Accept'] = 'application/json'
    faraday.headers['Authorization'] =
      "Basic #{Base64.strict_encode64("#{ZENDESK_USER}/token:#{ZENDESK_API_KEY}")}"
    faraday.adapter Faraday.default_adapter
  end
end

.create(resource, params) ⇒ Hash

Creates a resource in Zendesk.

Parameters:

  • resource (String)

    the resource type

  • params (Hash)

    the creation parameters

Returns:

  • (Hash)

    the created resource data



586
587
588
589
590
591
592
# File 'app/services/zendesk_api_service.rb', line 586

def create(resource, params)
  plural_resource = resource.pluralize
  response = conn.post("#{plural_resource}.json", {
                         resource => params
                       })
  soft_parse(response.body)
end

.each_search_page(params, per_page: PER_PAGE) {|response, current_page| ... } ⇒ Object

Iterates over each search page.

Parameters:

  • params (Hash)

    the search parameters

  • per_page (Integer) (defaults to: PER_PAGE)

    the number of results per page

Yields:

  • (response, current_page)

    the search response and current page number



535
536
537
538
539
540
541
542
543
544
# File 'app/services/zendesk_api_service.rb', line 535

def each_search_page(params, per_page: PER_PAGE)
  current_page = 1
  loop do
    response = search(params, page: current_page, per_page: per_page)
    yield response, current_page
    break if response[:data].empty?

    current_page += 1
  end
end

.each_search_result(params, per_page: PER_PAGE) {|result| ... } ⇒ Object

Iterates over each search result.

Parameters:

  • params (Hash)

    the search parameters

  • per_page (Integer) (defaults to: PER_PAGE)

    the number of results per page

Yields:

  • (result)

    the search result



551
552
553
554
555
# File 'app/services/zendesk_api_service.rb', line 551

def each_search_result(params, per_page: PER_PAGE, &block)
  each_search_page(params, per_page: per_page) do |response, _current_page|
    response[:data].each(&block)
  end
end

.find(resource, id) ⇒ Hash

Finds a resource in Zendesk.

Parameters:

  • resource (String)

    the resource type

  • id (Integer)

    the resource ID

Returns:

  • (Hash)

    the resource data



599
600
601
602
603
# File 'app/services/zendesk_api_service.rb', line 599

def find(resource, id)
  plural_resource = resource.pluralize
  response = conn.get("#{plural_resource}/#{id}.json")
  soft_parse(response.body)
end

.find_many(resource, ids, key_name = 'ids') ⇒ Hash

Finds multiple resources in Zendesk.

Parameters:

  • resource (String)

    the resource type

  • ids (Array<Integer>)

    the resource IDs

  • key_name (String) (defaults to: 'ids')

    the key name for the IDs

Returns:

  • (Hash)

    the resources data



611
612
613
614
615
616
617
# File 'app/services/zendesk_api_service.rb', line 611

def find_many(resource, ids, key_name = 'ids')
  plural_resource = resource.pluralize
  response = conn.get("#{plural_resource}/show_many.json", {
                        key_name => ids.join(',')
                      })
  soft_parse(response.body)
end

.get(endpoint, params = { page: 1, per_page: PER_PAGE }) ⇒ Hash

Retrieves data from an endpoint in Zendesk.

Parameters:

  • endpoint (String)

    the endpoint

  • params (Hash) (defaults to: { page: 1, per_page: PER_PAGE })

    the parameters

Returns:

  • (Hash)

    the response data



624
625
626
627
628
629
630
# File 'app/services/zendesk_api_service.rb', line 624

def get(endpoint, params = {
  page: 1,
  per_page: PER_PAGE
})
  response = conn.get(endpoint, params)
  soft_parse(response.body)
end

.params_to_query(params) ⇒ String

Converts parameters to a query string.

Parameters:

  • params (Hash)

    the parameters

Returns:

  • (String)

    the query string



561
562
563
564
565
# File 'app/services/zendesk_api_service.rb', line 561

def params_to_query(params)
  params.map do |key, value|
    "#{URI.encode_www_form_component(key.to_s)}:#{URI.encode_www_form_component(value.to_s)}"
  end.join(' ')
end

.search(params, page: 1, per_page: PER_PAGE) ⇒ Hash

Searches for resources in Zendesk.

Parameters:

  • params (Hash)

    the search parameters

  • page (Integer) (defaults to: 1)

    the page number

  • per_page (Integer) (defaults to: PER_PAGE)

    the number of results per page

Returns:

  • (Hash)

    the search results and metadata



512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'app/services/zendesk_api_service.rb', line 512

def search(params, page: 1, per_page: PER_PAGE)
  response = conn.get('search.json', {
                        query: params_to_query(params),
                        page: page,
                        per_page: per_page
                      })
  data = soft_parse(response.body)

  {
    data: data['results'],
    metadata: {
      total: data['count'],
      limit: per_page,
      offset: (page - 1) * per_page
    }
  }
end

.soft_parse(body) ⇒ Hash

Parses the response body.

Parameters:

  • body (String)

    the response body

Returns:

  • (Hash)

    the parsed response body



657
658
659
660
661
# File 'app/services/zendesk_api_service.rb', line 657

def soft_parse(body)
  JSON.parse(body)
rescue StandardError
  body || {}
end

.update(resource, id, params) ⇒ Hash

Updates a resource in Zendesk.

Parameters:

  • resource (String)

    the resource type

  • id (Integer)

    the resource ID

  • params (Hash)

    the update parameters

Returns:

  • (Hash)

    the updated resource data



573
574
575
576
577
578
579
# File 'app/services/zendesk_api_service.rb', line 573

def update(resource, id, params)
  plural_resource = resource.pluralize
  response = conn.put("#{plural_resource}/#{id}.json", {
                        resource => params
                      })
  soft_parse(response.body)
end

Instance Method Details

#create_ticket(local_user:, subject:, description:, uploads:, priority:) ⇒ Hash

Creates a ticket in Zendesk.

Parameters:

  • local_user (ErpUser)

    the local user object

  • subject (String)

    the ticket subject

  • description (String)

    the ticket description

  • uploads (Array)

    the uploads for the ticket

Returns:

  • (Hash)

    the created ticket data



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/services/zendesk_api_service.rb', line 138

def create_ticket(
  local_user:,
  subject:,
  description:,
  uploads:,
  priority:
)
  self.class.create(RESOURCE_TYPES[:TICKET], {
                      priority: priority,
                      type: DEFAULT_TICKET_TYPE,
                      status: DEFAULT_TICKET_STATUS,
                      requester_id: user_id(local_user),
                      subject: subject,
                      comment: {
                        body: description,
                        uploads: attachments(uploads).pluck('token')
                      }
                    })['ticket']
end

#create_ticket_comment(ticket_id:, local_user:, html:, uploads:) ⇒ Hash

Creates a comment on a ticket in Zendesk.

Parameters:

  • ticket_id (Integer)

    the ticket ID

  • local_user (ErpUser)

    the local user object

  • html (String)

    the HTML content of the comment

  • uploads (Array)

    the uploads for the comment

Returns:

  • (Hash)

    the updated ticket data



196
197
198
199
200
201
202
203
204
# File 'app/services/zendesk_api_service.rb', line 196

def create_ticket_comment(ticket_id:, local_user:, html:, uploads:)
  self.class.update(RESOURCE_TYPES[:TICKET], ticket_id, {
                      comment: {
                        html_body: html,
                        author_id: user_id(local_user),
                        uploads: attachments(uploads).pluck('token')
                      }
                    })['ticket']
end

#create_ticket_with_cc(cc_users:, subject:, description:, uploads:, priority:) ⇒ Hash

Creates a ticket in Zendesk with CC users. The first user in the cc_users array will be set as the requester.

Parameters:

  • cc_users (Array<ErpUser>)

    the local user objects to be CC’d. The first user becomes the requester.

  • subject (String)

    the ticket subject

  • description (String)

    the ticket description

  • uploads (Array)

    the uploads for the ticket

  • priority (String)

    the ticket priority

Returns:

  • (Hash)

    the created ticket data



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'app/services/zendesk_api_service.rb', line 167

def create_ticket_with_cc(
  cc_users:,
  subject:,
  description:,
  uploads:,
  priority:
)
  cc_user_ids = cc_users.map { |user| user_id(user) }
  self.class.create(RESOURCE_TYPES[:TICKET], {
                      priority: priority,
                      type: DEFAULT_TICKET_TYPE,
                      status: DEFAULT_TICKET_STATUS,
                      requester_id: cc_user_ids.first,
                      email_cc_ids: cc_user_ids,
                      subject: subject,
                      comment: {
                        body: description,
                        uploads: attachments(uploads).pluck('token')
                      }
                    })['ticket']
end

#organizationHash

Retrieves the organization from Zendesk.

Returns:

  • (Hash)

    the organization data



72
73
74
75
76
77
# File 'app/services/zendesk_api_service.rb', line 72

def organization
  self.class.find(
    RESOURCE_TYPES[:ORGANIZATION],
    organization_id
  )['organization']
end

#organization_membership(local_user) ⇒ Hash

Retrieves the organization membership for a user.

Parameters:

  • local_user (ErpUser)

    the local user object

Returns:

  • (Hash)

    the organization membership data



115
116
117
118
119
# File 'app/services/zendesk_api_service.rb', line 115

def organization_membership(local_user)
  self.class.find(
    RESOURCE_TYPES[:ORGANIZATION_MEMBERSHIPS], organization_membership_id(local_user)
  )['organization_membership']
end

#populated_tickets(page: 1, per_page: PER_PAGE, sort_by: 'updated_at', sort_order: 'desc') ⇒ Hash

Retrieves tickets with requesters from Zendesk.

Parameters:

  • page (Integer) (defaults to: 1)

    the page number

  • per_page (Integer) (defaults to: PER_PAGE)

    the number of tickets per page

  • sort_by (String) (defaults to: 'updated_at')

    the field to sort by

  • sort_order (String) (defaults to: 'desc')

    the sort order

Returns:

  • (Hash)

    the tickets data and metadata



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'app/services/zendesk_api_service.rb', line 254

def populated_tickets(
  page: 1,
  per_page: PER_PAGE,
  sort_by: 'updated_at',
  sort_order: 'desc'
)
  data,  = tickets(
    page: page,
    per_page: per_page,
    sort_by: sort_by,
    sort_order: sort_order
  ).values_at(:data, :metadata)
  data = populate_tickets_list_children(tickets: data)

  {
    data: data,
    metadata: 
  }
end

#suspend_user(local_user) ⇒ Hash

Suspends a user in Zendesk.

Parameters:

  • local_user (ErpUser)

    the local user object

Returns:

  • (Hash)

    the suspended user data



125
126
127
128
129
# File 'app/services/zendesk_api_service.rb', line 125

def suspend_user(local_user)
  self.class.update(RESOURCE_TYPES[:USER], user_id(local_user), {
                      suspended: true
                    })['user']
end

#ticket(ticket_id) ⇒ Hash

Retrieves a ticket from Zendesk.

Parameters:

  • ticket_id (Integer)

    the ticket ID

Returns:

  • (Hash)

    the ticket data



210
211
212
213
214
215
216
217
# File 'app/services/zendesk_api_service.rb', line 210

def ticket(ticket_id)
  resource = self.class.find(RESOURCE_TYPES[:TICKET], ticket_id)['ticket']
  ticket_organization_id = resource['organization_id']
  resource['description'] = sanitize(resource['description'])
  raise 'Ticket not found' if ticket_organization_id != organization_id

  resource
end

#ticket_with_requester(ticket_id) ⇒ Hash

Retrieves a ticket with requester from Zendesk.

Parameters:

  • ticket_id (Integer)

    the ticket ID

Returns:

  • (Hash)

    the ticket data with requester information



278
279
280
281
# File 'app/services/zendesk_api_service.rb', line 278

def ticket_with_requester(ticket_id)
  ticket = ticket(ticket_id)
  populate_ticket_children(ticket: ticket)
end

#tickets(page: 1, per_page: PER_PAGE, sort_by: 'updated_at', sort_order: 'desc') ⇒ Hash

Retrieves tickets from Zendesk.

Parameters:

  • page (Integer) (defaults to: 1)

    the page number

  • per_page (Integer) (defaults to: PER_PAGE)

    the number of tickets per page

  • sort_by (String) (defaults to: 'updated_at')

    the field to sort by

  • sort_order (String) (defaults to: 'desc')

    the sort order

Returns:

  • (Hash)

    the tickets data and metadata



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'app/services/zendesk_api_service.rb', line 226

def tickets(page: 1, per_page: PER_PAGE, sort_by: 'updated_at', sort_order: 'desc')
  response = self.class.get(
    "organizations/#{organization_id}/tickets.json",
    {
      page: page,
      per_page: per_page,
      sort_by: sort_by,
      sort_order: sort_order
    }
  )

  {
    data: response['tickets'],
    metadata: {
      total: response['count'],
      limit: per_page,
      offset: (page - 1) * per_page
    }
  }
end

#user(local_user) ⇒ Hash

Retrieves a user from Zendesk.

Parameters:

  • local_user (ErpUser)

    the local user object

Returns:

  • (Hash)

    the user data



107
108
109
# File 'app/services/zendesk_api_service.rb', line 107

def user(local_user)
  self.class.find(RESOURCE_TYPES[:USER], user_id(local_user))
end

#users(page: 1, per_page: PER_PAGE) ⇒ Hash

Retrieves users from Zendesk.

Parameters:

  • page (Integer) (defaults to: 1)

    the page number

  • per_page (Integer) (defaults to: PER_PAGE)

    the number of users per page

Returns:

  • (Hash)

    the users data and metadata



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'app/services/zendesk_api_service.rb', line 84

def users(page: 1, per_page: PER_PAGE)
  response = self.class.get(
    "organizations/#{organization_id}/users.json",
    {
      page: page,
      per_page: per_page
    }
  )

  {
    data: response['users'],
    metadata: {
      total: response['count'],
      limit: per_page,
      offset: (page - 1) * per_page
    }
  }
end