bumbleworks 0.0.69 → 0.0.70

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.
@@ -13,6 +13,7 @@ require "bumbleworks/entity"
13
13
  require "bumbleworks/participant"
14
14
  require "bumbleworks/workitem"
15
15
  require "bumbleworks/tracker"
16
+ require "bumbleworks/user"
16
17
 
17
18
  # default implementations
18
19
  require "bumbleworks/simple_logger"
@@ -299,10 +299,10 @@ module Bumbleworks
299
299
 
300
300
  def framework_root
301
301
  case
302
- when defined?(Rails) then Rails.root
303
- when defined?(Rory) then Rory.root
304
- when defined?(Padrino) then Padrino.root
305
- when defined?(Sinatra::Application) then Sinatra::Application.root
302
+ when defined?(::Rails) then ::Rails.root
303
+ when defined?(::Rory) then ::Rory.root
304
+ when defined?(::Padrino) then ::Padrino.root
305
+ when defined?(::Sinatra::Application) then ::Sinatra::Application.root
306
306
  end
307
307
  end
308
308
 
@@ -1,12 +1,15 @@
1
1
  require 'ruote/exp/flow_expression'
2
+ require 'bumbleworks/support/flow_expression'
2
3
 
3
4
  module Ruote::Exp
4
5
  class BroadcastEventExpression < FlowExpression
6
+ include Bumbleworks::Support::FlowExpression
7
+
5
8
  names :broadcast_event
6
9
 
7
10
  def consider_tag
8
11
  update_tree
9
- h.updated_tree[1]['tag'] = attribute_text.to_s
12
+ h.updated_tree[1]['tag'] = tag_from_attribute
10
13
  super
11
14
  end
12
15
 
@@ -1,8 +1,11 @@
1
1
  require 'ruote/exp/flow_expression'
2
2
  require 'ruote/exp/fe_await'
3
+ require 'bumbleworks/support/flow_expression'
3
4
 
4
5
  module Ruote::Exp
5
6
  class WaitForEventExpression < AwaitExpression
7
+ include Bumbleworks::Support::FlowExpression
8
+
6
9
  names :wait_for_event
7
10
 
8
11
  # This does the same as the base AwaitExpression#apply, except that this
@@ -13,7 +16,7 @@ module Ruote::Exp
13
16
  def apply
14
17
  update_tree
15
18
  h.updated_tree[1]['global'] = true
16
- h.updated_tree[1]['left_tag'] = attribute_text.to_s
19
+ h.updated_tree[1]['left_tag'] = tag_from_attribute
17
20
  h.updated_tree[1]['merge'] = 'drop'
18
21
  super
19
22
  end
