Commit 9a226174cb2a5313328d96f65fefc5f774b9daac

Authored by Victor Costa
1 parent c9eccb09

Send network activity by email

app/helpers/person_notifier_helper.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +module PersonNotifierHelper
  2 +
  3 + include ApplicationHelper
  4 +
  5 + private
  6 +
  7 + def path_to_image(source)
  8 + top_url + source
  9 + end
  10 +
  11 + def top_url
  12 + top_url = @profile.environment ? @profile.environment.top_url : ''
  13 + end
  14 +
  15 +end
... ...
app/models/person.rb
... ... @@ -491,6 +491,17 @@ class Person < Profile
491 491 gravatar_profile_image_url(self.email, :size=>20, :d => gravatar_default)
492 492 end
493 493  
  494 + settings_items :last_notification, :type => DateTime
  495 + settings_items :notification_time, :type => :integer, :default => 0
  496 +
  497 + def notifier
  498 + @notifier ||= PersonNotifier.new(self)
  499 + end
  500 +
  501 + after_update do |person|
  502 + person.notifier.reschedule_next_notification_mail
  503 + end
  504 +
494 505 protected
495 506  
496 507 def followed_by?(profile)
... ...
app/models/person_notifier.rb 0 → 100644
... ... @@ -0,0 +1,87 @@
  1 +class PersonNotifier
  2 +
  3 + def initialize(person)
  4 + @person = person
  5 + end
  6 +
  7 + def self.schedule_all_next_notification_mail
  8 + Delayed::Job.enqueue(NotifyAllJob.new) unless NotifyAllJob.exists?
  9 + end
  10 +
  11 + def schedule_next_notification_mail
  12 + dispatch_notification_mail if !NotifyJob.exists?(@person.id)
  13 + end
  14 +
  15 + def dispatch_notification_mail
  16 + Delayed::Job.enqueue(NotifyJob.new(@person.id), nil, @person.notification_time.hours.from_now) if @person.notification_time>0
  17 + end
  18 +
  19 + def reschedule_next_notification_mail
  20 + return nil unless @person.setting_changed?(:notification_time) || @person.setting_changed?(:last_notification)
  21 + NotifyJob.find(@person.id).delete_all
  22 + schedule_next_notification_mail
  23 + end
  24 +
  25 + def notify
  26 + if @person.notification_time && @person.notification_time > 0
  27 + from = @person.last_notification || DateTime.now - @person.notification_time.hours
  28 + notifications = @person.tracked_notifications.find(:all, :conditions => ["created_at > ?", from])
  29 + Mailer::deliver_content_summary(@person, notifications) unless notifications.empty?
  30 + @person.settings[:last_notification] = DateTime.now
  31 + @person.save!
  32 + end
  33 + end
  34 +
  35 + class NotifyAllJob
  36 + def self.exists?
  37 + Delayed::Job.where(:handler => "--- !ruby/object:PersonNotifier::NotifyAllJob {}\n\n").count > 0
  38 + end
  39 +
  40 + def perform
  41 + Person.find_each {|person| person.notifier.schedule_next_notification_mail }
  42 + end
  43 + end
  44 +
  45 + class NotifyJob < Struct.new(:person_id)
  46 +
  47 + def self.exists?(person_id)
  48 + !find(person_id).empty?
  49 + end
  50 +
  51 + def self.find(person_id)
  52 + Delayed::Job.where(:handler => "--- !ruby/struct:PersonNotifier::NotifyJob \nperson_id: #{person_id}\n")
  53 + end
  54 +
  55 + def perform
  56 + Person.find(person_id).notifier.notify
  57 + end
  58 +
  59 + def on_permanent_failure
  60 + person = Person.find(person_id)
  61 + person.notifier.dispatch_notification_mail
  62 + end
  63 +
  64 + end
  65 +
  66 + class Mailer < ActionMailer::Base
  67 +
  68 + add_template_helper(PersonNotifierHelper)
  69 +
  70 + def session
  71 + {:theme => nil}
  72 + end
  73 +
  74 + def content_summary(person, notifications)
  75 + @current_theme = 'default'
  76 + @profile = person
  77 + recipients person.email
  78 + from "#{@profile.environment.name} <#{@profile.environment.contact_email}>"
  79 + subject _("[%s] Network Activity") % [@profile.environment.name]
  80 + body :recipient => @profile.nickname || @profile.name,
  81 + :environment => @profile.environment.name,
  82 + :url => @profile.environment.top_url,
  83 + :notifications => notifications
  84 + content_type "text/html"
  85 + end
  86 + end
  87 +end
