refactored post receiving; only update cache on verfied received objects

This commit is contained in:
Ilya Zhitomirskiy 2011-10-05 20:05:53 -07:00
parent 53c98e16e7
commit d891e78652
9 changed files with 175 additions and 55 deletions

View file

@ -96,46 +96,6 @@ class Post < ActiveRecord::Base
end end
end end
# @param [User] user The user that is receiving this post.
# @param [Person] person The person who dispatched this post to the
# @return [void]
def receive(user, person)
#exists locally, but you dont know about it
#does not exsist locally, and you dont know about it
#exists_locally?
#you know about it, and it is mutable
#you know about it, and it is not mutable
self.class.transaction do
local_post = self.class.where(:guid => self.guid).first
if local_post && local_post.author_id == self.author_id
known_post = user.find_visible_post_by_id(self.guid, :key => :guid)
if known_post
if known_post.mutable?
known_post.update_attributes(self.attributes)
else
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=abort sender=#{self.diaspora_handle} reason=immutable existing_post=#{known_post.id}")
end
else
user.contact_for(person).receive_post(local_post)
user.notify_if_mentioned(local_post)
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=complete sender=#{self.diaspora_handle} existing_post=#{local_post.id}")
return local_post
end
elsif !local_post
if self.save
user.contact_for(person).receive_post(self)
user.notify_if_mentioned(self)
Rails.logger.info("event=receive payload_type=#{self.class} update=false status=complete sender=#{self.diaspora_handle}")
return self
else
Rails.logger.info("event=receive payload_type=#{self.class} update=false status=abort sender=#{self.diaspora_handle} reason=#{self.errors.full_messages}")
end
else
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=abort sender=#{self.diaspora_handle} reason='update not from post owner' existing_post=#{self.id}")
end
end
end
def activity_streams? def activity_streams?
false false
end end
@ -173,4 +133,72 @@ class Post < ActiveRecord::Base
self.triggers_caching? && RedisCache.configured? && self.triggers_caching? && RedisCache.configured? &&
RedisCache.acceptable_types.include?(self.type) && user = self.author.owner RedisCache.acceptable_types.include?(self.type) && user = self.author.owner
end end
# @param [User] user The user that is receiving this post.
# @param [Person] person The person who dispatched this post to the
# @return [void]
def receive(user, person)
#exists locally, but you dont know about it
#does not exsist locally, and you dont know about it
#exists_locally?
#you know about it, and it is mutable
#you know about it, and it is not mutable
self.class.transaction do
local_post = persisted_post
if local_post && verify_persisted_post(local_post)
self.receive_persisted(user, person, local_post)
elsif !local_post
self.receive_non_persisted(user, person)
else
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=abort sender=#{self.diaspora_handle} reason='update not from post owner' existing_post=#{self.id}")
false
end
end
end
protected
# @return [Post,void]
def persisted_post
self.class.where(:guid => self.guid).first
end
# @return [Boolean]
def verify_persisted_post(persisted_post)
persisted_post.author_id == self.author_id
end
def receive_persisted(user, person, local_post)
known_post = user.find_visible_post_by_id(self.guid, :key => :guid)
if known_post
if known_post.mutable?
known_post.update_attributes(self.attributes)
true
else
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=abort sender=#{self.diaspora_handle} reason=immutable") #existing_post=#{known_post.id}")
false
end
else
user.contact_for(person).receive_post(local_post)
user.notify_if_mentioned(local_post)
Rails.logger.info("event=receive payload_type=#{self.class} update=true status=complete sender=#{self.diaspora_handle}") #existing_post=#{local_post.id}")
true
end
end
def receive_non_persisted(user, person)
if self.save
user.contact_for(person).receive_post(self)
user.notify_if_mentioned(self)
Rails.logger.info("event=receive payload_type=#{self.class} update=false status=complete sender=#{self.diaspora_handle}")
true
else
Rails.logger.info("event=receive payload_type=#{self.class} update=false status=abort sender=#{self.diaspora_handle} reason=#{self.errors.full_messages}")
false
end
end
end end

