bumbleworks 0.0.69 → 0.0.70

Sign up to get free protection for your applications and to get access to all the features.
@@ -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