lita-locker 1.0.10 → 1.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/.rubocop.yml +5 -2
- data/.ruby-version +1 -0
- data/.travis.yml +1 -2
- data/Gemfile +2 -0
- data/README.md +15 -6
- data/Rakefile +3 -1
- data/lib/lita-locker.rb +3 -0
- data/lib/lita/handlers/locker.rb +11 -5
- data/lib/lita/handlers/locker_events.rb +2 -0
- data/lib/lita/handlers/locker_http.rb +2 -0
- data/lib/lita/handlers/locker_labels.rb +37 -20
- data/lib/lita/handlers/locker_misc.rb +8 -6
- data/lib/lita/handlers/locker_resources.rb +37 -20
- data/lib/locker/label.rb +5 -5
- data/lib/locker/list.rb +57 -0
- data/lib/locker/misc.rb +2 -0
- data/lib/locker/regex.rb +2 -0
- data/lib/locker/resource.rb +3 -1
- data/lita-locker.gemspec +4 -1
- data/locales/en.yml +7 -3
- data/spec/lita/handlers/locker_events_spec.rb +2 -0
- data/spec/lita/handlers/locker_http_spec.rb +3 -1
- data/spec/lita/handlers/locker_labels_spec.rb +54 -3
- data/spec/lita/handlers/locker_misc_spec.rb +6 -0
- data/spec/lita/handlers/locker_resources_spec.rb +49 -3
- data/spec/lita/handlers/locker_spec.rb +2 -0
- data/spec/locker/list_spec.rb +100 -0
- data/spec/spec_helper.rb +11 -6
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40e3c6cfb38098e4089ab667b84796cf38dddb98
|
4
|
+
data.tar.gz: 01c834e9d945c39cf53fa37c5984384505f557b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9d7e3f1151c101a757688053d3d8f82f446db64e7bacabb72ee9baa064f1221f6489ec6d891201eba9c2284158ae6f59c2c31300918d84be75d10d6ad9cb674
|
7
|
+
data.tar.gz: bde7f3cf399c8e069ab48bdf7fc48b93f1aad29ef6d2fbbdb2dad7684291ab28f2bf9ad0cafc37d05227ed443e87c951992519636f640df26e746eef1d06fb66
|
data/.rubocop.yml
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.2
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -19,7 +19,16 @@ gem "lita-locker"
|
|
19
19
|
|
20
20
|
## Configuration
|
21
21
|
|
22
|
-
|
22
|
+
### Optional attributes
|
23
|
+
|
24
|
+
* `per_page` - The number of items to show at once when listing labels or resources. Default: 10
|
25
|
+
|
26
|
+
### Example
|
27
|
+
|
28
|
+
``` ruby
|
29
|
+
Lita.configure do |config|
|
30
|
+
config.handlers.locker.per_page = 3
|
31
|
+
```
|
23
32
|
|
24
33
|
## Usage
|
25
34
|
|
@@ -61,7 +70,7 @@ locker dequeue <label> - Remove yourself from the queue for <label>
|
|
61
70
|
|
62
71
|
### Labels
|
63
72
|
```
|
64
|
-
locker label list
|
73
|
+
locker label list [--page N] - List all labels
|
65
74
|
locker label create <name> - Create a label with <name>.
|
66
75
|
locker label delete <name> - Delete the label with <name>. Clears all locks associated.
|
67
76
|
locker label add <resource> to <name> - Adds <resource> to the list of things to lock/unlock for <name>
|
@@ -71,10 +80,10 @@ locker label show <name> - Show all resources for <name>
|
|
71
80
|
|
72
81
|
### Resources
|
73
82
|
```
|
74
|
-
locker resource list
|
75
|
-
locker resource create <name>
|
76
|
-
locker resource delete <name>
|
77
|
-
locker resource show <name>
|
83
|
+
locker resource list [--page N] - List all resources
|
84
|
+
locker resource create <name> - Create a resource with <name>. (Restricted to locker_admins group)
|
85
|
+
locker resource delete <name> - Delete the resource with <name>. Clears all locks associated. (Restricted to locker_admins group)
|
86
|
+
locker resource show <name> - Show the state of <name>
|
78
87
|
```
|
79
88
|
|
80
89
|
### HTTP access
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bundler/gem_tasks'
|
2
4
|
require 'rspec/core/rake_task'
|
3
5
|
require 'rubocop/rake_task'
|
@@ -5,4 +7,4 @@ require 'rubocop/rake_task'
|
|
5
7
|
RSpec::Core::RakeTask.new(:spec)
|
6
8
|
RuboCop::RakeTask.new(:rubocop)
|
7
9
|
|
8
|
-
task default: [
|
10
|
+
task default: %i[spec rubocop]
|
data/lib/lita-locker.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'lita'
|
2
4
|
|
3
5
|
Lita.load_locales Dir[File.expand_path(
|
@@ -6,6 +8,7 @@ Lita.load_locales Dir[File.expand_path(
|
|
6
8
|
|
7
9
|
require 'redis-objects'
|
8
10
|
require 'time-lord'
|
11
|
+
require 'lita-keyword-arguments'
|
9
12
|
|
10
13
|
require 'locker/label'
|
11
14
|
require 'locker/misc'
|
data/lib/lita/handlers/locker.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
# Handy, isn't it?
|
3
5
|
module Handlers
|
4
6
|
# Top-level class for Locker
|
5
7
|
class Locker < Handler
|
8
|
+
config :per_page, type: Integer, default: 10
|
9
|
+
|
6
10
|
on :loaded, :setup_redis
|
7
11
|
|
8
12
|
include ::Locker::Label
|
@@ -72,7 +76,7 @@ module Lita
|
|
72
76
|
|
73
77
|
return response.reply(failed(t('label.does_not_exist', name: name))) unless Label.exists?(name)
|
74
78
|
l = Label.new(name)
|
75
|
-
return response.reply(failed(t('label.no_resources', name: name))) unless l.membership.count
|
79
|
+
return response.reply(failed(t('label.no_resources', name: name))) unless l.membership.count.positive?
|
76
80
|
return response.reply(t('label.self_lock', name: name, user: response.user.name)) if l.owner == response.user
|
77
81
|
return response.reply(success(t('label.lock', name: name))) if l.lock!(response.user.id)
|
78
82
|
|
@@ -134,10 +138,12 @@ module Lita
|
|
134
138
|
l = Label.new(name)
|
135
139
|
return response.reply(failed(t('give.not_owned', label: name))) unless l.locked?
|
136
140
|
owner_mention = render_template('mention', name: l.owner.mention_name, id: l.owner.id)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
+
unless l.owner == response.user
|
142
|
+
return response.reply(t('give.not_owner',
|
143
|
+
label: name,
|
144
|
+
owner: l.owner.name,
|
145
|
+
mention: owner_mention))
|
146
|
+
end
|
141
147
|
recipient_name = response.match_data['username'].rstrip
|
142
148
|
recipient = Lita::User.fuzzy_find(recipient_name)
|
143
149
|
return response.reply(t('user.unknown', user: recipient_name)) unless recipient
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'locker/list'
|
4
|
+
|
1
5
|
module Lita
|
2
6
|
module Handlers
|
3
7
|
# Label-related handlers
|
@@ -10,64 +14,77 @@ module Lita
|
|
10
14
|
include ::Locker::Resource
|
11
15
|
|
12
16
|
route(
|
13
|
-
/^locker\slabel\slist
|
17
|
+
/^locker\slabel\slist/,
|
14
18
|
:list,
|
15
19
|
command: true,
|
20
|
+
kwargs: { page: { default: 1 } },
|
16
21
|
help: { t('help.label.list.syntax') => t('help.label.list.desc') }
|
17
22
|
)
|
18
23
|
|
19
24
|
route(
|
20
|
-
/^locker\slabel\screate\s#{LABELS_REGEX}$/,
|
25
|
+
/^locker\slabel\screate\s#{LABELS_REGEX}#{COMMENT_REGEX}$/,
|
21
26
|
:create,
|
22
27
|
command: true,
|
23
28
|
help: { t('help.label.create.syntax') => t('help.label.create.desc') }
|
24
29
|
)
|
25
30
|
|
26
31
|
route(
|
27
|
-
/^locker\slabel\sdelete\s#{LABELS_REGEX}$/,
|
32
|
+
/^locker\slabel\sdelete\s#{LABELS_REGEX}#{COMMENT_REGEX}$/,
|
28
33
|
:delete,
|
29
34
|
command: true,
|
30
35
|
help: { t('help.label.delete.syntax') => t('help.label.delete.desc') }
|
31
36
|
)
|
32
37
|
|
33
38
|
route(
|
34
|
-
/^locker\slabel\sshow\s#{LABEL_REGEX}$/,
|
39
|
+
/^locker\slabel\sshow\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
|
35
40
|
:show,
|
36
41
|
command: true,
|
37
42
|
help: { t('help.label.show.syntax') => t('help.label.show.desc') }
|
38
43
|
)
|
39
44
|
|
40
45
|
route(
|
41
|
-
/^locker\slabel\sadd\s#{RESOURCES_REGEX}\sto\s#{LABEL_REGEX}$/,
|
46
|
+
/^locker\slabel\sadd\s#{RESOURCES_REGEX}\sto\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
|
42
47
|
:add,
|
43
48
|
command: true,
|
44
49
|
help: { t('help.label.add.syntax') => t('help.label.add.desc') }
|
45
50
|
)
|
46
51
|
|
47
52
|
route(
|
48
|
-
/^locker\slabel\sremove\s#{RESOURCES_REGEX}\sfrom\s#{LABEL_REGEX}$/,
|
53
|
+
/^locker\slabel\sremove\s#{RESOURCES_REGEX}\sfrom\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
|
49
54
|
:remove,
|
50
55
|
command: true,
|
51
56
|
help: { t('help.label.remove.syntax') => t('help.label.remove.desc') }
|
52
57
|
)
|
53
58
|
|
54
59
|
def list(response)
|
55
|
-
|
56
|
-
|
60
|
+
begin
|
61
|
+
list = ::Locker::List.new(Label, config.per_page, response.extensions[:kwargs][:page])
|
62
|
+
rescue ArgumentError
|
63
|
+
return response.reply(t('list.invalid_page_type'))
|
64
|
+
end
|
57
65
|
|
58
|
-
|
59
|
-
if should_rate_limit
|
60
|
-
sleep 3
|
61
|
-
else
|
62
|
-
should_rate_limit = true
|
63
|
-
end
|
66
|
+
return response.reply(t('list.page_outside_range', pages: list.pages)) unless list.valid_page?
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
message = list.requested_page.map do |key|
|
69
|
+
label = Label.new(key)
|
70
|
+
|
71
|
+
state = label.state.value.to_s
|
72
|
+
|
73
|
+
case state
|
74
|
+
when 'unlocked'
|
75
|
+
unlocked(t('label.desc', name: key, state: state))
|
76
|
+
when 'locked'
|
77
|
+
locked(t('label.desc', name: key, state: state))
|
78
|
+
else
|
79
|
+
# This case shouldn't happen, but it will if a label
|
80
|
+
# gets saved with some other value for `state`.
|
81
|
+
t('label.desc', name: key, state: state)
|
69
82
|
end
|
70
|
-
end
|
83
|
+
end.join("\n")
|
84
|
+
|
85
|
+
message += "\n#{t('list.paginate', page: list.page, pages: list.pages)}" if list.multiple_pages?
|
86
|
+
|
87
|
+
response.reply(message)
|
71
88
|
end
|
72
89
|
|
73
90
|
def create(response)
|
@@ -104,7 +121,7 @@ module Lita
|
|
104
121
|
name = response.match_data['label']
|
105
122
|
return response.reply(failed(t('label.does_not_exist', name: name))) unless Label.exists?(name)
|
106
123
|
l = Label.new(name)
|
107
|
-
return response.reply(t('label.has_no_resources', name: name)) unless l.membership.count
|
124
|
+
return response.reply(t('label.has_no_resources', name: name)) unless l.membership.count.positive?
|
108
125
|
res = []
|
109
126
|
l.membership.each do |member|
|
110
127
|
res.push(member)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
module Handlers
|
3
5
|
# Misc Locker handlers
|
@@ -10,28 +12,28 @@ module Lita
|
|
10
12
|
include ::Locker::Resource
|
11
13
|
|
12
14
|
route(
|
13
|
-
/^locker\sstatus\s#{LABEL_WILDCARD_REGEX}$/,
|
15
|
+
/^locker\sstatus\s#{LABEL_WILDCARD_REGEX}#{COMMENT_REGEX}$/,
|
14
16
|
:status,
|
15
17
|
command: true,
|
16
18
|
help: { t('help.status.syntax') => t('help.status.desc') }
|
17
19
|
)
|
18
20
|
|
19
21
|
route(
|
20
|
-
/^locker\slist\s#{USER_REGEX}$/,
|
22
|
+
/^locker\slist\s#{USER_REGEX}#{COMMENT_REGEX}$/,
|
21
23
|
:list,
|
22
24
|
command: true,
|
23
25
|
help: { t('help.list.syntax') => t('help.list.desc') }
|
24
26
|
)
|
25
27
|
|
26
28
|
route(
|
27
|
-
/^locker\s(dq|dequeue)\s#{LABEL_REGEX}$/,
|
29
|
+
/^locker\s(dq|dequeue)\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
|
28
30
|
:dequeue,
|
29
31
|
command: true,
|
30
32
|
help: { t('help.dequeue.syntax') => t('help.dequeue.desc') }
|
31
33
|
)
|
32
34
|
|
33
35
|
route(
|
34
|
-
/^locker\slog\s#{LABEL_REGEX}$/,
|
36
|
+
/^locker\slog\s#{LABEL_REGEX}#{COMMENT_REGEX}$/,
|
35
37
|
:log,
|
36
38
|
command: true,
|
37
39
|
help: { t('help.log.syntax.') => t('help.log.desc') }
|
@@ -48,7 +50,7 @@ module Lita
|
|
48
50
|
|
49
51
|
def status(response)
|
50
52
|
name = response.match_data['label']
|
51
|
-
unless name
|
53
|
+
unless name.match?(/\*/)
|
52
54
|
# Literal query
|
53
55
|
return response.reply(status_label(name)) if Label.exists?(name)
|
54
56
|
return response.reply(status_resource(name)) if Resource.exists?(name)
|
@@ -90,7 +92,7 @@ module Lita
|
|
90
92
|
def status_label(name)
|
91
93
|
l = Label.new(name)
|
92
94
|
return unlocked(t('label.desc', name: name, state: l.state.value)) unless l.locked?
|
93
|
-
if l.wait_queue.count
|
95
|
+
if l.wait_queue.count.positive?
|
94
96
|
queue = []
|
95
97
|
l.wait_queue.each do |u|
|
96
98
|
usr = Lita::User.find_by_id(u)
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'locker/list'
|
4
|
+
|
1
5
|
module Lita
|
2
6
|
module Handlers
|
3
7
|
# Resource-related handlers
|
@@ -10,14 +14,15 @@ module Lita
|
|
10
14
|
include ::Locker::Resource
|
11
15
|
|
12
16
|
route(
|
13
|
-
/^locker\sresource\slist
|
17
|
+
/^locker\sresource\slist/,
|
14
18
|
:list,
|
15
19
|
command: true,
|
20
|
+
kwargs: { page: { default: 1 } },
|
16
21
|
help: { t('help.resource.list.syntax') => t('help.resource.list.desc') }
|
17
22
|
)
|
18
23
|
|
19
24
|
route(
|
20
|
-
/^locker\sresource\screate\s#{RESOURCES_REGEX}$/,
|
25
|
+
/^locker\sresource\screate\s#{RESOURCES_REGEX}#{COMMENT_REGEX}$/,
|
21
26
|
:create,
|
22
27
|
command: true,
|
23
28
|
restrict_to: [:locker_admins],
|
@@ -27,7 +32,7 @@ module Lita
|
|
27
32
|
)
|
28
33
|
|
29
34
|
route(
|
30
|
-
/^locker\sresource\sdelete\s#{RESOURCES_REGEX}$/,
|
35
|
+
/^locker\sresource\sdelete\s#{RESOURCES_REGEX}#{COMMENT_REGEX}$/,
|
31
36
|
:delete,
|
32
37
|
command: true,
|
33
38
|
restrict_to: [:locker_admins],
|
@@ -37,29 +42,41 @@ module Lita
|
|
37
42
|
)
|
38
43
|
|
39
44
|
route(
|
40
|
-
/^locker\sresource\sshow\s#{RESOURCE_REGEX}$/,
|
45
|
+
/^locker\sresource\sshow\s#{RESOURCE_REGEX}#{COMMENT_REGEX}$/,
|
41
46
|
:show,
|
42
47
|
command: true,
|
43
48
|
help: { t('help.resource.show.syntax') => t('help.resource.show.desc') }
|
44
49
|
)
|
45
50
|
|
46
51
|
def list(response)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
if should_rate_limit
|
52
|
-
sleep 3
|
53
|
-
else
|
54
|
-
should_rate_limit = true
|
55
|
-
end
|
56
|
-
|
57
|
-
slice.each do |r|
|
58
|
-
res = Resource.new(r)
|
59
|
-
response.reply(t('resource.desc', name: r, state: res.state.value))
|
60
|
-
end
|
61
|
-
end
|
52
|
+
begin
|
53
|
+
list = ::Locker::List.new(Resource, config.per_page, response.extensions[:kwargs][:page])
|
54
|
+
rescue ArgumentError
|
55
|
+
return response.reply(t('list.invalid_page_type'))
|
62
56
|
end
|
57
|
+
|
58
|
+
return response.reply(t('list.page_outside_range', pages: list.pages)) unless list.valid_page?
|
59
|
+
|
60
|
+
message = list.requested_page.map do |key|
|
61
|
+
resource = Resource.new(key)
|
62
|
+
|
63
|
+
state = resource.state.value
|
64
|
+
|
65
|
+
case state
|
66
|
+
when 'unlocked'
|
67
|
+
unlocked(t('resource.desc', name: key, state: state))
|
68
|
+
when 'locked'
|
69
|
+
locked(t('resource.desc', name: key, state: state))
|
70
|
+
else
|
71
|
+
# This case shouldn't happen, but it will if a label
|
72
|
+
# gets saved with some other value for `state`.
|
73
|
+
t('resource.desc', name: key, state: state)
|
74
|
+
end
|
75
|
+
end.join("\n")
|
76
|
+
|
77
|
+
message += "\n#{t('list.paginate', page: list.page, pages: list.pages)}" if list.multiple_pages?
|
78
|
+
|
79
|
+
response.reply(message)
|
63
80
|
end
|
64
81
|
|
65
82
|
def create(response)
|
@@ -99,7 +116,7 @@ module Lita
|
|
99
116
|
return response.reply(t('resource.does_not_exist', name: name)) unless Resource.exists?(name)
|
100
117
|
r = Resource.new(name)
|
101
118
|
resp = t('resource.desc', name: name, state: r.state.value)
|
102
|
-
if r.labels.count
|
119
|
+
if r.labels.count.positive?
|
103
120
|
resp += ', used by: '
|
104
121
|
r.labels.each do |label|
|
105
122
|
resp += Label.new(label).id
|
data/lib/locker/label.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Locker subsystem
|
2
4
|
module Locker
|
3
5
|
# Label helpers
|
@@ -40,7 +42,7 @@ module Locker
|
|
40
42
|
|
41
43
|
def self.delete(key)
|
42
44
|
raise 'Unknown label key' unless Label.exists?(key)
|
43
|
-
%w
|
45
|
+
%w[state owner_id membership wait_queue journal observer_ids].each do |item|
|
44
46
|
redis.del("label:#{key}:#{item}")
|
45
47
|
end
|
46
48
|
redis.srem('label-list', Label.normalize(key))
|
@@ -93,7 +95,7 @@ module Locker
|
|
93
95
|
log('Unlocked')
|
94
96
|
|
95
97
|
# FIXME: Possible race condition where resources become unavailable between unlock and relock
|
96
|
-
if wait_queue.count
|
98
|
+
if wait_queue.count.positive?
|
97
99
|
next_user = wait_queue.shift
|
98
100
|
lock!(next_user)
|
99
101
|
end
|
@@ -207,9 +209,7 @@ module Locker
|
|
207
209
|
l = Label.new(name)
|
208
210
|
l.membership.each do |resource_name|
|
209
211
|
resource = Locker::Resource::Resource.new(resource_name)
|
210
|
-
if resource.state.value == 'locked'
|
211
|
-
deps.push "#{resource_name} - #{resource.owner.name}"
|
212
|
-
end
|
212
|
+
deps.push "#{resource_name} - #{resource.owner.name}" if resource.state.value == 'locked'
|
213
213
|
end
|
214
214
|
msg += deps.join("\n")
|
215
215
|
msg
|
data/lib/locker/list.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Locker subsystem
|
4
|
+
module Locker
|
5
|
+
# A paginated list of items (e.g. labels or resources).
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class List
|
9
|
+
# @return [#list] The Ruby class of the item to be listed.
|
10
|
+
attr_reader :item_class
|
11
|
+
|
12
|
+
# @return [Enumerable] The full list of items.
|
13
|
+
attr_reader :list
|
14
|
+
|
15
|
+
# @return [Integer] The number of items displayed per page.
|
16
|
+
attr_reader :per_page
|
17
|
+
|
18
|
+
# @return [Integer] The page the user has requested.
|
19
|
+
attr_reader :page
|
20
|
+
|
21
|
+
# @return [Integer] The total number of pages.
|
22
|
+
attr_reader :pages
|
23
|
+
|
24
|
+
# @return [Integer] The zero-based index offset that the requested page starts on within the full list.
|
25
|
+
attr_reader :offset
|
26
|
+
|
27
|
+
def initialize(item_class, per_page, page)
|
28
|
+
@item_class = item_class
|
29
|
+
@list = item_class.list
|
30
|
+
@per_page = per_page
|
31
|
+
@page = Integer(page.to_s, 10)
|
32
|
+
@pages = (list.count / per_page).ceil + 1
|
33
|
+
@offset = per_page * (self.page - 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Whether or not the list has multiple pages.
|
37
|
+
#
|
38
|
+
# @return [Boolean]
|
39
|
+
def multiple_pages?
|
40
|
+
list.count > per_page
|
41
|
+
end
|
42
|
+
|
43
|
+
# An enumerable of the items in the requested page.
|
44
|
+
#
|
45
|
+
# @return [Enumerable]
|
46
|
+
def requested_page
|
47
|
+
list[offset, per_page]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Whether or not the requested page exists.
|
51
|
+
#
|
52
|
+
# @return [Boolean]
|
53
|
+
def valid_page?
|
54
|
+
page >= 1 && page <= pages
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/locker/misc.rb
CHANGED
data/lib/locker/regex.rb
CHANGED
data/lib/locker/resource.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Locker subsystem
|
2
4
|
module Locker
|
3
5
|
# Resource helpers
|
@@ -34,7 +36,7 @@ module Locker
|
|
34
36
|
|
35
37
|
def self.delete(key)
|
36
38
|
raise 'Unknown resource key' unless Resource.exists?(key)
|
37
|
-
%w
|
39
|
+
%w[state owner_id].each do |item|
|
38
40
|
redis.del("resource:#{key}:#{item}")
|
39
41
|
end
|
40
42
|
redis.srem('resource-list', key)
|
data/lita-locker.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Gem::Specification.new do |spec|
|
2
4
|
spec.name = 'lita-locker'
|
3
|
-
spec.version = '1.0
|
5
|
+
spec.version = '1.1.0'
|
4
6
|
spec.authors = ['Eric Sigler']
|
5
7
|
spec.email = ['me@esigler.com']
|
6
8
|
spec.description = '"lock" and "unlock" arbitrary subjects'
|
@@ -15,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
15
17
|
spec.require_paths = ['lib']
|
16
18
|
|
17
19
|
spec.add_runtime_dependency 'lita', '>= 4.2'
|
20
|
+
spec.add_runtime_dependency 'lita-keyword-arguments'
|
18
21
|
spec.add_runtime_dependency 'redis-objects'
|
19
22
|
spec.add_runtime_dependency 'time-lord'
|
20
23
|
|
data/locales/en.yml
CHANGED
@@ -16,6 +16,10 @@ en:
|
|
16
16
|
already_observing: "%{user}, you are already observing %{name}"
|
17
17
|
stopped_observing: "%{user}, you have stopped observing %{name}"
|
18
18
|
were_not_observing: "%{user}, you were not observing %{name}"
|
19
|
+
list:
|
20
|
+
paginate: "Page %{page} of %{pages} shown. Use --page to specify additional pages."
|
21
|
+
invalid_page_type: "Page specified must be an integer."
|
22
|
+
page_outside_range: "Page specified must be between 1 and %{pages}."
|
19
23
|
help:
|
20
24
|
log:
|
21
25
|
syntax: locker log <label>
|
@@ -49,7 +53,7 @@ en:
|
|
49
53
|
desc: Show what locks a user currently holds
|
50
54
|
resource:
|
51
55
|
list:
|
52
|
-
syntax: locker resource list
|
56
|
+
syntax: locker resource list [--page N]
|
53
57
|
desc: List all resources
|
54
58
|
create:
|
55
59
|
syntax: "locker resource create <name>[, <name> ...]"
|
@@ -62,7 +66,7 @@ en:
|
|
62
66
|
desc: Show the state of <name>
|
63
67
|
label:
|
64
68
|
list:
|
65
|
-
syntax: locker label list
|
69
|
+
syntax: locker label list [--page N]
|
66
70
|
desc: List all labels
|
67
71
|
create:
|
68
72
|
syntax: "locker label create <name>[, <name> ...]"
|
@@ -105,7 +109,7 @@ en:
|
|
105
109
|
unlocked_no_queue: "%{name} is unlocked and no one is next up %{mention}"
|
106
110
|
unable_to_lock: "%{name} unable to be locked"
|
107
111
|
lock: "%{name} locked"
|
108
|
-
desc: "%{name} is
|
112
|
+
desc: "%{name} is %{state}"
|
109
113
|
desc_owner: "%{name} is locked by %{owner_name} (taken %{time})"
|
110
114
|
desc_owner_queue: "%{name} is locked by %{owner_name} (taken %{time}). Next up: %{queue}"
|
111
115
|
created: "Label %{name} created"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Lita::Handlers::LockerHttp, lita_handler: true do
|
@@ -24,7 +26,7 @@ describe Lita::Handlers::LockerHttp, lita_handler: true do
|
|
24
26
|
it 'shows json if the label exists' do
|
25
27
|
send_command('locker label create foo')
|
26
28
|
subject.label_show(request, response)
|
27
|
-
expect(response.body).to eq(['{"id":"foo","state":"unlocked","membership":""}'])
|
29
|
+
expect(response.body).to eq(['{"id":"foo","state":"unlocked","membership":{"key":"label:foo:membership","options":{"type":"set"},"value":[]}}'])
|
28
30
|
end
|
29
31
|
|
30
32
|
it 'shows 404 if the label does not exist' do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Lita::Handlers::LockerLabels, lita_handler: true do
|
@@ -17,6 +19,12 @@ describe Lita::Handlers::LockerLabels, lita_handler: true do
|
|
17
19
|
is_expected.to route_command("locker label add foo, bar to #{l}").to(:add)
|
18
20
|
is_expected.to route_command("locker label remove resource from #{l}").to(:remove)
|
19
21
|
is_expected.to route_command("locker label remove foo, bar from #{l}").to(:remove)
|
22
|
+
|
23
|
+
is_expected.to route_command("locker label create #{l} # comment").to(:create)
|
24
|
+
is_expected.to route_command("locker label delete #{l} # comment").to(:delete)
|
25
|
+
is_expected.to route_command("locker label show #{l} # comment").to(:show)
|
26
|
+
is_expected.to route_command("locker label add resource to #{l} # comment").to(:add)
|
27
|
+
is_expected.to route_command("locker label remove resource from #{l} # comment").to(:remove)
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
@@ -33,12 +41,55 @@ describe Lita::Handlers::LockerLabels, lita_handler: true do
|
|
33
41
|
|
34
42
|
describe '#label_list' do
|
35
43
|
it 'shows a list of labels if there are any' do
|
44
|
+
send_command('locker resource create whatever')
|
36
45
|
send_command('locker label create foobar')
|
37
46
|
send_command('locker label create bazbat')
|
47
|
+
send_command('locker label add whatever to bazbat')
|
48
|
+
send_command('lock bazbat')
|
38
49
|
send_command('locker label list')
|
39
|
-
|
40
|
-
expect(replies.include
|
41
|
-
|
50
|
+
expect(replies.last).to include('foobar is unlocked')
|
51
|
+
expect(replies.last).to include('bazbat is locked')
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when per_page is configured to 3' do
|
55
|
+
before do
|
56
|
+
robot.config.handlers.locker.per_page = 3
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when there are 4 labels' do
|
60
|
+
before do
|
61
|
+
send_command('locker label create 1')
|
62
|
+
send_command('locker label create 2')
|
63
|
+
send_command('locker label create 3')
|
64
|
+
send_command('locker label create 4')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'includes details about what page was shown' do
|
68
|
+
send_command('locker label list')
|
69
|
+
expect(replies.last).to include('Page 1 of 2 shown. Use --page to specify additional pages.')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'displays the page specified' do
|
73
|
+
send_command('locker label list --page 2')
|
74
|
+
expect(replies.last).to include('4 is unlocked')
|
75
|
+
expect(replies.last).to include('Page 2 of 2 shown. Use --page to specify additional pages.')
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'rejects pages lower than 1' do
|
79
|
+
send_command('locker label list --page 0')
|
80
|
+
expect(replies.last).to eq('Page specified must be between 1 and 2.')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'rejects pages higher than the number there are' do
|
84
|
+
send_command('locker label list --page 3')
|
85
|
+
expect(replies.last).to eq('Page specified must be between 1 and 2.')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'rejects non-integer values for pages' do
|
90
|
+
send_command('locker label list --page x')
|
91
|
+
expect(replies.last).to eq('Page specified must be an integer.')
|
92
|
+
end
|
42
93
|
end
|
43
94
|
end
|
44
95
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Lita::Handlers::LockerMisc, lita_handler: true do
|
@@ -18,19 +20,23 @@ describe Lita::Handlers::LockerMisc, lita_handler: true do
|
|
18
20
|
end
|
19
21
|
|
20
22
|
it { is_expected.to route_command('locker status foo*').to(:status) }
|
23
|
+
it { is_expected.to route_command('locker status foo* # comment').to(:status) }
|
21
24
|
|
22
25
|
it do
|
23
26
|
is_expected.to route_command('locker list @alice').to(:list)
|
24
27
|
is_expected.to route_command('locker list Alice').to(:list)
|
28
|
+
is_expected.to route_command('locker list Alice # comment').to(:list)
|
25
29
|
end
|
26
30
|
|
27
31
|
it do
|
28
32
|
is_expected.to route_command('locker log something').to(:log)
|
33
|
+
is_expected.to route_command('locker log something # comment').to(:log)
|
29
34
|
end
|
30
35
|
|
31
36
|
it do
|
32
37
|
is_expected.to route_command('locker dequeue something something').to(:dequeue)
|
33
38
|
is_expected.to route_command('locker dq something something').to(:dequeue)
|
39
|
+
is_expected.to route_command('locker dq something something # comment').to(:dequeue)
|
34
40
|
end
|
35
41
|
|
36
42
|
let(:alice) do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Lita::Handlers::LockerResources, lita_handler: true do
|
@@ -12,6 +14,9 @@ describe Lita::Handlers::LockerResources, lita_handler: true do
|
|
12
14
|
is_expected.to route_command("locker resource create #{r}").to(:create)
|
13
15
|
is_expected.to route_command("locker resource delete #{r}").to(:delete)
|
14
16
|
is_expected.to route_command("locker resource show #{r}").to(:show)
|
17
|
+
is_expected.to route_command("locker resource create #{r} # comment").to(:create)
|
18
|
+
is_expected.to route_command("locker resource delete #{r} # comment").to(:delete)
|
19
|
+
is_expected.to route_command("locker resource show #{r} # comment").to(:show)
|
15
20
|
end
|
16
21
|
end
|
17
22
|
|
@@ -25,15 +30,56 @@ describe Lita::Handlers::LockerResources, lita_handler: true do
|
|
25
30
|
end
|
26
31
|
|
27
32
|
it { is_expected.to route_command('locker resource list').to(:list) }
|
33
|
+
it { is_expected.to route_command('locker resource list # comment').to(:list) }
|
28
34
|
|
29
35
|
describe '#resource_list' do
|
30
36
|
it 'shows a list of resources if there are any' do
|
31
37
|
send_command('locker resource create foobar')
|
32
38
|
send_command('locker resource create bazbat')
|
33
39
|
send_command('locker resource list')
|
34
|
-
|
35
|
-
expect(replies).to include('Resource:
|
36
|
-
|
40
|
+
expect(replies.last).to include('Resource: foobar, state: unlocked')
|
41
|
+
expect(replies.last).to include('Resource: bazbat, state: unlocked')
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when per_page is configured to 3' do
|
45
|
+
before do
|
46
|
+
robot.config.handlers.locker.per_page = 3
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when there are 4 resources' do
|
50
|
+
before do
|
51
|
+
send_command('locker resource create 1')
|
52
|
+
send_command('locker resource create 2')
|
53
|
+
send_command('locker resource create 3')
|
54
|
+
send_command('locker resource create 4')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'includes details about what page was shown' do
|
58
|
+
send_command('locker resource list')
|
59
|
+
expect(replies.last).to include('Page 1 of 2 shown. Use --page to specify additional pages.')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'displays the page specified' do
|
63
|
+
send_command('locker resource list --page 2')
|
64
|
+
expect(replies.last).to include('Resource: 4, state: unlocked')
|
65
|
+
expect(replies.last).to include('Page 2 of 2 shown. Use --page to specify additional pages.')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'rejects pages lower than 1' do
|
69
|
+
send_command('locker resource list --page 0')
|
70
|
+
expect(replies.last).to eq('Page specified must be between 1 and 2.')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'rejects pages higher than the number there are' do
|
74
|
+
send_command('locker resource list --page 3')
|
75
|
+
expect(replies.last).to eq('Page specified must be between 1 and 2.')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'rejects non-integer values for pages' do
|
80
|
+
send_command('locker resource list --page x')
|
81
|
+
expect(replies.last).to eq('Page specified must be an integer.')
|
82
|
+
end
|
37
83
|
end
|
38
84
|
end
|
39
85
|
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Locker::List do
|
6
|
+
let(:item_class) { double('item class', list: [one, two, three, four]) }
|
7
|
+
|
8
|
+
let(:one) { double('one') }
|
9
|
+
let(:two) { double('two') }
|
10
|
+
let(:three) { double('three') }
|
11
|
+
let(:four) { double('four') }
|
12
|
+
|
13
|
+
it 'raises an argument error if a non-integer page is requested' do
|
14
|
+
expect { described_class.new(item_class, 3, 'z') }.to raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#multiple_pages' do
|
18
|
+
it 'is true when there are more total items than can be displayed on one page' do
|
19
|
+
subject = described_class.new(item_class, 1, 1)
|
20
|
+
|
21
|
+
expect(subject).to be_multiple_pages
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is false when the whole list fits in one page' do
|
25
|
+
subject = described_class.new(item_class, 10, 1)
|
26
|
+
|
27
|
+
expect(subject).not_to be_multiple_pages
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#requested_page' do
|
32
|
+
context 'with an empty list' do
|
33
|
+
let(:item_class) { double('item class', list: []) }
|
34
|
+
|
35
|
+
it 'returns an empty list' do
|
36
|
+
subject = described_class.new(item_class, 3, 1)
|
37
|
+
|
38
|
+
expect(subject.requested_page).to be_empty
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with a single item list' do
|
43
|
+
let(:item_class) { double('item class', list: [one]) }
|
44
|
+
|
45
|
+
it 'returns a list with one item' do
|
46
|
+
subject = described_class.new(item_class, 3, 1)
|
47
|
+
|
48
|
+
expect(subject.requested_page).to eq([one])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'with a four item list' do
|
53
|
+
it 'splits the pages correctly when there are two items per page' do
|
54
|
+
subject = described_class.new(item_class, 2, 1)
|
55
|
+
|
56
|
+
expect(subject.requested_page).to eq([one, two])
|
57
|
+
|
58
|
+
subject = described_class.new(item_class, 2, 2)
|
59
|
+
|
60
|
+
expect(subject.requested_page).to eq([three, four])
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'splits the pages correctly when there are three items per page' do
|
64
|
+
subject = described_class.new(item_class, 3, 1)
|
65
|
+
|
66
|
+
expect(subject.requested_page).to eq([one, two, three])
|
67
|
+
|
68
|
+
subject = described_class.new(item_class, 3, 2)
|
69
|
+
|
70
|
+
expect(subject.requested_page).to eq([four])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#valid_page?' do
|
76
|
+
it 'is true when the first page is requested' do
|
77
|
+
subject = described_class.new(item_class, 3, 1)
|
78
|
+
|
79
|
+
expect(subject).to be_valid_page
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'is true when the page is between 1 and the total number of pages' do
|
83
|
+
subject = described_class.new(item_class, 3, 2)
|
84
|
+
|
85
|
+
expect(subject).to be_valid_page
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'is false when the page is less than 1' do
|
89
|
+
subject = described_class.new(item_class, 3, 0)
|
90
|
+
|
91
|
+
expect(subject).not_to be_valid_page
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'is false when the page is greater than the total number of pages' do
|
95
|
+
subject = described_class.new(item_class, 3, 10)
|
96
|
+
|
97
|
+
expect(subject).not_to be_valid_page
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'simplecov'
|
2
4
|
require 'coveralls'
|
3
5
|
SimpleCov.formatters = [
|
@@ -12,12 +14,15 @@ Lita.version_3_compatibility_mode = false
|
|
12
14
|
|
13
15
|
RSpec.configure do |config|
|
14
16
|
config.before do
|
15
|
-
registry
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
if defined? registry
|
18
|
+
registry.register_hook(:trigger_route, Lita::Extensions::KeywordArguments)
|
19
|
+
registry.register_handler(Lita::Handlers::Locker)
|
20
|
+
registry.register_handler(Lita::Handlers::LockerEvents)
|
21
|
+
registry.register_handler(Lita::Handlers::LockerHttp)
|
22
|
+
registry.register_handler(Lita::Handlers::LockerLabels)
|
23
|
+
registry.register_handler(Lita::Handlers::LockerMisc)
|
24
|
+
registry.register_handler(Lita::Handlers::LockerResources)
|
25
|
+
end
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lita-locker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Sigler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lita
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: lita-keyword-arguments
|
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'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: redis-objects
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -146,6 +160,7 @@ files:
|
|
146
160
|
- ".gitignore"
|
147
161
|
- ".rspec"
|
148
162
|
- ".rubocop.yml"
|
163
|
+
- ".ruby-version"
|
149
164
|
- ".travis.yml"
|
150
165
|
- CONTRIBUTING.md
|
151
166
|
- Gemfile
|
@@ -161,6 +176,7 @@ files:
|
|
161
176
|
- lib/lita/handlers/locker_misc.rb
|
162
177
|
- lib/lita/handlers/locker_resources.rb
|
163
178
|
- lib/locker/label.rb
|
179
|
+
- lib/locker/list.rb
|
164
180
|
- lib/locker/misc.rb
|
165
181
|
- lib/locker/regex.rb
|
166
182
|
- lib/locker/resource.rb
|
@@ -172,6 +188,7 @@ files:
|
|
172
188
|
- spec/lita/handlers/locker_misc_spec.rb
|
173
189
|
- spec/lita/handlers/locker_resources_spec.rb
|
174
190
|
- spec/lita/handlers/locker_spec.rb
|
191
|
+
- spec/locker/list_spec.rb
|
175
192
|
- spec/spec_helper.rb
|
176
193
|
- templates/failed.erb
|
177
194
|
- templates/failed.hipchat.erb
|
@@ -209,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
226
|
version: '0'
|
210
227
|
requirements: []
|
211
228
|
rubyforge_project:
|
212
|
-
rubygems_version: 2.
|
229
|
+
rubygems_version: 2.6.13
|
213
230
|
signing_key:
|
214
231
|
specification_version: 4
|
215
232
|
summary: '"lock" and "unlock" arbitrary subjects'
|
@@ -220,4 +237,5 @@ test_files:
|
|
220
237
|
- spec/lita/handlers/locker_misc_spec.rb
|
221
238
|
- spec/lita/handlers/locker_resources_spec.rb
|
222
239
|
- spec/lita/handlers/locker_spec.rb
|
240
|
+
- spec/locker/list_spec.rb
|
223
241
|
- spec/spec_helper.rb
|