lita-locker 0.5.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8c1387e7b5b34330a06b4b423c09baf6a07c910
4
- data.tar.gz: 7aff63b7b66afb89c1b4409be77a1e1902d4be49
3
+ metadata.gz: c652f7dfc79a47babe632a2f9516bfeedf1b4781
4
+ data.tar.gz: d4f5f7802f48182a08fab5f573f44b35ecac6b90
5
5
  SHA512:
6
- metadata.gz: 3dd3c6ae9eaa86fd70333347c288509022b7cd056db2daab328d185210dd4ec5e02e9bd2ff1028094aa361f9ddd0acf61b7ae83f8b7b2cf0e544f1d0157d23ee
7
- data.tar.gz: d2da98d29c48a71b87795a41e7377b11f00aba25e95234bf4e05d4311fa1a2669dc70e1bc7ca84995644d949603be2d26a3e8c9dfc6f5a3b7b6cb99e8482d2f9
6
+ metadata.gz: c9113338335470eca38f6b2b947618b115c624ffeea5dc81acf94e43636bb1aaecc359f00128653784aace1ed48647e2da0ec5dad5318d90b533e361d66a5fe5
7
+ data.tar.gz: 2acb94c1f70b702c67baedb3e2cd8095a68c79517c1ec46e57558e8d755e18a203bc5d6987181301999ce1e67aada7cb028fe91289291e0a55bf650b50dad748
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  *.rbc
3
+ *.swp
3
4
  .bundle
4
5
  .config
5
6
  .yardoc
data/.rubocop.yml CHANGED
@@ -1,26 +1,21 @@
1
- BlockNesting:
2
- Max: 5
3
-
4
1
  ClassLength:
5
- Max: 500
2
+ Max: 103
6
3
 
7
4
  CyclomaticComplexity:
8
- Max: 8
9
-
10
- Documentation:
11
- Exclude:
12
- - lib/lita/handlers/locker.rb
5
+ Max: 7
13
6
 
14
7
  FileName:
15
8
  Exclude:
16
9
  - lib/lita-locker.rb
17
10
 
18
11
  MethodLength:
19
- Max: 200
12
+ Max: 31
13
+
14
+ PerceivedComplexity:
15
+ Max: 12
20
16
 
21
17
  LineLength:
22
- Max: 85
18
+ Max: 120
23
19
 
24
- GuardClause:
25
- Exclude:
26
- - lib/lita/handlers/locker.rb
20
+ AbcSize:
21
+ Max: 49
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
3
+ - 2.1
4
4
  script: bundle exec rake
5
5
  before_install:
6
6
  - gem update --system
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,9 @@
1
+ Pull requests are awesome! Pull requests with tests are even more awesome!
2
+
3
+ ## Quick steps
4
+
5
+ 1. Fork the repo.
6
+ 2. Run the tests: `bundle && rake`
7
+ 3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, it needs a test!
8
+ 4. Make the test pass.
9
+ 5. Push to your fork and submit a pull request.
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/lib/lita-locker.rb CHANGED
@@ -4,4 +4,14 @@ Lita.load_locales Dir[File.expand_path(
4
4
  File.join('..', '..', 'locales', '*.yml'), __FILE__
5
5
  )]
6
6
 
7
+ require 'locker/label'
8
+ require 'locker/misc'
9
+ require 'locker/regex'
10
+ require 'locker/resource'
11
+
12
+ require 'lita/handlers/locker_events'
13
+ require 'lita/handlers/locker_http'
14
+ require 'lita/handlers/locker_labels'
15
+ require 'lita/handlers/locker_misc'
16
+ require 'lita/handlers/locker_resources'
7
17
  require 'lita/handlers/locker'
@@ -1,20 +1,20 @@
1
1
  module Lita
2
+ # Handy, isn't it?
2
3
  module Handlers
4
+ # Top-level class for Locker
3
5
  class Locker < Handler
