lita-zendesk 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|