View file

@ -8,8 +8,9 @@ class Postzord::Receiver
require File.join(Rails.root, 'lib/postzord/receiver/public') require File.join(Rails.root, 'lib/postzord/receiver/public')
def perform! def perform!
receive! if self.receive!
update_cache! if cache? self.update_cache! if cache?
end
end end
# @return [Boolean] # @return [Boolean]

View file

@ -23,6 +23,8 @@ class Postzord::Receiver::LocalBatch < Postzord::Receiver
# 09/27/11 this is slow # 09/27/11 this is slow
#socket_to_users if @object.respond_to?(:socket_to_user) #socket_to_users if @object.respond_to?(:socket_to_user)
notify_users notify_users
true
end end
def update_cache! def update_cache!

View file

@ -23,7 +23,7 @@ class Postzord::Receiver::Private < Postzord::Receiver
parse_and_receive(salmon.parsed_data) parse_and_receive(salmon.parsed_data)
else else
Rails.logger.info("event=receive status=abort recipient=#{@user.diaspora_handle} sender=#{@salmon.author_id} reason='not_verified for key'") Rails.logger.info("event=receive status=abort recipient=#{@user.diaspora_handle} sender=#{@salmon.author_id} reason='not_verified for key'")
nil false
end end
end end

View file

@ -19,12 +19,13 @@ class Postzord::Receiver::Public < Postzord::Receiver
# @return [void] # @return [void]
def receive! def receive!
return false unless verified_signature? return false unless verified_signature?
return unless save_object return false unless save_object
if @object.respond_to?(:relayable?) if @object.respond_to?(:relayable?)
receive_relayable receive_relayable
else else
Resque.enqueue(Jobs::ReceiveLocalBatch, @object.class.to_s, @object.id, self.recipient_user_ids) Resque.enqueue(Jobs::ReceiveLocalBatch, @object.class.to_s, @object.id, self.recipient_user_ids)
true
end end
end end

View file

@ -53,28 +53,28 @@ describe Postzord::Receiver::Private do
@salmon = @zord.instance_variable_get(:@salmon) @salmon = @zord.instance_variable_get(:@salmon)
end end
context 'returns nil' do context 'returns false' do
it 'if the salmon author does not exist' do it 'if the salmon author does not exist' do
@zord.instance_variable_set(:@sender, nil) @zord.instance_variable_set(:@sender, nil)
@zord.perform!.should be_nil @zord.receive!.should == false
end end
it 'if the author does not match the signature' do it 'if the author does not match the signature' do
@zord.instance_variable_set(:@sender, Factory(:person)) @zord.instance_variable_set(:@sender, Factory(:person))
@zord.perform!.should be_nil @zord.receive!.should == false
end end
end end
context 'returns the sent object' do context 'returns the sent object' do
it 'returns the received object on success' do it 'returns the received object on success' do
@zord.perform! @zord.receive!
@zord.instance_variable_get(:@object).should respond_to(:to_diaspora_xml) @zord.instance_variable_get(:@object).should respond_to(:to_diaspora_xml)
end end
end end
it 'parses the salmon object' do it 'parses the salmon object' do
Diaspora::Parser.should_receive(:from_xml).with(@salmon.parsed_data).and_return(@original_post) Diaspora::Parser.should_receive(:from_xml).with(@salmon.parsed_data).and_return(@original_post)
@zord.perform! @zord.receive!
end end
end end

View file

@ -44,6 +44,11 @@ describe Postzord::Receiver::Public do
@receiver.perform! @receiver.perform!
end end
it 'returns false if signature is not verified' do
@receiver.should_receive(:verified_signature?).and_return(false)
@receiver.perform!.should be_false
end
context 'if signature is valid' do context 'if signature is valid' do
it 'calls recipient_user_ids' do it 'calls recipient_user_ids' do
@receiver.should_receive(:recipient_user_ids) @receiver.should_receive(:recipient_user_ids)