@@ -0,0 +1,18 @@
1
+ module Bumbleworks
2
+ module Support
3
+ module FlowExpression
4
+ def tag_from_attribute
5
+ tag = attribute_text.to_s
6
+ if h.updated_tree[1]['for_entity'].to_s == 'true'
7
+ workitem_fields = h.applied_workitem['fields']
8
+ entity_type, entity_id = workitem_fields.values_at('entity_type', 'entity_id')
9
+ if entity_type && entity_id
10
+ entity_tag = "#{Bumbleworks::Support.tokenize(entity_type)}_#{entity_id}"
11
+ tag += "__for_entity__#{entity_tag}"
12
+ end
13
+ end
14
+ tag
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,91 @@
1
+ module Bumbleworks
2
+ module User
3
+ class NoRoleIdentifiersMethodDefined < StandardError; end
4
+ class NoClaimTokenMethodDefined < StandardError; end
5
+ class MissingRoleQueryMethod < StandardError; end
6
+ class AmbiguousRoleQueryMethod < StandardError; end
7
+ class UnauthorizedClaimAttempt < StandardError; end
8
+ class UnauthorizedReleaseAttempt < StandardError; end
9
+
10
+ # The return value from this method is used as the "claimant" token on
11
+ # tasks, both for claiming a task and for checking if the user is the
12
+ # current claimant.
13
+ #
14
+ # By default, claim_token will first check for `username`, then `email`, and
15
+ # finally raise an exception if neither method exists. Including classes
16
+ # should override this method if using something other than username or
17
+ # email (or if both respond, but email should be preferred).
18
+ def claim_token
19
+ [:username, :email].each do |token_method|
20
+ return send(token_method) if respond_to?(token_method)
21
+ end
22
+ raise NoClaimTokenMethodDefined,
23
+ "If your user class does not respond to :username or :email, define a `claim_token` method"
24
+ end
25
+
26
+ # The return value from this method is used when determining which tasks in
27
+ # the queue this user should be authorized for. Must return an array of
28
+ # strings.
29
+ def role_identifiers
30
+ raise NoRoleIdentifiersMethodDefined,
31
+ "Define a `role_identifiers` method that returns an array of role names"
32
+ end
33
+
34
+ # Returns true if the array returned by #role_identifiers includes the given
35
+ # name. Can be used to determine authority to perform actions on a task,
36
+ # for example.
37
+ def has_role?(role_name)
38
+ role_identifiers.include? role_name
39
+ end
40
+
41
+ # Attempts to set self as the claimant of the given task. If not authorized
42
+ # to claim the task, raises exception. Also bubbles exception from Task
43
+ # when task is already claimed by a different claimant.
44
+ def claim(task)
45
+ raise UnauthorizedClaimAttempt unless has_role?(task.role)
46
+ task.claim(claim_token)
47
+ end
48
+
49
+ # Same as #claim, but first releases (by force) the task, to avoid any
50
+ # possible UnauthorizedClaimAttempt or AlreadyClaimed exceptions. Should
51
+ # only be made available to supervisory roles.
52
+ def claim!(task)
53
+ release!(task)
54
+ claim(task)
55
+ end
56
+
57
+ # If we are the current claimant of the given task, release the task. Does
58
+ # nothing if the task is not claimed, but raises exception if the task is
59
+ # currently claimed by someone else.
60
+ def release(task, force = false)
61
+ return unless task.claimed?
62
+ raise UnauthorizedReleaseAttempt unless force || task.claimant == claim_token
63
+ task.release
64
+ end
65
+
66
+ # Same as #release, but releases the task even if we're not the current
67
+ # claimant. Allows an administrator, for example, to wrench a task away
68
+ # from an employee who is lagging. Should only be made available to
69
+ # supervisory roles.
70
+ def release!(task)
71
+ release(task, true)
72
+ end
73
+
74
+ # Returns Task::Finder instance filtered by roles assigned to this user.
75
+ def authorized_tasks
76
+ Bumbleworks::Task.for_roles(role_identifiers)
77
+ end
78
+
79
+ # Returns Task::Finder instance filtered by user roles and availability
80
+ # (unclaimed and completable).
81
+ def available_tasks
82
+ authorized_tasks.available
83
+ end
84
+
85
+ # Returns Task::Finder instance filtered by claimant - only tasks this user
86
+ # has claimed (and not released or completed).
87
+ def claimed_tasks
88
+ Bumbleworks::Task.for_claimant(claim_token)
89
+ end
90
+ end
91
+ end
@@ -1,3 +1,3 @@
1
1
  module Bumbleworks
2
- VERSION = "0.0.69"
2
+ VERSION = "0.0.70"
3
3
  end
@@ -21,4 +21,20 @@ describe Ruote::Exp::BroadcastEventExpression do
21
21
  Bumbleworks.dashboard.wait_for(waiter.wfid)
22
22
  @tracer.should == ['amazing']
23
23
  end
24
+
25
+ it 'appends entity info to tag when :for_entity is true' do
26
+ Bumbleworks.define_process 'waiter' do
27
+ await :left_tag => :the_event__for_entity__pig_widget_15, :global => true
28
+ echo 'amazing'
29
+ end
30
+
31
+ Bumbleworks.define_process 'sender' do
32
+ broadcast_event :the_event, :for_entity => true
33
+ end
34
+
35
+ waiter = Bumbleworks.launch!('waiter')
36
+ sender = Bumbleworks.launch!('sender', :entity_type => 'PigWidget', :entity_id => 15)
37
+ Bumbleworks.dashboard.wait_for(waiter.wfid)
38
+ @tracer.should == ['amazing']
39
+ end
24
40
  end
@@ -76,4 +76,21 @@ describe Ruote::Exp::WaitForEventExpression do
76
76
  Bumbleworks.dashboard.wait_for(waiter3.wfid)
77
77
  @tracer.should == ['entities! Rhubarb,spitpickle-4boof']
78
78
  end
