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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +7 -8
  4. data/Gemfile +1 -1
  5. data/README.textile +44 -3
  6. data/app/assets/images/eventifier/notifications-bell.png +0 -0
  7. data/app/assets/images/eventifier/notifications-tower.png +0 -0
  8. data/app/assets/javascripts/eventifier/notifications.coffee +196 -0
  9. data/app/assets/javascripts/eventifier/templates/dropdown.hamlc +10 -0
  10. data/app/assets/javascripts/eventifier/templates/settings.hamlc +11 -0
  11. data/app/assets/stylesheets/eventifier/notifications.scss +167 -0
  12. data/app/controllers/eventifier/application_controller.rb +4 -0
  13. data/app/controllers/eventifier/notifications_controller.rb +36 -0
  14. data/app/controllers/eventifier/preferences_controller.rb +19 -0
  15. data/app/helpers/eventifier/notification_helper.rb +87 -0
  16. data/app/helpers/eventifier/path_helper.rb +15 -0
  17. data/app/mailers/eventifier/mailer.rb +12 -0
  18. data/app/models/event_tracking.rb +3 -0
  19. data/app/models/eventifier/event.rb +22 -0
  20. data/app/models/eventifier/ghost.rb +21 -0
  21. data/app/models/eventifier/notification.rb +38 -0
  22. data/app/models/eventifier/notification_setting.rb +14 -0
  23. data/app/views/eventifier/_notification.haml +1 -0
  24. data/app/views/eventifier/email/_notification.haml +2 -0
  25. data/app/views/eventifier/mailer/notifications.haml +5 -0
  26. data/app/views/eventifier/notifications/index.jbuilder +6 -0
  27. data/config/routes.rb +7 -0
  28. data/config.ru +7 -0
  29. data/{lib/generators/eventifier/install/templates/migration.rb → db/migrate/1_eventifier_setup.rb} +2 -3
  30. data/db/migrate/2_eventifier_notification_settings.rb +11 -0
  31. data/db/migrate/3_notification_sent_status.rb +15 -0
  32. data/db/migrate/4_event_groupable.rb +19 -0
  33. data/eventifier.gemspec +12 -15
  34. data/lib/eventifier/delivery.rb +59 -0
  35. data/lib/eventifier/{railtie.rb → engine.rb} +4 -2
  36. data/lib/eventifier/event_subscriber.rb +44 -0
  37. data/lib/eventifier/event_tracking.rb +5 -58
  38. data/lib/eventifier/mailers/helpers.rb +70 -0
  39. data/lib/eventifier/notifier/notification_mapping.rb +34 -0
  40. data/lib/eventifier/notifier/notification_subscriber.rb +23 -0
  41. data/lib/eventifier/notifier/notifier.rb +21 -0
  42. data/lib/eventifier/preferences.rb +44 -0
  43. data/lib/eventifier/relationship.rb +36 -0
  44. data/lib/eventifier/trackable_class.rb +74 -0
  45. data/lib/eventifier/tracker.rb +18 -0
  46. data/lib/eventifier.rb +35 -11
  47. data/lib/generators/eventifier/install/install_generator.rb +2 -5
  48. data/lib/generators/eventifier/install/templates/events.en.yaml +1 -0
  49. data/lib/tasks/email.rake +8 -0
  50. data/spec/controllers/eventifier/notifications_controller_spec.rb +24 -0
  51. data/spec/controllers/eventifier/preferences_controller_spec.rb +56 -0
  52. data/spec/eventifier/delivery_spec.rb +110 -0
  53. data/spec/eventifier/preferences_spec.rb +69 -0
  54. data/spec/eventifier/relationship_spec.rb +33 -0
  55. data/spec/eventifier_spec.rb +6 -48
  56. data/spec/fabricators/fabricator.rb +11 -11
  57. data/spec/helpers/eventifier/notification_helper_spec.rb +169 -0
  58. data/spec/helpers/eventifier/path_helper_spec.rb +19 -0
  59. data/spec/integration/eventifier_spec.rb +113 -70
  60. data/spec/integration/internationalisation_spec.rb +39 -0
  61. data/spec/internal/app/controllers/application_controller.rb +3 -0
  62. data/spec/internal/app/lib/event_tracking.rb +12 -0
  63. data/spec/internal/app/models/category.rb +3 -0
  64. data/spec/internal/app/models/post.rb +8 -0
  65. data/spec/internal/app/models/subscription.rb +4 -0
  66. data/spec/internal/app/models/user.rb +4 -0
  67. data/spec/internal/app/views/eventifier/dropdown/_awesome_object.haml +0 -0
  68. data/spec/internal/config/database.yml +4 -0
  69. data/spec/internal/config/initializers/eventifier.rb +1 -0
  70. data/spec/internal/config/locales/events.en.yml +20 -0
  71. data/spec/internal/config/routes.rb +5 -0
  72. data/spec/internal/db/schema.rb +31 -0
  73. data/spec/internal/log/.gitignore +1 -0
  74. data/spec/internal/public/favicon.ico +0 -0
  75. data/spec/models/eventifier/event_spec.rb +23 -0
  76. data/spec/{ghost_spec.rb → models/eventifier/ghost_spec.rb} +3 -3
  77. data/spec/{notification_spec.rb → models/eventifier/notification_spec.rb} +1 -9
  78. data/spec/notification_mailer_spec.rb +8 -4
  79. data/spec/notifier/notification_mapping_spec.rb +28 -0
  80. data/spec/spec_helper.rb +14 -8
  81. data/spec/support/controller_helpers.rb +14 -0
  82. metadata +205 -128
  83. data/Gemfile.lock +0 -97
  84. data/lib/eventifier/active_record/event.rb +0 -10
  85. data/lib/eventifier/active_record/event_observer.rb +0 -8
  86. data/lib/eventifier/active_record/event_tracking.rb +0 -11
  87. data/lib/eventifier/active_record/ghost.rb +0 -9
  88. data/lib/eventifier/active_record/notification.rb +0 -13
  89. data/lib/eventifier/active_record_support.rb +0 -5
  90. data/lib/eventifier/event_helper.rb +0 -40
  91. data/lib/eventifier/event_mixin.rb +0 -45
  92. data/lib/eventifier/event_observer_mixin.rb +0 -44
  93. data/lib/eventifier/ghost_mixin.rb +0 -27
  94. data/lib/eventifier/helper_methods.rb +0 -36
  95. data/lib/eventifier/mongoid/event.rb +0 -16
  96. data/lib/eventifier/mongoid/event_observer.rb +0 -7
  97. data/lib/eventifier/mongoid/event_tracking.rb +0 -13
  98. data/lib/eventifier/mongoid/ghost.rb +0 -15
  99. data/lib/eventifier/mongoid/notification.rb +0 -19
  100. data/lib/eventifier/mongoid/user_patch.rb +0 -3
  101. data/lib/eventifier/mongoid_support.rb +0 -6
  102. data/lib/eventifier/notification_helper.rb +0 -42
  103. data/lib/eventifier/notification_mailer.rb +0 -18
  104. data/lib/eventifier/notification_mixin.rb +0 -50
  105. data/lib/eventifier/version.rb +0 -3
  106. data/spec/event_helper_spec.rb +0 -67
  107. data/spec/event_observer_spec.rb +0 -20
  108. data/spec/event_spec.rb +0 -39
  109. data/spec/helper_methods_spec.rb +0 -36
  110. data/spec/notification_helper_spec.rb +0 -65
  111. data/spec/support/action_mailer.rb +0 -3
  112. data/spec/support/database_cleaner.rb +0 -3
  113. data/spec/test_classes/active_record_support.rb +0 -72
  114. 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}
