activity_notification 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/.coveralls.yml +1 -0
- data/.gitignore +56 -0
- data/.rspec +3 -0
- data/.travis.yml +28 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +174 -0
- data/MIT-LICENSE +20 -0
- data/README.md +437 -0
- data/Rakefile +19 -0
- data/activity_notification.gemspec +33 -0
- data/app/controllers/activity_notification/notifications_controller.rb +119 -0
- data/app/controllers/activity_notification/notifications_with_devise_controller.rb +29 -0
- data/app/mailers/activity_notification/mailer.rb +13 -0
- data/app/views/activity_notification/mailer/default/default.html.erb +7 -0
- data/app/views/activity_notification/notifications/default/_default.html.erb +36 -0
- data/app/views/activity_notification/notifications/default/_index.html.erb +9 -0
- data/app/views/activity_notification/notifications/default/destroy.js.erb +2 -0
- data/app/views/activity_notification/notifications/default/index.html.erb +17 -0
- data/app/views/activity_notification/notifications/default/open.js.erb +2 -0
- data/app/views/activity_notification/notifications/default/open_all.js.erb +2 -0
- data/app/views/activity_notification/notifications/default/show.html.erb +2 -0
- data/config/locales/en.yml +8 -0
- data/lib/activity_notification.rb +52 -0
- data/lib/activity_notification/apis/notification_api.rb +147 -0
- data/lib/activity_notification/common.rb +86 -0
- data/lib/activity_notification/config.rb +23 -0
- data/lib/activity_notification/controllers/store_controller.rb +30 -0
- data/lib/activity_notification/helpers/polymorphic_helpers.rb +32 -0
- data/lib/activity_notification/helpers/view_helpers.rb +108 -0
- data/lib/activity_notification/mailers/helpers.rb +97 -0
- data/lib/activity_notification/models/notifiable.rb +136 -0
- data/lib/activity_notification/models/notification.rb +50 -0
- data/lib/activity_notification/models/notifier.rb +11 -0
- data/lib/activity_notification/models/target.rb +104 -0
- data/lib/activity_notification/rails.rb +6 -0
- data/lib/activity_notification/rails/routes.rb +105 -0
- data/lib/activity_notification/renderable.rb +142 -0
- data/lib/activity_notification/roles/acts_as_notifiable.rb +37 -0
- data/lib/activity_notification/roles/acts_as_target.rb +30 -0
- data/lib/activity_notification/version.rb +3 -0
- data/lib/generators/activity_notification/controllers_generator.rb +44 -0
- data/lib/generators/activity_notification/install_generator.rb +45 -0
- data/lib/generators/activity_notification/migration/migration_generator.rb +17 -0
- data/lib/generators/activity_notification/notification/notification_generator.rb +17 -0
- data/lib/generators/activity_notification/views_generator.rb +44 -0
- data/lib/generators/templates/README +53 -0
- data/lib/generators/templates/active_record/migration.rb +18 -0
- data/lib/generators/templates/activity_notification.rb +18 -0
- data/lib/generators/templates/controllers/README +13 -0
- data/lib/generators/templates/controllers/notifications_controller.rb +66 -0
- data/lib/generators/templates/controllers/notifications_with_devise_controller.rb +74 -0
- data/lib/generators/templates/notification/notification.rb +3 -0
- data/lib/tasks/activity_notification_tasks.rake +4 -0
- data/spec/concerns/notification_api_spec.rb +531 -0
- data/spec/factories/articles.rb +5 -0
- data/spec/factories/comments.rb +6 -0
- data/spec/factories/notifications.rb +7 -0
- data/spec/factories/users.rb +5 -0
- data/spec/models/notification_spec.rb +259 -0
- data/spec/rails_app/Rakefile +6 -0
- data/spec/rails_app/app/controllers/application_controller.rb +5 -0
- data/spec/rails_app/app/controllers/concerns/.keep +0 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.keep +0 -0
- data/spec/rails_app/app/models/.keep +0 -0
- data/spec/rails_app/app/models/article.rb +12 -0
- data/spec/rails_app/app/models/comment.rb +18 -0
- data/spec/rails_app/app/models/concerns/.keep +0 -0
- data/spec/rails_app/app/models/user.rb +8 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/bin/bundle +3 -0
- data/spec/rails_app/bin/rails +4 -0
- data/spec/rails_app/bin/rake +4 -0
- data/spec/rails_app/bin/setup +29 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +20 -0
- data/spec/rails_app/config/boot.rb +5 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +12 -0
- data/spec/rails_app/config/environments/development.rb +44 -0
- data/spec/rails_app/config/environments/production.rb +79 -0
- data/spec/rails_app/config/environments/test.rb +45 -0
- data/spec/rails_app/config/initializers/activity_notification.rb +18 -0
- data/spec/rails_app/config/initializers/assets.rb +11 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec/rails_app/config/initializers/devise.rb +274 -0
- data/spec/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/rails_app/config/initializers/inflections.rb +16 -0
- data/spec/rails_app/config/initializers/mime_types.rb +4 -0
- data/spec/rails_app/config/initializers/session_store.rb +3 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/routes.rb +5 -0
- data/spec/rails_app/config/secrets.yml +22 -0
- data/spec/rails_app/db/migrate/20160715050420_create_notifications.rb +18 -0
- data/spec/rails_app/db/migrate/20160715050433_create_test_tables.rb +36 -0
- data/spec/rails_app/db/schema.rb +73 -0
- data/spec/rails_app/public/404.html +67 -0
- data/spec/rails_app/public/422.html +67 -0
- data/spec/rails_app/public/500.html +66 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/spec_helper.rb +34 -0
- metadata +309 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
class Notification < ActiveRecord::Base
|
|
3
|
+
include Renderable
|
|
4
|
+
include Common
|
|
5
|
+
include NotificationApi
|
|
6
|
+
self.table_name = ActivityNotification.config.table_name
|
|
7
|
+
|
|
8
|
+
belongs_to :target, polymorphic: true
|
|
9
|
+
belongs_to :notifiable, polymorphic: true
|
|
10
|
+
belongs_to :group, polymorphic: true
|
|
11
|
+
belongs_to :group_owner, class_name: :Notification
|
|
12
|
+
has_many :group_members,
|
|
13
|
+
class_name: "::ActivityNotification::Notification",
|
|
14
|
+
foreign_key: :group_owner_id
|
|
15
|
+
belongs_to :notifier, polymorphic: true
|
|
16
|
+
|
|
17
|
+
# Serialize parameters Hash
|
|
18
|
+
serialize :parameters, Hash
|
|
19
|
+
|
|
20
|
+
validates :target, presence: true
|
|
21
|
+
validates :notifiable, presence: true
|
|
22
|
+
validates :key, presence: true
|
|
23
|
+
|
|
24
|
+
scope :group_owners_only, -> { where(group_owner_id: nil) }
|
|
25
|
+
scope :group_members_only, -> { where.not(group_owner_id: nil) }
|
|
26
|
+
scope :unopened_only, -> { where(opened_at: nil) }
|
|
27
|
+
scope :unopened_index, -> { unopened_only.group_owners_only.latest_order }
|
|
28
|
+
scope :opened_only!, -> { where.not(opened_at: nil) }
|
|
29
|
+
scope :opened_only, ->(limit) { opened_only!.limit(limit) }
|
|
30
|
+
scope :opened_index, ->(limit) { opened_only(limit).group_owners_only.latest_order }
|
|
31
|
+
scope :unopened_index_group_members_only, -> { where(group_owner_id: unopened_index.pluck(:id)) }
|
|
32
|
+
scope :opened_index_group_members_only, ->(limit) { where(group_owner_id: opened_index(limit).pluck(:id)) }
|
|
33
|
+
|
|
34
|
+
scope :filtered_by_target, ->(target) { where(target: target) }
|
|
35
|
+
scope :filtered_by_instance, ->(notifiable) { where(notifiable: notifiable) }
|
|
36
|
+
scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
|
|
37
|
+
scope :filtered_by_group, ->(group) { where(group: group) }
|
|
38
|
+
scope :filtered_by_key, ->(key) { where(key: key) }
|
|
39
|
+
|
|
40
|
+
scope :with_target, -> { includes(:target) }
|
|
41
|
+
scope :with_notifiable, -> { includes(:notifiable) }
|
|
42
|
+
scope :with_group, -> { includes(:group) }
|
|
43
|
+
scope :with_notifier, -> { includes(:notifier) }
|
|
44
|
+
|
|
45
|
+
scope :latest_order, -> { order(created_at: :desc) }
|
|
46
|
+
scope :earliest_order, -> { order(created_at: :asc) }
|
|
47
|
+
scope :latest, -> { latest_order.first }
|
|
48
|
+
scope :earliest, -> { earliest_order.first }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
module Target
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
included do
|
|
5
|
+
include Common
|
|
6
|
+
include ActsAsTarget
|
|
7
|
+
has_many :notifications,
|
|
8
|
+
class_name: "::ActivityNotification::Notification",
|
|
9
|
+
as: :target
|
|
10
|
+
class_attribute :_notification_email, :_notification_email_allowed
|
|
11
|
+
set_target_class_defaults
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class_methods do
|
|
15
|
+
def set_target_class_defaults
|
|
16
|
+
self._notification_email = nil
|
|
17
|
+
self._notification_email_allowed = false
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def mailer_to
|
|
22
|
+
resolve_value(_notification_email)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def notification_email_allowed?(notifiable, key)
|
|
26
|
+
resolve_value(_notification_email_allowed, notifiable, key)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def unopened_notification_count
|
|
30
|
+
unopened_notification_index.count
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def has_unopened_notifications?
|
|
34
|
+
unopened_notification_index.exists?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#TODO is this switching the best solution?
|
|
38
|
+
def notification_index(limit = nil)
|
|
39
|
+
# When the target have unopened notifications
|
|
40
|
+
notifications.unopened_index.exists? ?
|
|
41
|
+
# Return unopened notifications
|
|
42
|
+
unopened_notification_index(limit) :
|
|
43
|
+
# Otherwise, return opened notifications
|
|
44
|
+
limit.present? ?
|
|
45
|
+
opened_notification_index(limit) :
|
|
46
|
+
opened_notification_index
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def unopened_notification_index(limit = nil)
|
|
50
|
+
limit.present? ?
|
|
51
|
+
notifications.unopened_index.limit(limit) :
|
|
52
|
+
notifications.unopened_index
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def opened_notification_index(limit = ActivityNotification.config.opened_limit)
|
|
56
|
+
notifications.opened_index(limit)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Wrapper methods of SimpleNotify class methods
|
|
61
|
+
|
|
62
|
+
def notify_to(notifiable, options = {})
|
|
63
|
+
Notification.notify_to(self, notifiable, options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def open_all_notifications(opened_at = nil)
|
|
67
|
+
Notification.open_all_of(self, opened_at)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Methods to be overriden
|
|
71
|
+
|
|
72
|
+
# Typical method to get notifications index
|
|
73
|
+
def notification_index_with_attributes(limit = nil)
|
|
74
|
+
# When the target have unopened notifications
|
|
75
|
+
unopened_notification_index.exists? ?
|
|
76
|
+
# Return unopened notifications
|
|
77
|
+
unopened_notification_index_with_attributes(limit) :
|
|
78
|
+
# Otherwise, return opened notifications
|
|
79
|
+
limit.present? ?
|
|
80
|
+
opened_notification_index_with_attributes(limit) :
|
|
81
|
+
opened_notification_index_with_attributes
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def unopened_notification_index_with_attributes(limit = nil)
|
|
85
|
+
Notification.group_member_exists?(unopened_notification_index(limit)) ?
|
|
86
|
+
unopened_notification_index(limit).with_target.with_notifiable.with_group.with_notifier :
|
|
87
|
+
unopened_notification_index(limit).with_target.with_notifiable.with_notifier
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def opened_notification_index_with_attributes(limit = ActivityNotification.config.opened_limit)
|
|
91
|
+
Notification.group_member_exists?(opened_notification_index(limit)) ?
|
|
92
|
+
opened_notification_index(limit).with_target.with_notifiable.with_group.with_notifier :
|
|
93
|
+
opened_notification_index(limit).with_target.with_notifiable.with_notifier
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def authenticate_with_devise?(current_resource)
|
|
97
|
+
unless current_resource.instance_of? self.class
|
|
98
|
+
raise TypeError, "Defferent type of devise resource #{current_resource.class.to_s} has been passed to #{self.class}##{__method__}. You have to override #{self.class}##{__method__} method."
|
|
99
|
+
end
|
|
100
|
+
current_resource == self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require "active_support/core_ext/object/try"
|
|
2
|
+
require "active_support/core_ext/hash/slice"
|
|
3
|
+
|
|
4
|
+
module ActionDispatch::Routing
|
|
5
|
+
class Mapper
|
|
6
|
+
# Includes notify_to method for routes.
|
|
7
|
+
# This method is responsible to generate all needed routes for activity_notification
|
|
8
|
+
#
|
|
9
|
+
# ==== Examples
|
|
10
|
+
#
|
|
11
|
+
# notify_to :users
|
|
12
|
+
# notify_to :users, with_devise: :users
|
|
13
|
+
# notify_to :users, with_devise: :users, only: [:open, :open_all, :move]
|
|
14
|
+
#
|
|
15
|
+
# When you have an User model configured as a target (e.g. defined acts_as_target),
|
|
16
|
+
# you can creat this inside your routes:
|
|
17
|
+
#
|
|
18
|
+
# notify_to :users
|
|
19
|
+
#
|
|
20
|
+
# This method creates the needed routes:
|
|
21
|
+
#
|
|
22
|
+
# # Notification routes
|
|
23
|
+
# user_notifications GET /users/:user_id/notifications(.:format)
|
|
24
|
+
# {controller:"activity_notification/notifications", action:"index", target_type:"users"}
|
|
25
|
+
# user_notification GET /users/:user_id/notifications/:id(.:format)
|
|
26
|
+
# {controller:"activity_notification/notifications", action:"show", target_type:"users"}
|
|
27
|
+
# user_notification DELETE /users/:user_id/notifications/:id(.:format)
|
|
28
|
+
# {controller:"activity_notification/notifications", action:"destroy", target_type:"users"}
|
|
29
|
+
# open_all_user_notifications POST /users/:user_id/notifications/open_all(.:format)
|
|
30
|
+
# {controller:"activity_notification/notifications", action:"open_all", target_type:"users"}
|
|
31
|
+
# move_user_notification POST /users/:user_id/notifications/:id/move(.:format)
|
|
32
|
+
# {controller:"activity_notification/notifications", action:"move", target_type:"users"}
|
|
33
|
+
# open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
|
|
34
|
+
# {controller:"activity_notification/notifications", action:"open", target_type:"users"}
|
|
35
|
+
#
|
|
36
|
+
# When you use devise for authentication and you want make notification target assciated with devise,
|
|
37
|
+
# you can creat this inside your routes:
|
|
38
|
+
#
|
|
39
|
+
# notify_to :users, with_devise: true
|
|
40
|
+
#
|
|
41
|
+
# This with_devise option creates the needed routes assciated with devise authentication:
|
|
42
|
+
#
|
|
43
|
+
# # Notification with devise routes
|
|
44
|
+
# user_notifications GET /users/:user_id/notifications(.:format)
|
|
45
|
+
# {controller:"activity_notification/notifications_with_devise", action:"index", devise_type:"users", target_type:"users"}
|
|
46
|
+
# user_notification GET /users/:user_id/notifications/:id(.:format)
|
|
47
|
+
# {controller:"activity_notification/notifications_with_devise", action:"show", devise_type:"users", target_type:"users"}
|
|
48
|
+
# user_notification DELETE /users/:user_id/notifications/:id(.:format)
|
|
49
|
+
# {controller:"activity_notification/notifications_with_devise", action:"destroy", devise_type:"users", target_type:"users"}
|
|
50
|
+
# open_all_user_notifications POST /users/:user_id/notifications/open_all(.:format)
|
|
51
|
+
# {controller:"activity_notification/notifications_with_devise", action:"open_all", devise_type:"users", target_type:"users"}
|
|
52
|
+
# move_user_notification POST /users/:user_id/notifications/:id/move(.:format)
|
|
53
|
+
# {controller:"activity_notification/notifications_with_devise", action:"move", devise_type:"users", target_type:"users"}
|
|
54
|
+
# open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
|
|
55
|
+
# {controller:"activity_notification/notifications_with_devise", action:"open", devise_type:"users", target_type:"users"}
|
|
56
|
+
#
|
|
57
|
+
# ==== Options
|
|
58
|
+
#TODO add document for options
|
|
59
|
+
#
|
|
60
|
+
def notify_to(*resources)
|
|
61
|
+
options = resources.extract_options!
|
|
62
|
+
|
|
63
|
+
#TODO check resources if it includes target module
|
|
64
|
+
|
|
65
|
+
if (with_devise = options.delete(:with_devise)).present?
|
|
66
|
+
options[:controller] ||= "activity_notification/notifications_with_devise"
|
|
67
|
+
options[:as] ||= "notifications"
|
|
68
|
+
#TODO check device configuration in model
|
|
69
|
+
devise_defaults = { devise_type: with_devise.to_s }
|
|
70
|
+
else
|
|
71
|
+
options[:controller] ||= "activity_notification/notifications"
|
|
72
|
+
end
|
|
73
|
+
options[:except] ||= []
|
|
74
|
+
options[:except].concat( [:new, :create, :edit, :update] )
|
|
75
|
+
|
|
76
|
+
#TODO other options
|
|
77
|
+
# :as, :path_prefix, :path_names ...
|
|
78
|
+
|
|
79
|
+
resources.each do |resource|
|
|
80
|
+
self.resources resource, only: :none do
|
|
81
|
+
options[:defaults] = (devise_defaults || {}).merge({ target_type: resource.to_s })
|
|
82
|
+
self.resources :notifications, options do
|
|
83
|
+
collection do
|
|
84
|
+
post :open_all unless ignore_path?(:open_all, options)
|
|
85
|
+
end
|
|
86
|
+
member do
|
|
87
|
+
get :move unless ignore_path?(:move, options)
|
|
88
|
+
post :open unless ignore_path?(:open, options)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def ignore_path?(action, options)
|
|
99
|
+
return true if options[:except].present? and options[:except].include?(action)
|
|
100
|
+
return true if options[:only].present? and not options[:only].include?(action)
|
|
101
|
+
false
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
# Provides logic for rendering notifications.
|
|
3
|
+
# Handles both i18n strings support and smart partials rendering (different templates per notification key).
|
|
4
|
+
# Deeply uses PublicActivity as reference
|
|
5
|
+
module Renderable
|
|
6
|
+
# Virtual attribute returning text description of the notification
|
|
7
|
+
# using the notification's key to translate using i18n.
|
|
8
|
+
def text(params = {})
|
|
9
|
+
k = key.split('.')
|
|
10
|
+
k.unshift('notification') if k.first != 'notification'
|
|
11
|
+
if params.has_key?(:target)
|
|
12
|
+
k.insert(1, params[:target])
|
|
13
|
+
else
|
|
14
|
+
k.insert(1, target.to_resource_name)
|
|
15
|
+
end
|
|
16
|
+
k = k.join('.')
|
|
17
|
+
|
|
18
|
+
I18n.t(k, parameters.merge(params) || {})
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Renders notification from views.
|
|
22
|
+
#
|
|
23
|
+
# @param [ActionView::Base] context
|
|
24
|
+
# @return [nil] nil
|
|
25
|
+
#
|
|
26
|
+
# The preferred way of rendering notifications is
|
|
27
|
+
# to provide a template specifying how the rendering should be happening.
|
|
28
|
+
# However, you can choose using _I18n_ based approach when developing
|
|
29
|
+
# an application that supports plenty of languages.
|
|
30
|
+
#
|
|
31
|
+
# If partial view exists that matches the "key" attribute
|
|
32
|
+
# renders that partial with local variables set to contain both
|
|
33
|
+
# Activity and activity_parameters (hash with indifferent access).
|
|
34
|
+
#
|
|
35
|
+
# If the partial view does not exist and you wish to fallback to rendering
|
|
36
|
+
# through the I18n translation, you can do so by passing in a :fallback
|
|
37
|
+
# parameter whose value equals :text.
|
|
38
|
+
#
|
|
39
|
+
# If you do not want to define a partial view, and instead want to have
|
|
40
|
+
# all missing views fallback to a default, you can define the :fallback
|
|
41
|
+
# value equal to the partial you wish to use when the partial defined
|
|
42
|
+
# by the notification key does not exist.
|
|
43
|
+
#
|
|
44
|
+
# @example Render a list of all @target's notifications of from a view (erb)
|
|
45
|
+
# <ul>
|
|
46
|
+
# <% @target.notifications.each do |notification| %>
|
|
47
|
+
# <li><%= render_notification(notification) %></li>
|
|
48
|
+
# <% end %>
|
|
49
|
+
# </ul>
|
|
50
|
+
#
|
|
51
|
+
# @example Fallback to the I18n text translation if the view is missing
|
|
52
|
+
# <ul>
|
|
53
|
+
# <% @target.notifications.each do |notification| %>
|
|
54
|
+
# <li><%= render_notification(notification, fallback: :text) %></li>
|
|
55
|
+
# <% end %>
|
|
56
|
+
# </ul>
|
|
57
|
+
#
|
|
58
|
+
# @example Fallback to a default view if the view for the current notification key is missing.
|
|
59
|
+
# The string is the partial name you wish to use.
|
|
60
|
+
# <ul>
|
|
61
|
+
# <% @target.notifications.each do |notification| %>
|
|
62
|
+
# <li><%= render_notification(notification, fallback: 'default') %></li>
|
|
63
|
+
# <% end %>
|
|
64
|
+
# </ul>
|
|
65
|
+
#
|
|
66
|
+
# # Layouts
|
|
67
|
+
#TODO
|
|
68
|
+
#
|
|
69
|
+
# # Creating a template
|
|
70
|
+
#
|
|
71
|
+
# To use templates for formatting how the notification should render,
|
|
72
|
+
# create a template based on target type and notification key, for example:
|
|
73
|
+
#
|
|
74
|
+
# Given a target type users and key _notification.article.create_, create directory tree
|
|
75
|
+
# _app/views/activity_notifications/users/article/_ and create the _create_ partial there
|
|
76
|
+
#
|
|
77
|
+
# Note that if a key consists of more than three parts splitted by commas, your
|
|
78
|
+
# directory structure will have to be deeper, for example:
|
|
79
|
+
# notification.article.comments.destroy => app/views/activity_notifications/users/articles/comments/_destroy.html.erb
|
|
80
|
+
#
|
|
81
|
+
# ## Custom Directory
|
|
82
|
+
#TODO
|
|
83
|
+
#
|
|
84
|
+
# ## Variables in templates
|
|
85
|
+
#TODO
|
|
86
|
+
def render(context, params = {})
|
|
87
|
+
params[:i18n] and return context.render text: self.text(params)
|
|
88
|
+
|
|
89
|
+
partial = partial_path(*params.values_at(:partial, :partial_root, :target))
|
|
90
|
+
layout = layout_path(*params.values_at(:layout, :layout_root))
|
|
91
|
+
locals = prepare_locals(params)
|
|
92
|
+
|
|
93
|
+
begin
|
|
94
|
+
context.render params.merge(partial: partial, layout: layout, locals: locals)
|
|
95
|
+
rescue ActionView::MissingTemplate => e
|
|
96
|
+
if params[:fallback] == :text
|
|
97
|
+
context.render text: self.text(params)
|
|
98
|
+
elsif params[:fallback].present?
|
|
99
|
+
partial = partial_path(*params.values_at(:fallback, :partial_root, :target))
|
|
100
|
+
context.render params.merge(partial: partial, layout: layout, locals: locals)
|
|
101
|
+
else
|
|
102
|
+
raise e
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def partial_path(path = nil, root = nil, target = nil)
|
|
108
|
+
controller = ActivityNotification.get_controller if ActivityNotification.respond_to?(:get_controller)
|
|
109
|
+
root ||= "activity_notification/notifications/#{target}" if target.present?
|
|
110
|
+
root ||= controller.target_view_path if controller.present? and controller.respond_to?(:target_view_path)
|
|
111
|
+
root ||= 'activity_notification/notifications/default'
|
|
112
|
+
path ||= self.key.gsub('.', '/')
|
|
113
|
+
select_path(path, root)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def layout_path(path = nil, root = nil)
|
|
117
|
+
path.nil? and return
|
|
118
|
+
root ||= 'layouts'
|
|
119
|
+
select_path(path, root)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def prepare_locals(params)
|
|
123
|
+
locals = params.delete(:locals) || {}
|
|
124
|
+
|
|
125
|
+
prepared_parameters = prepare_parameters(params)
|
|
126
|
+
locals.merge\
|
|
127
|
+
notification: self,
|
|
128
|
+
parameters: prepared_parameters
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def prepare_parameters(params)
|
|
132
|
+
@prepared_params ||= self.parameters.with_indifferent_access.merge(params)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def select_path(path, root)
|
|
138
|
+
[root, path].map(&:to_s).join('/')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
module ActsAsNotifiable
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
class_methods do
|
|
6
|
+
# Adds required callbacks for creating and updating
|
|
7
|
+
# notifiable models.
|
|
8
|
+
#
|
|
9
|
+
# == Parameters:
|
|
10
|
+
# [:targets]
|
|
11
|
+
#TODO
|
|
12
|
+
def acts_as_notifiable(target_type, opts = {})
|
|
13
|
+
options = opts.clone
|
|
14
|
+
assign_globals target_type, options
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def available_options
|
|
19
|
+
[:targets, :group, :notifier, :parameters, :email_allowed, :notifiable_path].freeze
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def assign_globals(target_type, options)
|
|
23
|
+
[:targets, :group, :parameters, :email_allowed].each do |key|
|
|
24
|
+
if options[key]
|
|
25
|
+
self.send("_notification_#{key}".to_sym).store(target_type.to_sym, options.delete(key))
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
[:notifier, :notifiable_path].each do |key|
|
|
29
|
+
if options[key]
|
|
30
|
+
self.send("_#{key}".to_sym).store(target_type.to_sym, options.delete(key))
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|