79
+
80
+ it 'appends entity info to expected tag when :for_entity is true' do
81
+ Bumbleworks.define_process 'waiter' do
82
+ wait_for_event :the_event, :for_entity => true
83
+ echo 'i found your tag, sucka'
84
+ end
85
+
86
+ Bumbleworks.define_process 'sender' do
87
+ noop :tag => 'the_event__for_entity__fun_face_yellow5'
88
+ end
89
+
90
+ waiter = Bumbleworks.launch!('waiter', 'entity_type' => 'FunFace', 'entity_id' => 'yellow5')
91
+ sender = Bumbleworks.launch!('sender')
92
+
93
+ Bumbleworks.dashboard.wait_for(waiter.wfid)
94
+ @tracer.should == ['i found your tag, sucka']
95
+ end
79
96
  end
@@ -0,0 +1,152 @@
1
+ describe Bumbleworks::User do
2
+ let(:user_class) { Class.new { include Bumbleworks::User } }
3
+ let(:subject) { user_class.new }
4
+
5
+ describe '#claim_token' do
6
+ it 'returns username by default' do
7
+ subject.stub(:username => 'nerfobot')
8
+ subject.claim_token.should == 'nerfobot'
9
+ end
10
+
11
+ it 'returns email if no username' do
12
+ subject.stub(:email => 'fromp@nougatcountry.com')
13
+ subject.claim_token.should == 'fromp@nougatcountry.com'
14
+ end
15
+
16
+ it 'prefers username to email when both respond' do
17
+ subject.stub(:username => 'dumb', :email => 'moar dumb')
18
+ subject.claim_token.should == 'dumb'
19
+ end
20
+
21
+ it 'returns nil if method defined' do
22
+ subject.stub(:username)
23
+ subject.claim_token.should be_nil
24
+ end
25
+
26
+ it 'raises exception if neither username nor email defined' do
27
+ expect {
28
+ subject.claim_token
29
+ }.to raise_error(Bumbleworks::User::NoClaimTokenMethodDefined)
30
+ end
31
+ end
32
+
33
+ describe '#claim' do
34
+ before(:each) do
35
+ subject.stub(:role_identifiers => ['snoogat'])
36
+ subject.stub(:claim_token => "the umpire of snorts")
37
+ end
38
+
39
+ it 'claims a task if authorized' do
40
+ task = double('task', :role => 'snoogat')
41
+ task.should_receive(:claim).with("the umpire of snorts")
42
+ subject.claim(task)
43
+ end
44
+
45
+ it 'raises exception if unauthorized' do
46
+ task = double('task', :role => 'fashbone')
47
+ task.should_receive(:claim).never
48
+ expect {
49
+ subject.claim(task)
50
+ }.to raise_error(Bumbleworks::User::UnauthorizedClaimAttempt)
51
+ end
52
+
53
+ it 'raises exception if already claimed by another' do
54
+ task = double('task', :role => 'snoogat')
55
+ task.should_receive(:claim).and_raise(Bumbleworks::Task::AlreadyClaimed)
56
+ expect {
57
+ subject.claim(task)
58
+ }.to raise_error(Bumbleworks::Task::AlreadyClaimed)
59
+ end
60
+
61
+ describe '!' do
62
+ it 'resets even if claimed by another' do
63
+ task = double('task', :role => 'snoogat', :claimed? => true, :claimant => 'fumbo the monfey')
64
+ task.should_receive(:release).ordered
65
+ task.should_receive(:claim).with("the umpire of snorts").ordered
66
+ subject.claim!(task)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '#release' do
72
+ before(:each) do
73
+ subject.stub(:claim_token => "the umpire of snorts")
74
+ end
75
+
76
+ it 'releases a claimed task if claimant' do
77
+ task = double('task', :claimed? => true, :claimant => "the umpire of snorts")
78
+ task.should_receive(:release)
79
+ subject.release(task)
80
+ end
81
+
82
+ it 'does nothing if task not claimed' do
83
+ task = double('task', :claimed? => false)
84
+ task.should_receive(:release).never
85
+ subject.release(task)
86
+ end
87
+
88
+ it 'raises exception if not claimant' do
89
+ task = double('task', :claimed? => true, :claimant => 'a castanet expert')
90
+ task.should_receive(:release).never
91
+ expect {
92
+ subject.release(task)
93
+ }.to raise_error(Bumbleworks::User::UnauthorizedReleaseAttempt)
94
+ end
95
+
96
+ describe '!' do
97
+ it 'releases even if not claimant' do
98
+ task = double('task', :claimed? => true, :claimant => 'a castanet expert')
99
+ task.should_receive(:release)
100
+ subject.release!(task)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#role_identifiers' do
106
+ it 'raises exception by default' do
107
+ expect {
108
+ subject.role_identifiers
109
+ }.to raise_error(Bumbleworks::User::NoRoleIdentifiersMethodDefined)
110
+ end
111
+ end
112
+
113
+ describe '#has_role?' do
114
+ before(:each) do
115
+ subject.stub(:role_identifiers => ['role1', 'role2'])
116
+ end
117
+
118
+ it 'returns true if role_identifiers includes given role' do
119
+ subject.has_role?('role1').should be_true
120
+ end
121
+
122
+ it 'returns false if role_identifiers does not include given role' do
123
+ subject.has_role?('role3').should be_false
124
+ end
125
+ end
126
+
127
+ describe '#authorized_tasks' do
128
+ it 'returns task query for all tasks for user roles' do
129
+ subject.stub(:role_identifiers => ['goose', 'midget'])
130
+ Bumbleworks::Task.stub(:for_roles).with(['goose', 'midget']).and_return(:all_the_tasks)
131
+ subject.authorized_tasks.should == :all_the_tasks
132
+ end
133
+ end
134
+
135
+ describe '#claimed_tasks' do
136
+ it 'returns task query for all user claimed tasks' do
137
+ subject.stub(:claim_token => :yay_its_me)
138
+ Bumbleworks::Task.stub(:for_claimant).with(:yay_its_me).and_return(:my_tasks)
139
+ subject.claimed_tasks.should == :my_tasks
140
+ end
141
+ end
142
+
143
+ describe '#available_tasks' do
144
+ it 'returns authorized tasks filtered by available' do
145
+ subject.stub(:role_identifiers => ['goose', 'midget'])
146
+ task_finder = double('task_finder')
147
+ task_finder.stub(:available => :only_the_available_tasks)
148
+ Bumbleworks::Task.stub(:for_roles).with(['goose', 'midget']).and_return(task_finder)
149
+ subject.available_tasks.should == :only_the_available_tasks
150
+ end
151
+ end
152
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bumbleworks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.69
4
+ version: 0.0.70
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-02-12 00:00:00.000000000 Z
15
+ date: 2014-02-19 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: ruote
@@ -187,11 +187,13 @@ files:
187
187
  - lib/bumbleworks/simple_logger.rb
188
188
  - lib/bumbleworks/storage_adapter.rb
189
189
  - lib/bumbleworks/support.rb
190
+ - lib/bumbleworks/support/flow_expression.rb
190
191
  - lib/bumbleworks/task.rb
191
192
  - lib/bumbleworks/task/base.rb
192
193
  - lib/bumbleworks/task/finder.rb
193
194
  - lib/bumbleworks/tracker.rb
194
195
  - lib/bumbleworks/tree_builder.rb
196
+ - lib/bumbleworks/user.rb
195
197
  - lib/bumbleworks/version.rb
196
198
  - lib/bumbleworks/workitem.rb
197
199
  - lib/bumbleworks/workitem_entity_storage.rb
@@ -240,6 +242,7 @@ files:
240
242
  - spec/lib/bumbleworks/task_spec.rb
241
243
  - spec/lib/bumbleworks/tracker_spec.rb
242
244
  - spec/lib/bumbleworks/tree_builder_spec.rb
245
+ - spec/lib/bumbleworks/user_spec.rb
243
246
  - spec/lib/bumbleworks/workitem_entity_storage_spec.rb
244
247
  - spec/lib/bumbleworks/workitem_spec.rb
245
248
  - spec/lib/bumbleworks_spec.rb
@@ -263,7 +266,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
266
  version: '0'
264
267
  segments:
265
268
  - 0
266
- hash: 3077608415877383800
269
+ hash: -1442108325624690777
267
270
  required_rubygems_version: !ruby/object:Gem::Requirement
268
271
  none: false
269
272
  requirements:
@@ -272,7 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
275
  version: '0'
273
276
  segments:
274
277
  - 0
275
- hash: 3077608415877383800
278
+ hash: -1442108325624690777
276
279
  requirements: []
277
280
  rubyforge_project:
278
281
  rubygems_version: 1.8.23
@@ -324,6 +327,7 @@ test_files:
324
327
  - spec/lib/bumbleworks/task_spec.rb
325
328
  - spec/lib/bumbleworks/tracker_spec.rb
326
329
  - spec/lib/bumbleworks/tree_builder_spec.rb
330
+ - spec/lib/bumbleworks/user_spec.rb
327
331
  - spec/lib/bumbleworks/workitem_entity_storage_spec.rb
328
332
  - spec/lib/bumbleworks/workitem_spec.rb
329
333
  - spec/lib/bumbleworks_spec.rb