Skip to content
Extraits de code Groupes Projets
Valider 6e60905d rédigé par Maxwell Salzberg's avatar Maxwell Salzberg
Parcourir les fichiers

DG MS major refactor of salmon and corresponding federation logic

parent 87c994fa
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de
avec 304 ajouts et 150 suppressions
...@@ -50,7 +50,7 @@ class PublicsController < ApplicationController ...@@ -50,7 +50,7 @@ class PublicsController < ApplicationController
end end
def receive_public def receive_public
Postzord::Receiver::Public.new(params[:xml]) Resque.enqueue(Job::ReceivePublicSalmon, params[:xml])
render :nothing => true, :status => :ok render :nothing => true, :status => :ok
end end
......
...@@ -19,6 +19,8 @@ class Contact < ActiveRecord::Base ...@@ -19,6 +19,8 @@ class Contact < ActiveRecord::Base
validates_uniqueness_of :person_id, :scope => :user_id validates_uniqueness_of :person_id, :scope => :user_id
before_destroy :destroy_notifications
# contact.sharing is true when contact.person is sharing with contact.user # contact.sharing is true when contact.person is sharing with contact.user
scope :sharing, lambda { scope :sharing, lambda {
where(:sharing => true) where(:sharing => true)
...@@ -33,7 +35,6 @@ class Contact < ActiveRecord::Base ...@@ -33,7 +35,6 @@ class Contact < ActiveRecord::Base
sharing.where(:receiving => false) sharing.where(:receiving => false)
} }
before_destroy :destroy_notifications
def destroy_notifications def destroy_notifications
Notification.where(:target_type => "Person", Notification.where(:target_type => "Person",
:target_id => person_id, :target_id => person_id,
......
...@@ -2,56 +2,18 @@ ...@@ -2,56 +2,18 @@
# licensed under the Affero General Public License version 3 or later. See # licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file. # the COPYRIGHT file.
require File.join(Rails.root, 'lib/postzord/receiver')
require File.join(Rails.root, 'lib/postzord/receiver/local_post_batch')
module Job module Job
class ReceiveLocalBatch < Base class ReceiveLocalBatch < Base
require File.join(Rails.root, 'lib/postzord/receiver')
@queue = :receive @queue = :receive
def self.perform(post_id, recipient_user_ids) def self.perform(post_id, recipient_user_ids)
post = Post.find(post_id) post = Post.find(post_id)
create_visibilities(post, recipient_user_ids) receiver = Postzord::Receiver::LocalPostBatch.new(post, recipient_user_ids)
socket_to_users(post, recipient_user_ids) if post.respond_to?(:socket_to_user) receiver.perform!
notify_mentioned_users(post)
notify_users(post, recipient_user_ids)
end
def self.create_visibilities(post, recipient_user_ids)
contacts = Contact.where(:user_id => recipient_user_ids, :person_id => post.author_id)
if postgres?
# Take the naive approach to inserting our new visibilities for now.
contacts.each do |contact|
PostVisibility.find_or_create_by_contact_id_and_post_id(contact.id, post.id)
end
else
# Use a batch insert on mySQL.
new_post_visibilities = contacts.map do |contact|
PostVisibility.new(:contact_id => contact.id, :post_id => post.id)
end
PostVisibility.import(new_post_visibilities)
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 end
end end
...@@ -2,31 +2,16 @@ ...@@ -2,31 +2,16 @@
# licensed under the Affero General Public License version 3 or later. See # licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file. # the COPYRIGHT file.
require 'spec_helper'
require File.join(Rails.root, 'lib/postzord') module Job
require File.join(Rails.root, 'lib/postzord/receiver/public') class ReceivePublicSalmon < Base
require File.join(Rails.root, 'lib/postzord/receiver')
describe Postzord::Receiver::Public do @queue = :receive
describe '#initialize' do
end
describe '#verify_signature' do
end
describe '#collect_recipients' do
def self.perform(xml)
receiver = Postzord::Receiver::Public.new(xml)
receiver.perform!
end
end end
describe '#batch_insert_visibilities' do
end
describe '#batch_notify' do
end
end end
...@@ -5,4 +5,20 @@ ...@@ -5,4 +5,20 @@
class PostVisibility < ActiveRecord::Base class PostVisibility < ActiveRecord::Base
belongs_to :contact belongs_to :contact
belongs_to :post belongs_to :post
def self.batch_import(contacts, post)
if postgres?
# Take the naive approach to inserting our new visibilities for now.
contacts.each do |contact|
PostVisibility.find_or_create_by_contact_id_and_post_id(contact.id, post.id)
end
else
# Use a batch insert on mySQL.
new_post_visibilities = contacts.map do |contact|
PostVisibility.new(:contact_id => contact.id, :post_id => post.id)
end
PostVisibility.import(new_post_visibilities)
end
end
end end
...@@ -59,6 +59,10 @@ class User < ActiveRecord::Base ...@@ -59,6 +59,10 @@ class User < ActiveRecord::Base
:invitation_identifier :invitation_identifier
def self.all_sharing_with_person(person)
User.joins(:contacts).where(:contacts => {:person_id => person.id})
end
# @return [User] # @return [User]
def self.find_by_invitation(invitation) def self.find_by_invitation(invitation)
service = invitation.service service = invitation.service
......
...@@ -18,7 +18,7 @@ class Postzord::Dispatch ...@@ -18,7 +18,7 @@ class Postzord::Dispatch
end end
def salmon def salmon
@salmon_factory ||= Salmon::EncryptedSlap.create(@sender, @xml) @salmon_factory ||= Salmon::EncryptedSlap.create_by_user_and_activity(@sender, @xml)
end end
def post(opts = {}) def post(opts = {})
......
...@@ -45,7 +45,7 @@ module Postzord ...@@ -45,7 +45,7 @@ module Postzord
protected protected
def salmon def salmon
@salmon ||= Salmon::EncryptedSlap.parse(@salmon_xml, @user) @salmon ||= Salmon::EncryptedSlap.from_xml(@salmon_xml, @user)
end end
def xml_author def xml_author
......
module Postzord
class Receiver
class LocalPostBatch
attr_reader :post, :recipient_user_ids, :users
def initialize(post, recipient_user_ids)
@post = post
@recipient_user_ids = recipient_user_ids
@users = User.where(:id => @recipient_user_ids)
end
def perform!
create_visibilities
socket_to_users if @post.respond_to?(:socket_to_user)
notify_mentioned_users
notify_users
end
def create_visibilities
contacts = Contact.where(:user_id => @recipient_user_ids, :person_id => @post.author_id)
PostVisibility.batch_import(contacts, post)
end
def socket_to_users
@users.each do |user|
@post.socket_to_user(user)
end
end
def notify_mentioned_users
@post.mentions.each do |mention|
mention.notify_recipient
end
end
def notify_users
if @post.respond_to?(:notification_type)
@users.each do |user|
Notification.notify(user, @post, @post.author)
end
end
end
end
end
end
...@@ -5,12 +5,55 @@ ...@@ -5,12 +5,55 @@
module Postzord module Postzord
class Receiver class Receiver
class Public class Public
attr_accessor :xml attr_accessor :salmon, :author
def initialize(xml) def initialize(xml)
@xml = xml @salmon = Salmon::Slap.from_xml(xml)
@author = Webfinger.new(@salmon.author_email).fetch
end end
# @return [Boolean]
def verified_signature?
@salmon.verified_for_key?(@author.public_key)
end
# @return [void]
def perform!
return false unless verified_signature?
return unless save_object
if @object.respond_to?(:relayable)
receive_relayable
else
Resque.enqueue(Job::ReceiveLocalBatch, @object.id, self.recipient_user_ids)
end
end
def receive_relayable
raise RelayableObjectWithoutParent.new("Receiving a relayable object without parent object present locally!") unless @object.parent.user.present?
# receive relayable object only for the owner of the parent object
@object.receive(@object.parent.user, @author)
# notify everyone who can see the parent object
receiver = Postzord::Receiver::LocalPostBatch.new(nil, self.recipient_user_ids)
receiver.notify_users
end
# @return [Object]
def save_object
@object = Diaspora::Parser::from_xml(@salmon.parsed_data)
raise "Object is not public" unless @object.public?
@object.save!
end
# @return [Array<Integer>] User ids
def recipient_user_ids
User.all_sharing_with_person(@author).select('users.id').map!{ |u| u.id }
end
class RelayableObjectWithoutParent < StandardError ; ; end
end end
end end
end end
...@@ -6,7 +6,6 @@ module Salmon ...@@ -6,7 +6,6 @@ module Salmon
class MagicSigEnvelope class MagicSigEnvelope
attr_accessor :data, :data_type, :encoding, :alg, :sig, :author attr_accessor :data, :data_type, :encoding, :alg, :sig, :author
def self.parse(doc) def self.parse(doc)
puts doc.to_s
env = self.new env = self.new
ns = {'me'=>'http://salmon-protocol.org/ns/magic-env'} ns = {'me'=>'http://salmon-protocol.org/ns/magic-env'}
env.encoding = doc.search('//me:env/me:encoding', ns).text.strip env.encoding = doc.search('//me:env/me:encoding', ns).text.strip
......
...@@ -31,9 +31,9 @@ describe PublicsController do ...@@ -31,9 +31,9 @@ describe PublicsController do
response.code.should == '422' response.code.should == '422'
end end
it 'calls Postzord::Receiver:Public' do it 'enqueues a ReceivePublicSalmon job' do
xml = "stuff" xml = "stuff"
Postzord::Receiver::Public.should_receive(:new).with(xml) Resque.should_receive(:enqueue).with(Job::ReceivePublicSalmon, xml)
post :receive_public, :xml => xml post :receive_public, :xml => xml
end end
end end
...@@ -57,7 +57,7 @@ describe PublicsController do ...@@ -57,7 +57,7 @@ describe PublicsController do
xml2 = post1.to_diaspora_xml xml2 = post1.to_diaspora_xml
user2 = Factory(:user) user2 = Factory(:user)
salmon_factory = Salmon::EncryptedSlap.create(@user, xml2) salmon_factory = Salmon::EncryptedSlap.create_by_user_and_activity(@user, xml2)
enc_xml = salmon_factory.xml_for(user2.person) enc_xml = salmon_factory.xml_for(user2.person)
Resque.should_receive(:enqueue).with(Job::ReceiveSalmon, @user.id, enc_xml).once Resque.should_receive(:enqueue).with(Job::ReceiveSalmon, @user.id, enc_xml).once
......
...@@ -231,7 +231,7 @@ describe Postzord::Dispatch do ...@@ -231,7 +231,7 @@ describe Postzord::Dispatch do
it 'calls salmon_for each remote person' do it 'calls salmon_for each remote person' do
salmon = @mailman.salmon salmon = @mailman.salmon
Salmon::EncryptedSlap.stub(:create).and_return(salmon) Salmon::EncryptedSlap.stub(:create_by_user_and_activity).and_return(salmon)
salmon.should_receive(:xml_for).with(alice.person).and_return('what') salmon.should_receive(:xml_for).with(alice.person).and_return('what')
@hydra.stub!(:queue) @hydra.stub!(:queue)
@hydra.stub!(:run) @hydra.stub!(:run)
......
require 'spec_helper'
require File.join(Rails.root, 'lib','postzord', 'receiver', 'local_post_batch')
describe Postzord::Receiver::LocalPostBatch do
before do
@post = Factory(:status_message, :author => alice.person)
@ids = [bob.id]
@receiver = Postzord::Receiver::LocalPostBatch.new(@post, @ids)
end
describe '.initialize' do
it 'sets @post, @recipient_user_ids, and @user' do
[:post, :recipient_user_ids, :users].each do |instance_var|
@receiver.send(instance_var).should_not be_nil
end
end
end
describe '#perform!' do
it 'calls .create_visibilities' do
@receiver.should_receive(:create_visibilities)
@receiver.perform!
end
it 'sockets to users' do
@receiver.should_receive(:socket_to_users)
@receiver.perform!
end
it 'notifies mentioned users' do
@receiver.should_receive(:notify_mentioned_users)
@receiver.perform!
end
it 'notifies users' do
@receiver.should_receive(:notify_users)
@receiver.perform!
end
end
describe '#create_visibilities' do
it 'calls Postvisibility.batch_import' do
PostVisibility.should_receive(:batch_import)
@receiver.create_visibilities
end
end
describe '#socket_to_users' do
before do
@controller = mock()
SocketsController.stub(:new).and_return(@controller)
end
it 'sockets to each user' do
@controller.should_receive(:outgoing).with(bob, @post, instance_of(Hash))
@receiver.socket_to_users
end
end
describe '#notify_mentioned_users' do
it 'calls notify person for a mentioned person' do
sm = Factory(:status_message,
:author => alice.person,
:text => "Hey @{Bob; #{bob.diaspora_handle}}")
receiver = Postzord::Receiver::LocalPostBatch.new(sm, @ids)
Notification.should_receive(:notify).with(bob, anything, alice.person)
receiver.notify_mentioned_users
end
it 'does not call notify person for a non-mentioned person' do
Notification.should_not_receive(:notify)
@receiver.notify_mentioned_users
end
end
describe '#notify_users' do
it 'calls notify for posts with notification type' do
reshare = Factory.create(:reshare)
Notification.should_receive(:notify)
receiver = Postzord::Receiver::LocalPostBatch.new(reshare, @ids)
receiver.notify_users
end
it 'calls notify for posts with notification type' do
sm = Factory.create(:status_message, :author => alice.person)
receiver = Postzord::Receiver::LocalPostBatch.new(sm, @ids)
Notification.should_not_receive(:notify)
receiver.notify_users
end
end
end
...@@ -8,52 +8,60 @@ require File.join(Rails.root, 'lib/postzord') ...@@ -8,52 +8,60 @@ require File.join(Rails.root, 'lib/postzord')
require File.join(Rails.root, 'lib/postzord/receiver/public') require File.join(Rails.root, 'lib/postzord/receiver/public')
describe Postzord::Receiver::Public do describe Postzord::Receiver::Public do
before do
@post = Factory.build(:status_message, :author => alice.person, :public => true)
@created_salmon = Salmon::Slap.create_by_user_and_activity(alice, @post.to_diaspora_xml)
@xml = @created_salmon.xml_for(nil)
end
describe '#initialize' do describe '#initialize' do
it 'sets xml as instance variable' do it 'creates a Salmon instance variable' do
receiver = Postzord::Receiver::Public.new("blah") receiver = Postzord::Receiver::Public.new(@xml)
receiver.xml.should == 'blah' receiver.salmon.should_not be_nil
end end
end end
describe '#perform' do describe '#perform!' do
it 'calls verify_signature' do before do
@receiver = Postzord::Receiver::Public.new(@xml)
end
it 'calls verify_signature' do
@receiver.should_receive(:verified_signature?)
@receiver.perform!
end end
context 'if signature is valid' do context 'if signature is valid' do
it 'calls collect_recipients' do it 'calls recipient_user_ids' do
@receiver.should_receive(:recipient_user_ids)
@receiver.perform!
end end
it 'saves the parsed object' do it 'saves the parsed object' do
@receiver.should_receive(:save_object)
@receiver.perform!
end end
it 'calls batch_insert_visibilities' do it 'enqueues a Job::ReceiveLocalBatch' do
Resque.should_receive(:enqueue).with(Job::ReceiveLocalBatch, anything, anything)
end @receiver.perform!
it 'calls batch_notify' do
end end
end end
end end
describe '#verify_signature' do describe '#verify_signature?' do
it 'calls Slap#verified_for_key?' do
end receiver = Postzord::Receiver::Public.new(@xml)
receiver.salmon.should_receive(:verified_for_key?).with(instance_of(OpenSSL::PKey::RSA))
describe '#collect_recipients' do receiver.verified_signature?
end
end
describe '#batch_insert_visibilities' do
end end
describe '#batch_notify' do describe '#recipient_user_ids' do
it 'calls User.all_sharing_with_person' do
User.should_receive(:all_sharing_with_person).and_return(stub(:select => []))
receiver = Postzord::Receiver::Public.new(@xml)
receiver.perform!
end
end end
end end
...@@ -24,7 +24,7 @@ describe Postzord::Receiver do ...@@ -24,7 +24,7 @@ describe Postzord::Receiver do
describe '.initialize' do describe '.initialize' do
it 'valid for local' do it 'valid for local' do
Webfinger.should_not_receive(:new) Webfinger.should_not_receive(:new)
Salmon::EncryptedSlap.should_not_receive(:parse) Salmon::EncryptedSlap.should_not_receive(:from_xml)
zord = Postzord::Receiver.new(@user, :person => @person2, :object => @original_post) zord = Postzord::Receiver.new(@user, :person => @person2, :object => @original_post)
zord.instance_variable_get(:@user).should_not be_nil zord.instance_variable_get(:@user).should_not be_nil
...@@ -37,7 +37,7 @@ describe Postzord::Receiver do ...@@ -37,7 +37,7 @@ describe Postzord::Receiver do
web_mock = mock() web_mock = mock()
web_mock.should_receive(:fetch).and_return true web_mock.should_receive(:fetch).and_return true
salmon_mock.should_receive(:author_email).and_return(true) salmon_mock.should_receive(:author_email).and_return(true)
Salmon::EncryptedSlap.should_receive(:parse).with(@salmon_xml, @user).and_return(salmon_mock) Salmon::EncryptedSlap.should_receive(:from_xml).with(@salmon_xml, @user).and_return(salmon_mock)
Webfinger.should_receive(:new).and_return(web_mock) Webfinger.should_receive(:new).and_return(web_mock)
zord = Postzord::Receiver.new(@user, :salmon_xml => @salmon_xml) zord = Postzord::Receiver.new(@user, :salmon_xml => @salmon_xml)
......
...@@ -9,73 +9,10 @@ describe Job::ReceiveLocalBatch do ...@@ -9,73 +9,10 @@ describe Job::ReceiveLocalBatch do
@post = alice.build_post(:status_message, :text => 'Hey Bob') @post = alice.build_post(:status_message, :text => 'Hey Bob')
@post.save! @post.save!
end end
describe '.perform' do
it 'calls .create_visibilities' do
Job::ReceiveLocalBatch.should_receive(:create_visibilities).with(@post, [bob.id])
Job::ReceiveLocalBatch.perform(@post.id, [bob.id])
end
it 'sockets to users' do
Job::ReceiveLocalBatch.should_receive(:socket_to_users).with(@post, [bob.id])
Job::ReceiveLocalBatch.perform(@post.id, [bob.id])
end
it 'notifies mentioned users' 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
PostVisibility.exists?(:contact_id => bob.contact_for(alice.person).id, :post_id => @post.id).should be_false
Job::ReceiveLocalBatch.create_visibilities(@post, [bob.id])
PostVisibility.exists?(:contact_id => bob.contact_for(alice.person).id, :post_id => @post.id).should be_true
end
it 'does not raise if a visibility already exists' do
PostVisibility.create!(:contact_id => bob.contact_for(alice.person).id, :post_id => @post.id)
lambda {
Job::ReceiveLocalBatch.create_visibilities(@post, [bob.id])
}.should_not raise_error
end
end
describe '.socket_to_users' do
before do
@controller = mock()
SocketsController.stub(:new).and_return(@controller)
end
it 'sockets to each user' do
@controller.should_receive(:outgoing).with(bob.id, @post, instance_of(Hash))
Job::ReceiveLocalBatch.socket_to_users(@post, [bob.id])
end
end
describe '.notify_mentioned_users' do
it 'calls notify person for a mentioned person' do
@post = alice.build_post(:status_message, :text => "Hey @{Bob; #{bob.diaspora_handle}}")
@post.save!
Notification.should_receive(:notify).with(bob, anything, alice.person)
Job::ReceiveLocalBatch.notify_mentioned_users(@post)
end
it 'does not call notify person for a non-mentioned person' do
Notification.should_not_receive(:notify)
Job::ReceiveLocalBatch.notify_mentioned_users(@post)
end
end
describe '.notify_users' do describe '.perform' do
it 'calls notify for posts with notification type' do it 'calls Postzord::Receiver::LocalPostBatch' do
reshare = Factory.create(:reshare) pending
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 end
end end
# 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 PostVisibility do
describe '.batch_import' do
before do
@post = Factory(:status_message, :author => alice.person)
@contact = bob.contact_for(alice.person)
end
it 'creates a visibility for each user' do
lambda {
PostVisibility.batch_import([@contact], @post)
}.should change {
PostVisibility.exists?(:contact_id => @contact.id, :post_id => @post.id)
}.from(false).to(true)
end
it 'does not raise if a visibility already exists' do
PostVisibility.create!(:contact_id => @contact.id, :post_id => @post.id)
lambda {
PostVisibility.batch_import([@contact], @post)
}.should_not raise_error
end
end
end
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter