eventifier 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/Gemfile +4 -0
  2. data/Gemfile.lock +83 -0
  3. data/README.textile +43 -0
  4. data/Rakefile +13 -0
  5. data/eventifier.gemspec +29 -0
  6. data/lib/eventifier.rb +42 -0
  7. data/lib/eventifier/event.rb +35 -0
  8. data/lib/eventifier/event_helper.rb +40 -0
  9. data/lib/eventifier/event_observer.rb +35 -0
  10. data/lib/eventifier/event_tracking.rb +81 -0
  11. data/lib/eventifier/helper_methods.rb +34 -0
  12. data/lib/eventifier/matchers.rb +34 -0
  13. data/lib/eventifier/notification.rb +40 -0
  14. data/lib/eventifier/notification_helper.rb +51 -0
  15. data/lib/eventifier/notification_mailer.rb +20 -0
  16. data/lib/eventifier/version.rb +3 -0
  17. data/lib/generators/active_record/eventifier_generator.rb +11 -0
  18. data/lib/generators/eventifier/install/install_generator.rb +25 -0
  19. data/lib/generators/eventifier/install/templates/event_tracking.rb +12 -0
  20. data/lib/generators/eventifier/install/templates/events.en.yaml +13 -0
  21. data/lib/generators/eventifier/install/templates/migration.rb +30 -0
  22. data/spec/event_helper_spec.rb +57 -0
  23. data/spec/event_observer_spec.rb +25 -0
  24. data/spec/event_spec.rb +28 -0
  25. data/spec/eventifier_spec.rb +179 -0
  26. data/spec/helper_methods_spec.rb +36 -0
  27. data/spec/integration/eventifier_spec.rb +67 -0
  28. data/spec/notification_helper_spec.rb +58 -0
  29. data/spec/notification_mailer_spec.rb +12 -0
  30. data/spec/notification_spec.rb +83 -0
  31. data/spec/spec_helper.rb +8 -0
  32. data/spec/support/action_mailer.rb +3 -0
  33. data/spec/support/active_record_support.rb +63 -0
  34. data/spec/support/blueprints.rb +24 -0
  35. metadata +170 -0
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventifier::EventHelper do
4
+
5
+ class TestClass
6
+ def self.helper_method(*args); end
7
+ include Eventifier::HelperMethods
8
+ end
9
+
10
+ let!(:helper) { TestClass.new }
11
+
12
+ describe ".replace_vars" do
13
+ let(:event) { Eventifier::Event.make }
14
+
15
+ it "should replace {{stuff}} with awesome" do
16
+ message = "I'm really loving {{eventable.title}}"
17
+ helper.replace_vars(message, event).should == "I'm really loving <strong>#{event.eventable.title}</strong>"
18
+ end
19
+
20
+ it "should replace multiple {{stuff}} with multiple awesome" do
21
+ message = "I'm really loving {{eventable.title}} and all {{eventable.class.name}}s"
22
+ helper.replace_vars(message, event).should == "I'm really loving <strong>#{event.eventable.title}</strong> and all <strong>Post</strong>s"
23
+ end
24
+ end
25
+
26
+ describe ".load_event_for_template" do
27
+
28
+ it "should add some handy methods to an event instance" do
29
+ event = Eventifier::Event.make!
30
+ event = helper.load_event_for_template event
31
+ event.object.should == event.eventable
32
+ event.object_type.should == event.eventable_type
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,67 @@
1
+
2
+ describe Eventifier do
3
+ let(:post) { mock_model('Post', :group => group) }
4
+ let(:group) { double('group', :user => owner,
5
+ :members => [owner, member]) }
6
+ let(:owner) { User.make! }
7
+ let(:member) { double('member') }
8
+
9
+ before :each do
10
+ Eventifier::Notification.stub :create => true
11
+ end
12
+
13
+ context 'a new post' do
14
+ let(:event) { Eventifier::Event.new :eventable => post, :verb => :create,
15
+ :user => owner }
16
+
17
+ it "notifies the members of the group" do
18
+ Eventifier::Notification.should_receive(:create).
19
+ with(:user => member, :event => event)
20
+ ActiveRecord::Observer.with_observers(Eventifier::EventObserver) do
21
+ event.save
22
+ end
23
+ end
24
+
25
+ it "does not notify the person initiating the event" do
26
+ Eventifier::Notification.should_not_receive(:create).
27
+ with(:user => owner, :event => event)
28
+
29
+ event.save
30
+ end
31
+ end
32
+
33
+ context 'an existing post' do
34
+ let(:event) { Eventifier::Event.new :eventable => post, :verb => :update,
35
+ :user => owner }
36
+ let(:guest) { double('guest') }
37
+
38
+ before :each do
39
+ post.group.stub :members => [owner, guest]
40
+ end
41
+
42
+ it "notifies the members of the post" do
43
+ Eventifier::Notification.should_receive(:create).
44
+ with(:user => guest, :event => event)
45
+ ActiveRecord::Observer.with_observers(Eventifier::EventObserver) do
46
+ event.save
47
+ end
48
+ end
49
+
50
+ it "does not notify the person initiating the event" do
51
+ Eventifier::Notification.should_not_receive(:create).
52
+ with(:user => owner, :event => event)
53
+
54
+ ActiveRecord::Observer.with_observers(Eventifier::EventObserver) do
55
+ event.save
56
+ end
57
+ end
58
+ end
59
+
60
+ it "should create a notification for users of a post when it's changed" do
61
+ post = event.eventable
62
+ user = User.make!
63
+
64
+ lambda { post.update_attribute :date, 5.days.from_now }.should change(user.notifications, :count).by(1)
65
+ end
66
+
67
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventifier::NotificationHelper do
4
+
5
+ class TestClass
6
+ def self.helper_method(*args); end
7
+ include Eventifier::NotificationHelper
8
+ end
9
+
10
+ let!(:helper) {TestClass.new}
11
+
12
+ before do
13
+ @notification_strings = {
14
+ :post => {
15
+ :create => "{{user.name}} just created an Post - you should check it out",
16
+ :destroy => "{{user.name}} just deleted an Post",
17
+ :update => {
18
+ :single => "{{user.name}} made a change to their Post",
19
+ :multiple => "{{user.name}} made some changes to their Post"
20
+ }
21
+ }
22
+ }
23
+ I18n.backend.store_translations :en, :notifications => @notification_strings
24
+ end
25
+
26
+ describe ".notification_message" do
27
+ it "should return the I18n message for that event" do
28
+
29
+ event = Eventifier::Event.make! :eventable => Post.make!, :verb => :create
30
+ helper.notification_message(event).should == "<strong>#{event.user.name}</strong> just created an Post - you should check it out"
31
+ end
32
+
33
+ it "should return a message specific to a single change if only 1 change has been made" do
34
+ event = Eventifier::Event.make! :eventable => Post.make!, :verb => :update, :change_data => { :name => ["Fred", "Mike"] }
35
+ helper.notification_message(event).should == "<strong>#{event.user.name}</strong> made a change to their Post"
36
+ end
37
+
38
+ it "should return a message specific to multiple changes if more than 1 change has been made" do
39
+ event = Eventifier::Event.make! :eventable => Post.make!, :verb => :update, :change_data => { :name => ["Fred", "Mike"], :age => [55, 65] }
40
+ helper.notification_message(event).should == "<strong>#{event.user.name}</strong> made some changes to their Post"
41
+ end
42
+
43
+ it "should return the default I18n message if one doesn't exist" do
44
+ I18n.backend.reload!
45
+ @notification_strings = {
46
+ :default => {
47
+ :create => "{{user.name}} created a {{eventable_type}}",
48
+ :update => "{{user.name}} updated a {{eventable_type}}"
49
+ }
50
+ }
51
+ I18n.backend.store_translations :test, :notifications => @notification_strings
52
+ I18n.with_locale("test") do
53
+ event = Eventifier::Event.make! :eventable => Post.make!, :verb => :create
54
+ helper.notification_message(event).should == "<strong>#{event.user.name}</strong> created a <strong>Post</strong>"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventifier::NotificationMailer do
4
+ describe "#notification_email" do
5
+ it "should response to notification emails" do
6
+ Eventifier::NotificationMailer.should respond_to(:notification_email)
7
+ end
8
+ it "should be able to send a 'notification' email" do
9
+ proc { Eventifier::NotificationMailer.notification_email(Eventifier::Notification.make!).deliver }.should change(ActionMailer::Base.deliveries, :count)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventifier::Notification do
4
+ let(:notification) { Eventifier::Notification.make! }
5
+
6
+ describe '.expire_for_past_events!' do
7
+ let(:notification) { double('notification', :expire! => true) }
8
+ let(:expired_event_ids) { [1, 3, 5, 7] }
9
+
10
+ before :each do
11
+ Eventifier::Event.stub :expired_ids => expired_event_ids
12
+ Eventifier::Notification.stub :for_events => [notification]
13
+ end
14
+
15
+ it "finds all notifications belonging to past activities" do
16
+ Eventifier::Notification.should_receive(:for_events).with(expired_event_ids).
17
+ and_return([notification])
18
+
19
+ Eventifier::Notification.expire_for_past_events!
20
+ end
21
+
22
+ it "expires each notification" do
23
+ notification.should_receive(:expire!)
24
+
25
+ Eventifier::Notification.expire_for_past_events!
26
+ end
27
+ end
28
+
29
+ describe ".unread_for" do
30
+ it "should return unread notifications for a user" do
31
+ user = notification.user
32
+
33
+ Eventifier::Notification.unread_for(user).should include notification
34
+ end
35
+
36
+ it "should return unread notifications for a user" do
37
+ user = notification.user
38
+
39
+ user.notifications_last_read_at = Time.now
40
+ second_notification = Eventifier::Notification.make!
41
+
42
+ Eventifier::Notification.unread_for(user).should_not include notification
43
+ Eventifier::Notification.unread_for(user).should_not include second_notification
44
+ end
45
+ end
46
+
47
+ describe "#create" do
48
+ it "sends an email to the user" do
49
+ ActionMailer::Base.deliveries.clear
50
+ notification = Eventifier::Notification.make!
51
+ ActionMailer::Base.deliveries.count.should > 0
52
+ end
53
+ end
54
+
55
+ # describe "#valid?" do
56
+ # it_requires_a :user
57
+ # it_requires_an :event
58
+ # end
59
+
60
+ describe "#unread_for?" do
61
+ let(:user) { double(User, :notifications_last_read_at => last_read) }
62
+ subject { Eventifier::Notification.make(:created_at => Time.now).unread_for?(user) }
63
+ context 'when the user has never read notifications' do
64
+ let(:last_read) { nil }
65
+ it 'should return true' do
66
+ subject.should be_true
67
+ end
68
+ end
69
+ context 'when the user has read notifications before' do
70
+
71
+ describe 'notificication newer than that time' do
72
+ let(:last_read) { Time.now - 1.day }
73
+
74
+ it { should be_true }
75
+ end
76
+ describe 'notificication older than that time' do
77
+ let(:last_read) { Time.now + 1.day }
78
+
79
+ it { should be_false }
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ $LOAD_PATH.unshift File.dirname(__FILE__)
3
+
4
+ Dir["./spec/support/**/*.rb"].each {|f| require f}
5
+
6
+ require 'rubygems'
7
+ require 'rspec'
8
+ require 'eventifier'
@@ -0,0 +1,3 @@
1
+ require 'action_mailer'
2
+
3
+ ActionMailer::Base.delivery_method = :test
@@ -0,0 +1,63 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ :adapter => "postgresql",
5
+ :database => "eventifier"
6
+ )
7
+
8
+ ActiveRecord::Schema.define(:version => 0) do
9
+
10
+ create_table :events, :force => true do |t|
11
+ t.integer :user_id
12
+ t.string :eventable_type
13
+ t.integer :eventable_id
14
+ t.string :verb
15
+ t.text :change_data
16
+
17
+ t.timestamps
18
+ end
19
+
20
+ create_table :notifications, :force => true do |t|
21
+ t.integer :event_id
22
+ t.integer :user_id
23
+ t.integer :parent_id
24
+
25
+ t.timestamps
26
+ end
27
+
28
+ create_table :users, :force => true do |t|
29
+ t.column :name, :string
30
+ t.column :email, :string
31
+ t.column :notifications_last_read_at, :datetime
32
+ end
33
+
34
+ create_table :posts, :force => true do |t|
35
+ t.column :title, :string
36
+ t.column :author_id, :integer
37
+ t.column :body, :text
38
+ end
39
+
40
+ create_table :subscriptions, :force => true do |t|
41
+ t.column :user_id, :integer
42
+ t.column :post_id, :integer
43
+ end
44
+
45
+ end
46
+
47
+ class User < ActiveRecord::Base
48
+ has_many :subscriptions
49
+ validates :name, :presence => true, :uniqueness => true
50
+ end
51
+
52
+ class Subscription < ActiveRecord::Base
53
+ belongs_to :user
54
+ belongs_to :post
55
+ end
56
+
57
+ class Post < ActiveRecord::Base
58
+ belongs_to :author, :class_name => "User"
59
+ has_many :subscriptions
60
+ has_many :readers, :through => :subscriptions, :source => :user
61
+
62
+ alias_method :user, :author
63
+ end
@@ -0,0 +1,24 @@
1
+ require 'machinist/active_record'
2
+ require 'eventifier'
3
+
4
+ Eventifier::Event.blueprint do
5
+ user { object.user || User.make! }
6
+ eventable { object.eventable || Post.make! }
7
+ verb { :update }
8
+ change_data { { :date => [ 5.days.ago, 3.days.ago ] } }
9
+ end
10
+
11
+ Eventifier::Notification.blueprint do
12
+ event { object.event || Eventifier::Event.make! }
13
+ user { object.user || User.make! }
14
+ end
15
+
16
+ Post.blueprint do
17
+ title { "My amazing blog post" }
18
+ body { "A deep and profound analysis of life" }
19
+ end
20
+
21
+ User.blueprint do
22
+ name { "Billy #{sn}" }
23
+ email { "billy#{sn}@email.com" }
24
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eventifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nathan Sampimon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &70095162476700 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70095162476700
25
+ - !ruby/object:Gem::Dependency
26
+ name: actionmailer
27
+ requirement: &70095162475660 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70095162475660
36
+ - !ruby/object:Gem::Dependency
37
+ name: machinist
38
+ requirement: &70095162474080 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70095162474080
47
+ - !ruby/object:Gem::Dependency
48
+ name: pg
49
+ requirement: &70095162472540 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70095162472540
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &70095162470940 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70095162470940
69
+ - !ruby/object:Gem::Dependency
70
+ name: activerecord
71
+ requirement: &70095162470020 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70095162470020
80
+ - !ruby/object:Gem::Dependency
81
+ name: actionmailer
82
+ requirement: &70095162469140 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *70095162469140
91
+ description: Tracks and logs events and sends notifications of events on Active Record
92
+ models.
93
+ email:
94
+ - nathan@inspire9.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - Gemfile
100
+ - Gemfile.lock
101
+ - README.textile
102
+ - Rakefile
103
+ - eventifier.gemspec
104
+ - lib/eventifier.rb
105
+ - lib/eventifier/event.rb
106
+ - lib/eventifier/event_helper.rb
107
+ - lib/eventifier/event_observer.rb
108
+ - lib/eventifier/event_tracking.rb
109
+ - lib/eventifier/helper_methods.rb
110
+ - lib/eventifier/matchers.rb
111
+ - lib/eventifier/notification.rb
112
+ - lib/eventifier/notification_helper.rb
113
+ - lib/eventifier/notification_mailer.rb
114
+ - lib/eventifier/version.rb
115
+ - lib/generators/active_record/eventifier_generator.rb
116
+ - lib/generators/eventifier/install/install_generator.rb
117
+ - lib/generators/eventifier/install/templates/event_tracking.rb
118
+ - lib/generators/eventifier/install/templates/events.en.yaml
119
+ - lib/generators/eventifier/install/templates/migration.rb
120
+ - spec/event_helper_spec.rb
121
+ - spec/event_observer_spec.rb
122
+ - spec/event_spec.rb
123
+ - spec/eventifier_spec.rb
124
+ - spec/helper_methods_spec.rb
125
+ - spec/integration/eventifier_spec.rb
126
+ - spec/notification_helper_spec.rb
127
+ - spec/notification_mailer_spec.rb
128
+ - spec/notification_spec.rb
129
+ - spec/spec_helper.rb
130
+ - spec/support/action_mailer.rb
131
+ - spec/support/active_record_support.rb
132
+ - spec/support/blueprints.rb
133
+ homepage: http://github.com/inspire9/eventifier
134
+ licenses: []
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project: eventifier
153
+ rubygems_version: 1.8.11
154
+ signing_key:
155
+ specification_version: 3
156
+ summary: Event tracking and notifying for active record models
157
+ test_files:
158
+ - spec/event_helper_spec.rb
159
+ - spec/event_observer_spec.rb
160
+ - spec/event_spec.rb
161
+ - spec/eventifier_spec.rb
162
+ - spec/helper_methods_spec.rb
163
+ - spec/integration/eventifier_spec.rb
164
+ - spec/notification_helper_spec.rb
165
+ - spec/notification_mailer_spec.rb
166
+ - spec/notification_spec.rb
167
+ - spec/spec_helper.rb
168
+ - spec/support/action_mailer.rb
169
+ - spec/support/active_record_support.rb
170
+ - spec/support/blueprints.rb