... ...
app/views/person_notifier/mailer/_add_member_in_community.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => { :activity => activity } %>
... ...
app/views/person_notifier/mailer/_comment.rhtml 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +<% Comment %>
  2 +<% Profile %>
  3 +<% Person %>
  4 +
  5 +<table style="background: #f0f0f1;border-bottom: 1px solid #d2d2d2 !important;border-top: 1px solid #fff;margin-bottom: 0;">
  6 +<tr>
  7 + <td>
  8 + <% if comment.author %>
  9 + <%= link_to profile_image(comment.author, :minor),
  10 + comment.author_url,
  11 + :class => 'comment-picture',
  12 + :title => comment.author_name
  13 + %>
  14 + <% end %>
  15 + </td>
  16 + <td>
  17 + <%= comment.author.present? ? link_to(comment.author_name, comment.author.url, :style => "font-size: 12px; color: #333; font-weight: bold; text-decoration: none;") : content_tag('strong', comment.author_name) %>
  18 + <% unless comment.title.blank? %>
  19 + <span style="font-size: 12px;"><%= comment.title %></span><br/>
  20 + <% end %>
  21 + <span style="font-size: 10px;"><%= txt2html comment.body %></span><br/>
  22 + <span style="font-size: 8px; color: #444444"><%= time_ago_as_sentence(comment.created_at) %></span>
  23 + <br style="clear: both;" />
  24 +
  25 + <% unless comment.replies.blank? %>
  26 + <ul class="comment-replies">
  27 + <% comment.replies.each do |reply| %>
  28 + <%= render :partial => 'comment', :locals => { :comment => reply } %>
  29 + <% end %>
  30 + </ul>
  31 + <% end %>
  32 + </td>
  33 +</table>
... ...
app/views/person_notifier/mailer/_create_article.rhtml 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +<table>
  2 +<tr>
  3 + <td>
  4 + <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  5 + </td>
  6 + <td>
  7 + <p style="width:550px">
  8 + <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span>
  9 + <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span>
  10 + <span style="font-size: 10px; color: #444444; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  11 + </p>
  12 + <p>
  13 + <span style="font-size: 14px;"><%= link_to(activity.params['name'], activity.params['url'], :style => "color: #333; font-weight: bold; text-decoration: none;") %></span>
  14 + <br/>
  15 + <span title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-new<%= activity.target.class.icon_name %>'></span>
  16 + <%= image_tag(activity.params['first_image']) unless activity.params['first_image'].blank? %><%= strip_tags(truncate(activity.params['lead'], :length => 1000, :ommision => '...')).gsub(/(\xC2\xA0|\s)+/, ' ').gsub(/^\s+/, '') %>
  17 + </p>
  18 + <p><%= content_tag(:p, link_to(_('See complete forum'), activity.get_url), :class => 'see-forum') if activity.target.is_a?(Forum) %></p>
  19 + </td>
  20 +</tr>
  21 +<tr>
  22 + <td></td>
  23 + <td>
  24 + <%= render :partial => 'profile_comments', :locals => { :activity => activity } %>
  25 + </td>
  26 +</tr>
  27 +</table>
... ...
app/views/person_notifier/mailer/_default_activity.rhtml 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +<table>
  2 +<tr>
  3 + <td>
  4 + <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  5 + </td>
  6 + <td>
  7 + <p style="width:550px">
  8 + <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
  9 + <span style="font-size: 10px; color: #444444; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  10 + </p>
  11 + </td>
  12 +</tr>
  13 +<tr>
  14 + <td></td>
  15 + <td>
  16 + <%= render :partial => 'profile_comments', :locals => { :activity => activity } %>
  17 + </td>
  18 +</tr>
  19 +</table>
