diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 3f69849e2..2fc4611cf 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -9,34 +9,18 @@ module NotificationsHelper def object_link(note, actors) target_type = note.popup_translation_key actors_count = note.actors.count + if note.instance_of?(Notifications::Mentioned) - post = Mention.find(note.target_id).post - if post + if post = note.linked_object translation(target_type, :actors => actors, :count => actors_count, :post_link => link_to(t('notifications.post'), post_path(post)).html_safe) else - t('notifications.mentioned_deleted', :actors => actors, :count => actors_count).html_safe + t(note.deleted_translation_key, :actors => actors, :count => actors_count).html_safe end - elsif note.instance_of?(Notifications::CommentOnPost) - post = Post.where(:id => note.target_id).first - if post - translation(target_type, :actors => actors, :count => actors_count, :post_link => link_to(t('notifications.post'), post_path(post), 'data-ref' => post.id, :class => 'hard_object_link').html_safe) - else - t('notifications.also_commented_deleted', :actors => actors, :count => actors_count).html_safe - end - elsif note.instance_of?(Notifications::AlsoCommented) - post = Post.where(:id => note.target_id).first - if post + elsif note.instance_of?(Notifications::CommentOnPost) || note.instance_of?(Notifications::AlsoCommented) || note.instance_of?(Notifications::Reshared) || note.instance_of?(Notifications::Liked) + if post = note.linked_object translation(target_type, :actors => actors, :count => actors_count, :post_author => h(post.author.name), :post_link => link_to(t('notifications.post'), post_path(post), 'data-ref' => post.id, :class => 'hard_object_link').html_safe) else - t('notifications.also_commented_deleted', :actors => actors, :count => actors_count).html_safe - end - elsif note.instance_of?(Notifications::Liked) - post = note.target - post = post.target if post.is_a? Like - if post - translation(target_type, :actors => actors, :count => actors_count, :post_author => h(post.author.name), :post_link => link_to(t('notifications.post'), post_path(post), 'data-ref' => post.id, :class => 'hard_object_link').html_safe) - else - t('notifications.liked_post_deleted', :actors => actors, :count => actors_count).html_safe + t(note.deleted_translation_key, :actors => actors, :count => actors_count).html_safe end else #Notifications:StartedSharing, etc. translation(target_type, :actors => actors, :count => actors_count) diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index 76387c56d..eb51fd1d8 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -51,6 +51,19 @@ class Notifier < ActionMailer::Base end end + def reshared(recipient_id, sender_id, reshare_id) + @receiver = User.find_by_id(recipient_id) + @sender = Person.find_by_id(sender_id) + @reshare = Reshare.find(reshare_id) + + log_mail(recipient_id, sender_id, 'reshared') + + I18n.with_locale(@receiver.language) do + mail(:to => "\"#{@receiver.name}\" <#{@receiver.email}>", + :subject => I18n.t('notifier.reshared.reshared', :name => @sender.name), :host => AppConfig[:pod_uri].host) + end + end + def mentioned(recipient_id, sender_id, target_id) @receiver = User.find_by_id(recipient_id) @sender = Person.find_by_id(sender_id) diff --git a/app/models/job/mail/reshared.rb b/app/models/job/mail/reshared.rb new file mode 100644 index 000000000..5dd92dec3 --- /dev/null +++ b/app/models/job/mail/reshared.rb @@ -0,0 +1,11 @@ +module Job + module Mail + class Reshared < Base + @queue = :mail + def self.perform(recipient_id, sender_id, reshare_id) + Notifier.reshared(recipient_id, sender_id, reshare_id).deliver + end + end + end +end + diff --git a/app/models/job/receive_local_batch.rb b/app/models/job/receive_local_batch.rb index cc42d1cfa..d7e0801d6 100644 --- a/app/models/job/receive_local_batch.rb +++ b/app/models/job/receive_local_batch.rb @@ -13,6 +13,7 @@ module Job create_visibilities(post, recipient_user_ids) socket_to_users(post, recipient_user_ids) if post.respond_to?(:socket_to_user) notify_mentioned_users(post) + notify_users(post, recipient_user_ids) end def self.create_visibilities(post, recipient_user_ids) @@ -32,15 +33,25 @@ module Job end end + def self.socket_to_users(post, recipient_user_ids) recipient_user_ids.each do |id| post.socket_to_user(id) end end + def self.notify_mentioned_users(post) post.mentions.each do |mention| mention.notify_recipient end end + + def self.notify_users(post, recipient_user_ids) + if post.respond_to?(:notification_type) + recipient_user_ids.each{|id| + Notification.notify(User.find(id), post, post.author) + } + end + end end end diff --git a/app/models/notification.rb b/app/models/notification.rb index ec1dbe138..db91c05c6 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -20,6 +20,8 @@ class Notification < ActiveRecord::Base if note_type = target.notification_type(recipient, actor) if(target.is_a? Comment) || (target.is_a? Like) n = note_type.concatenate_or_create(recipient, target.parent, actor, note_type) + elsif(target.is_a? Reshare) + n = note_type.concatenate_or_create(recipient, target.root, actor, note_type) else n = note_type.make_notification(recipient, target, actor, note_type) end diff --git a/app/models/notifications/also_commented.rb b/app/models/notifications/also_commented.rb index b731ef2ca..5fc3a9664 100644 --- a/app/models/notifications/also_commented.rb +++ b/app/models/notifications/also_commented.rb @@ -2,7 +2,16 @@ class Notifications::AlsoCommented < Notification def mail_job Job::Mail::AlsoCommented end + def popup_translation_key 'notifications.also_commented' end + + def deleted_translation_key + 'notifications.also_commented_deleted' + end + + def linked_object + Post.where(:id => self.target_id).first + end end diff --git a/app/models/notifications/comment_on_post.rb b/app/models/notifications/comment_on_post.rb index 44fca16d6..f451a8613 100644 --- a/app/models/notifications/comment_on_post.rb +++ b/app/models/notifications/comment_on_post.rb @@ -2,7 +2,16 @@ class Notifications::CommentOnPost < Notification def mail_job Job::Mail::CommentOnPost end + def popup_translation_key 'notifications.comment_on_post' end + + def deleted_translation_key + 'notifications.also_commented_deleted' + end + + def linked_object + Post.where(:id => self.target_id).first + end end diff --git a/app/models/notifications/liked.rb b/app/models/notifications/liked.rb index 96ddd3a16..bab64a017 100644 --- a/app/models/notifications/liked.rb +++ b/app/models/notifications/liked.rb @@ -2,7 +2,18 @@ class Notifications::Liked < Notification def mail_job Job::Mail::Liked end + def popup_translation_key 'notifications.liked' end + + def deleted_translation_key + 'notifications.liked_post_deleted' + end + + def linked_object + post = self.target + post = post.target if post.is_a? Like + post + end end diff --git a/app/models/notifications/mentioned.rb b/app/models/notifications/mentioned.rb index 3bf93fd53..c9008936c 100644 --- a/app/models/notifications/mentioned.rb +++ b/app/models/notifications/mentioned.rb @@ -2,7 +2,16 @@ class Notifications::Mentioned < Notification def mail_job Job::Mail::Mentioned end + def popup_translation_key 'notifications.mentioned' end + + def deleted_translation_key + 'notifications.mentioned_deleted' + end + + def linked_object + Mention.find(self.target_id).post + end end diff --git a/app/models/notifications/reshared.rb b/app/models/notifications/reshared.rb new file mode 100644 index 000000000..3e8f8310b --- /dev/null +++ b/app/models/notifications/reshared.rb @@ -0,0 +1,18 @@ +class Notifications::Reshared < Notification + def mail_job + Job::Mail::Reshared + #Job::Mail::Liked + end + + def popup_translation_key + 'notifications.reshared' + end + + def deleted_translation_key + 'notifications.reshared_post_deleted' + end + + def linked_object + self.target + end +end diff --git a/app/models/reshare.rb b/app/models/reshare.rb index 2b89ccd9f..21613e29a 100644 --- a/app/models/reshare.rb +++ b/app/models/reshare.rb @@ -28,6 +28,11 @@ class Reshare < Post def comment_email_subject I18n.t('reshares.comment_email_subject', :resharer => author.name, :author => root.author.name) end + + def notification_type(user, person) + Notifications::Reshared if root.author == user.person + end + private def after_parse diff --git a/app/views/notifier/reshared.html.haml b/app/views/notifier/reshared.html.haml new file mode 100644 index 000000000..98985bd45 --- /dev/null +++ b/app/views/notifier/reshared.html.haml @@ -0,0 +1,8 @@ +%p + = "#{t('.reshared', :name => "#{@sender.name}")}:" + +%p{:style => "font-style:italic;color:#666"} + = post_message(@reshare.root, :process_newlines => true) + +%p + = link_to t('.view_post'), post_url(@reshare) diff --git a/app/views/notifier/reshared.text.haml b/app/views/notifier/reshared.text.haml new file mode 100644 index 000000000..ab9a73f7d --- /dev/null +++ b/app/views/notifier/reshared.text.haml @@ -0,0 +1,3 @@ +!= "#{t('notifier.reshared.reshared', :name => "#{@sender.name}")}:" +!=post_message(@reshare.root) + diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index c43c9b58e..c2783abcc 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -379,6 +379,12 @@ en: few: "%{actors} has just liked your %{post_link}." many: "%{actors} has just liked your %{post_link}." other: "%{actors} has just liked your %{post_link}." + reshared: + zero: "%{actors} has reshared your %{post_link}." + one: "%{actors} has reshared your %{post_link}." + few: "%{actors} has reshared your %{post_link}." + many: "%{actors} has reshared your %{post_link}." + other: "%{actors} has reshared your %{post_link}." post: "post" also_commented_deleted: zero: "%{actors} commented on a deleted post." @@ -392,6 +398,12 @@ en: few: "%{actors} liked your deleted post." many: "%{actors} liked your deleted post." other: "%{actors} liked your deleted post." + reshared_post_deleted: + zero: "%{actors} reshared your deleted post." + one: "%{actors} reshared your deleted post." + few: "%{actors} reshared your deleted post." + many: "%{actors} reshared your deleted post." + other: "%{actors} reshared your deleted post." mentioned_deleted: zero: "%{actors} mentioned you in a deleted post." one: "%{actors} mentioned you in a deleted post." @@ -440,6 +452,9 @@ en: liked: liked: "%{name} just liked your post" view_post: "View post >" + reshared: + reshared: "%{name} just reshared your post" + view_post: "View post >" confirm_email: subject: "Please activate your new email address %{unconfirmed_email}" click_link: "To activate your new email address %{unconfirmed_email}, please click this link:" diff --git a/features/notifications.feature b/features/notifications.feature index 5f6b7d254..92610b588 100644 --- a/features/notifications.feature +++ b/features/notifications.feature @@ -7,6 +7,7 @@ Feature: Notifications Background: Given a user with email "bob@bob.bob" And a user with email "alice@alice.alice" + And "alice@alice.alice" has a public post with text "check this out!" When I sign in as "bob@bob.bob" Scenario: someone shares with me @@ -20,10 +21,10 @@ Feature: Notifications Then I should see "started sharing with you" When I follow "View all" Then I should see "started sharing with you" + And I should have 1 email delivery Scenario: someone re-shares my post And a user with email "bob@bob.bob" is connected with "alice@alice.alice" - And "alice@alice.alice" has a public post with text "reshare this!" And I am on "alice@alice.alice"'s page And I preemptively confirm the alert And I follow "Reshare" @@ -35,6 +36,27 @@ Feature: Notifications And I follow "notifications" in the header And I wait for the ajax to finish Then the notification dropdown should be visible + And I wait for the ajax to finish Then I should see "reshared your post" When I follow "View all" Then I should see "reshared your post" + And I should have 1 email delivery + + Scenario: someone likes my post + And a user with email "bob@bob.bob" is connected with "alice@alice.alice" + And I am on "alice@alice.alice"'s page + And I preemptively confirm the alert + And I follow "Like" + And I wait for the ajax to finish + + And I go to the destroy user session page + When I sign in as "alice@alice.alice" + + And I follow "notifications" in the header + And I wait for the ajax to finish + Then the notification dropdown should be visible + And I wait for the ajax to finish + Then I should see "just liked your post" + When I follow "View all" + Then I should see "just liked your post" + And I should have 1 email delivery diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 278a064a8..d4a09e765 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -154,6 +154,10 @@ Then /^I should have (\d+) Devise email delivery$/ do |n| Devise.mailer.deliveries.length.should == n.to_i end +Then /^I should have (\d+) email delivery$/ do |n| + ActionMailer::Base.deliveries.length.should == n.to_i +end + When /^"([^\"]+)" has posted a status message with a photo$/ do |email| user = User.find_for_database_authentication(:username => email) diff --git a/spec/factories.rb b/spec/factories.rb index d6edc0355..78dbe5949 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -17,7 +17,7 @@ Factory.define :profile do |p| end Factory.define :person do |p| - p.sequence(:diaspora_handle) { |n| "bob-person-#{n}#{r_str}@aol.com" } + p.sequence(:diaspora_handle) { |n| "bob-person-#{n}#{r_str}@example.net" } p.sequence(:url) { |n| AppConfig[:pod_url] } p.serialized_public_key OpenSSL::PKey::RSA.generate(1024).public_key.export p.after_build do |person| diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index c5ece598a..58e04355d 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -123,12 +123,37 @@ describe Notifier do end it 'can handle a activity streams photo' do - reshare = Factory(:activity_streams_photo) - like = reshare.likes.create!(:author => bob.person) + as_photo = Factory(:activity_streams_photo) + like = as_photo.likes.create!(:author => bob.person) mail = Notifier.liked(alice.id, like.author.id, like.id) end end + describe ".reshared" do + before do + @sm = Factory.create(:status_message, :author => alice.person, :public => true) + @reshare = Factory.create(:reshare, :root => @sm, :author => bob.person) + @mail = Notifier.reshared(alice.id, @reshare.author.id, @reshare.id) + end + + it 'TO: goes to the right person' do + @mail.to.should == [alice.email] + end + + it 'BODY: contains the truncated original post' do + @mail.body.encoded.should include(@sm.formatted_message) + end + + it 'BODY: contains the name of person liking' do + @mail.body.encoded.should include(@reshare.author.name) + end + + it 'should not include translation fallback' do + @mail.body.encoded.should_not include(I18n.translate 'notifier.a_post_you_shared') + end + end + + describe ".private_message" do before do @user2 = bob diff --git a/spec/models/jobs/mail/mail_reshared_spec.rb b/spec/models/jobs/mail/mail_reshared_spec.rb new file mode 100644 index 000000000..172508ed9 --- /dev/null +++ b/spec/models/jobs/mail/mail_reshared_spec.rb @@ -0,0 +1,20 @@ +# Copyright (c) 2010, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3 or later. See +# the COPYRIGHT file. + +require 'spec_helper' + +describe Job::Mail::Reshared do + describe '#perfom' do + it 'should call .deliver on the notifier object' do + sm = Factory(:status_message, :author => bob.person, :public => true) + reshare = Factory.create(:reshare, :author => alice.person, :root=> sm) + + mail_mock = mock() + mail_mock.should_receive(:deliver) + Notifier.should_receive(:reshared).with(bob.id, reshare.author.id, reshare.id).and_return(mail_mock) + + Job::Mail::Reshared.perform(bob.id, reshare.author.id, reshare.id) + end + end +end diff --git a/spec/models/jobs/receive_local_batch_spec.rb b/spec/models/jobs/receive_local_batch_spec.rb index 848a50602..a6eb038e0 100644 --- a/spec/models/jobs/receive_local_batch_spec.rb +++ b/spec/models/jobs/receive_local_batch_spec.rb @@ -22,6 +22,10 @@ describe Job::ReceiveLocalBatch do Job::ReceiveLocalBatch.should_receive(:notify_mentioned_users).with(@post) Job::ReceiveLocalBatch.perform(@post.id, [bob.id]) end + it 'notifies users' do + Job::ReceiveLocalBatch.should_receive(:notify_users).with(@post, [bob.id]) + Job::ReceiveLocalBatch.perform(@post.id, [bob.id]) + end end describe '.create_visibilities' do it 'creates a visibility for each user' do @@ -58,4 +62,20 @@ describe Job::ReceiveLocalBatch do Job::ReceiveLocalBatch.notify_mentioned_users(@post) end end + + describe '.notify_users' do + it 'calls notify for posts with notification type' do + reshare = Factory.create(:reshare) + Notification.should_receive(:notify) + + Job::ReceiveLocalBatch.notify_users(reshare, [bob.id]) + end + + it 'calls notify for posts with notification type' do + sm = Factory.create(:status_message, :author => alice.person) + Notification.should_not_receive(:notify) + + Job::ReceiveLocalBatch.notify_users(sm, [bob.id]) + end + end end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 609392db1..4a4fd5a5c 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -55,7 +55,7 @@ describe Notification do Notification.notify(@user, @sm, @person) end - context 'with a request' do + context 'with a request' do before do @request = Request.diaspora_initialize(:from => @user.person, :to => @user2.person, :into => @aspect) end diff --git a/spec/models/notifications/reshared_spec.rb b/spec/models/notifications/reshared_spec.rb new file mode 100644 index 000000000..ef478416a --- /dev/null +++ b/spec/models/notifications/reshared_spec.rb @@ -0,0 +1,43 @@ +# Copyright (c) 2010, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3 or later. See +# the COPYRIGHT file. + +require 'spec_helper' + +describe Notifications::Reshared do + before do + @sm = Factory.create(:status_message, :author => alice.person, :public => true) + @reshare1 = Factory.create(:reshare, :root => @sm) + @reshare2 = Factory.create(:reshare, :root => @sm) + end + + describe 'Notification.notify' do + it 'calls concatenate_or_create with root post' do + Notifications::Reshared.should_receive(:concatenate_or_create).with(alice, @reshare1.root, @reshare1.author, Notifications::Reshared) + + Notification.notify(alice, @reshare1, @reshare1.author) + end + end + + describe '#mail_job' do + it "does not raise" do + lambda{ + Notifications::Reshared.new.mail_job + }.should_not raise_error + end + end + + describe '#concatenate_or_create' do + it 'creates a new notification if one does not already exist' do + Notifications::Reshared.should_receive(:make_notification).with(alice, @reshare1.root, @reshare1.author, Notifications::Reshared) + Notifications::Reshared.concatenate_or_create(alice, @reshare1.root, @reshare1.author, Notifications::Reshared) + end + + it "appends the actors to the aldeady existing notification" do + note = Notifications::Reshared.make_notification(alice, @reshare1.root, @reshare1.author, Notifications::Reshared) + lambda{ + Notifications::Reshared.concatenate_or_create(alice, @reshare2.root, @reshare2.author, Notifications::Reshared) + }.should change(note.actors, :count).by(1) + end + end +end diff --git a/spec/models/reshare_spec.rb b/spec/models/reshare_spec.rb index d64095a94..fd4be6c23 100644 --- a/spec/models/reshare_spec.rb +++ b/spec/models/reshare_spec.rb @@ -53,14 +53,15 @@ describe Reshare do describe '#notification_type' do before do - @reshare = Factory.create(:reshare, :author => alice.person) + sm = Factory.create(:status_message, :author => alice.person, :public => true) + @reshare = Factory.create(:reshare, :root => sm) end - it 'does not return anything for the author' do + it 'does not return anything for non-author of the original post' do @reshare.notification_type(bob, @reshare.author).should be_nil end - it 'returns private mesage for an actual receiver' do - @reshare.notification_type(alice, @reshare.author).should == Notifications::PrivateMessage + it 'returns "Reshared" for the original post author' do + @reshare.notification_type(alice, @reshare.author).should == Notifications::Reshared end end