4
- http.get '/locker/label/:name', :http_label_show
5
- http.get '/locker/resource/:name', :http_resource_show
6
-
7
- LABEL_REGEX = /([\.\w\s-]+)/
8
- RESOURCE_REGEX = /([\.\w-]+)/
9
- COMMENT_REGEX = /(\s\#.+)?/
6
+ include ::Locker::Label
7
+ include ::Locker::Misc
8
+ include ::Locker::Regex
9
+ include ::Locker::Resource
10
10
 
11
11
  route(
12
- /^\(lock\)\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
12
+ /^#{LOCK_REGEX}#{LABEL_REGEX}#{COMMENT_REGEX}$/,
13
13
  :lock
14
14
  )
15
15
 
16
16
  route(
17
- /^(?:\(unlock\)|\(release\))\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
17
+ /^#{UNLOCK_REGEX}#{LABEL_REGEX}#{COMMENT_REGEX}$/,
18
18
  :unlock
19
19
  )
20
20
 
@@ -39,435 +39,84 @@ module Lita
39
39
  help: { t('help.steal.syntax') => t('help.steal.desc') }
40
40
  )
41
41
 
42
- route(
43
- /^locker\sstatus\s#{LABEL_REGEX}$/,
44
- :status,
45
- command: true,
46
- help: { t('help.status.syntax') => t('help.status.desc') }
47
- )
48
-
49
- route(
50
- /^locker\sresource\slist$/,
51
- :resource_list,
52
- command: true,
53
- help: { t('help.resource.list.syntax') => t('help.resource.list.desc') }
54
- )
55
-
56
- route(
57
- /^locker\sresource\screate\s#{RESOURCE_REGEX}$/,
58
- :resource_create,
59
- command: true,
60
- restrict_to: [:locker_admins],
61
- help: {
62
- t('help.resource.create.syntax') => t('help.resource.create.desc')
63
- }
64
- )
65
-
66
- route(
67
- /^locker\sresource\sdelete\s#{RESOURCE_REGEX}$/,
68
- :resource_delete,
69
- command: true,
70
- restrict_to: [:locker_admins],
71
- help: {
72
- t('help.resource.delete.syntax') => t('help.resource.delete.desc')
73
- }
74
- )
75
-
76
- route(
77
- /^locker\sresource\sshow\s#{RESOURCE_REGEX}$/,
78
- :resource_show,
79
- command: true,
80
- help: { t('help.resource.show.syntax') => t('help.resource.show.desc') }
81
- )
82
-
83
- route(
84
- /^locker\slabel\slist$/,
85
- :label_list,
86
- command: true,
87
- help: { t('help.label.list.syntax') => t('help.label.list.desc') }
88
- )
89
-
90
- route(
91
- /^locker\slabel\screate\s#{LABEL_REGEX}$/,
92
- :label_create,
93
- command: true,
94
- help: { t('help.label.create.syntax') => t('help.label.create.desc') }
95
- )
96
-
97
- route(
98
- /^locker\slabel\sdelete\s#{LABEL_REGEX}$/,
99
- :label_delete,
100
- command: true,
101
- help: { t('help.label.delete.syntax') => t('help.label.delete.desc') }
102
- )
103
-
104
- route(
105
- /^locker\slabel\sshow\s#{LABEL_REGEX}$/,
106
- :label_show,
107
- command: true,
108
- help: { t('help.label.show.syntax') => t('help.label.show.desc') }
109
- )
110
-
111
- route(
112
- /^locker\slabel\sadd\s#{RESOURCE_REGEX}\sto\s#{LABEL_REGEX}$/,
113
- :label_add,
114
- command: true,
115
- help: { t('help.label.add.syntax') => t('help.label.add.desc') }
116
- )
117
-
118
- route(
119
- /^locker\slabel\sremove\s#{RESOURCE_REGEX}\sfrom\s#{LABEL_REGEX}$/,
120
- :label_remove,
121
- command: true,
122
- help: { t('help.label.remove.syntax') => t('help.label.remove.desc') }
123
- )
124
-
125
- def http_label_show(request, response)
126
- name = request.env['router.params'][:name]
127
- response.headers['Content-Type'] = 'application/json'
128
- response.write(label(name).to_json)
129
- end
130
-
131
- def http_resource_show(request, response)
132
- name = request.env['router.params'][:name]
133
- response.headers['Content-Type'] = 'application/json'
134
- response.write(resource(name).to_json)
135
- end
136
-
137
42
  def lock(response)
138
43
  name = response.matches[0][0]
139
44
 
