lita-zendesk 0.0.6 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +7 -11
- data/lib/lita/handlers/zendesk.rb +136 -97
- data/lita-zendesk.gemspec +3 -4
- metadata +12 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38716ec59f092963728bc33ed8856579870eda1a
|
4
|
+
data.tar.gz: 967a1bba6739466e7522a8c7bb4c3327b2ef7612
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9684aee6cc7da35e3bbef1ba930842d51b8464e6e6cc753e9f99f15c68cb02e8e6b2f90c8e81b760ff4ff40c9617f3443a9a4b990f391a632e6368ecf0235052
|
7
|
+
data.tar.gz: 3c906b02640c45574f335bee74a7a7032b8f44499c917a31358c65ff72a2021a6e3d4e4d013a92f86df91094cd17d383fc1b99d5432f738f207a0a0eb7524d76
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
---------
|
3
|
+
- **0.1.0** - 2015-09-12
|
4
|
+
- Additions
|
5
|
+
- Add comments to ticket details
|
6
|
+
- Add ticket requester to ticket details
|
7
|
+
- Add use of official Zendesk SDK
|
8
|
+
- Breaking Changes
|
9
|
+
- Update config to match Zendesk SDK, `user` is now `username`
|
3
10
|
- **0.0.6** - 2016-09-05
|
4
11
|
- Make routes case insensitive
|
5
12
|
- Add additional logging
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Lita Zendesk Handler
|
|
11
11
|
[![Docs][docs-rubydoc-svg]][docs-rubydoc-link]
|
12
12
|
[![License][license-svg]][license-link]
|
13
13
|
|
14
|
-
`lita-zendesk` is
|
14
|
+
`lita-zendesk` is a handler for [Lita](https://www.lita.io/) that allows you to use the robot with [Zendesk](https://zendesk.com/) ticket queries.
|
15
15
|
|
16
16
|
## Installation
|
17
17
|
|
@@ -23,27 +23,23 @@ gem "lita-zendesk"
|
|
23
23
|
|
24
24
|
## Configuration
|
25
25
|
|
26
|
-
Both Token and Password authentication are supported
|
26
|
+
Both Token and Password authentication are supported.
|
27
27
|
|
28
28
|
``` ruby
|
29
29
|
Lita.configure do |config|
|
30
30
|
|
31
31
|
# Zendesk user info
|
32
32
|
config.handlers.zendesk.subdomain = 'my_zendesk_subdomain'
|
33
|
-
config.handlers.zendesk.
|
34
|
-
config.handlers.zendesk.
|
35
|
-
config.handlers.zendesk.password = 'my_zendesk_password'
|
36
|
-
config.handlers.zendesk.token = 'my_zendesk_token'
|
37
|
-
|
38
|
-
# Optional config
|
39
|
-
config.handlers.zendesk.use_command = false # defaults to true
|
33
|
+
config.handlers.zendesk.username = 'my_zendesk_username'
|
34
|
+
config.handlers.zendesk.token = 'my_zendesk_token' # Use token or password
|
35
|
+
config.handlers.zendesk.password = 'my_zendesk_password' # Use token or password
|
40
36
|
|
41
37
|
end
|
42
38
|
```
|
43
39
|
|
44
40
|
## Usage
|
45
41
|
|
46
|
-
`zd` or `zendesk` both work for
|
42
|
+
`zd` or `zendesk` both work for triggering the handler.
|
47
43
|
|
48
44
|
```
|
49
45
|
Lita > @lita help
|
@@ -62,7 +58,7 @@ Lita: zd list pending tickets - returns a list of pending tickets
|
|
62
58
|
Lita: zd list new tickets - returns a list of new tickets
|
63
59
|
Lita: zd list esclated tickets - returns a list of escalated tickets
|
64
60
|
Lita: zd list open tickets - returns a list of open tickets
|
65
|
-
Lita: zd list
|
61
|
+
Lita: zd list on hold tickets - returns a list of on hold tickets
|
66
62
|
Lita: zd ticket <ID> - returns information about the specified ticket
|
67
63
|
```
|
68
64
|
|
@@ -1,70 +1,48 @@
|
|
1
|
-
require '
|
2
|
-
require 'faraday'
|
3
|
-
require 'faraday_middleware'
|
4
|
-
|
5
|
-
require 'pp'
|
1
|
+
require 'zendesk_api'
|
6
2
|
|
7
3
|
module Lita
|
8
4
|
module Handlers
|
9
5
|
class Zendesk < Handler
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
QUERY_TICKETS_UNSOLVED = 'search.json?query=status<solved+type:ticket'
|
7
|
+
API_VERSION_URL_PATH = 'api/v2'
|
8
|
+
WEB_TICKETS_URL_PATH = 'tickets'
|
9
|
+
QUERY_TICKETS_ALL = 'type:ticket'
|
10
|
+
QUERY_TICKETS_ESCALATED = 'type:ticket tags:escalated status:open status:pending'
|
11
|
+
QUERY_TICKETS_HOLD = 'type:ticket status:hold'
|
12
|
+
QUERY_TICKETS_OPEN = 'type:ticket status:open'
|
13
|
+
QUERY_TICKETS_NEW = 'type:ticket status:new'
|
14
|
+
QUERY_TICKETS_PENDING = 'type:ticket status:pending'
|
15
|
+
QUERY_TICKETS_UNSOLVED = 'type:ticket status<solved'
|
21
16
|
QUERY_USERS = 'users'
|
22
17
|
|
23
|
-
config :use_command, types: [TrueClass, FalseClass], default: true
|
24
|
-
|
25
18
|
config :subdomain, type: String, required: true
|
26
|
-
config :
|
27
|
-
config :user, type: String, required: true
|
19
|
+
config :username, type: String, required: true
|
28
20
|
config :token, type: String, default: ''
|
29
21
|
config :password, type: String, default: ''
|
30
22
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
faraday.response :logger # log requests to STDOUT
|
42
|
-
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
43
|
-
end
|
44
|
-
else
|
45
|
-
@conn = Faraday.new(url: @version_url) do |faraday|
|
46
|
-
faraday.response :json # JSON response
|
47
|
-
faraday.response :logger # log requests to STDOUT
|
48
|
-
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
49
|
-
end
|
50
|
-
@conn.basic_auth("#{config.user}/token", config.token)
|
23
|
+
config :max_results, type: Integer, default: 10
|
24
|
+
|
25
|
+
def client
|
26
|
+
return @_client if @_client
|
27
|
+
Lita.logger.info "#{logger_prefix}Connecting Zendesk Client to #{api_version_url}"
|
28
|
+
@_client = ZendeskAPI::Client.new do |client|
|
29
|
+
client.url = api_version_url.to_s
|
30
|
+
client.username = config.username || config.user
|
31
|
+
client.token = config.token
|
32
|
+
client.password = config.password
|
51
33
|
end
|
52
34
|
end
|
53
35
|
|
54
36
|
def base_url
|
55
|
-
"https://#{config.subdomain
|
37
|
+
"https://#{config.subdomain}.zendesk.com"
|
56
38
|
end
|
57
39
|
|
58
|
-
def
|
59
|
-
|
40
|
+
def api_version_url
|
41
|
+
uri_join base_url, API_VERSION_URL_PATH
|
60
42
|
end
|
61
43
|
|
62
|
-
def
|
63
|
-
|
64
|
-
if url.index('http') != 0
|
65
|
-
url = "#{@version_url}/#{url}"
|
66
|
-
end
|
67
|
-
@conn.get url
|
44
|
+
def web_tickets_url
|
45
|
+
uri_join base_url, WEB_TICKETS_URL_PATH
|
68
46
|
end
|
69
47
|
|
70
48
|
# General
|
@@ -76,7 +54,7 @@ module Lita
|
|
76
54
|
|
77
55
|
route(/^(?:zd|zendesk)\s+search\s+tickets?\s+(\S.*?)\s*$/i, :search_tickets, command: true, help: { 'zd search tickets <QUERY>' => 'returns search results' })
|
78
56
|
def search_tickets(response)
|
79
|
-
ticket_search response,
|
57
|
+
ticket_search response, response.matches[0][0]
|
80
58
|
end
|
81
59
|
|
82
60
|
# Ticket Counts
|
@@ -111,7 +89,7 @@ module Lita
|
|
111
89
|
ticket_count response, QUERY_TICKETS_OPEN, 'open'
|
112
90
|
end
|
113
91
|
|
114
|
-
route(/^(?:zd|zendesk)\s+on\s
|
92
|
+
route(/^(?:zd|zendesk)\s+on\s*hold\s+tickets?\s*$/i, :onhold_tickets, command: true, help: { 'zd on hold tickets' => 'returns the count of all on hold tickets' })
|
115
93
|
def onhold_tickets(response)
|
116
94
|
ticket_count response, QUERY_TICKETS_HOLD, 'on hold'
|
117
95
|
end
|
@@ -148,73 +126,134 @@ module Lita
|
|
148
126
|
ticket_list response, QUERY_TICKETS_OPEN, 'open'
|
149
127
|
end
|
150
128
|
|
151
|
-
route(/^(?:zd|zendesk)\s+list\s+on\s
|
129
|
+
route(/^(?:zd|zendesk)\s+list\s+on\s*hold\s+tickets?\s*$/i, :onhold_tickets_list, command: true, help: { 'zd list on hold tickets' => 'returns a list of on hold tickets' })
|
152
130
|
def onhold_tickets_list(response)
|
153
131
|
ticket_list response, QUERY_TICKETS_HOLD, 'on hold'
|
154
132
|
end
|
155
133
|
|
156
134
|
# Ticket Details
|
157
135
|
|
158
|
-
route(/^(?:zd|zendesk)\s+ticket\s+(\d+)\s*$/i, :
|
159
|
-
def
|
136
|
+
route(/^(?:zd|zendesk)\s+ticket\s+(\d+)\s*$/i, :ticket_details_with_comments, command: true, help: { 'zd ticket <ID>' => 'returns information about the specified ticket' })
|
137
|
+
def ticket_details_with_comments(response)
|
160
138
|
Lita.logger.info "#{logger_prefix}Processing Zendesk Ticket Details"
|
161
|
-
ticket_id = response.matches[0][0]
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
message += "\nAdded: #{data['ticket']['created_at']}"
|
170
|
-
message += "\nSubject: #{data['ticket']['subject']}"
|
171
|
-
message += "\nDescription:\n-----\n#{data['ticket']['description']}\n-----\n"
|
172
|
-
response.reply message
|
139
|
+
ticket_id = response.matches[0][0].to_i
|
140
|
+
begin
|
141
|
+
ticket = client.ticket.find!(id: ticket_id)
|
142
|
+
response.reply get_text_for_ticket_with_comments(ticket)
|
143
|
+
rescue => e
|
144
|
+
Lita.logger.warn "#{logger_prefix}#{e}"
|
145
|
+
response.reply "Error processing ticket #{ticket_id}"
|
146
|
+
end
|
173
147
|
end
|
174
148
|
|
175
149
|
private
|
176
150
|
|
177
|
-
def
|
178
|
-
Lita.logger.info "#{logger_prefix}Processing Zendesk
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
151
|
+
def get_text_for_ticket(ticket, include_description = true)
|
152
|
+
Lita.logger.info "#{logger_prefix}Processing Zendesk ticket details for [#{ticket.id}]"
|
153
|
+
unless ticket.is_a? ZendeskAPI::Ticket
|
154
|
+
raise 'ticket is not a ZendeskAPI::Ticket'
|
155
|
+
end
|
156
|
+
message = "# Ticket #{ticket.id}: #{ticket_url_web(ticket.id)}"
|
157
|
+
message += "\n- Subject: #{ticket.subject}"
|
158
|
+
message += "\n- Status: #{ticket.status}"
|
159
|
+
message += "\n- Updated: #{ticket.updated_at}"
|
160
|
+
message += "\n- Created: #{ticket.created_at}"
|
161
|
+
message += "\n- Requester: #{user_display(ticket.requester)}"
|
162
|
+
message += "\n- Description: #{ticket.description}" if include_description
|
163
|
+
return message
|
184
164
|
end
|
185
165
|
|
186
|
-
def
|
187
|
-
Lita.logger.info "#{logger_prefix}Processing Zendesk
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
166
|
+
def get_text_for_ticket_comments(ticket)
|
167
|
+
Lita.logger.info "#{logger_prefix}Processing Zendesk ticket comments for [#{ticket.id}]"
|
168
|
+
unless ticket.is_a? ZendeskAPI::Ticket
|
169
|
+
raise 'ticket is not a ZendeskAPI::Ticket'
|
170
|
+
end
|
171
|
+
comments_text = []
|
172
|
+
ticket.audits.each_with_index do |audit,i|
|
173
|
+
if (comment = audit.events.detect {|e| e.type.downcase == 'comment'})
|
174
|
+
author_text = user_display comment.author
|
175
|
+
comment_text = "## Comment: #{author_text}"
|
176
|
+
comment_text += "\n- Created: #{audit.created_at}"
|
177
|
+
comment_text += "\n- Comment: #{comment.body}"
|
178
|
+
comments_text.push comment_text
|
179
|
+
end
|
180
|
+
end
|
181
|
+
return comments_text.reverse.join("\n")
|
182
|
+
end
|
183
|
+
|
184
|
+
def get_text_for_ticket_with_comments(ticket)
|
185
|
+
Lita.logger.info "#{logger_prefix}Processing Zendesk ticket details for [#{ticket.id}] with comments"
|
186
|
+
message = get_text_for_ticket ticket, false
|
187
|
+
comments = get_text_for_ticket_comments ticket
|
188
|
+
if !comments.nil? && comments.length>0
|
189
|
+
message += "\n#{comments}"
|
190
|
+
end
|
191
|
+
return message
|
192
|
+
end
|
193
|
+
|
194
|
+
def ticket_count(response, query, ticket_type = '')
|
195
|
+
Lita.logger.info "#{logger_prefix}Processing Zendesk Ticket Count Query [#{query}]"
|
196
|
+
begin
|
197
|
+
ticket_count = client.search!(query: query).count
|
198
|
+
Lita.logger.info "#{logger_prefix}Ticket count #{ticket_count}"
|
199
|
+
ticket_desc = ticket_type == '' ? '' : "#{ticket_type} "
|
200
|
+
ticket_word = ticket_count == 1 ? 'ticket' : 'tickets'
|
201
|
+
response.reply "#{ticket_count} #{ticket_desc}#{ticket_word}."
|
202
|
+
rescue
|
203
|
+
response.reply "A Zendesk error has been encountered."
|
193
204
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
205
|
+
end
|
206
|
+
|
207
|
+
def ticket_search(response, raw_query)
|
208
|
+
Lita.logger.info "#{logger_prefix}Processing Zendesk Ticket Search"
|
209
|
+
tickets = client.search!(query: "#{QUERY_TICKETS_ALL} #{raw_query}")
|
210
|
+
serp_count = reply_tickets response, tickets
|
211
|
+
response.reply "Listing #{serp_count} of #{tickets.count} #{ticket_word(tickets.count)} matching #{raw_query}."
|
212
|
+
end
|
213
|
+
|
214
|
+
def ticket_list(response, query, ticket_status = '')
|
215
|
+
Lita.logger.info "#{logger_prefix}Processing Zendesk ticket list query"
|
216
|
+
tickets = client.search!(query: query)
|
217
|
+
serp_count = reply_tickets response, tickets
|
218
|
+
ticket_desc = ticket_status == '' ? '' : "#{ticket_status} "
|
219
|
+
response.reply "Listing #{serp_count} of #{tickets.count} #{ticket_desc}#{ticket_word(tickets.count)}."
|
220
|
+
end
|
221
|
+
|
222
|
+
def reply_tickets(response, tickets)
|
223
|
+
serp_count = 0
|
224
|
+
tickets.each_with_index do |ticket, i|
|
225
|
+
break if i >= config.max_results
|
226
|
+
serp_count += 1
|
227
|
+
response.reply "Ticket #{ticket.id} is #{ticket.status}: #{ticket_url_web(ticket.id)} - #{ticket.subject}"
|
206
228
|
end
|
207
|
-
|
208
|
-
ticket_count = res.body['count']
|
209
|
-
ticket_word = ticket_count == 1 ? 'ticket' : 'tickets'
|
210
|
-
ticket_desc = ticket_type == '' ? '' : "#{ticket_type} "
|
211
|
-
response.reply "Listing #{ticket_length} of #{ticket_count} #{ticket_desc}#{ticket_word}."
|
229
|
+
return serp_count
|
212
230
|
end
|
213
231
|
|
214
|
-
def
|
232
|
+
def ticket_url_web(ticket_id)
|
233
|
+
uri_join web_tickets_url.to_s, ticket_id.to_s
|
234
|
+
end
|
235
|
+
|
236
|
+
def ticket_word(count)
|
215
237
|
count == 1 ? 'ticket' : 'tickets'
|
216
238
|
end
|
217
239
|
|
240
|
+
def user_display(user)
|
241
|
+
parts = []
|
242
|
+
if user.name.to_s.length > 0
|
243
|
+
parts.push user.name
|
244
|
+
end
|
245
|
+
if user.email.to_s.length > 0
|
246
|
+
if parts.length < 1 || user.email != user.name
|
247
|
+
parts.push "(#{user.email})"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
user_text = parts.join(' ')
|
251
|
+
end
|
252
|
+
|
253
|
+
def uri_join(*args)
|
254
|
+
args.join('/').gsub(/\/\s*\//, '/').gsub(/\/+/, '/').gsub(/^(https?:\/)/i, '\1/')
|
255
|
+
end
|
256
|
+
|
218
257
|
def logger_prefix
|
219
258
|
" -- #{self.class.name}: "
|
220
259
|
end
|
data/lita-zendesk.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = 'lita-zendesk'
|
3
|
-
spec.date = '2016-09-
|
4
|
-
spec.version = '0.0
|
3
|
+
spec.date = '2016-09-13'
|
4
|
+
spec.version = '0.1.0'
|
5
5
|
spec.authors = ['John Wang']
|
6
6
|
spec.email = ['johncwang@gmail.com']
|
7
7
|
spec.description = %q{A Zendesk handler for Lita.}
|
@@ -15,9 +15,8 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
16
|
spec.require_paths = ['lib']
|
17
17
|
|
18
|
-
spec.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9'
|
19
|
-
spec.add_runtime_dependency 'faraday_middleware', '~> 0', '>= 0'
|
20
18
|
spec.add_runtime_dependency 'lita', '>= 4.4.3'
|
19
|
+
spec.add_runtime_dependency 'zendesk_api', '>= 1.14.0', '~> 1.0'
|
21
20
|
|
22
21
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
23
22
|
spec.add_development_dependency 'pry-byebug'
|
metadata
CHANGED
@@ -1,69 +1,49 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lita-zendesk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Wang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: lita
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0.9'
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
19
|
+
version: 4.4.3
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0.9'
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
26
|
+
version: 4.4.3
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
28
|
+
name: zendesk_api
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '0'
|
40
31
|
- - ">="
|
41
32
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
43
|
-
type: :runtime
|
44
|
-
prerelease: false
|
45
|
-
version_requirements: !ruby/object:Gem::Requirement
|
46
|
-
requirements:
|
33
|
+
version: 1.14.0
|
47
34
|
- - "~>"
|
48
35
|
- !ruby/object:Gem::Version
|
49
|
-
version: '0'
|
50
|
-
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: '0'
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: lita
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: 4.4.3
|
36
|
+
version: '1.0'
|
60
37
|
type: :runtime
|
61
38
|
prerelease: false
|
62
39
|
version_requirements: !ruby/object:Gem::Requirement
|
63
40
|
requirements:
|
64
41
|
- - ">="
|
65
42
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
43
|
+
version: 1.14.0
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.0'
|
67
47
|
- !ruby/object:Gem::Dependency
|
68
48
|
name: bundler
|
69
49
|
requirement: !ruby/object:Gem::Requirement
|