Refactor notification to have subclasses, just a start

This commit is contained in:
Raphael Sofaer 2011-03-01 10:20:23 -08:00
parent 809ee8a678
commit 1c1fba63e7
14 changed files with 47 additions and 42 deletions

View file

@ -1,26 +1,26 @@
module NotificationsHelper module NotificationsHelper
def object_link(note) def object_link(note)
target_type = note.action target_type = note.class
case target_type case target_type
when 'mentioned' when Notifications::Mentioned
post = Mention.find(note.target_id).post post = Mention.find(note.target_id).post
if post if post
"#{translation(target_type)} #{link_to t('notifications.post'), object_path(post)}".html_safe "#{translation(target_type)} #{link_to t('notifications.post'), object_path(post)}".html_safe
else else
"#{translation(target_type)} #{t('notifications.deleted')} #{t('notifications.post')}" "#{translation(target_type)} #{t('notifications.deleted')} #{t('notifications.post')}"
end end
when 'request_accepted' when Notifications::RequestAccepted
translation(target_type) translation(target_type)
when 'new_request' when Notifications::NewRequest
translation(target_type) translation(target_type)
when 'comment_on_post' when Notifications::CommentOnPost
post = Post.where(:id => note.target_id).first post = Post.where(:id => note.target_id).first
if post if post
"#{translation(target_type)} #{link_to t('notifications.post'), object_path(post)}".html_safe "#{translation(target_type)} #{link_to t('notifications.post'), object_path(post)}".html_safe
else else
"#{translation(target_type)} #{t('notifications.deleted')} #{t('notifications.post')}" "#{translation(target_type)} #{t('notifications.deleted')} #{t('notifications.post')}"
end end
when 'also_commented' when Notifications::AlsoCommented
post = Post.where(:id => note.target_id).first post = Post.where(:id => note.target_id).first
if post if post
"#{translation(target_type, post.person.name)} #{link_to t('notifications.post'), object_path(post)}".html_safe "#{translation(target_type, post.person.name)} #{link_to t('notifications.post'), object_path(post)}".html_safe

View file

@ -44,9 +44,9 @@ class Comment < ActiveRecord::Base
def notification_type(user, person) def notification_type(user, person)
if self.post.person == user.person if self.post.person == user.person
return "comment_on_post" return Notifications::CommentOnPost
elsif self.post.comments.where(:person_id => user.person.id) != [] && self.person_id != user.person.id elsif self.post.comments.where(:person_id => user.person.id) != [] && self.person_id != user.person.id
return "also_commented" return Notifications::AlsoCommented
else else
return false return false
end end

View file

@ -19,7 +19,7 @@ class Mention < ActiveRecord::Base
def notification_type(*args) def notification_type(*args)
'mentioned' Notifications::Mentioned
end end
def delete_notification def delete_notification

View file

@ -17,11 +17,11 @@ class Notification < ActiveRecord::Base
def self.notify(recipient, target, actor) def self.notify(recipient, target, actor)
if target.respond_to? :notification_type if target.respond_to? :notification_type
if action = target.notification_type(recipient, actor) if note_type = target.notification_type(recipient, actor)
if target.is_a? Comment if target.is_a? Comment
n = concatenate_or_create(recipient, target.post, actor, action) n = concatenate_or_create(recipient, target.post, actor, note_type)
else else
n = make_notification(recipient, target, actor, action) n = make_notification(recipient, target, actor, note_type)
end end
n.email_the_user(target, actor) if n n.email_the_user(target, actor) if n
n.socket_to_user(recipient, :actor => actor) if n n.socket_to_user(recipient, :actor => actor) if n
@ -33,12 +33,14 @@ class Notification < ActiveRecord::Base
def email_the_user(target, actor) def email_the_user(target, actor)
self.recipient.mail(self.mail_job, self.recipient_id, actor.id, target.id) self.recipient.mail(self.mail_job, self.recipient_id, actor.id, target.id)
end end
def mail_job
raise NotImplementedError.new('Subclass this.')
end
private private
def self.concatenate_or_create(recipient, target, actor, action) def self.concatenate_or_create(recipient, target, actor, notification_type)
if n = Notification.where(:target_id => target.id, if n = notification_type.where(:target_id => target.id,
:target_type => target.class.base_class, :target_type => target.class.base_class,
:action => action,
:recipient_id => recipient.id).first :recipient_id => recipient.id).first
unless n.actors.include?(actor) unless n.actors.include?(actor)
n.actors << actor n.actors << actor
@ -48,13 +50,12 @@ private
n.save! n.save!
n n
else else
make_notification(recipient, target, actor, action) make_notification(recipient, target, actor, notification_type)
end end
end end
def self.make_notification(recipient, target, actor, action) def self.make_notification(recipient, target, actor, notification_type)
n = Notification.new(:target => target, n = notification_type.new(:target => target,
:action => action,
:recipient_id => recipient.id) :recipient_id => recipient.id)
n.actors << actor n.actors << actor
n.unread = false if target.is_a? Request n.unread = false if target.is_a? Request