140
- if label_exists?(name)
141
- m = label_membership(name)
142
- if m.count > 0
143
- if lock_label!(name, response.user, nil)
144
- response.reply('(successful) ' + t('label.lock', name: name))
145
- else
146
- l = label(name)
147
- if l['state'] == 'locked'
148
- o = Lita::User.find_by_id(l['owner_id'])
149
- if o.mention_name
150
- response.reply('(failed) ' + t('label.owned_mention',
151
- name: name,
152
- owner_name: o.name,
153
- owner_mention: o.mention_name))
154
- else
155
- response.reply('(failed) ' + t('label.owned',
156
- name: name,
157
- owner_name: o.name))
158
- end
159
- else
160
- response.reply('(failed) ' + t('label.dependency'))
161
- end
162
- end
45
+ return response.reply('(failed) ' + t('label.does_not_exist', name: name)) unless label_exists?(name)
46
+ m = label_membership(name)
47
+ return response.reply('(failed) ' + t('label.no_resources', name: name)) unless m.count > 0
48
+ return response.reply('(successful) ' + t('label.lock', name: name)) if lock_label!(name, response.user, nil)
49
+
50
+ l = label(name)
51
+ if l['state'] == 'locked'
52
+ o = Lita::User.find_by_id(l['owner_id'])
53
+ if o.mention_name
54
+ response.reply('(failed) ' + t('label.owned_mention',
55
+ name: name,
56
+ owner_name: o.name,
57
+ owner_mention: o.mention_name))
163
58
  else
164
- response.reply('(failed) ' + t('label.no_resources', name: name))
59
+ response.reply('(failed) ' + t('label.owned',
60
+ name: name,
61
+ owner_name: o.name))
165
62
  end
166
63
  else
167
- response.reply('(failed) ' + t('label.does_not_exist', name: name))
168
- end
169
- end
170
-
171
- def unlock(response)
172
- name = response.matches[0][0]
173
- if label_exists?(name)
174
- l = label(name)
175
- if l['state'] == 'unlocked'
176
- response.reply('(successful) ' + t('label.is_unlocked',
177
- name: name))
178
- else
179
- if response.user.id == l['owner_id']
180
- unlock_label!(name)
181
- response.reply('(successful) ' + t('label.unlock', name: name))
182
- else
183
- o = Lita::User.find_by_id(l['owner_id'])
184
- if o.mention_name
185
- response.reply('(failed) ' + t('label.owned_mention',
186
- name: name,
187
- owner_name: o.name,
188
- owner_mention: o.mention_name))
189
- else
190
- response.reply('(failed) ' + t('label.owned',
191
- name: name,
192
- owner_name: o.name))
193
- end
64
+ msg = '(failed) ' + t('label.dependency') + "\n"
65
+ deps = []
66
+ label_membership(name).each do |resource_name|
67
+ resource = resource(resource_name)
68
+ u = Lita::User.find_by_id(resource['owner_id'])
69
+ if resource['state'] == 'locked'
70
+ deps.push "#{resource_name} - #{u.name}"
194
71
  end
195
72
  end
196
- else
197
- response.reply('(failed) ' + t('subject.does_not_exist', name: name))
73
+ msg += deps.join("\n")
74
+ response.reply(msg)
198
75
  end
199
76
  end
200
77
 
201
- def steal(response)
78
+ def unlock(response)
202
79
  name = response.matches[0][0]
203
- if label_exists?(name)
80
+ return response.reply('(failed) ' + t('subject.does_not_exist', name: name)) unless label_exists?(name)
81
+ l = label(name)
82
+ return response.reply('(successful) ' + t('label.is_unlocked', name: name)) if l['state'] == 'unlocked'
83
+
84
+ if response.user.id == l['owner_id']
204
85
  unlock_label!(name)
205
86
  response.reply('(successful) ' + t('label.unlock', name: name))