View file

@ -13,7 +13,7 @@ describe Postzord::Receiver do
describe "#perform!" do describe "#perform!" do
before do before do
@receiver.stub(:receive!) @receiver.stub(:receive!).and_return(true)
end end
it 'calls receive!' do it 'calls receive!' do
@ -22,8 +22,11 @@ describe Postzord::Receiver do
end end
context 'update_cache!' do context 'update_cache!' do
it "gets called if cache?" do before do
@receiver.stub(:cache?).and_return(true) @receiver.stub(:cache?).and_return(true)
end
it "gets called if cache?" do
@receiver.should_receive(:update_cache!) @receiver.should_receive(:update_cache!)
@receiver.perform! @receiver.perform!
end end
@ -33,6 +36,12 @@ describe Postzord::Receiver do
@receiver.should_not_receive(:update_cache!) @receiver.should_not_receive(:update_cache!)
@receiver.perform! @receiver.perform!
end end
it 'does not get called if receive! is false' do
@receiver.stub(:receive!).and_return(false)
@receiver.should_not_receive(:update_cache!)
@receiver.perform!
end
end end
end end

View file

@ -199,9 +199,83 @@ describe Post do
@post.should_cache_for_author?.should be_false @post.should_cache_for_author?.should be_false
end end
end end
describe "#receive" do
it 'returns false if the post does not verify' do
@post = Factory(:status_message, :author => bob.person)
@post.should_receive(:verify_persisted_post).and_return(false)
@post.receive(bob, eve.person).should == false
end
end
#user exists, describe "#receive_persisted" do
# cache configured, before do
# triggers caching, @post = Factory.build(:status_message, :author => bob.person)
# of the cachable type @known_post = Post.new
bob.stub(:contact_for).with(eve.person).and_return(stub(:receive_post => true))
end
context "user knows about the post" do
before do
bob.stub(:find_visible_post_by_id).and_return(@known_post)
end
it 'updates attributes only if mutable' do
@known_post.stub(:mutable?).and_return(true)
@known_post.should_receive(:update_attributes)
@post.send(:receive_persisted, bob, eve.person, @known_post).should == true
end
it 'returns false if trying to update a non-mutable object' do
@known_post.stub(:mutable?).and_return(false)
@known_post.should_not_receive(:update_attributes)
@post.send(:receive_persisted, bob, eve.person, @known_post).should == false
end
end
context "the user does not know about the post" do
before do
bob.stub(:find_visible_post_by_id).and_return(nil)
bob.stub(:notify_if_mentioned).and_return(true)
end
it "receives the post from the contact of the author" do
@post.send(:receive_persisted, bob, eve.person, @known_post).should == true
end
it 'notifies the user if they are mentioned' do
bob.stub(:contact_for).with(eve.person).and_return(stub(:receive_post => true))
bob.should_receive(:notify_if_mentioned).and_return(true)
@post.send(:receive_persisted, bob, eve.person, @known_post).should == true
end
end
end
describe '#receive_non_persisted' do
context "the user does not know about the post" do
before do
@post = Factory.build(:status_message, :author => bob.person)
bob.stub(:find_visible_post_by_id).and_return(nil)
bob.stub(:notify_if_mentioned).and_return(true)
end
it "it receives the post from the contact of the author" do
bob.should_receive(:contact_for).with(eve.person).and_return(stub(:receive_post => true))
@post.send(:receive_non_persisted, bob, eve.person).should == true
end
it 'notifies the user if they are mentioned' do
bob.stub(:contact_for).with(eve.person).and_return(stub(:receive_post => true))
bob.should_receive(:notify_if_mentioned).and_return(true)
@post.send(:receive_non_persisted, bob, eve.person).should == true
end
it 'returns false if the post does not save' do
@post.stub(:save).and_return(false)
@post.send(:receive_non_persisted, bob, eve.person).should == false
end
end
end
end end