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
data/Rakefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'rdoc/task'
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
+
rdoc.title = 'ActivityNotification'
|
|
12
|
+
rdoc.options << '--line-numbers'
|
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Bundler::GemHelper.install_tasks
|
|
19
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
2
|
+
|
|
3
|
+
# Maintain your gem's version:
|
|
4
|
+
require "activity_notification/version"
|
|
5
|
+
|
|
6
|
+
# Describe your gem and declare its dependencies:
|
|
7
|
+
Gem::Specification.new do |s|
|
|
8
|
+
s.name = "activity_notification"
|
|
9
|
+
s.version = ActivityNotification::VERSION
|
|
10
|
+
s.platform = Gem::Platform::RUBY
|
|
11
|
+
s.authors = ["Shota Yamazaki"]
|
|
12
|
+
s.email = ["shota.yamazaki.8@gmail.com"]
|
|
13
|
+
s.homepage = "https://github.com/simukappu/activity_notification"
|
|
14
|
+
s.summary = "Integrated user activity notifications for Rails"
|
|
15
|
+
s.description = "Integrated user activity notifications for Rails. Provides functions to configure multiple notification targets and make activity notifications with notifiable models, like adding comments, responding etc."
|
|
16
|
+
s.license = "MIT"
|
|
17
|
+
|
|
18
|
+
s.files = `git ls-files`.split("\n")
|
|
19
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
|
20
|
+
s.require_paths = ["lib"]
|
|
21
|
+
s.required_ruby_version = '>= 2.1.0'
|
|
22
|
+
|
|
23
|
+
s.add_dependency 'rails', '~> 4.2'
|
|
24
|
+
#s.add_dependency 'railties', '>= 3.0.0'
|
|
25
|
+
s.add_dependency 'i18n', '>= 0.5.0'
|
|
26
|
+
s.add_dependency 'activerecord', '>= 3.0'
|
|
27
|
+
|
|
28
|
+
s.add_development_dependency 'sqlite3', '~> 1.3.11'
|
|
29
|
+
s.add_development_dependency "rspec-rails", '~> 3.5.1'
|
|
30
|
+
s.add_development_dependency "factory_girl_rails", '~> 4.7.0'
|
|
31
|
+
s.add_development_dependency 'simplecov', '~> 0.12.0'
|
|
32
|
+
s.add_development_dependency "devise", '~> 4.2.0'
|
|
33
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
class NotificationsController < ActivityNotification.config.parent_controller.constantize
|
|
3
|
+
include ActivityNotification::StoreController
|
|
4
|
+
include ActivityNotification::PolymorphicHelpers
|
|
5
|
+
prepend_before_action :set_target
|
|
6
|
+
before_action :set_notification, except: [:index, :open_all]
|
|
7
|
+
before_action :set_view_prefixes, except: [:move]
|
|
8
|
+
|
|
9
|
+
DEFAULT_VIEW_DIRECTORY = "default"
|
|
10
|
+
|
|
11
|
+
# GET /:target_type/:target_id/notifcations
|
|
12
|
+
def index
|
|
13
|
+
@notifications = load_notification_index(params[:filter], params[:limit]) if params[:reload].to_s.to_boolean(true)
|
|
14
|
+
respond_to do |format|
|
|
15
|
+
format.html # index.html.erb
|
|
16
|
+
format.json { render json: @notifications.to_json(include: [:target, :notifiable, :group]) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# POST /:target_type/:target_id/notifcations/open_all
|
|
21
|
+
def open_all
|
|
22
|
+
@target.open_all_notifications
|
|
23
|
+
@notifications = load_notification_index(params[:filter], params[:limit]) if params[:reload].to_s.to_boolean(true)
|
|
24
|
+
return_back_or_ajax(params[:filter], params[:limit])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# GET /:target_type/:target_id/notifcations/:id
|
|
28
|
+
def show
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# DELETE /:target_type/:target_id/notifcations/:id
|
|
32
|
+
def destroy
|
|
33
|
+
@notification.destroy
|
|
34
|
+
@notifications = load_notification_index(params[:filter], params[:limit]) if params[:reload].to_s.to_boolean(true)
|
|
35
|
+
return_back_or_ajax(params[:filter], params[:limit])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# POST /:target_type/:target_id/notifcations/:id/open
|
|
39
|
+
def open
|
|
40
|
+
@notification.open!
|
|
41
|
+
@notifications = load_notification_index(params[:filter], params[:limit]) if params[:reload].to_s.to_boolean(true)
|
|
42
|
+
params[:move].to_s.to_boolean(false) ?
|
|
43
|
+
move :
|
|
44
|
+
return_back_or_ajax(params[:filter], params[:limit])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# GET /:target_type/:target_id/notifcations/:id/move
|
|
48
|
+
def move
|
|
49
|
+
@notification.open! if params[:open].to_s.to_boolean(false)
|
|
50
|
+
redirect_to @notification.notifiale_path
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# No action routing
|
|
54
|
+
# This method is called from target_view_path method
|
|
55
|
+
# This method can be overriden
|
|
56
|
+
def controller_path
|
|
57
|
+
"activity_notification/notifications"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# No action routing
|
|
61
|
+
# This method needs to be public since it is called from view helper
|
|
62
|
+
def target_view_path
|
|
63
|
+
target_type = @target.to_resources_name
|
|
64
|
+
view_path = [controller_path, target_type].join('/')
|
|
65
|
+
lookup_context.exists?(action_name, view_path) ?
|
|
66
|
+
view_path :
|
|
67
|
+
[controller_path, DEFAULT_VIEW_DIRECTORY].join('/')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
protected
|
|
71
|
+
|
|
72
|
+
def set_target
|
|
73
|
+
if (target_type = params[:target_type]).present?
|
|
74
|
+
target_class = target_type.to_model_class
|
|
75
|
+
@target = params[:target_id].present? ?
|
|
76
|
+
target_class.find_by_id!(params[:target_id]) :
|
|
77
|
+
target_class.find_by_id!(params["#{target_type.to_resource_name}_id"])
|
|
78
|
+
else
|
|
79
|
+
render text: "400 Bad Request: Missing parameter", status: 400
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def set_notification
|
|
84
|
+
@notification = Notification.find_by_id!(params[:id])
|
|
85
|
+
if @target.present? and @notification.target != @target
|
|
86
|
+
render text: "403 Forbidden: Wrong target", status: 403
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def load_notification_index(filter, limit)
|
|
91
|
+
limit = nil unless limit.to_i > 0
|
|
92
|
+
case filter
|
|
93
|
+
when 'opened'
|
|
94
|
+
@target.opened_notification_index_with_attributes(limit)
|
|
95
|
+
when 'unopened'
|
|
96
|
+
@target.unopened_notification_index_with_attributes(limit)
|
|
97
|
+
else
|
|
98
|
+
@target.notification_index_with_attributes(limit)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def set_view_prefixes
|
|
103
|
+
lookup_context.prefixes.prepend(target_view_path)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def return_back_or_ajax(filter, limit)
|
|
107
|
+
respond_to do |format|
|
|
108
|
+
if request.xhr?
|
|
109
|
+
format.js
|
|
110
|
+
elsif request.referer
|
|
111
|
+
redirect_to :back, filter: filter, limit: limit and return
|
|
112
|
+
else
|
|
113
|
+
redirect_to action: :index, filter: filter, limit: limit and return
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
class NotificationsWithDeviseController < NotificationsController
|
|
3
|
+
prepend_before_action :authenticate_devise_resource!
|
|
4
|
+
before_action :authenticate_target!
|
|
5
|
+
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def authenticate_devise_resource!
|
|
9
|
+
authenticate_method_name = "authenticate_#{params[:devise_type].to_resource_name}!"
|
|
10
|
+
if respond_to?(authenticate_method_name)
|
|
11
|
+
send(authenticate_method_name)
|
|
12
|
+
else
|
|
13
|
+
render text: "403 Forbidden: Unauthenticated", status: 403
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def authenticate_target!
|
|
18
|
+
current_resource_method_name = "current_#{params[:devise_type].to_resource_name}"
|
|
19
|
+
if respond_to?(current_resource_method_name)
|
|
20
|
+
unless @target.authenticate_with_devise?(send(current_resource_method_name))
|
|
21
|
+
render text: "403 Forbidden: Unauthorized target", status: 403
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
render text: "403 Forbidden: Unauthenticated", status: 403
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
if defined?(ActionMailer)
|
|
2
|
+
class ActivityNotification::Mailer < ActivityNotification.config.parent_mailer.constantize
|
|
3
|
+
include ActivityNotification::Mailers::Helpers
|
|
4
|
+
|
|
5
|
+
def send_notification_email(notification)
|
|
6
|
+
if notification.target.notification_email_allowed?(notification.notifiable, notification.key) and
|
|
7
|
+
notification.notifiable.notification_email_allowed?(notification.target, notification.key)
|
|
8
|
+
notification_mail(notification)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<li>
|
|
2
|
+
<div>
|
|
3
|
+
<%= notification.notifier.present? ? notification.notifier.printable_name : 'Someone' %>
|
|
4
|
+
<% if notification.group_member_exists? %>
|
|
5
|
+
<%= " and other #{notification.group_member_count} people" %>
|
|
6
|
+
<% end %>
|
|
7
|
+
notified you of <%= notification.notifiable.printable_name %>
|
|
8
|
+
<%= "in #{notification.group.printable_name}" if notification.group.present? %>
|
|
9
|
+
</div>
|
|
10
|
+
<div>
|
|
11
|
+
<%= notification.opened? ? "Opened" : "Unopened" %>
|
|
12
|
+
</div>
|
|
13
|
+
<div>
|
|
14
|
+
<%= link_to "Move", move_notification_path_for(notification) %>
|
|
15
|
+
</div>
|
|
16
|
+
<% if notification.unopened? %>
|
|
17
|
+
<div>
|
|
18
|
+
<%= link_to "Open and move (GET)", move_notification_path_for(notification, open: true) %>
|
|
19
|
+
</div>
|
|
20
|
+
<div>
|
|
21
|
+
<%= link_to "Open and move (POST)", open_notification_path_for(notification, move: true), method: :post %>
|
|
22
|
+
</div>
|
|
23
|
+
<div>
|
|
24
|
+
<%= link_to "Open", open_notification_path_for(notification, filter: params[:filter], limit: params[:limit]), method: :post %>
|
|
25
|
+
</div>
|
|
26
|
+
<div>
|
|
27
|
+
<%= link_to "Open (Ajax)", open_notification_path_for(notification, filter: params[:filter], limit: params[:limit]), method: :post, remote: true %>
|
|
28
|
+
</div>
|
|
29
|
+
<% end %>
|
|
30
|
+
<div>
|
|
31
|
+
<%= link_to "Destroy", notification_path_for(notification, filter: params[:filter], limit: params[:limit]), method: :delete %>
|
|
32
|
+
</div>
|
|
33
|
+
<div>
|
|
34
|
+
<%= link_to "Destroy (Ajax)", notification_path_for(notification, filter: params[:filter], limit: params[:limit]), method: :delete, remote: true %>
|
|
35
|
+
</div>
|
|
36
|
+
</li>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<%= link_to open_all_notifications_path_for(@target), method: :post, remote: true do %>
|
|
3
|
+
<div id="notification_count"><%= @target.unopened_notification_count %></div>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<div id="notification_index">
|
|
7
|
+
<%= yield :notification_index %>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<h1>Notifications for <%= @target.printable_name %></h1>
|
|
2
|
+
<div id="notification_count"><%= @target.unopened_notification_count %></div>
|
|
3
|
+
|
|
4
|
+
<div>
|
|
5
|
+
<%= link_to "Open all", open_all_notifications_path_for(@target), method: :post %>
|
|
6
|
+
</div>
|
|
7
|
+
<div>
|
|
8
|
+
<%= link_to "Open all (ajax)", open_all_notifications_path_for(@target), method: :post, remote: true %>
|
|
9
|
+
</div>
|
|
10
|
+
<ul>
|
|
11
|
+
<div id="notifications">
|
|
12
|
+
<%= render_notification(@notifications, fallback: :default) %>
|
|
13
|
+
<%#= render_notification(@notifications, fallback: :text) %>
|
|
14
|
+
</div>
|
|
15
|
+
</ul>
|
|
16
|
+
|
|
17
|
+
<%#= render_notifications_of @target, fallback: :default, index_content: :with_attributes %>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
require 'active_support'
|
|
3
|
+
require 'action_view'
|
|
4
|
+
|
|
5
|
+
module ActivityNotification
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
extend ActiveSupport::Autoload
|
|
8
|
+
|
|
9
|
+
autoload :Notification, 'activity_notification/models/notification'
|
|
10
|
+
autoload :Target, 'activity_notification/models/target'
|
|
11
|
+
autoload :Notifiable, 'activity_notification/models/notifiable'
|
|
12
|
+
autoload :ActsAsTarget, 'activity_notification/roles/acts_as_target'
|
|
13
|
+
autoload :ActsAsNotifiable, 'activity_notification/roles/acts_as_notifiable'
|
|
14
|
+
autoload :StoreController, 'activity_notification/controllers/store_controller'
|
|
15
|
+
autoload :NotificationApi, 'activity_notification/apis/notification_api'
|
|
16
|
+
autoload :Common
|
|
17
|
+
autoload :Config
|
|
18
|
+
autoload :Renderable
|
|
19
|
+
autoload :VERSION
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
module Mailers
|
|
23
|
+
autoload :Helpers, 'activity_notification/mailers/helpers'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns ActivityNotification's configuration object.
|
|
27
|
+
def self.config
|
|
28
|
+
@config ||= ActivityNotification::Config.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Lets you set global configuration options.
|
|
32
|
+
#
|
|
33
|
+
# All available options and their defaults are in the example below:
|
|
34
|
+
# @example Initializer for Rails
|
|
35
|
+
# ActivityNotification.configure do |config|
|
|
36
|
+
# config.enabled = false
|
|
37
|
+
# config.table_name = "notifications"
|
|
38
|
+
# ...
|
|
39
|
+
# end
|
|
40
|
+
def self.configure(&block)
|
|
41
|
+
yield(config) if block_given?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Load ActivityNotification helpers
|
|
47
|
+
require 'activity_notification/helpers/polymorphic_helpers'
|
|
48
|
+
require 'activity_notification/helpers/view_helpers'
|
|
49
|
+
|
|
50
|
+
# Define Rails::Engine
|
|
51
|
+
require 'activity_notification/rails'
|
|
52
|
+
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module ActivityNotification
|
|
2
|
+
module NotificationApi
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
# Define store_notification as private clas method
|
|
6
|
+
included do
|
|
7
|
+
private_class_method :store_notification
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# For notification API
|
|
11
|
+
class_methods do
|
|
12
|
+
def notify(target_type, notifiable, options = {})
|
|
13
|
+
targets = notifiable.notification_targets(target_type, options[:key])
|
|
14
|
+
unless targets.blank?
|
|
15
|
+
notify_all(targets, notifiable, options)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def notify_all(targets, notifiable, options = {})
|
|
20
|
+
targets.each do |target|
|
|
21
|
+
notify_to(target, notifiable, options)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def notify_to(target, notifiable, options = {})
|
|
26
|
+
send_email = options.has_key?(:send_email) ? options[:send_email] : true
|
|
27
|
+
send_later = options.has_key?(:send_later) ? options[:send_later] : true
|
|
28
|
+
# Store notification
|
|
29
|
+
notification = store_notification(target, notifiable, options)
|
|
30
|
+
# Send notification email
|
|
31
|
+
notification.send_notification_email(send_later) if send_email
|
|
32
|
+
notification
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Open all notifications of specified target
|
|
36
|
+
def open_all_of(target, opened_at = nil)
|
|
37
|
+
opened_at = DateTime.now if opened_at.blank?
|
|
38
|
+
Notification.where(target: target, opened_at: nil).update_all(opened_at: opened_at)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#TODO description
|
|
42
|
+
# Call from controllers or views to avoid N+1
|
|
43
|
+
def group_member_exists?(notifications)
|
|
44
|
+
Notification.where(group_owner_id: notifications.pluck(:id)).exists?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def available_options
|
|
48
|
+
[:key, :group, :parameters, :notifier, :send_email, :send_later].freeze
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Private class methods
|
|
52
|
+
|
|
53
|
+
def store_notification(target, notifiable, options = {})
|
|
54
|
+
target_type = target.to_class_name
|
|
55
|
+
key = options[:key] || notifiable.default_notification_key
|
|
56
|
+
group = options[:group] || notifiable.notification_group(target_type, key)
|
|
57
|
+
notifier = options[:notifier] || notifiable.notifier(target_type, key)
|
|
58
|
+
parameters = options[:parameters] || {}
|
|
59
|
+
parameters.merge!(options.except(*available_options))
|
|
60
|
+
parameters.merge!(notifiable.notification_parameters(target_type, key))
|
|
61
|
+
|
|
62
|
+
# Bundle notification group by target, notifiable_type, group and key
|
|
63
|
+
# Defferent notifiable.id can be made in a same group
|
|
64
|
+
group_owner = Notification.where(target: target, notifiable_type: notifiable.to_class_name, key: key, group: group)
|
|
65
|
+
.where(group_owner_id: nil, opened_at: nil).earliest
|
|
66
|
+
if group.present? and group_owner.present?
|
|
67
|
+
create(target: target, notifiable: notifiable, key: key, group: group, group_owner: group_owner, parameters: parameters, notifier: notifier)
|
|
68
|
+
else
|
|
69
|
+
create(target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# Public instance methods
|
|
76
|
+
|
|
77
|
+
def send_notification_email(send_later = true)
|
|
78
|
+
if send_later
|
|
79
|
+
Mailer.send_notification_email(self).deliver_later
|
|
80
|
+
else
|
|
81
|
+
Mailer.send_notification_email(self).deliver_now
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def open!(opened_at = nil)
|
|
86
|
+
opened_at = DateTime.now if opened_at.blank?
|
|
87
|
+
update(opened_at: opened_at)
|
|
88
|
+
group_members.update_all(opened_at: opened_at)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def unopened?
|
|
92
|
+
!opened?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def opened?
|
|
96
|
+
opened_at.present?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def group_owner?
|
|
100
|
+
group_owner_id.blank?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def group_member?
|
|
104
|
+
group_owner_id.present?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Cache group-by query result to avoid N+1 call
|
|
108
|
+
def group_member_exists?(limit = ActivityNotification.config.opened_limit)
|
|
109
|
+
group_member_count(limit) > 0
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Cache group-by query result to avoid N+1 call
|
|
113
|
+
def group_member_count(limit = ActivityNotification.config.opened_limit)
|
|
114
|
+
notification = group_member? ? group_owner : self
|
|
115
|
+
notification.opened? ?
|
|
116
|
+
notification.opened_group_member_count(limit) :
|
|
117
|
+
notification.unopened_group_member_count
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def notifiale_path
|
|
121
|
+
notifiable.notifiable_path(target_type)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Protected instance methods
|
|
126
|
+
protected
|
|
127
|
+
|
|
128
|
+
def unopened_group_member_count
|
|
129
|
+
# Cache group-by query result to avoid N+1 call
|
|
130
|
+
unopened_group_member_counts = target.notifications
|
|
131
|
+
.unopened_index_group_members_only
|
|
132
|
+
.group(:group_owner_id)
|
|
133
|
+
.count
|
|
134
|
+
unopened_group_member_counts[id] || 0
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def opened_group_member_count(limit = ActivityNotification.config.opened_limit)
|
|
138
|
+
# Cache group-by query result to avoid N+1 call
|
|
139
|
+
opened_group_member_counts = target.notifications
|
|
140
|
+
.opened_index_group_members_only(limit)
|
|
141
|
+
.group(:group_owner_id)
|
|
142
|
+
.count
|
|
143
|
+
opened_group_member_counts[id] || 0
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|