View file

@ -56,9 +56,9 @@ class Request < ActiveRecord::Base
def notification_type(user, person) def notification_type(user, person)
if Contact.where(:user_id => user.id, :person_id => person.id).first if Contact.where(:user_id => user.id, :person_id => person.id).first
"request_accepted" Notifications::RequestAccepted
else else
"new_request" Notifications::NewRequest
end end
end end

View file

@ -8,8 +8,8 @@ class NotificationSubclasses < ActiveRecord::Migration
:mentioned => 'Notifications::Mentioned' :mentioned => 'Notifications::Mentioned'
}.each_pair do |key, value| }.each_pair do |key, value|
execute("UPDATE notifications execute("UPDATE notifications
set type = #{value} set type = '#{value}'
where action = #{key.to_s}") where action = '#{key.to_s}'")
end end
remove_column :notifications, :action remove_column :notifications, :action
end end
@ -23,8 +23,9 @@ class NotificationSubclasses < ActiveRecord::Migration
:mentioned => 'Notifications::Mentioned' :mentioned => 'Notifications::Mentioned'
}.each_pair do |key, value| }.each_pair do |key, value|
execute("UPDATE notifications execute("UPDATE notifications
set action = #{key.to_s} set action = '#{key.to_s}'
where type = #{value}") where type = '#{value}'")
end
remove_column :notifications, :type remove_column :notifications, :type
end end
end end

View file

@ -318,10 +318,10 @@ ActiveRecord::Schema.define(:version => 20110228201109) do
t.string "target_type" t.string "target_type"
t.integer "target_id" t.integer "target_id"
t.integer "recipient_id", :null => false t.integer "recipient_id", :null => false
t.string "action", :null => false
t.boolean "unread", :default => true, :null => false t.boolean "unread", :default => true, :null => false
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "type"
end end
add_index "notifications", ["recipient_id"], :name => "index_notifications_on_recipient_id" add_index "notifications", ["recipient_id"], :name => "index_notifications_on_recipient_id"

View file

@ -92,10 +92,10 @@ end
Factory.define(:notification) do |n| Factory.define(:notification) do |n|
n.association :recipient, :factory => :user n.association :recipient, :factory => :user
n.association :target, :factory => :comment n.association :target, :factory => :comment
n.type 'Notifications::AlsoCommented'
n.after_build do |note| n.after_build do |note|
note.actors << Factory.build( :person ) note.actors << Factory.build( :person )
note.action = note.target.notification_type(note.recipient, note.actors.first)
end end
end end

View file

@ -20,7 +20,7 @@ describe Comment do
it "returns 'comment_on_post' if the comment is on a post you own" do it "returns 'comment_on_post' if the comment is on a post you own" do
comment = bob.comment("why so formal?", :on => @alices_post) comment = bob.comment("why so formal?", :on => @alices_post)
comment.notification_type(alice, bob.person).should == 'comment_on_post' comment.notification_type(alice, bob.person).should == Notifications::CommentOnPost
end end
it 'returns false if the comment is not on a post you own and no one "also_commented"' do it 'returns false if the comment is not on a post you own and no one "also_commented"' do
@ -39,7 +39,7 @@ describe Comment do
end end
it "returns 'also_commented' if another person commented on a post you commented on" do it "returns 'also_commented' if another person commented on a post you commented on" do
@comment.notification_type(bob, alice.person).should == 'also_commented' @comment.notification_type(bob, alice.person).should == Notifications::AlsoCommented
end end
end end
end end

View file

@ -21,7 +21,7 @@ describe Mention do
@m.save @m.save
end end
it 'should only notify if the person is local' do it 'should only notify if the person is local' do
m = Mention.new(:person => Factory(:person), :post => @sm) m = Mention.new(:person => Factory(:person), :post => @sm)
Notification.should_not_receive(:notify) Notification.should_not_receive(:notify)
m.save m.save
@ -44,10 +44,10 @@ describe Mention do
describe '#notification_type' do describe '#notification_type' do
it "returns 'mentioned'" do it "returns 'mentioned'" do
Mention.new.notification_type.should == 'mentioned' Mention.new.notification_type.should == Notifications::Mentioned
end end
end end
describe 'after destroy' do describe 'after destroy' do
it 'destroys a notification' do it 'destroys a notification' do
@user = alice @user = alice

View file

@ -13,7 +13,7 @@ describe Notification do
@aspect = @user.aspects.create(:name => "dudes") @aspect = @user.aspects.create(:name => "dudes")
@opts = {:target_id => @sm.id, @opts = {:target_id => @sm.id,
:target_type => @sm.class.name, :target_type => @sm.class.name,
:action => "comment_on_post", :type => 'Notifications::CommentOnPost',
:actors => [@person], :actors => [@person],
:recipient_id => @user.id} :recipient_id => @user.id}
@note = Notification.new(@opts) @note = Notification.new(@opts)
@ -61,11 +61,10 @@ describe Notification do
it 'sockets to the recipient' do it 'sockets to the recipient' do
opts = {:target_id => @request.id, opts = {:target_id => @request.id,
:target_type => "Request", :target_type => "Request",
:action => @request.notification_type(@user, @person),
:actors => [@person], :actors => [@person],
:recipient_id => @user.id} :recipient_id => @user.id}
n = Notification.create(opts) n = @request.notification_type(@user, @person).create(opts)
Notification.stub!(:make_notification).and_return n Notification.stub!(:make_notification).and_return n
n.should_receive(:socket_to_user).once n.should_receive(:socket_to_user).once
@ -75,15 +74,14 @@ describe Notification do
describe '#emails_the_user' do describe '#emails_the_user' do
it 'calls mail' do it 'calls mail' do
opts = { opts = {
:action => "new_request",
:actors => [@person], :actors => [@person],
:recipient_id => @user.id} :recipient_id => @user.id}
n = Notification.new(opts) n = Notifications::NewRequest.new(opts)
n.stub!(:recipient).and_return @user n.stub!(:recipient).and_return @user
@user.should_receive(:mail) @user.should_receive(:mail)
n.email_the_user("mock", @person) n.email_the_user(@request, @person)
end end
end end

View file

@ -56,11 +56,11 @@ describe Request do
end end
it "returns 'request_accepted' if there is a pending contact" do it "returns 'request_accepted' if there is a pending contact" do
Contact.create(:user_id => @user.id, :person_id => @person.id) Contact.create(:user_id => @user.id, :person_id => @person.id)
@request.notification_type(@user, @person).should == "request_accepted" @request.notification_type(@user, @person).should == Notifications::RequestAccepted
end end
it 'returns new_request if there is not a pending contact' do it 'returns new_request if there is not a pending contact' do
@request.notification_type(@user, @person).should == "new_request" @request.notification_type(@user, @person).should == Notifications::NewRequest
end end
end end

View file

@ -67,7 +67,7 @@ describe Diaspora::UserModules::Connecting do
end end
it 'enqueues a mail job' do it 'enqueues a mail job' do
Resque.should_receive(:enqueue).with(Job::MailRequestReceived, user.id, person.id) Resque.should_receive(:enqueue).with(Job::MailRequestReceived, user.id, person.id, anything)
zord = Postzord::Receiver.new(user, :object => @r, :person => person) zord = Postzord::Receiver.new(user, :object => @r, :person => person)
zord.receive_object zord.receive_object
end end
@ -87,7 +87,7 @@ describe Diaspora::UserModules::Connecting do
Request.where(:sender_id => user2.person.id, :recipient_id => user.person.id).should be_empty Request.where(:sender_id => user2.person.id, :recipient_id => user.person.id).should be_empty
end end
it 'enqueues a mail job' do it 'enqueues a mail job' do
Resque.should_receive(:enqueue).with(Job::MailRequestAcceptance, user.id, user2.person.id).once Resque.should_receive(:enqueue).with(Job::MailRequestAcceptance, user.id, user2.person.id, nil).once
zord = Postzord::Receiver.new(user, :object => @acceptance, :person => user2.person) zord = Postzord::Receiver.new(user, :object => @acceptance, :person => user2.person)
zord.receive_object zord.receive_object
end end

View file

@ -0,0 +1,5 @@
class Object
def id
raise "You have called id on a non-ActiveRecord object."
end
end