lita-redmine2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1241e2ab1d47e594c9cc6a43ce19ee3aeeddd52a
4
+ data.tar.gz: d528aea74380621f684e4cc2e6abee8e88bbcb42
5
+ SHA512:
6
+ metadata.gz: 2c431781f5103c893d28f924e4a907a418c68e1d9b24e41e2fcaa2378ea55766603617c37f6f25ec5d3491461eb7e7e096565da7efe28ac9dd121f796d5dbdf4
7
+ data.tar.gz: 6c3246cf86c6ae34fae42db9a993fd47be849694f15b57447ca877f9aa2da93e94c4bd584ed10f7ad2340f001f5adfc25345da201eed6468f3d7e373054a6a5d
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 NetBrick s.r.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # lita-redmine
2
+
3
+ Lita Redmine Plugin - Redmine handlers
4
+
5
+ ## Installation
6
+
7
+ Add lita-redmine to your Lita instance's Gemfile:
8
+
9
+ ``` ruby
10
+ gem "lita-redmine2", git: "https://github.com/netbrick/lita-redmine2", branch: "master"
11
+ ```
12
+
13
+ ## Configuration
14
+
15
+ add into lita_config.rb Redmine URL
16
+
17
+ ``` ruby
18
+ Lita.configure do |config|
19
+ ...
20
+ config.handlers.redmine.url = "https://redmine.site.cz"
21
+ config.handlers.redmine.secret_key = "<secret key to encrypt tokens in redis>"
22
+ ...
23
+ end
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```
29
+ redmine|rm list <object #> - Redmine list objects, calls Redmine API as /:object.json
30
+ redmine|rm time entry new [Issue_id] [Hours] [Activity name] [Comment] - Create new time entry with today's date
31
+
32
+ redmine|rm issue <issue #> - Displays issue id and subject
33
+ redmine|rm issue close <issue #> - Selects first status with closing attribute and updates issue to this status
34
+ redmine|rm issue detail <issue #> - Displays issue detail
35
+ redmine|rm issue journal <issue #> - Displays issue journal
36
+ redmine|rm issue link <issue #> - Displays issue link
37
+ redmine|rm issue new [Project name] [Subject] [Description] <firstname secondname> - Create new issue, name is optional and selects user to assign issue to
38
+ redmine|rm issue state change <issue #> <status_name> - Change issue status to specified
39
+
40
+ redmine|rm issues - List my issues
41
+ redmine|rm issue note <issue #> note - Add note to issue
42
+ redmine|rm issue assign <issue #> [firstname secondname] <note> - Assign issue to user, note is optional
43
+
44
+ redmine|rm projects - List my projects
45
+
46
+ redmine|rm register <api token> - Register API token
47
+ redmine|rm unregister - Unregister API token
48
+ redmine|rm token - Show registered token (PM)
49
+
50
+ redmine|rm info - Display info
51
+ <something>#<issue #><something> - Displays issue subject when mentoied in conversation
52
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,12 @@
1
+ require "lita"
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join("..", "..", "locales", "*.yml"), __FILE__
5
+ )]
6
+
7
+ require "lita/handlers/redmine2"
8
+
9
+ Lita::Handlers::Redmine2.template_root File.expand_path(
10
+ File.join("..", "..", "templates"),
11
+ __FILE__
12
+ )
@@ -0,0 +1,531 @@
1
+ require "lita"
2
+ require "crypt/blowfish"
3
+ require "#{File.dirname(__FILE__)}/../../resources/redmine_resource"
4
+
5
+ module Lita
6
+ module Handlers
7
+ class Redmine2 < Handler
8
+ config :url
9
+ config :secret_key
10
+
11
+ route /^(redmine|rm)\slist\s([a-zA-Z_]+)/, :list_objects, help: { "redmine|rm list <object #>" => "Redmine list objects, calls Redmine API as /:object.json" }
12
+
13
+ route /^(redmine|rm)\stime entry\snew\s\[(\d+)\]\s\[([^\[\]]+)\]\s\[([^\[\]]+)\]\s\[([^\[\]]+)\]/, :time_entry_new, help: { "redmine|rm time entry new [Issue_id] [Hours] [Activity name] [Comment]" => "Create new time entry with today's date" }
14
+
15
+ route /^(redmine|rm)\sissue\s(\d+)/, :issue, help: { "redmine|rm issue <issue #>" => "Displays issue id and subject" }
16
+ route /^(redmine|rm)\sissue\sclose\s(\d+)/, :issue_close, help: { "redmine|rm issue close <issue #>" => "Selects first status with closing attribute and updates issue to this status" }
17
+ route /^(redmine|rm)\sissue\sdetail\s(\d+)/, :issue_detail, help: { "redmine|rm issue detail <issue #>" => "Displays issue detail" }
18
+ route /^(redmine|rm)\sissue\sjournal\s(\d+)/, :issue_journal, help: { "redmine|rm issue journal <issue #>" => "Displays issue journal" }
19
+ route /^(redmine|rm)\sissue\slink\s(\d+)/, :issue_link, help: { "redmine|rm issue link <issue #>" => "Displays issue link" }
20
+ route /^(redmine|rm)\sissue\snew\s\[([^\[\]]+)\]\s\[([^\[\]]+)\]\s\[([^\[\]]+)\](\s\[[^\[\]]+\])?/, :issue_new, help: { "redmine|rm issue new [Project name] [Subject] [Description] [Firstname Secondname]" => "Create new issue, name is optional and selects user to assign issue to" }
21
+ route /^(redmine|rm)\sissue\sstate\schange\s\[(\d+)\]\s\[([^\[\]]+)\]/, :issue_change_state, help: {"redmine|rm issue state change [Issue_id] [Status_name]" => "Change issue status to specified" }
22
+ route /^(redmine|rm)\sissues/, :issues, help: {"redmine|rm issues" => "List my issues" }
23
+ route /^(redmine|rm)\sissue\snote\s\[(\d+)\]\s\[([^\[\]]+)\]/, :issue_note, help: {"redmine|rm issue note [Issue_id] [Note]" => "Add note to issue" }
24
+ route /^(redmine|rm)\sissue\sassign\s\[(\d+)\]\s\[([^\[\]]+)\](\s\[[^\[\]]+\])?/, :issue_assign, help: {"redmine|rm issue assign [Issue_id] [Firstname Secondname] [Note]" => "Assign issue to user, note is optional" }
25
+
26
+ route /^(redmine|rm)\sprojects/, :projects, help: {"redmine|rm projects" => "List my projects" }
27
+
28
+ route /^(redmine|rm)\sregister\s([a-zA-z0-9])/, :register, help: { "redmine|rm register <api token>" => "Register API token" }
29
+ route /^(redmine|rm)\sunregister/, :unregister, help: { "redmine|rm unregister" => "Unregister API token" }
30
+ route /^(redmine|rm)\stoken/, :token, help: { "redmine|rm token" => "Show registered token (PM)"}
31
+
32
+ route /^(redmine|rm)\sinfo/, :info, help: {"redmine|rm info" => "Display info"}
33
+ route /.*\#(\d+).*/, :issue_mention, help: {"<something>#<issue #><something>" => "Displays issue subject when mentoied in conversation" }
34
+
35
+ def info(response)
36
+ response.reply "Lita Redmine Bot by NetBrick"
37
+ end
38
+
39
+ # get list of objects
40
+ def list_objects(response)
41
+ resource = get_user_token(response.user.id)
42
+
43
+ if resource.nil?
44
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
45
+ else
46
+ object = response.matches.flatten[1]
47
+
48
+ # Update route as there objects require 'enumerations' in the url
49
+ if object == 'time_entry_activities' || object == 'issue_priorities'
50
+ object = 'enumerations/' + object
51
+ end
52
+
53
+ message = resource.list(object: object)
54
+ if message[:resource_error].nil?
55
+ response.reply parse_list_objects(message)
56
+ else
57
+ response.reply_privately message[:resource_error]
58
+ end
59
+ end
60
+ end
61
+
62
+ # create new time entry
63
+ def time_entry_new(response)
64
+ resource = get_user_token(response.user.id)
65
+
66
+ if resource.nil?
67
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
68
+ else
69
+ issue_id = response.matches.flatten[1]
70
+ hours = response.matches.flatten[2]
71
+ activity_name = response.matches.flatten[3]
72
+ comments = response.matches.flatten[4]
73
+
74
+ if activity_id = get_activity_by_name(activity_name, resource)
75
+ message = resource.create_entry({issue_id: issue_id, hours: hours, activity_id: activity_id, comments: comments})
76
+
77
+ if message[:resource_error].nil?
78
+ response.reply message[:message]
79
+ else
80
+ response.reply_privately message[:resource_error]
81
+ end
82
+ else
83
+ response.reply_privately "Unable to find activity by specified name"
84
+ end
85
+ end
86
+ end
87
+
88
+ # show issue subject
89
+ def issue(response)
90
+ resource = get_user_token(response.user.id)
91
+
92
+ if resource.nil?
93
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
94
+ else
95
+ issue_id = response.matches.flatten[1]
96
+ issue = resource.issue(id: issue_id)
97
+
98
+ if issue[:resource_error].nil?
99
+ issue = issue['issue']
100
+ response.reply "#{issue['id']}: (#{issue['project']['name']}) #{issue["subject"]}"
101
+ else
102
+ response.reply_privately issue[:resource_error]
103
+ end
104
+ end
105
+ end
106
+
107
+ # show issue subject and description
108
+ def issue_detail(response)
109
+ resource = get_user_token(response.user.id)
110
+
111
+ if resource.nil?
112
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
113
+ else
114
+ issue_id = response.matches.flatten[1]
115
+ issue = resource.issue(id: issue_id)
116
+
117
+ if issue[:resource_error].nil?
118
+ issue = issue['issue']
119
+ response.reply "#{issue['id']}: (#{issue['project']['name']}) #{issue["subject"]}\n#{issue['description']}"
120
+ else
121
+ response.reply_privately issue[:resource_error]
122
+ end
123
+ end
124
+ end
125
+
126
+ # show issue subject and description
127
+ def issue_journal(response)
128
+ resource = get_user_token(response.user.id)
129
+
130
+ if resource.nil?
131
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
132
+ else
133
+ issue_id = response.matches.flatten[1]
134
+ issue = resource.issue(id: issue_id)
135
+
136
+ if issue[:resource_error].nil?
137
+ issue = issue['issue']
138
+
139
+ message = "#{issue['id']}: (#{issue['project']['name']}) #{issue["subject"]}\n#{issue['description']}"
140
+
141
+ issue['journals'] = issue['journals'].nil? ? {} : issue['journals']
142
+ issue['journals'].each do |j|
143
+ if !j['notes'].nil? && !j['notes'].empty?
144
+ message = message + "\n"
145
+ message = message + "Author: #{j['user']['name']}\n"
146
+ message = message + j['notes'] + "\n"
147
+ end
148
+ end
149
+
150
+ response.reply message
151
+ else
152
+ response.reply_privately issue[:resource_error]
153
+ end
154
+ end
155
+ end
156
+
157
+ # show issue link
158
+ def issue_link(response)
159
+ response.reply "Issue ##{response.matches.flatten[1]}: #{config.url}/issues/#{response.matches.flatten[1]}"
160
+ end
161
+
162
+ # change status of issue
163
+ def issue_change_state(response)
164
+ resource = get_user_token(response.user.id)
165
+
166
+ if resource.nil?
167
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
168
+ else
169
+ issue_id = response.matches.flatten[1]
170
+ status_name = response.matches.flatten[2]
171
+
172
+ if status_id = get_status_by_name(status_name, resource)
173
+ issue = resource.update_issue({ status_id: status_id }, id: issue_id)
174
+ if issue[:resource_error].nil?
175
+ response.reply issue[:message]
176
+ else
177
+ response.reply_privately issue[:resource_error]
178
+ end
179
+ else
180
+ response.reply_privately "Unable to find status by specified name"
181
+ end
182
+ end
183
+ end
184
+
185
+ # close issue
186
+ def issue_close(response)
187
+ resource = get_user_token(response.user.id)
188
+
189
+ if resource.nil?
190
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
191
+ else
192
+ issue_id = response.matches.flatten[1]
193
+
194
+ if status_id = get_closing_status_id(resource)
195
+ issue = resource.update_issue({ status_id: status_id }, id: issue_id)
196
+ if issue[:resource_error].nil?
197
+ response.reply issue[:message]
198
+ else
199
+ response.reply_privately issue[:resource_error]
200
+ end
201
+ else
202
+ response.reply_privately "Unable to find any closing status"
203
+ end
204
+ end
205
+ end
206
+
207
+ # assign issue to user specified by name
208
+ def issue_assign(response)
209
+ resource = get_user_token(response.user.id)
210
+
211
+ if resource.nil?
212
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
213
+ else
214
+ issue_id = response.matches.flatten[1]
215
+ name = response.matches.flatten[2]
216
+ note = response.matches.flatten[3].nil? ? "" : response.matches.flatten[3].strip
217
+ note = note[1, note.length - 2]
218
+
219
+ if user_id = get_user_by_name(name, resource)
220
+ issue = resource.update_issue({ assigned_to_id: user_id, notes: note }, id: issue_id)
221
+ if issue[:resource_error].nil?
222
+ response.reply issue[:message]
223
+ else
224
+ response.reply_privately issue[:resource_error]
225
+ end
226
+ else
227
+ response.reply_privately "Unable to find user by name"
228
+ end
229
+ end
230
+ end
231
+
232
+ # create issue in project specified by name
233
+ def issue_new(response)
234
+ resource = get_user_token(response.user.id)
235
+
236
+ if resource.nil?
237
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
238
+ else
239
+ project_name = response.matches.flatten[1]
240
+ subject = response.matches.flatten[2]
241
+ description = response.matches.flatten[3]
242
+ assignee_name = response.matches.flatten[4].nil? ? "" : response.matches.flatten[4].strip
243
+ assignee_name = assignee_name[1, assignee_name.length - 2]
244
+
245
+ project_id = get_project_by_name(project_name, resource)
246
+ user_id = get_user_by_name(assignee_name, resource)
247
+
248
+ if project_id
249
+ issue = resource.create_issue({ project_id: project_id, subject: subject, description: description, assigned_to_id: user_id })
250
+ if issue[:resource_error].nil?
251
+ issue = issue['issue']
252
+ response.reply "Issue created with id #{issue['id']}"
253
+ else
254
+ response.reply_privately issue[:resource_error]
255
+ end
256
+ else
257
+ response.reply_privately "Unable to find project by name"
258
+ end
259
+ end
260
+ end
261
+
262
+ # show issue subject when someone mention issue #
263
+ def issue_mention(response)
264
+ resource = get_user_token(response.user.id)
265
+
266
+ if resource.nil?
267
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
268
+ else
269
+ issue_id = response.matches.flatten[0]
270
+ issue = resource.issue(id: issue_id)
271
+
272
+ if issue[:resource_error].nil?
273
+ issue = issue['issue']
274
+ response.reply "#{issue['id']}: (#{issue['project']['name']}) #{issue["subject"]}"
275
+ else
276
+ response.reply_privately issue[:resource_error]
277
+ end
278
+ end
279
+ end
280
+
281
+ # write new issue note
282
+ def issue_note(response)
283
+ resource = get_user_token(response.user.id)
284
+
285
+ if resource.nil?
286
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
287
+ else
288
+ issue_id = response.matches.flatten[1]
289
+ issue_note = response.matches.flatten[2]
290
+
291
+ issue = resource.update_issue({ notes: issue_note }, id: issue_id)
292
+ if issue[:resource_error].nil?
293
+ response.reply issue[:message]
294
+ else
295
+ response.reply_privately issue[:resource_error]
296
+ end
297
+ end
298
+ end
299
+
300
+ # list issues of user
301
+ def issues(response)
302
+ resource = get_user_token(response.user.id)
303
+
304
+ if resource.nil?
305
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
306
+ else
307
+ issues = resource.issues
308
+
309
+ if issues[:resource_error].nil?
310
+ message = ''
311
+ issues = issues['issues'].nil? ? {} : issues['issues']
312
+ issues.each do |issue|
313
+ message << "#{issue['id']}: (#{issue['project']['name']}) #{issue['subject']}\n"
314
+ end
315
+
316
+ response.reply message
317
+ else
318
+ response.reply_privately issue[:resource_error]
319
+ end
320
+ end
321
+ end
322
+
323
+ # list projects of user
324
+ def projects(response)
325
+ resource = get_user_token(response.user.id)
326
+
327
+ if resource.nil?
328
+ response.reply_privately "Token not registered, register token via 'redmine register <api_token>'"
329
+ else
330
+ projects = resource.projects
331
+
332
+ if projects[:resource_error].nil?
333
+ message = ''
334
+ projects = projects['projects'].nil? ? {} : projects['projects']
335
+ projects.each do |prj|
336
+ message << "#{prj['id']}: (#{prj['name']})\n"
337
+ end
338
+
339
+ response.reply message
340
+ else
341
+ response.reply_privately projects[:resource_error]
342
+ end
343
+ end
344
+ end
345
+
346
+ # save user API token into redis
347
+ def register(response)
348
+ user_id = response.user.id
349
+ api_token = response.args[1]
350
+
351
+ api_token = encryptor.encrypt_string(api_token)
352
+ redis.set("user_#{user_id}", api_token)
353
+
354
+ message = "Registered: #{user_id} url #{config.url}"
355
+ response.reply message
356
+ end
357
+
358
+ # send saved API token to DM/PM
359
+ def token(response)
360
+ user_id = response.user.id
361
+
362
+ token = redis.get("user_#{user_id}")
363
+ token = decrypt_token(token, user_id)
364
+
365
+ message = "Token: #{token}"
366
+ response.reply_privately message
367
+ end
368
+
369
+ # delete saved API token
370
+ def unregister(response)
371
+ user_id = response.user.id
372
+
373
+ redis.set("user_#{user_id}", "")
374
+
375
+ message = "Unregistered: #{user_id}"
376
+ response.reply message
377
+ end
378
+
379
+ # retrieve user API token from redis
380
+ def get_user_token(user_id)
381
+ token = redis.get("user_#{user_id}")
382
+ token = decrypt_token(token, user_id)
383
+
384
+ if !token.nil? && !token.empty?
385
+ connection = Faraday.new(url: config.url, headers: { "X-Redmine-API-Key" => token })
386
+ resource = RedmineResource.new(connection: connection)
387
+ else
388
+ resource = nil
389
+ end
390
+ end
391
+
392
+ # find user id by name via API
393
+ def get_user_by_name(name, resource)
394
+ users = resource.users
395
+ users = users[:resource_error].nil? ? users['users'] : {}
396
+
397
+ id = nil
398
+ users.each do |user|
399
+ user_name = user['firstname'] + " " + user['lastname']
400
+ id = user['id'] if user_name == name
401
+ end
402
+
403
+ id
404
+ end
405
+
406
+ # find user id by name via API
407
+ def get_project_by_name(name, resource)
408
+ projects = resource.projects
409
+ projects = projects[:resource_error].nil? ? projects['projects'] : {}
410
+
411
+ id = nil
412
+ projects.each do |prj|
413
+ id = prj['id'] if prj['name'] == name
414
+ end
415
+
416
+ id
417
+ end
418
+
419
+ # get activity id by name
420
+ def get_activity_by_name(name, resource)
421
+ activities = resource.list(object: 'enumerations/time_entry_activities')
422
+ activities = activities[:resource_error].nil? ? activities['time_entry_activities'] : {}
423
+
424
+ activity_id = nil
425
+ activities.each do |a|
426
+ activity_id = a['id'] if a['name'] == name
427
+ end
428
+
429
+ activity_id
430
+ end
431
+
432
+ def get_status_by_name(name, resource)
433
+ states = resource.list(object: 'issue_statuses')
434
+ states = states['issue_statuses'].nil? ? [] : states['issue_statuses']
435
+
436
+ status_id = nil
437
+ states.each do |s|
438
+ status_id = s['id'] if s['name'] == name
439
+ end
440
+
441
+ status_id
442
+ end
443
+
444
+ # get status id with close attribute
445
+ def get_closing_status_id(resource)
446
+ states = resource.list(object: 'issue_statuses')
447
+ states = states['issue_statuses'].nil? ? [] : states['issue_statuses']
448
+
449
+ status_id = nil
450
+ states.each do |s|
451
+ if s['is_closed']
452
+ status_id = s['id']
453
+ break
454
+ end
455
+ end
456
+
457
+ status_id
458
+ end
459
+
460
+ # parse list of objects
461
+ def parse_list_objects(list)
462
+ message = ''
463
+
464
+ case list.keys[0]
465
+ when 'users'
466
+ users = list['users']
467
+ users.each do |u|
468
+ message << "#{u['id']}: #{u['firstname']} #{u['lastname']}\n"
469
+ end
470
+ when 'issues'
471
+ issues = list['issues']
472
+ issues.each do |i|
473
+ message << "#{i['id']}: (#{i['project']['name']}) #{i['subject']}\n"
474
+ end
475
+ when 'projects'
476
+ projects = list['projects']
477
+ projects.each do |p|
478
+ message << "#{p['id']}: (#{p['name']})\n"
479
+ end
480
+ when 'time_entries'
481
+ time_entries = list['time_entries']
482
+ time_entries.each do |t|
483
+ message << "Issue_id: #{t['issue']['id']}, spent_on: #{t['spent_on']}, hours: #{t['hours']}\n"
484
+ end
485
+ when 'time_entry_activities'
486
+ time_entry_activities = list['time_entry_activities']
487
+ time_entry_activities.each do |t|
488
+ message << "Name: #{t['name']}\n"
489
+ end
490
+ when 'issue_statuses'
491
+ issue_statuses = list['issue_statuses']
492
+ issue_statuses.each do |s|
493
+ message << "Name: #{s['name']}, closes issue: #{s['is_closed'] ? 'yes' : 'no'}\n"
494
+ end
495
+ when 'trackers'
496
+ trackers = list['trackers']
497
+ trackers.each do |t|
498
+ message << "Name: #{t['name']}\n"
499
+ end
500
+ when 'issue_priorities'
501
+ issue_priorities = list['issue_priorities']
502
+ issue_priorities.each do |p|
503
+ message << "Name: #{p['name']}\n"
504
+ end
505
+ else
506
+ message = 'Currently unsupported'
507
+ end
508
+
509
+ message
510
+ end
511
+
512
+ # try decrypt token and if not ecrypted, update redis record
513
+ def decrypt_token(token, user_id)
514
+ decrypted_token = encryptor.decrypt_string(token)
515
+ rescue
516
+ encrypted_token = encryptor.encrypt_string(token)
517
+ redis.set("user_#{user_id}", encrypted_token)
518
+
519
+ token
520
+ end
521
+
522
+ # encrypting mechanism
523
+ def encryptor
524
+ secret_key = config.secret_key.nil? ? "BqJYq7FQjhXuaPSkbTxw" : config.secret_key
525
+ @encryptor ||= Crypt::Blowfish.new(secret_key)
526
+ end
527
+ end
528
+
529
+ Lita.register_handler(Redmine2)
530
+ end
531
+ end
@@ -0,0 +1,70 @@
1
+ require 'resource_kit'
2
+ require 'faraday'
3
+ require 'json'
4
+
5
+ class RedmineResource < ResourceKit::Resource
6
+ resources do
7
+ default_handler (401) { |response| { resource_error: "Wrong API token, please register new one" } }
8
+ default_handler (403) { |response| { resource_error: "You are not authorized to do this action" } }
9
+ default_handler (404) { |response| { resource_error: "Server responded with error code 404, please check you have correct parameters" } }
10
+ default_handler (422) { |response| { resource_error: "Wrong parameters" } }
11
+ default_handler { |response| { resource_error: "Unknown error, status: #{response.status}" } }
12
+
13
+ action :list do
14
+ verb :get
15
+ path '/:object.json?limit=1000'
16
+ handler (:ok) { |response| JSON.parse(response.body) }
17
+ end
18
+
19
+ action :create_entry do
20
+ verb :post
21
+ path '/time_entries.json'
22
+ body { |object| { time_entry: object } }
23
+ handler (:created) { |response| { message: "Time entry created" } }
24
+ end
25
+
26
+ action :users do
27
+ verb :get
28
+ path '/users.json?limit=1000'
29
+ handler (:ok) { |response| JSON.parse(response.body) }
30
+ end
31
+
32
+ action :projects do
33
+ verb :get
34
+ path '/projects.json?limit=1000'
35
+ handler (:ok) { |response| JSON.parse(response.body) }
36
+ end
37
+
38
+ action :create_issue do
39
+ verb :post
40
+ path '/issues.json'
41
+ body { |object| { issue: object } }
42
+ handler (:created) { |response| JSON.parse(response.body) }
43
+ end
44
+
45
+ action :update_issue do
46
+ verb :put
47
+ path '/issues/:id.json'
48
+ body { |object| { issue: object } }
49
+ handler (:ok) { |response| { message: "Issue updated" } }
50
+ end
51
+
52
+ action :issues do
53
+ verb :get
54
+ path '/issues.json?assigned_to_id=me'
55
+ handler (:ok) { |response| JSON.parse(response.body) }
56
+ end
57
+
58
+ action :issue do
59
+ verb :get
60
+ path '/issues/:id.json'
61
+ handler (:ok) { |response| JSON.parse(response.body) }
62
+ end
63
+
64
+ action :issue_journals do
65
+ verb :get
66
+ path '/issues/:id.json?include=journals'
67
+ handler (:ok) { |response| JSON.parse(response.body) }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-redmine2"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Jindrich Skupa / David Herman"]
5
+ spec.email = ["dev@netbrick.eu"]
6
+ spec.description = "Lita handlers for Redmine."
7
+ spec.summary = "Lita handlers for Redmine issue management."
8
+ spec.homepage = "https://github.com/netbrick/lita-redmine2"
9
+ spec.license = "MIT"
10
+ spec.metadata = { "lita_plugin_type" => "handler" }
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency "lita", ">= 4.3"
18
+ spec.add_runtime_dependency "resource_kit"
19
+ spec.add_runtime_dependency "json"
20
+ spec.add_runtime_dependency "crypt"
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "pry-byebug"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rack-test"
26
+ spec.add_development_dependency "rspec", ">= 3.0.0"
27
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ redmine:
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Handlers::Redmine, lita_handler: true do
4
+ end
@@ -0,0 +1,6 @@
1
+ require "lita-redmine"
2
+ require "lita/rspec"
3
+
4
+ # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
5
+ # was generated with Lita 4, the compatibility mode should be left disabled.
6
+ Lita.version_3_compatibility_mode = false
File without changes
File without changes
File without changes
File without changes
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-redmine2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jindrich Skupa / David Herman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '4.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '4.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: resource_kit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: crypt
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rack-test
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: 3.0.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: 3.0.0
139
+ description: Lita handlers for Redmine.
140
+ email:
141
+ - dev@netbrick.eu
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - .gitignore
147
+ - Gemfile
148
+ - LICENSE
149
+ - README.md
150
+ - Rakefile
151
+ - lib/lita-redmine2.rb
152
+ - lib/lita/handlers/redmine2.rb
153
+ - lib/resources/redmine_resource.rb
154
+ - lita-redmine.gemspec
155
+ - locales/en.yml
156
+ - spec/lita/handlers/redmine_spec.rb
157
+ - spec/spec_helper.rb
158
+ - templates/.gitkeep
159
+ - templates/issue.slack.erb
160
+ - templates/issue_detail.slack.erb
161
+ - templates/issues.slack.erb
162
+ homepage: https://github.com/netbrick/lita-redmine2
163
+ licenses:
164
+ - MIT
165
+ metadata:
166
+ lita_plugin_type: handler
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubyforge_project:
183
+ rubygems_version: 2.0.14
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: Lita handlers for Redmine issue management.
187
+ test_files:
188
+ - spec/lita/handlers/redmine_spec.rb
189
+ - spec/spec_helper.rb