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