206
- # FIXME: Handle the case where things can't be unlocked?
207
- else
208
- response.reply('(failed) ' + t('subject.does_not_exist', name: name))
209
- end
210
- end
211
-
212
- def status(response)
213
- name = response.matches[0][0]
214
- if label_exists?(name)
215
- l = label(name)
216
- if l['owner_id'] && l['owner_id'] != ''
217
- o = Lita::User.find_by_id(l['owner_id'])
218
- response.reply(t('label.desc_owner', name: name,
219
- state: l['state'],
220
- owner_name: o.name))
221
- else
222
- response.reply(t('label.desc', name: name, state: l['state']))
223
- end
224
- elsif resource_exists?(name)
225
- r = resource(name)
226
- response.reply(t('resource.desc', name: name, state: r['state']))
227
- else
228
- response.reply(t('subject.does_not_exist', name: name))
229
- end
230
- end
231
-
232
- def label_list(response)
233
- labels.each do |n|
234
- name = n.sub('label_', '')
235
- l = label(name)
236
- response.reply(t('label.desc', name: name, state: l['state']))
237
- end
238
- end
239
-
240
- def label_create(response)
241
- name = response.matches[0][0]
242
- if create_label(name)
243
- response.reply(t('label.created', name: name))
244
- else
245
- response.reply(t('label.exists', name: name))
246
- end
247
- end
248
-
249
- def label_delete(response)
250
- name = response.matches[0][0]
251
- if delete_label(name)
252
- response.reply(t('label.deleted', name: name))
253
- else
254
- response.reply(t('label.does_not_exist', name: name))
255
- end
256
- end
257
-
258
- def label_show(response)
259
- name = response.matches[0][0]
260
- if label_exists?(name)
261
- members = label_membership(name)
262
- if members.count > 0
263
- response.reply(t('label.resources', name: name,
264
- resources: members.join(', ')))
265
- else
266
- response.reply(t('label.has_no_resources', name: name))
267
- end
268
87
  else
269
- response.reply(t('label.does_not_exist', name: name))
270
- end
271
- end
272
-
273
- def label_add(response)
274
- resource_name = response.matches[0][0]
275
- label_name = response.matches[0][1]
276
- if label_exists?(label_name)
277
- if resource_exists?(resource_name)
278
- add_resource_to_label(label_name, resource_name)
279
- response.reply(t('label.resource_added', label: label_name,
280
- resource: resource_name))
88
+ o = Lita::User.find_by_id(l['owner_id'])
89
+ if o.mention_name
90
+ response.reply('(failed) ' + t('label.owned_mention',
91
+ name: name,
92
+ owner_name: o.name,
93
+ owner_mention: o.mention_name))
281
94
  else
282
- response.reply(t('resource.does_not_exist', name: resource_name))
95
+ response.reply('(failed) ' + t('label.owned',
96
+ name: name,
97
+ owner_name: o.name))
283
98
  end
284
- else
285
- response.reply(t('label.does_not_exist', name: label_name))
286
99
  end
287
100
  end
288
101
 
289
- def label_remove(response)
290
- resource_name = response.matches[0][0]
291
- label_name = response.matches[0][1]
292
- if label_exists?(label_name)
293
- if resource_exists?(resource_name)
294
- members = label_membership(label_name)
295
- if members.include?(resource_name)
296
- remove_resource_from_label(label_name, resource_name)
297
- response.reply(t('label.resource_removed',
298
- label: label_name, resource: resource_name))
299
- else
300
- response.reply(t('label.does_not_have_resource',
301
- label: label_name, resource: resource_name))
302
- end
303
- else
304
- response.reply(t('resource.does_not_exist', name: resource_name))
305
- end
306
- else
307
- response.reply(t('label.does_not_exist', name: label_name))
308
- end
309
- end
310
-
311
- def resource_list(response)
312
- output = ''
313
- resources.each do |r|
314
- r_name = r.sub('resource_', '')
315
- res = resource(r_name)
316
- output += t('resource.desc', name: r_name, state: res['state'])
317
- end
318
- response.reply(output)
319
- end
320
-
321
- def resource_create(response)
322
- name = response.matches[0][0]
323
- if create_resource(name)
324
- response.reply(t('resource.created', name: name))
325
- else
326
- response.reply(t('resource.exists', name: name))
327
- end
328
- end
329
-
330
- def resource_delete(response)
331
- name = response.matches[0][0]
332
- if delete_resource(name)
333
- response.reply(t('resource.deleted', name: name))
334
- else
335
- response.reply(t('resource.does_not_exist', name: name))
336
- end
337
- end
338
-
339
- def resource_show(response)
102
+ def steal(response)
340
103
  name = response.matches[0][0]