... ...
app/views/person_notifier/mailer/_join_community.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => { :activity => activity } %>
... ...
app/views/person_notifier/mailer/_leave_scrap.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => { :activity => activity } %>
... ...
app/views/person_notifier/mailer/_leave_scrap_to_self.rhtml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +_leave_scrap.rhtml
0 2 \ No newline at end of file
... ...
app/views/person_notifier/mailer/_new_friendship.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => { :activity => activity } %>
... ...
app/views/person_notifier/mailer/_profile_comments.rhtml 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +<% if activity.comments_count > 2 %>
  2 + <div style="font-size: 10px;">
  3 + <% if activity.params['url'].blank? %>
  4 + <%= _("%s comments") % activity.comments_count %>
  5 + <% else %>
  6 + <%= link_to(_("View all %s comments") % activity.comments_count, activity.params['url']) %>
  7 + <% end %>
  8 + </div>
  9 +<% else %>
  10 + <ul>
  11 + <%= render :partial => 'comment', :collection => activity.comments_as_thread %>
  12 + </ul>
  13 +<% end %>
... ...
app/views/person_notifier/mailer/_reply_scrap_on_self.rhtml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +_leave_scrap.rhtml
0 2 \ No newline at end of file
... ...
app/views/person_notifier/mailer/_upload_image.rhtml 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +<table>
  2 + <tr>
  3 + <td>
  4 + <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  5 + </td>
  6 + <td>
  7 + <p style="width:550px">
  8 + <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
  9 + <span style="font-size: 10px; color: #444444; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  10 + </p>
  11 + </td>
  12 +</tr>
  13 +</table>
  14 +<div title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div>
  15 +<br/>
... ...
app/views/person_notifier/mailer/content_summary.rhtml 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +<h3><%= _("%s's network activity") % @profile.name %></h3>
  2 +<br/>
  3 +<div>
  4 +<% @notifications.each do |activity| %>
  5 + <div style="border-left:none;border-right:none;border-top:1px solid #ccc;border-bottom:none;padding:10px;width:600px">
  6 + <%= render :partial => activity.verb, :locals => { :activity => activity } rescue "cannot render notification for #{activity.verb}" %>
  7 + </div>
  8 +<% end %>
  9 +</div>
  10 +
  11 +<div style="color:#444444;font-size:11px;">
  12 +<p><%= _("Greetings,") %></p>
  13 +<br/>
  14 +<p>--</p>
  15 +<p><%= _('%s team.') % @environment %></p>
  16 +<p><%= url_for @url %></p>
  17 +</div>
  18 +<br/>
