activity_hub 0.0.1

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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +260 -0
  5. data/Rakefile +20 -0
  6. data/lib/generators/public_activity.rb +16 -0
  7. data/lib/generators/public_activity/migration/migration_generator.rb +19 -0
  8. data/lib/generators/public_activity/migration_upgrade/migration_upgrade_generator.rb +19 -0
  9. data/lib/generators/public_activity/migration_upgrade/templates/upgrade.rb +11 -0
  10. data/lib/public_activity.rb +70 -0
  11. data/lib/public_activity/actions/creation.rb +19 -0
  12. data/lib/public_activity/actions/destruction.rb +19 -0
  13. data/lib/public_activity/actions/update.rb +20 -0
  14. data/lib/public_activity/activity.rb +8 -0
  15. data/lib/public_activity/common.rb +363 -0
  16. data/lib/public_activity/config.rb +102 -0
  17. data/lib/public_activity/models/activist.rb +11 -0
  18. data/lib/public_activity/models/activity.rb +6 -0
  19. data/lib/public_activity/models/adapter.rb +7 -0
  20. data/lib/public_activity/models/trackable.rb +11 -0
  21. data/lib/public_activity/orm/active_record.rb +7 -0
  22. data/lib/public_activity/orm/active_record/activist.rb +35 -0
  23. data/lib/public_activity/orm/active_record/activity.rb +66 -0
  24. data/lib/public_activity/orm/active_record/adapter.rb +23 -0
  25. data/lib/public_activity/orm/active_record/trackable.rb +17 -0
  26. data/lib/public_activity/orm/mongo_mapper.rb +6 -0
  27. data/lib/public_activity/orm/mongo_mapper/activist.rb +36 -0
  28. data/lib/public_activity/orm/mongo_mapper/activity.rb +35 -0
  29. data/lib/public_activity/orm/mongo_mapper/adapter.rb +19 -0
  30. data/lib/public_activity/orm/mongo_mapper/trackable.rb +13 -0
  31. data/lib/public_activity/orm/mongoid.rb +6 -0
  32. data/lib/public_activity/orm/mongoid/activist.rb +36 -0
  33. data/lib/public_activity/orm/mongoid/activity.rb +34 -0
  34. data/lib/public_activity/orm/mongoid/adapter.rb +19 -0
  35. data/lib/public_activity/orm/mongoid/trackable.rb +13 -0
  36. data/lib/public_activity/renderable.rb +166 -0
  37. data/lib/public_activity/roles/deactivatable.rb +44 -0
  38. data/lib/public_activity/roles/tracked.rb +196 -0
  39. data/lib/public_activity/testing.rb +37 -0
  40. data/lib/public_activity/utility/store_controller.rb +32 -0
  41. data/lib/public_activity/utility/view_helpers.rb +30 -0
  42. data/lib/public_activity/version.rb +6 -0
  43. data/test/migrations/001_create_activities.rb +25 -0
  44. data/test/migrations/002_create_articles.rb +15 -0
  45. data/test/migrations/003_create_users.rb +12 -0
  46. data/test/migrations/004_add_nonstandard_to_activities.rb +11 -0
  47. data/test/migrations_base.rb +7 -0
  48. data/test/mongo_mapper.yml +4 -0
  49. data/test/mongoid.yml +6 -0
  50. data/test/test_activist.rb +58 -0
  51. data/test/test_activity.rb +89 -0
  52. data/test/test_common.rb +194 -0
  53. data/test/test_controller_integration.rb +42 -0
  54. data/test/test_generators.rb +31 -0
  55. data/test/test_helper.rb +144 -0
  56. data/test/test_testing.rb +37 -0
  57. data/test/test_tracking.rb +385 -0
  58. data/test/test_view_helpers.rb +38 -0
  59. data/test/views/custom/_layout.erb +1 -0
  60. data/test/views/custom/_test.erb +1 -0
  61. data/test/views/layouts/_activity.erb +1 -0
  62. data/test/views/public_activity/_test.erb +8 -0
  63. metadata +295 -0
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ describe PublicActivity do
5
+
6
+ describe "self.with_tracking" do
7
+ after do
8
+ PublicActivity.enabled = true
9
+ end
10
+
11
+ it "enables tracking inside the block" do
12
+ PublicActivity.enabled = false
13
+
14
+ PublicActivity.with_tracking do
15
+ PublicActivity.enabled?.must_equal true
16
+ end
17
+ end
18
+
19
+ it "restores previous `enabled` state" do
20
+ PublicActivity.enabled = false
21
+ PublicActivity.with_tracking do
22
+ # something
23
+ end
24
+ PublicActivity.enabled?.must_equal false
25
+ end
26
+ end
27
+
28
+ describe "self.without_tracking" do
29
+ it "disables tracking inside the block" do
30
+ PublicActivity.enabled = true
31
+
32
+ PublicActivity.without_tracking do
33
+ PublicActivity.enabled?.must_equal false
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,385 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ describe PublicActivity::Tracked do
6
+ describe 'defining instance options' do
7
+ subject { article.new }
8
+ let :options do
9
+ { :key => 'key',
10
+ :params => {:a => 1},
11
+ :owner => User.create,
12
+ :recipient => User.create }
13
+ end
14
+ before(:each) { subject.activity(options) }
15
+ let(:activity){ subject.save; subject.activities.last }
16
+
17
+ specify { subject.activity_key.must_be_same_as options[:key] }
18
+ specify { activity.key.must_equal options[:key] }
19
+
20
+ specify { subject.activity_owner.must_be_same_as options[:owner] }
21
+ specify { activity.owner.must_equal options[:owner] }
22
+
23
+ specify { subject.activity_params.must_be_same_as options[:params] }
24
+ specify { activity.parameters.must_equal options[:params] }
25
+
26
+ specify { subject.activity_recipient.must_be_same_as options[:recipient] }
27
+ specify { activity.recipient.must_equal options[:recipient] }
28
+ end
29
+
30
+ it 'can be tracked and be an activist at the same time' do
31
+ case PublicActivity.config.orm
32
+ when :mongoid
33
+ class ActivistAndTrackedArticle
34
+ include Mongoid::Document
35
+ include Mongoid::Timestamps
36
+ include PublicActivity::Model
37
+
38
+ if ::Mongoid::VERSION.split('.')[0].to_i >= 7
39
+ belongs_to :user, optional: true
40
+ else
41
+ belongs_to :user
42
+ end
43
+
44
+ field :name, type: String
45
+ field :published, type: Boolean
46
+ tracked
47
+ activist
48
+ end
49
+ when :mongo_mapper
50
+ class ActivistAndTrackedArticle
51
+ include MongoMapper::Document
52
+ include PublicActivity::Model
53
+
54
+ belongs_to :user
55
+
56
+ key :name, String
57
+ key :published, Boolean
58
+ tracked
59
+ activist
60
+ timestamps!
61
+ end
62
+ when :active_record
63
+ class ActivistAndTrackedArticle < ActiveRecord::Base
64
+ self.table_name = 'articles'
65
+ include PublicActivity::Model
66
+ tracked
67
+ activist
68
+
69
+ if ::ActiveRecord::VERSION::MAJOR < 4
70
+ attr_accessible :name, :published, :user
71
+ end
72
+ belongs_to :user
73
+ end
74
+ end
75
+
76
+ art = ActivistAndTrackedArticle.new
77
+ art.save
78
+ art.activities.last.trackable_id.must_equal art.id
79
+ assert_nil art.activities.last.owner_id
80
+ end
81
+
82
+ describe 'custom fields' do
83
+ describe 'global' do
84
+ it 'should resolve symbols' do
85
+ a = article(nonstandard: :name).new(name: 'Symbol resolved')
86
+ a.save
87
+ a.activities.last.nonstandard.must_equal 'Symbol resolved'
88
+ end
89
+
90
+ it 'should resolve procs' do
91
+ a = article(nonstandard: proc {|_, model| model.name}).new(name: 'Proc resolved')
92
+ a.save
93
+ a.activities.last.nonstandard.must_equal 'Proc resolved'
94
+ end
95
+ end
96
+
97
+ describe 'instance' do
98
+ it 'should resolve symbols' do
99
+ a = article.new(name: 'Symbol resolved')
100
+ a.activity nonstandard: :name
101
+ a.save
102
+ a.activities.last.nonstandard.must_equal 'Symbol resolved'
103
+ end
104
+
105
+ it 'should resolve procs' do
106
+ a = article.new(name: 'Proc resolved')
107
+ a.activity nonstandard: proc {|_, model| model.name}
108
+ a.save
109
+ a.activities.last.nonstandard.must_equal 'Proc resolved'
110
+ end
111
+ end
112
+ end
113
+
114
+ it 'should reset instance options on successful create_activity' do
115
+ a = article.new
116
+ a.activity key: 'test', params: {test: 1}
117
+ a.save
118
+ a.activities.count.must_equal 1
119
+ ->{a.create_activity}.must_raise PublicActivity::NoKeyProvided
120
+ a.activity_params.must_be_empty
121
+ a.activity key: 'asd'
122
+ a.create_activity
123
+ ->{a.create_activity}.must_raise PublicActivity::NoKeyProvided
124
+ end
125
+
126
+ it 'should not accept global key option' do
127
+ # this example tests the lack of presence of sth that should not be here
128
+ a = article(key: 'asd').new
129
+ a.save
130
+ ->{a.create_activity}.must_raise PublicActivity::NoKeyProvided
131
+ a.activities.count.must_equal 1
132
+ end
133
+
134
+ it 'should not change global custom fields' do
135
+ a = article(nonstandard: 'global').new
136
+ a.activity nonstandard: 'instance'
137
+ a.save
138
+ a.class.activity_custom_fields_global.must_equal nonstandard: 'global'
139
+ end
140
+
141
+ describe 'disabling functionality' do
142
+ it 'allows for global disable' do
143
+ PublicActivity.enabled = false
144
+ activity_count_before = PublicActivity::Activity.count
145
+
146
+ @article = article().new
147
+ @article.save
148
+ PublicActivity::Activity.count.must_equal activity_count_before
149
+
150
+ PublicActivity.enabled = true
151
+ end
152
+
153
+ it 'allows for class-wide disable' do
154
+ activity_count_before = PublicActivity::Activity.count
155
+
156
+ klass = article
157
+ klass.public_activity_off
158
+ @article = klass.new
159
+ @article.save
160
+ PublicActivity::Activity.count.must_equal activity_count_before
161
+
162
+ klass.public_activity_on
163
+ @article.name = 'Changed Article'
164
+ @article.save
165
+ PublicActivity::Activity.count.must_be :>, activity_count_before
166
+ end
167
+ end
168
+
169
+ describe '#tracked' do
170
+ subject { article(options) }
171
+ let(:options) { {} }
172
+
173
+ it 'allows skipping the tracking on CRUD actions' do
174
+ case PublicActivity.config.orm
175
+ when :mongoid
176
+ art = Class.new do
177
+ include Mongoid::Document
178
+ include Mongoid::Timestamps
179
+ include PublicActivity::Model
180
+
181
+ belongs_to :user
182
+
183
+ field :name, type: String
184
+ field :published, type: Boolean
185
+ tracked :skip_defaults => true
186
+ end
187
+ when :mongo_mapper
188
+ art = Class.new do
189
+ include MongoMapper::Document
190
+ include PublicActivity::Model
191
+
192
+ belongs_to :user
193
+
194
+ key :name, String
195
+ key :published, Boolean
196
+ tracked :skip_defaults => true
197
+
198
+ timestamps!
199
+ end
200
+ when :active_record
201
+ art = article(:skip_defaults => true)
202
+ end
203
+
204
+ art.must_include PublicActivity::Common
205
+ art.wont_include PublicActivity::Creation
206
+ art.wont_include PublicActivity::Update
207
+ art.wont_include PublicActivity::Destruction
208
+ end
209
+
210
+ describe 'default options' do
211
+ subject { article }
212
+
213
+ specify { subject.must_include PublicActivity::Creation }
214
+ specify { subject.must_include PublicActivity::Destruction }
215
+ specify { subject.must_include PublicActivity::Update }
216
+
217
+ specify { subject._create_callbacks.select do |c|
218
+ c.kind.eql?(:after) && c.filter == :activity_on_create
219
+ end.wont_be_empty }
220
+
221
+ specify { subject._update_callbacks.select do |c|
222
+ c.kind.eql?(:after) && c.filter == :activity_on_update
223
+ end.wont_be_empty }
224
+
225
+ specify { subject._destroy_callbacks.select do |c|
226
+ c.kind.eql?(:before) && c.filter == :activity_on_destroy
227
+ end.wont_be_empty }
228
+ end
229
+
230
+ it 'accepts :except option' do
231
+ case PublicActivity.config.orm
232
+ when :mongoid
233
+ art = Class.new do
234
+ include Mongoid::Document
235
+ include Mongoid::Timestamps
236
+ include PublicActivity::Model
237
+
238
+ belongs_to :user
239
+
240
+ field :name, type: String
241
+ field :published, type: Boolean
242
+ tracked :except => [:create]
243
+ end
244
+ when :mongo_mapper
245
+ art = Class.new do
246
+ include MongoMapper::Document
247
+ include PublicActivity::Model
248
+
249
+ belongs_to :user
250
+
251
+ key :name, String
252
+ key :published, Boolean
253
+ tracked :except => [:create]
254
+
255
+ timestamps!
256
+ end
257
+ when :active_record
258
+ art = article(:except => [:create])
259
+ end
260
+
261
+ art.wont_include PublicActivity::Creation
262
+ art.must_include PublicActivity::Update
263
+ art.must_include PublicActivity::Destruction
264
+ end
265
+
266
+ it 'accepts :only option' do
267
+ case PublicActivity.config.orm
268
+ when :mongoid
269
+ art = Class.new do
270
+ include Mongoid::Document
271
+ include Mongoid::Timestamps
272
+ include PublicActivity::Model
273
+
274
+ belongs_to :user
275
+
276
+ field :name, type: String
277
+ field :published, type: Boolean
278
+
279
+ tracked :only => [:create, :update]
280
+ end
281
+ when :mongo_mapper
282
+ art = Class.new do
283
+ include MongoMapper::Document
284
+ include PublicActivity::Model
285
+
286
+ belongs_to :user
287
+
288
+ key :name, String
289
+ key :published, Boolean
290
+
291
+ tracked :only => [:create, :update]
292
+ end
293
+ when :active_record
294
+ art = article({:only => [:create, :update]})
295
+ end
296
+
297
+ art.must_include PublicActivity::Creation
298
+ art.wont_include PublicActivity::Destruction
299
+ art.must_include PublicActivity::Update
300
+ end
301
+
302
+ it 'accepts :owner option' do
303
+ owner = mock('owner')
304
+ subject.tracked(:owner => owner)
305
+ subject.activity_owner_global.must_equal owner
306
+ end
307
+
308
+ it 'accepts :params option' do
309
+ params = {:a => 1}
310
+ subject.tracked(:params => params)
311
+ subject.activity_params_global.must_equal params
312
+ end
313
+
314
+ it 'accepts :on option' do
315
+ on = {:a => lambda{}, :b => proc {}}
316
+ subject.tracked(:on => on)
317
+ subject.activity_hooks.must_equal on
318
+ end
319
+
320
+ it 'accepts :on option with string keys' do
321
+ on = {'a' => lambda {}}
322
+ subject.tracked(:on => on)
323
+ subject.activity_hooks.must_equal on.symbolize_keys
324
+ end
325
+
326
+ it 'accepts :on values that are procs' do
327
+ on = {:unpassable => 1, :proper => lambda {}, :proper_proc => proc {}}
328
+ subject.tracked(:on => on)
329
+ subject.activity_hooks.must_include :proper
330
+ subject.activity_hooks.must_include :proper_proc
331
+ subject.activity_hooks.wont_include :unpassable
332
+ end
333
+
334
+ describe 'global options' do
335
+ subject { article(recipient: :test, owner: :test2, params: {a: 'b'}) }
336
+
337
+ specify { subject.activity_recipient_global.must_equal :test }
338
+ specify { subject.activity_owner_global.must_equal :test2 }
339
+ specify { subject.activity_params_global.must_equal(a: 'b') }
340
+ end
341
+ end
342
+
343
+ describe 'activity hooks' do
344
+ subject { s = article; s.activity_hooks = {:test => hook}; s }
345
+ let(:hook) { lambda {} }
346
+
347
+ it 'retrieves hooks' do
348
+ assert_same hook, subject.get_hook(:test)
349
+ end
350
+
351
+ it 'retrieves hooks by string keys' do
352
+ assert_same hook, subject.get_hook('test')
353
+ end
354
+
355
+ it 'returns nil when no matching hook is present' do
356
+ nil.must_be_same_as subject.get_hook(:nonexistent)
357
+ end
358
+
359
+ it 'allows hooks to decide if activity should be created' do
360
+ subject.tracked
361
+ @article = subject.new(:name => 'Some Name')
362
+ PublicActivity.set_controller(mock('controller'))
363
+ pf = proc { |model, controller|
364
+ controller.must_be_same_as PublicActivity.get_controller
365
+ model.name.must_equal 'Some Name'
366
+ false
367
+ }
368
+ pt = proc { |model, controller|
369
+ controller.must_be_same_as PublicActivity.get_controller
370
+ model.name.must_equal 'Other Name'
371
+ true # this will save the activity with *.update key
372
+ }
373
+ @article.class.activity_hooks = {:create => pf, :update => pt, :destroy => pt}
374
+
375
+ @article.activities.to_a.must_be_empty
376
+ @article.save # create
377
+ @article.name = 'Other Name'
378
+ @article.save # update
379
+ @article.destroy # destroy
380
+
381
+ @article.activities.count.must_equal 2
382
+ @article.activities.first.key.must_equal 'article.update'
383
+ end
384
+ end
385
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ describe 'ViewHelpers Rendering' do
6
+ include PublicActivity::ViewHelpers
7
+
8
+ # is this a proper test?
9
+ it 'provides render_activity helper' do
10
+ activity = mock('activity')
11
+ activity.stubs(:is_a?).with(PublicActivity::Activity).returns(true)
12
+ activity.expects(:render).with(self, {})
13
+ render_activity(activity)
14
+ end
15
+
16
+ it 'handles multiple activities' do
17
+ activity = mock('activity')
18
+ activity.expects(:render).with(self, {})
19
+ render_activities([activity])
20
+ end
21
+
22
+ it 'flushes content_for between partials renderes' do
23
+ @view_flow = mock('view_flow')
24
+ @view_flow.expects(:set).twice.with('name', ActiveSupport::SafeBuffer.new)
25
+
26
+ single_content_for('name', 'content')
27
+ @name.must_equal 'name'
28
+ @content.must_equal 'content'
29
+ single_content_for('name', 'content2')
30
+ @name.must_equal 'name'
31
+ @content.must_equal 'content2'
32
+ end
33
+
34
+ def content_for(name, content, &block)
35
+ @name = name
36
+ @content = content
37
+ end
38
+ end