341
- if resource_exists?(name)
342
- r = resource(name)
343
- response.reply(t('resource.desc', name: name, state: r['state']))
344
- else
345
- response.reply(t('resource.does_not_exist', name: name))
346
- end
347
- end
348
-
349
- private
350
-
351
- def create_label(name)
352
- label_key = "label_#{name}"
353
- redis.hset(label_key, 'state', 'unlocked') unless
354
- resource_exists?(name) || label_exists?(name)
355
- end
356
-
357
- def delete_label(name)
358
- label_key = "label_#{name}"
359
- redis.del(label_key) if label_exists?(name)
360
- end
361
-
362
- def label_exists?(name)
363
- redis.exists("label_#{name}")
364
- end
365
-
366
- def label_membership(name)
367
- redis.smembers("membership_#{name}")
368
- end
369
-
370
- def add_resource_to_label(label, resource)
371
- if label_exists?(label) && resource_exists?(resource)
372
- redis.sadd("membership_#{label}", resource)
373
- end
374
- end
375
-
376
- def remove_resource_from_label(label, resource)
377
- if label_exists?(label) && resource_exists?(resource)
378
- redis.srem("membership_#{label}", resource)
379
- end
380
- end
381
-
382
- def create_resource(name)
383
- resource_key = "resource_#{name}"
384
- redis.hset(resource_key, 'state', 'unlocked') unless
385
- resource_exists?(name) || label_exists?(name)
386
- end
387
-
388
- def delete_resource(name)
389
- resource_key = "resource_#{name}"
390
- redis.del(resource_key) if resource_exists?(name)
391
- end
392
-
393
- def resource_exists?(name)
394
- redis.exists("resource_#{name}")
395
- end
396
-
397
- def lock_resource!(name, owner, time_until)
398
- if resource_exists?(name)
399
- resource_key = "resource_#{name}"
400
- value = redis.hget(resource_key, 'state')
401
- if value == 'unlocked'
402
- # FIXME: Race condition!
403
- redis.hset(resource_key, 'state', 'locked')
404
- redis.hset(resource_key, 'owner_id', owner.id)
405
- redis.hset(resource_key, 'until', time_until)
406
- true
407
- else
408
- false
409
- end
410
- else
411
- false
412
- end
413
- end
414
-
415
- def lock_label!(name, owner, time_until)
416
- if label_exists?(name)
417
- key = "label_#{name}"
418
- members = label_membership(name)
419
- members.each do |m|
420
- return false unless lock_resource!(m, owner, time_until)
421
- end
422
- redis.hset(key, 'state', 'locked')
423
- redis.hset(key, 'owner_id', owner.id)
424
- redis.hset(key, 'until', time_until)
425
- true
426
- else
427
- false
428
- end
429
- end
430
-
431
- def unlock_resource!(name)
432
- if resource_exists?(name)
433
- key = "resource_#{name}"
434
- redis.hset(key, 'state', 'unlocked')
435
- redis.hset(key, 'owner_id', '')
436
- else
437
- false
438
- end
439
- end
440
-
441
- def unlock_label!(name)
442
- if label_exists?(name)
443
- key = "label_#{name}"
444
- members = label_membership(name)
445
- members.each do |m|
446
- unlock_resource!(m)
447
- end
448
- redis.hset(key, 'state', 'unlocked')
449
- redis.hset(key, 'owner_id', '')
450
- true
104
+ return response.reply('(failed) ' + t('subject.does_not_exist', name: name)) unless label_exists?(name)
105
+ l = label(name)
106
+ return response.reply(t('steal.already_unlocked', label: name)) unless l['state'] == 'locked'
107
+ o = Lita::User.find_by_id(l['owner_id'])
108
+ if o.id != response.user.id
109
+ unlock_label!(name)
110
+ lock_label!(name, response.user, nil)
111
+ mention = o.mention_name ? "(@#{o.mention_name})" : ''
112
+ response.reply('(successful) ' + t('steal.stolen',
113
+ label: name,
114
+ old_owner: o.name,
115
+ mention: mention))
451
116
  else
452
- false
117
+ response.reply(t('steal.self'))
453
118
  end
454
119
  end
455
-
456
- def resource(name)
457
- redis.hgetall("resource_#{name}")
458
- end
459
-
460
- def resources
461
- redis.keys('resource_*')
462
- end
463
-
464
- def label(name)
465
- redis.hgetall("label_#{name}")
466
- end
467
-
468
- def labels
469
- redis.keys('label_*')
470
- end
471
120
  end
472
121
 
473
122
  Lita.register_handler(Locker)