... ...
app/views/profile_editor/_person.rhtml
... ... @@ -19,3 +19,9 @@
19 19 <%= @plugins.dispatch(:profile_info_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
20 20  
21 21 <%= render :partial => 'person_form', :locals => {:f => f} %>
  22 +
  23 + <h2><%= _('Notification options') %></h2>
  24 + <div>
  25 + <%= select_tag 'profile_data[notification_time]', options_for_select([[_('Disabled'), 0], [_('Hourly'), 1], [_('Half Day'), 12], [_('Daily'), 24]], @profile.notification_time) %>
  26 + </div>
  27 +
... ...
config/initializers/delayed_job_config.rb
1 1 Delayed::Worker.backend = :active_record
2 2 Delayed::Worker.max_attempts = 2
3 3 Delayed::Worker.max_run_time = 10.minutes
  4 +Delayed::Worker.destroy_failed_jobs = false
... ...
config/initializers/person_notification.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +PersonNotifier.schedule_all_next_notification_mail
... ...
lib/acts_as_having_settings.rb
... ... @@ -14,6 +14,17 @@ module ActsAsHavingSettings
14 14 def #{settings_field}
15 15 self[:#{settings_field}] ||= Hash.new
16 16 end
  17 +
  18 + def setting_changed?(setting_field)
  19 + setting_field = setting_field.to_sym
  20 + changed_settings = self.changes['#{settings_field}']
  21 + return false if changed_settings.nil?
  22 +
  23 + old_setting_value = changed_settings.first.nil? ? nil : changed_settings.first[setting_field]
  24 + new_setting_value = changed_settings.last[setting_field]
  25 + old_setting_value != new_setting_value
  26 + end
  27 +
17 28 before_save :symbolize_settings_keys
18 29 private
19 30 def symbolize_settings_keys
... ... @@ -36,11 +47,9 @@ module ActsAsHavingSettings
36 47 val.nil? ? (#{default}.is_a?(String) ? gettext(#{default}) : #{default}) : val
37 48 end
38 49 def #{setting}=(value)
39   -
40   - #UPGRADE Leandro: I add this line to save the serialize attribute
41   - send(self.class.settings_field.to_s + '_will_change!')
42   -
43   - send(self.class.settings_field)[:#{setting}] = self.class.acts_as_having_settings_type_cast(value, #{data_type.inspect})
  50 + h = send(self.class.settings_field).clone
  51 + h[:#{setting}] = self.class.acts_as_having_settings_type_cast(value, #{data_type.inspect})
  52 + send(self.class.settings_field.to_s + '=', h)
44 53 end
45 54 CODE
46 55 end
... ...
test/unit/acts_as_having_settings_test.rb
... ... @@ -80,4 +80,38 @@ class ActsAsHavingSettingsTest &lt; ActiveSupport::TestCase
80 80 assert obj.save
81 81 end
82 82  
  83 + should 'setting_changed be true if a setting passed as parameter was changed' do
  84 + obj = TestClass.new
  85 + obj.flag= true
  86 + assert obj.setting_changed? 'flag'
  87 + end
  88 +
  89 + should 'setting_changed be false if a setting passed as parameter was not changed' do
  90 + obj = TestClass.new
  91 + assert !obj.setting_changed?('flag')
  92 + end
  93 +
  94 + should 'setting_changed be false if a setting passed as parameter was changed with the same value' do
  95 + obj = TestClass.new
  96 + obj.flag= true
  97 + obj.save
  98 + obj.flag= true
  99 + assert !obj.setting_changed?('flag')
  100 + end
  101 +
  102 + should 'setting_changed be false if a setting passed as parameter was not changed but another setting is changed' do
  103 + obj = TestClass.new(:name => 'some name')
  104 + obj.save
  105 + obj.name= 'antoher nme'
  106 + assert !obj.setting_changed?('flag')
  107 + end
  108 +
  109 + should 'setting_changed be true for all changed fields' do
  110 + obj = TestClass.new(:name => 'some name', :flag => false)
  111 + obj.save
  112 + obj.name= 'another nme'
  113 + obj.flag= true
  114 + assert obj.setting_changed?('flag')
  115 + assert obj.setting_changed?('name')
  116 + end
83 117 end
... ...
test/unit/person_notifier_helper_test.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class PersonNotifierHelperTest < ActiveSupport::TestCase
  4 +
  5 + include PersonNotifierHelper
  6 + include ActionView::Helpers::TagHelper
  7 +
  8 + def setup
  9 + @profile = mock
  10 + @env = Environment.new
  11 + end
  12 + attr_reader :profile, :env
  13 +
  14 + should 'append top url of environment at image path' do
  15 + profile.expects(:environment).returns(env).at_least_once
  16 + assert_match /src="http:\/\/localhost\/image.png"/, image_tag("/image.png")
  17 + end
  18 +
  19 + should 'return original path if do not have an environment' do
  20 + profile.expects(:environment).returns(nil).at_least_once
  21 + assert_match /src="\/image.png"/, image_tag("/image.png")
  22 + end
  23 +
  24 +end
... ...
test/unit/person_notifier_test.rb 0 → 100644
... ... @@ -0,0 +1,213 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class PersonNotifierTest < ActiveSupport::TestCase
  4 + FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
  5 + CHARSET = "utf-8"
  6 +
  7 + def setup
  8 + ActionMailer::Base.delivery_method = :test
  9 + ActionMailer::Base.perform_deliveries = true
  10 + ActionMailer::Base.deliveries = []
  11 + Person.destroy_all
  12 + @admin = create_user('adminuser').person
  13 + @member = create_user('member').person
  14 + @admin.notification_time = 24
  15 + @member.notification_time = 24
  16 + @admin.save!
  17 + @member.save!
  18 + @community = fast_create(Community)
  19 + @community.add_member(@admin)
  20 + @article = fast_create(TextileArticle, :name => 'Article test', :profile_id => @community.id, :notify_comments => true)
  21 + Delayed::Job.destroy_all
  22 + end
  23 +
  24 + should 'deliver mail to community members' do
  25 + @community.add_member(@member)
  26 + notify
  27 + sent = ActionMailer::Base.deliveries.first
  28 + assert_equal [@member.email], sent.to
  29 + end
  30 +
  31 + should 'do not send mail if do not have notifications' do
  32 + @community.add_member(@member)
  33 + ActionTracker::Record.delete_all
  34 + notify
  35 + assert ActionMailer::Base.deliveries.empty?
  36 + end
  37 +
  38 + should 'do not send mail to people not joined to community' do
  39 + Comment.create!(:author => @admin, :title => 'test comment 2', :body => 'body 2!', :source => @article)
  40 + notify
  41 + sent = ActionMailer::Base.deliveries.first
  42 + assert !sent
  43 + end
  44 +
  45 + should 'display author name in delivered mail' do
  46 + @community.add_member(@member)
  47 + Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article)
  48 + notify
  49 + sent = ActionMailer::Base.deliveries.first
  50 + assert_match /#{@admin.name}/, sent.body
  51 + end
  52 +
  53 + should 'do not include comment created before last notification' do
  54 + @community.add_member(@member)
  55 + ActionTracker::Record.delete_all
  56 + comment = Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article )
  57 + @member.last_notification = DateTime.now + 1.day
  58 + notify
  59 + assert ActionMailer::Base.deliveries.empty?
  60 + end
  61 +
  62 + should 'update last notification date' do
  63 + Comment.create!(:author => @admin, :title => 'test comment 2', :body => 'body 2!', :source => @article)
  64 + @community.add_member(@member)
  65 + assert_equal nil, @member.last_notification
  66 + notify
  67 + assert @member.last_notification
  68 + end
  69 +
  70 + should 'reschedule after notification' do
  71 + Comment.create!(:author => @admin, :title => 'test comment 2', :body => 'body 2!', :source => @article)
  72 + @community.add_member(@member)
  73 + assert_equal nil, @member.last_notification
  74 + notify
  75 + assert PersonNotifier::NotifyJob.find(@member.id)
  76 + end
  77 +
  78 + should 'schedule next mail at notification time' do
  79 + @member.notification_time = 12
  80 + @member.notifier.schedule_next_notification_mail
  81 + assert_equal @member.notification_time, ((Delayed::Job.first.run_at - DateTime.now)/1.hour).round
  82 + end
  83 +
  84 + should 'do not schedule duplicated notification mail' do
  85 + @member.notification_time = 12
  86 + @member.notifier.schedule_next_notification_mail
  87 + @member.notifier.schedule_next_notification_mail
  88 + assert_equal 1, Delayed::Job.count
  89 + end
  90 +
  91 + should 'do not schedule next mail if notification time is zero' do
  92 + @member.notification_time = 0
  93 + @member.notifier.schedule_next_notification_mail
  94 + assert_equal 0, Delayed::Job.count
  95 + end
  96 +
  97 + should 'schedule next notifications for all person with notification time greater than zero' do
  98 + @member.notification_time = 1
  99 + @admin.notification_time = 0
  100 + @admin.save!
  101 + @member.save!
  102 + Delayed::Job.delete_all
  103 + PersonNotifier.schedule_all_next_notification_mail
  104 + process_delayed_job_queue
  105 + assert_equal 1, Delayed::Job.count
  106 + end
  107 +
  108 + should 'do not create duplicated job' do
  109 + PersonNotifier.schedule_all_next_notification_mail
  110 + PersonNotifier.schedule_all_next_notification_mail
  111 + assert_equal 1, Delayed::Job.count
  112 + end
  113 +
  114 + should 'schedule after update and set a valid notification time' do
  115 + @member.notification_time = 0
  116 + @member.save!
  117 + assert_equal 0, Delayed::Job.count
  118 + @member.notification_time = 12
  119 + @member.save!
  120 + assert_equal 1, Delayed::Job.count
  121 + end
  122 +
  123 + should 'reschedule with changed notification time' do
  124 + @member.notification_time = 2
  125 + @member.save!
  126 + assert_equal 1, Delayed::Job.count
  127 + @member.notification_time = 12
  128 + @member.save!
  129 + assert_equal 1, Delayed::Job.count
  130 + assert_equal @member.notification_time, ((Delayed::Job.first.run_at - DateTime.now)/1.hour).round
  131 + end
  132 +
  133 + should 'display error message if fail to render a notificiation' do
  134 + @community.add_member(@member)
  135 + Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article)
  136 + ActionTracker::Record.any_instance.stubs(:verb).returns("some_invalid_verb")
  137 + notify
  138 + sent = ActionMailer::Base.deliveries.first
  139 + assert_match /cannot render notification for some_invalid_verb/, sent.body
  140 + end
  141 +
  142 + ActionTrackerConfig.verb_names.each do |verb|
  143 + should "render notification for verb #{verb}" do
  144 + action = mock()
  145 + action.stubs(:verb).returns(verb)
  146 + action.stubs(:user).returns(@member)
  147 + action.stubs(:created_at).returns(DateTime.now)
  148 + action.stubs(:target).returns(fast_create(Forum))
  149 + action.stubs(:comments_count).returns(0)
  150 + action.stubs(:comments_as_thread).returns([])
  151 + action.stubs(:params).returns({'name' => 'home', 'url' => '/', 'lead' => ''})
  152 + action.stubs(:get_url).returns('')
  153 +
  154 + notifications = []
  155 + notifications.stubs(:find).returns([action])
  156 + Person.any_instance.stubs(:tracked_notifications).returns(notifications)
  157 +
  158 + notify
  159 + sent = ActionMailer::Base.deliveries.first
  160 + assert_no_match /cannot render notification for #{verb}/, sent.body
  161 + end
  162 + end
  163 +
  164 + should 'exists? method in NotifyAllJob return false if there is no instance of this class created' do
  165 + Delayed::Job.enqueue(PersonNotifier::NotifyJob.new)
  166 + assert !PersonNotifier::NotifyAllJob.exists?
  167 + end
  168 +
  169 + should 'exists? method in NotifyAllJob return false if there is no jobs created' do
  170 + assert !PersonNotifier::NotifyAllJob.exists?
  171 + end
  172 +
  173 + should 'exists? method in NotifyAllJob return true if there is at least one instance of this class' do
  174 + Delayed::Job.enqueue(PersonNotifier::NotifyAllJob.new)
  175 + assert PersonNotifier::NotifyAllJob.exists?
  176 + end
  177 +
  178 + should 'perform create NotifyJob for all users with notification_time' do
  179 + Delayed::Job.enqueue(PersonNotifier::NotifyAllJob.new)
  180 + process_delayed_job_queue
  181 + assert_equal 2, Delayed::Job.count
  182 + end
  183 +
  184 + should 'perform create NotifyJob for all users with notification_time defined greater than zero' do
  185 + @member.notification_time = 1
  186 + @admin.notification_time = 0
  187 + @admin.save!
  188 + @member.save!
  189 + Delayed::Job.delete_all
  190 + Delayed::Job.enqueue(PersonNotifier::NotifyAllJob.new)
  191 + process_delayed_job_queue
  192 + assert_equal 1, Delayed::Job.count
  193 + end
  194 +
  195 + should 'NotifyJob failed jobs create a new NotifyJob on permanent failure' do
  196 + Delayed::Job.enqueue(PersonNotifier::NotifyJob.new(@member.id))
  197 +
  198 + PersonNotifier.any_instance.stubs(:notify).raises('error')
  199 +
  200 + process_delayed_job_queue
  201 + jobs = Delayed::Job.all
  202 +
  203 + assert 1, jobs.select{|j| j.failed?}.size
  204 + assert 1, jobs.select{|j| !j.failed?}.size
  205 + end
  206 +
  207 + def notify
  208 + ActionTracker::Record.all.map{|action| Person.notify_activity(action)}
  209 + process_delayed_job_queue
  210 + @member.notifier.notify
  211 + end
  212 +
  213 +end
... ...
test/unit/person_test.rb
... ... @@ -1413,4 +1413,10 @@ class PersonTest &lt; ActiveSupport::TestCase
1413 1413 person.reload
1414 1414 assert_equal person.activities, []
1415 1415 end
  1416 +
  1417 + should 'person notifier be PersonNotifier class' do
  1418 + p = Person.new
  1419 + assert p.notifier.kind_of?(PersonNotifier)
  1420 + end
  1421 +
1416 1422 end
... ...