@@ -0,0 +1,2 @@
1
+ %a{ href: root_url }
2
+ #{event.user.try :to_s} #{pastize(event.verb)} a #{event.eventable_type.titleize}
@@ -0,0 +1,5 @@
1
+ %p You have new notifications
2
+
3
+ %ul.notifications
4
+ - @notifications.each do |notification|
5
+ %li= render_partial_view(notification, :email)
@@ -0,0 +1,6 @@
1
+ json.last_read_at current_user.notifications_last_read_at.to_i
2
+ json.notifications @notifications do |notification|
3
+ json.(notification, :id)
4
+ json.created_at notification.created_at.to_i
5
+ json.html render_partial_view(notification, :dropdown)
6
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ Eventifier::Engine.routes.draw do
2
+ resources :notifications, module: 'eventifier' do
3
+ collection { post :touch }
4
+ end
5
+
6
+ resource :preferences, module: 'eventifier'
7
+ end
data/config.ru ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+ run Combustion::Application
@@ -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 = Eventifier::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.add_development_dependency "activerecord"
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 "mongoid"
32
- s.add_runtime_dependency "actionmailer"
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
@@ -1,7 +1,9 @@
1
1
  module Eventifier
2
- class Railtie < Rails::Railtie
2
+ class Engine < Rails::Engine
3
+ engine_name :eventifier
4
+
3
5
  config.after_initialize do
4
6
  ::EventTracking.new
5
7
  end
6
8
  end
7
- end
9
+ 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
- # If the observer doesn't exist, create the class
25
- unless self.class.const_defined?("#{target_klass}Observer")
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
- methods = methods.kind_of?(Array) ? methods : [methods]
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
- # args will either be [:relation, {:on => :create}] or [{:relation => :second_relation, :on => :create}]
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