eventifier 0.0.7 → 0.0.8
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 +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +7 -8
- data/Gemfile +1 -1
- data/README.textile +44 -3
- data/app/assets/images/eventifier/notifications-bell.png +0 -0
- data/app/assets/images/eventifier/notifications-tower.png +0 -0
- data/app/assets/javascripts/eventifier/notifications.coffee +196 -0
- data/app/assets/javascripts/eventifier/templates/dropdown.hamlc +10 -0
- data/app/assets/javascripts/eventifier/templates/settings.hamlc +11 -0
- data/app/assets/stylesheets/eventifier/notifications.scss +167 -0
- data/app/controllers/eventifier/application_controller.rb +4 -0
- data/app/controllers/eventifier/notifications_controller.rb +36 -0
- data/app/controllers/eventifier/preferences_controller.rb +19 -0
- data/app/helpers/eventifier/notification_helper.rb +87 -0
- data/app/helpers/eventifier/path_helper.rb +15 -0
- data/app/mailers/eventifier/mailer.rb +12 -0
- data/app/models/event_tracking.rb +3 -0
- data/app/models/eventifier/event.rb +22 -0
- data/app/models/eventifier/ghost.rb +21 -0
- data/app/models/eventifier/notification.rb +38 -0
- data/app/models/eventifier/notification_setting.rb +14 -0
- data/app/views/eventifier/_notification.haml +1 -0
- data/app/views/eventifier/email/_notification.haml +2 -0
- data/app/views/eventifier/mailer/notifications.haml +5 -0
- data/app/views/eventifier/notifications/index.jbuilder +6 -0
- data/config/routes.rb +7 -0
- data/config.ru +7 -0
- data/{lib/generators/eventifier/install/templates/migration.rb → db/migrate/1_eventifier_setup.rb} +2 -3
- data/db/migrate/2_eventifier_notification_settings.rb +11 -0
- data/db/migrate/3_notification_sent_status.rb +15 -0
- data/db/migrate/4_event_groupable.rb +19 -0
- data/eventifier.gemspec +12 -15
- data/lib/eventifier/delivery.rb +59 -0
- data/lib/eventifier/{railtie.rb → engine.rb} +4 -2
- data/lib/eventifier/event_subscriber.rb +44 -0
- data/lib/eventifier/event_tracking.rb +5 -58
- data/lib/eventifier/mailers/helpers.rb +70 -0
- data/lib/eventifier/notifier/notification_mapping.rb +34 -0
- data/lib/eventifier/notifier/notification_subscriber.rb +23 -0
- data/lib/eventifier/notifier/notifier.rb +21 -0
- data/lib/eventifier/preferences.rb +44 -0
- data/lib/eventifier/relationship.rb +36 -0
- data/lib/eventifier/trackable_class.rb +74 -0
- data/lib/eventifier/tracker.rb +18 -0
- data/lib/eventifier.rb +35 -11
- data/lib/generators/eventifier/install/install_generator.rb +2 -5
- data/lib/generators/eventifier/install/templates/events.en.yaml +1 -0
- data/lib/tasks/email.rake +8 -0
- data/spec/controllers/eventifier/notifications_controller_spec.rb +24 -0
- data/spec/controllers/eventifier/preferences_controller_spec.rb +56 -0
- data/spec/eventifier/delivery_spec.rb +110 -0
- data/spec/eventifier/preferences_spec.rb +69 -0
- data/spec/eventifier/relationship_spec.rb +33 -0
- data/spec/eventifier_spec.rb +6 -48
- data/spec/fabricators/fabricator.rb +11 -11
- data/spec/helpers/eventifier/notification_helper_spec.rb +169 -0
- data/spec/helpers/eventifier/path_helper_spec.rb +19 -0
- data/spec/integration/eventifier_spec.rb +113 -70
- data/spec/integration/internationalisation_spec.rb +39 -0
- data/spec/internal/app/controllers/application_controller.rb +3 -0
- data/spec/internal/app/lib/event_tracking.rb +12 -0
- data/spec/internal/app/models/category.rb +3 -0
- data/spec/internal/app/models/post.rb +8 -0
- data/spec/internal/app/models/subscription.rb +4 -0
- data/spec/internal/app/models/user.rb +4 -0
- data/spec/internal/app/views/eventifier/dropdown/_awesome_object.haml +0 -0
- data/spec/internal/config/database.yml +4 -0
- data/spec/internal/config/initializers/eventifier.rb +1 -0
- data/spec/internal/config/locales/events.en.yml +20 -0
- data/spec/internal/config/routes.rb +5 -0
- data/spec/internal/db/schema.rb +31 -0
- data/spec/internal/log/.gitignore +1 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/models/eventifier/event_spec.rb +23 -0
- data/spec/{ghost_spec.rb → models/eventifier/ghost_spec.rb} +3 -3
- data/spec/{notification_spec.rb → models/eventifier/notification_spec.rb} +1 -9
- data/spec/notification_mailer_spec.rb +8 -4
- data/spec/notifier/notification_mapping_spec.rb +28 -0
- data/spec/spec_helper.rb +14 -8
- data/spec/support/controller_helpers.rb +14 -0
- metadata +205 -128
- data/Gemfile.lock +0 -97
- data/lib/eventifier/active_record/event.rb +0 -10
- data/lib/eventifier/active_record/event_observer.rb +0 -8
- data/lib/eventifier/active_record/event_tracking.rb +0 -11
- data/lib/eventifier/active_record/ghost.rb +0 -9
- data/lib/eventifier/active_record/notification.rb +0 -13
- data/lib/eventifier/active_record_support.rb +0 -5
- data/lib/eventifier/event_helper.rb +0 -40
- data/lib/eventifier/event_mixin.rb +0 -45
- data/lib/eventifier/event_observer_mixin.rb +0 -44
- data/lib/eventifier/ghost_mixin.rb +0 -27
- data/lib/eventifier/helper_methods.rb +0 -36
- data/lib/eventifier/mongoid/event.rb +0 -16
- data/lib/eventifier/mongoid/event_observer.rb +0 -7
- data/lib/eventifier/mongoid/event_tracking.rb +0 -13
- data/lib/eventifier/mongoid/ghost.rb +0 -15
- data/lib/eventifier/mongoid/notification.rb +0 -19
- data/lib/eventifier/mongoid/user_patch.rb +0 -3
- data/lib/eventifier/mongoid_support.rb +0 -6
- data/lib/eventifier/notification_helper.rb +0 -42
- data/lib/eventifier/notification_mailer.rb +0 -18
- data/lib/eventifier/notification_mixin.rb +0 -50
- data/lib/eventifier/version.rb +0 -3
- data/spec/event_helper_spec.rb +0 -67
- data/spec/event_observer_spec.rb +0 -20
- data/spec/event_spec.rb +0 -39
- data/spec/helper_methods_spec.rb +0 -36
- data/spec/notification_helper_spec.rb +0 -65
- data/spec/support/action_mailer.rb +0 -3
- data/spec/support/database_cleaner.rb +0 -3
- data/spec/test_classes/active_record_support.rb +0 -72
- data/spec/test_classes/mongoid_support.rb +0 -34
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Eventifier
|
|
2
|
+
class Event < ActiveRecord::Base
|
|
3
|
+
attr_accessible :user, :eventable, :verb, :change_data, :groupable
|
|
4
|
+
|
|
5
|
+
belongs_to :user
|
|
6
|
+
belongs_to :eventable, polymorphic: true
|
|
7
|
+
belongs_to :groupable, polymorphic: true
|
|
8
|
+
has_many :notifications, class_name: 'Eventifier::Notification',
|
|
9
|
+
dependent: :destroy
|
|
10
|
+
|
|
11
|
+
validates :user, presence: true
|
|
12
|
+
validates :eventable, presence: true
|
|
13
|
+
validates :verb, presence: true
|
|
14
|
+
validates :groupable, presence: true
|
|
15
|
+
|
|
16
|
+
serialize :change_data
|
|
17
|
+
|
|
18
|
+
def self.find_all_by_eventable object
|
|
19
|
+
where :eventable_id => object.id, :eventable_type => object.class.name
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Eventifier
|
|
2
|
+
class Ghost < ActiveRecord::Base
|
|
3
|
+
validates :ghost_class, :presence => true
|
|
4
|
+
validates :ghost_id, :presence => true
|
|
5
|
+
validates :data_hash, :presence => true
|
|
6
|
+
|
|
7
|
+
serialize :data_hash
|
|
8
|
+
|
|
9
|
+
def self.create_from_object object
|
|
10
|
+
create :ghost_class => object.class.name, :ghost_id => object.id, :data_hash => object.serializable_hash
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ghost
|
|
14
|
+
klass = Object.const_get(ghost_class)
|
|
15
|
+
ghost_object = klass.new data_hash
|
|
16
|
+
ghost_object.id = ghost_id
|
|
17
|
+
|
|
18
|
+
ghost_object
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Eventifier
|
|
2
|
+
class Notification < ActiveRecord::Base
|
|
3
|
+
attr_accessible :event, :user, :relations, :event_id, :user_id
|
|
4
|
+
|
|
5
|
+
belongs_to :event, :class_name => 'Eventifier::Event'
|
|
6
|
+
belongs_to :user
|
|
7
|
+
|
|
8
|
+
serialize :relations, MultiJson
|
|
9
|
+
|
|
10
|
+
validates :event, :presence => true
|
|
11
|
+
validates :user, :presence => true
|
|
12
|
+
validates :event_id, :uniqueness => { :scope => :user_id }
|
|
13
|
+
|
|
14
|
+
default_scope order("notifications.created_at DESC")
|
|
15
|
+
scope :for_events, -> ids { where(event_id: ids) }
|
|
16
|
+
scope :for_user, -> user { where(user_id: user.id) }
|
|
17
|
+
scope :since, -> date { where("created_at > ?", date) }
|
|
18
|
+
scope :latest, order('notifications.created_at DESC').limit(5)
|
|
19
|
+
scope :unsent, -> { where(sent: false) }
|
|
20
|
+
|
|
21
|
+
def self.expire_for_past_events!(time_limit = 1.day.ago)
|
|
22
|
+
self.for_events(Event.expired_ids(time_limit)).each &:expire!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.unread_for(user)
|
|
26
|
+
if user.notifications_last_read_at
|
|
27
|
+
for_user(user).since(user.notifications_last_read_at)
|
|
28
|
+
else
|
|
29
|
+
for_user(user)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def unread_for?(user)
|
|
34
|
+
return true if user.notifications_last_read_at.nil?
|
|
35
|
+
created_at > user.notifications_last_read_at
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class Eventifier::NotificationSetting < ActiveRecord::Base
|
|
2
|
+
belongs_to :user
|
|
3
|
+
|
|
4
|
+
serialize :preferences, MultiJson
|
|
5
|
+
|
|
6
|
+
attr_accessible :user
|
|
7
|
+
|
|
8
|
+
validates :user, :presence => true
|
|
9
|
+
validates :user_id, :uniqueness => true
|
|
10
|
+
|
|
11
|
+
def self.for_user(user)
|
|
12
|
+
where(:user_id => user.id).first || create!(:user => user)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#{event.user.try :to_s} #{pastize(event.verb)} a #{event.eventable_type.titleize}
|
data/config/routes.rb
ADDED
data/config.ru
ADDED
data/{lib/generators/eventifier/install/templates/migration.rb → db/migrate/1_eventifier_setup.rb}
RENAMED
|
@@ -9,7 +9,7 @@ class EventifierSetup < ActiveRecord::Migration
|
|
|
9
9
|
|
|
10
10
|
t.timestamps
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
add_index :events, :user_id
|
|
14
14
|
add_index :events, [:eventable_id, :eventable_type]
|
|
15
15
|
|
|
@@ -23,8 +23,7 @@ class EventifierSetup < ActiveRecord::Migration
|
|
|
23
23
|
add_index :notifications, :event_id
|
|
24
24
|
add_index :notifications, :user_id
|
|
25
25
|
add_index :notifications, :parent_id
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
add_column :users, :notifications_last_read_at, :datetime
|
|
28
28
|
end
|
|
29
|
-
|
|
30
29
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class EventifierNotificationSettings < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :notification_settings do |t|
|
|
4
|
+
t.integer :user_id, :null => false
|
|
5
|
+
t.text :preferences, :null => false, :default => '{}'
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
add_index :notification_settings, :user_id, :unique => true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class NotificationSentStatus < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
add_column :notifications, :sent, :boolean, :default => false
|
|
4
|
+
add_column :notifications, :relations, :text, :default => '[]'
|
|
5
|
+
add_index :notifications, :sent
|
|
6
|
+
|
|
7
|
+
Eventifier::Notification.reset_column_information
|
|
8
|
+
Eventifier::Notification.update_all :sent => true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def down
|
|
12
|
+
remove_column :notifications, :sent
|
|
13
|
+
remove_column :notifications, :relations
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class EventGroupable < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
add_column :events, :groupable_id, :integer
|
|
4
|
+
add_column :events, :groupable_type, :string
|
|
5
|
+
|
|
6
|
+
Eventifier::Event.reset_column_information
|
|
7
|
+
Eventifier::Event.update_all(
|
|
8
|
+
'groupable_id = eventable_id, groupable_type = eventable_type'
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
change_column :events, :groupable_id, :integer, :null => false
|
|
12
|
+
change_column :events, :groupable_type, :string, :null => false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def down
|
|
16
|
+
remove_column :events, :groupable_id
|
|
17
|
+
remove_column :events, :groupable_type
|
|
18
|
+
end
|
|
19
|
+
end
|
data/eventifier.gemspec
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
-
require "eventifier/version"
|
|
4
|
-
|
|
5
2
|
Gem::Specification.new do |s|
|
|
6
3
|
s.name = "eventifier"
|
|
7
|
-
s.version =
|
|
4
|
+
s.version = '0.0.8'
|
|
8
5
|
s.authors = ["Nathan Sampimon", "Peter Murray"]
|
|
9
6
|
s.email = ["nathan@inspire9.com"]
|
|
10
7
|
s.homepage = "http://github.com/inspire9/eventifier"
|
|
@@ -18,16 +15,16 @@ Gem::Specification.new do |s|
|
|
|
18
15
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
19
16
|
s.require_paths = ["lib"]
|
|
20
17
|
|
|
21
|
-
s.
|
|
22
|
-
s.add_development_dependency "mongoid"
|
|
23
|
-
s.add_runtime_dependency "actionmailer"
|
|
24
|
-
s.add_development_dependency "fabrication"
|
|
25
|
-
s.add_development_dependency "database_cleaner"
|
|
26
|
-
s.add_development_dependency "pg"
|
|
27
|
-
s.add_development_dependency "rspec"
|
|
28
|
-
|
|
29
|
-
s.add_runtime_dependency "activerecord"
|
|
18
|
+
s.add_runtime_dependency 'rails', '~> 3.2.0'
|
|
30
19
|
s.add_runtime_dependency "bson_ext"
|
|
31
|
-
s.add_runtime_dependency
|
|
32
|
-
s.add_runtime_dependency
|
|
20
|
+
s.add_runtime_dependency 'haml-rails', '~> 0.4'
|
|
21
|
+
s.add_runtime_dependency 'haml_coffee_assets'
|
|
22
|
+
s.add_runtime_dependency 'coffee-rails', '~> 3.2.1'
|
|
23
|
+
s.add_runtime_dependency 'compass-rails'
|
|
24
|
+
s.add_runtime_dependency 'multi_json', '~> 1.7.4'
|
|
25
|
+
|
|
26
|
+
s.add_development_dependency 'combustion', '~> 0.5.0'
|
|
27
|
+
s.add_development_dependency 'fabrication', '~> 2.7.1'
|
|
28
|
+
s.add_development_dependency "pg"
|
|
29
|
+
s.add_development_dependency 'rspec-rails', '~> 2.13.2'
|
|
33
30
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class Eventifier::Delivery
|
|
2
|
+
def self.deliver
|
|
3
|
+
unsent = Eventifier::Notification.unsent
|
|
4
|
+
unsent.group_by(&:user).each do |user, notifications|
|
|
5
|
+
new(user, notifications).deliver
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(user, notifications)
|
|
10
|
+
@user, @notifications = user, notifications
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def deliver
|
|
14
|
+
if anything_to_send?
|
|
15
|
+
Eventifier.mailer.notifications(user, notifications_to_send).deliver
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
notifications.each do |notification|
|
|
19
|
+
notification.update_attribute :sent, true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
attr_reader :user, :notifications
|
|
26
|
+
|
|
27
|
+
def anything_to_send?
|
|
28
|
+
!notifications_to_send.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def notifications_to_send
|
|
32
|
+
@notifications_to_send ||= notifications.select { |notification|
|
|
33
|
+
include_notification? notification
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def settings
|
|
38
|
+
@settings ||= Eventifier::NotificationSetting.for_user user
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def include_notification?(notification)
|
|
42
|
+
return true if settings.preferences['email'].nil?
|
|
43
|
+
|
|
44
|
+
specifics = notification.relations.collect { |relation|
|
|
45
|
+
key = [
|
|
46
|
+
notification.event.verb,
|
|
47
|
+
notification.event.eventable_type.underscore.pluralize,
|
|
48
|
+
'notify',
|
|
49
|
+
Eventifier::Relationship.new(self, relation).key
|
|
50
|
+
].join('_')
|
|
51
|
+
settings.preferences['email'][key]
|
|
52
|
+
}.compact
|
|
53
|
+
|
|
54
|
+
return specifics.any? unless specifics.empty?
|
|
55
|
+
|
|
56
|
+
default = settings.preferences['email']['default']
|
|
57
|
+
default.nil? || default
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Eventifier::EventSubscriber
|
|
2
|
+
def self.subscribe_to_all klass, names
|
|
3
|
+
names.each do |method_name|
|
|
4
|
+
new.subscribe_to_method klass, method_name
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def subscribe_to_method klass, method_name
|
|
9
|
+
name = "#{method_name}.#{klass.name.tableize}.event.eventifier"
|
|
10
|
+
|
|
11
|
+
return if ActiveSupport::Notifications.notifier.listening?(name)
|
|
12
|
+
|
|
13
|
+
ActiveSupport::Notifications.subscribe name do |*args|
|
|
14
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
15
|
+
event_user = if event.payload[:user]
|
|
16
|
+
Eventifier::Relationship.new(event.payload[:object], event.payload[:user]).users.first
|
|
17
|
+
else
|
|
18
|
+
event.payload[:object].user
|
|
19
|
+
end
|
|
20
|
+
groupable = event.payload[:object]
|
|
21
|
+
groupable = Eventifier::Relationship.new(groupable, event.payload[:group_by]).users.first if event.payload[:group_by]
|
|
22
|
+
|
|
23
|
+
eventifier_event = Eventifier::Event.create(
|
|
24
|
+
user: event_user,
|
|
25
|
+
eventable: event.payload[:object],
|
|
26
|
+
groupable: groupable,
|
|
27
|
+
verb: event.payload[:event],
|
|
28
|
+
change_data: change_data(event.payload[:object], event.payload[:options])
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
ActiveSupport::Notifications.instrument("#{method_name}.#{klass.name.tableize}.notification.eventifier", verb: :create, event: eventifier_event, object: event.payload[:object])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
def change_data object, options
|
|
37
|
+
change_data = object.changes.stringify_keys
|
|
38
|
+
|
|
39
|
+
change_data = change_data.reject { |attribute, value| options[:except].include?(attribute) } if options[:except]
|
|
40
|
+
change_data = change_data.select { |attribute, value| options[:only].include?(attribute) } if options[:only]
|
|
41
|
+
|
|
42
|
+
change_data.symbolize_keys
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -8,74 +8,22 @@ module Eventifier
|
|
|
8
8
|
methods = options.delete(:track_on)
|
|
9
9
|
attributes = options.delete(:attributes)
|
|
10
10
|
|
|
11
|
-
create_observers
|
|
12
|
-
|
|
13
11
|
if block.nil?
|
|
14
12
|
track_on methods, :attributes => attributes
|
|
15
13
|
else
|
|
16
14
|
instance_eval(&block)
|
|
17
15
|
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def create_observers
|
|
21
|
-
# Create all the observer classes
|
|
22
|
-
@klasses.each do |target_klass|
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
constant_name = "#{target_klass}Observer"
|
|
27
|
-
klass = Class.new(OBSERVER_CLASS)
|
|
28
|
-
self.class.qualified_const_set(constant_name, klass)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
17
|
+
@klasses.each { |klass| Eventifier.tracked_classes << klass }
|
|
18
|
+
Eventifier.tracked_classes.uniq!
|
|
31
19
|
end
|
|
32
20
|
|
|
33
|
-
def track_on methods, options = {
|
|
34
|
-
|
|
35
|
-
attributes = options.delete(:attributes) || {}
|
|
36
|
-
raise 'No events defined to track' if methods.compact.empty?
|
|
37
|
-
User.class_eval { has_many :notifications, :class_name => 'Eventifier::Notification' } unless User.respond_to?(:notifications)
|
|
38
|
-
Eventifier::EventObserver.instance
|
|
39
|
-
|
|
40
|
-
# set up each class with an observer and relationships
|
|
41
|
-
@klasses.each do |target_klass|
|
|
42
|
-
# Add relations to class
|
|
43
|
-
target_klass.class_eval { has_many :events, :as => :eventable, :class_name => 'Eventifier::Event', :dependent => :destroy }
|
|
44
|
-
add_notification_association(target_klass)
|
|
45
|
-
|
|
46
|
-
# create an observer and have it observe the class
|
|
47
|
-
klass = self.class.const_get("#{target_klass}Observer")
|
|
48
|
-
klass.observe target_klass
|
|
49
|
-
|
|
50
|
-
# create a callback for the methods we want to track
|
|
51
|
-
klass.class_eval do
|
|
52
|
-
methods.each do |event|
|
|
53
|
-
define_method "after_#{event}" do |object|
|
|
54
|
-
# create an event when the callback is fired
|
|
55
|
-
Eventifier::Event.create_event(event.to_sym, object, attributes) if object.changed?
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
# instantiate the observer
|
|
60
|
-
klass.instance
|
|
61
|
-
end
|
|
21
|
+
def track_on methods, options = {}
|
|
22
|
+
Eventifier::Tracker.new @klasses, methods, options
|
|
62
23
|
end
|
|
63
24
|
|
|
64
25
|
def notify *args
|
|
65
|
-
|
|
66
|
-
# if its the first one, relation is the first in the array, otherwise treat the whole thing like a hash
|
|
67
|
-
relation = args.delete_at(0) if args.length == 2
|
|
68
|
-
args = args.first
|
|
69
|
-
|
|
70
|
-
methods = args.delete(:on)
|
|
71
|
-
methods = methods.kind_of?(Array) ? methods : [methods]
|
|
72
|
-
relation ||= args
|
|
73
|
-
|
|
74
|
-
@klasses.each do |target_klass|
|
|
75
|
-
methods.each do |method|
|
|
76
|
-
Eventifier::Event.add_notification target_klass, relation, method
|
|
77
|
-
end
|
|
78
|
-
end
|
|
26
|
+
Eventifier::Notifier.new @klasses, *args
|
|
79
27
|
end
|
|
80
28
|
|
|
81
29
|
def url url_proc
|
|
@@ -87,6 +35,5 @@ module Eventifier
|
|
|
87
35
|
def self.url_mappings
|
|
88
36
|
@url_mapppings ||= {}
|
|
89
37
|
end
|
|
90
|
-
|
|
91
38
|
end
|
|
92
39
|
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Eventifier
|
|
2
|
+
module Mailers
|
|
3
|
+
module Helpers
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
attr_reader :scope_name, :resource
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
# Configure default email options
|
|
13
|
+
def eventifier_mail(user, records, action)
|
|
14
|
+
initialize_from_record(user, records)
|
|
15
|
+
mail headers_for(action)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize_from_record(user, records)
|
|
19
|
+
@user, @notifications = user, records
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def headers_for(action)
|
|
23
|
+
headers = {
|
|
24
|
+
:subject => I18n.t(:email_subject, :scope => [:notifications]),
|
|
25
|
+
:from => mailer_sender,
|
|
26
|
+
:to => @user.email,
|
|
27
|
+
:template_path => template_paths
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
headers[:reply_to] = headers[:from] unless headers.key?(:reply_to)
|
|
31
|
+
|
|
32
|
+
headers
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def mailer_sender
|
|
36
|
+
if default_params[:from].present?
|
|
37
|
+
default_params[:from]
|
|
38
|
+
else
|
|
39
|
+
Eventifier.mailer_sender
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def template_paths
|
|
44
|
+
self.class.mailer_name
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Setup a subject doing an I18n lookup. At first, it attemps to set a subject
|
|
48
|
+
# based on the current mapping:
|
|
49
|
+
#
|
|
50
|
+
# en:
|
|
51
|
+
# devise:
|
|
52
|
+
# mailer:
|
|
53
|
+
# confirmation_instructions:
|
|
54
|
+
# user_subject: '...'
|
|
55
|
+
#
|
|
56
|
+
# If one does not exist, it fallbacks to ActionMailer default:
|
|
57
|
+
#
|
|
58
|
+
# en:
|
|
59
|
+
# devise:
|
|
60
|
+
# mailer:
|
|
61
|
+
# confirmation_instructions:
|
|
62
|
+
# subject: '...'
|
|
63
|
+
#
|
|
64
|
+
def translate(mapping, key)
|
|
65
|
+
I18n.t(:"notifications_subject", :scope => [:eventifier, :notifications, key],
|
|
66
|
+
:default => [:subject, key.to_s.humanize])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class Eventifier::NotificationMapping
|
|
2
|
+
def self.add(key, relation)
|
|
3
|
+
notification_mappings[key] << relation
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def self.find(key)
|
|
7
|
+
notification_mappings[key]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.all
|
|
11
|
+
notification_mappings
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.users_and_relations(event, key, &block)
|
|
15
|
+
users = Hash.new { |hash, key| hash[key] = [] }
|
|
16
|
+
|
|
17
|
+
find(key).each do |relation|
|
|
18
|
+
Eventifier::Relationship.new(event.eventable, relation).users.each do |user|
|
|
19
|
+
users[user] << relation
|
|
20
|
+
users[user].uniq!
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
users.each(&block)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def self.notification_mappings
|
|
30
|
+
@notification_mapppings ||= Hash.new { |hash, key|
|
|
31
|
+
hash[key] = []
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class Eventifier::NotificationSubscriber
|
|
2
|
+
def self.subscribe_to_method klass, method_name
|
|
3
|
+
key = "#{method_name}.#{klass.name.tableize}"
|
|
4
|
+
name = "#{key}.notification.eventifier"
|
|
5
|
+
|
|
6
|
+
return if ActiveSupport::Notifications.notifier.listening?(name)
|
|
7
|
+
|
|
8
|
+
ActiveSupport::Notifications.subscribe name do |*args|
|
|
9
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
10
|
+
eventifier_event = event.payload[:event]
|
|
11
|
+
|
|
12
|
+
Eventifier::NotificationMapping.users_and_relations(eventifier_event, key) do |user, relations|
|
|
13
|
+
next if user == eventifier_event.user
|
|
14
|
+
|
|
15
|
+
Eventifier::Notification.create(
|
|
16
|
+
event: eventifier_event,
|
|
17
|
+
user: user,
|
|
18
|
+
relations: relations
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Eventifier::Notifier
|
|
2
|
+
def initialize klasses, *args
|
|
3
|
+
# args will either be [:relation, {:on => :create}] or [{:relation => :second_relation, :on => :create}]
|
|
4
|
+
# if its the first one, relation is the first in the array, otherwise treat the whole thing like a hash
|
|
5
|
+
|
|
6
|
+
@klasses = klasses
|
|
7
|
+
relation = args.delete_at(0) if args.length == 2
|
|
8
|
+
args = args.first || {}
|
|
9
|
+
|
|
10
|
+
methods = args.delete(:on)
|
|
11
|
+
methods = methods.kind_of?(Array) ? methods : [methods]
|
|
12
|
+
relation ||= args
|
|
13
|
+
|
|
14
|
+
@klasses.each do |target_klass|
|
|
15
|
+
methods.each do |method_name|
|
|
16
|
+
Eventifier::NotificationMapping.add "#{method_name}.#{target_klass.name.tableize}", relation
|
|
17
|
+
Eventifier::NotificationSubscriber.subscribe_to_method target_klass, method_name
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Eventifier::Preferences
|
|
2
|
+
def initialize(user)
|
|
3
|
+
@user = user
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def to_hashes
|
|
7
|
+
keys.collect do |key|
|
|
8
|
+
{
|
|
9
|
+
:key => key,
|
|
10
|
+
:label => label_for(key),
|
|
11
|
+
:value => value_for(key)
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
attr_reader :user
|
|
19
|
+
|
|
20
|
+
def keys
|
|
21
|
+
@keys ||= begin
|
|
22
|
+
hash = Eventifier::NotificationMapping.notification_mappings
|
|
23
|
+
['default'] + hash.keys.collect { |key|
|
|
24
|
+
hash[key].collect { |value|
|
|
25
|
+
(key.split('.') + ['notify', Eventifier::Relationship.new(user, value).key]).join('_')
|
|
26
|
+
}
|
|
27
|
+
}.flatten
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def label_for(key)
|
|
32
|
+
I18n.translate :"events.labels.preferences.#{key}", default: key
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def settings
|
|
36
|
+
@settings ||= Eventifier::NotificationSetting.for_user user
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def value_for(key)
|
|
40
|
+
settings.preferences['email'].nil? ||
|
|
41
|
+
settings.preferences['email'][key].nil? ||
|
|
42
|
+
settings.preferences['email'][key]
|
|
43
|
+
end
|
|
44
|
+
end
|