From 9e1816dc12186b0957873856cffcb1f4ea68aabc Mon Sep 17 00:00:00 2001 From: Dennis Collinson Date: Wed, 8 Feb 2012 18:24:40 -0800 Subject: [PATCH 1/5] Participations are a federated, relayable model :) --- app/models/federated_relayable.rb | 42 +++++++++++++++ app/models/like.rb | 51 +++---------------- app/models/participation.rb | 3 ++ app/models/user.rb | 16 +++++- .../20120208231253_create_participations.rb | 17 +++++++ db/schema.rb | 13 ++++- spec/models/like_spec.rb | 4 +- spec/models/participation_spec.rb | 22 ++++++++ 8 files changed, 119 insertions(+), 49 deletions(-) create mode 100644 app/models/federated_relayable.rb create mode 100644 app/models/participation.rb create mode 100644 db/migrate/20120208231253_create_participations.rb create mode 100644 spec/models/participation_spec.rb diff --git a/app/models/federated_relayable.rb b/app/models/federated_relayable.rb new file mode 100644 index 000000000..540ee0967 --- /dev/null +++ b/app/models/federated_relayable.rb @@ -0,0 +1,42 @@ +class FederatedRelayable < ActiveRecord::Base + self.abstract_class = true + + #crazy ordering issues - DEATH TO ROXML + include ROXML + + include Diaspora::Webhooks + include Diaspora::Guid + + #seriously, don't try to move this shit around until you have killed ROXML + xml_attr :target_type + include Diaspora::Relayable + + xml_attr :diaspora_handle + + belongs_to :target, :polymorphic => true + belongs_to :author, :class_name => 'Person' + #end crazy ordering issues + + validates_uniqueness_of :target_id, :scope => [:target_type, :author_id] + validates :parent, :presence => true #should be in relayable (pending on fixing Message) + + def diaspora_handle + self.author.diaspora_handle + end + + def diaspora_handle=(nh) + self.author = Webfinger.new(nh).fetch + end + + def parent_class + self.target_type.constantize + end + + def parent + self.target + end + + def parent= parent + self.target = parent + end +end \ No newline at end of file diff --git a/app/models/like.rb b/app/models/like.rb index 5466bddd1..07dc4e2ea 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -2,14 +2,16 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class Like < ActiveRecord::Base - include ROXML +class Like < FederatedRelayable + after_create do + self.parent.update_likes_counter + end - include Diaspora::Webhooks - include Diaspora::Guid + after_destroy do + self.parent.update_likes_counter + end - xml_attr :target_type - include Diaspora::Relayable + xml_attr :positive # NOTE API V1 to be extracted acts_as_api @@ -20,43 +22,6 @@ class Like < ActiveRecord::Base t.add :created_at end - xml_attr :positive - xml_attr :diaspora_handle - - belongs_to :target, :polymorphic => true - belongs_to :author, :class_name => 'Person' - - validates_uniqueness_of :target_id, :scope => [:target_type, :author_id] - validates :parent, :presence => true #should be in relayable (pending on fixing Message) - - after_create do - self.parent.update_likes_counter - end - - after_destroy do - self.parent.update_likes_counter - end - - def diaspora_handle - self.author.diaspora_handle - end - - def diaspora_handle= nh - self.author = Webfinger.new(nh).fetch - end - - def parent_class - self.target_type.constantize - end - - def parent - self.target - end - - def parent= parent - self.target = parent - end - def notification_type(user, person) #TODO(dan) need to have a notification for likes on comments, until then, return nil return nil if self.target_type == "Comment" diff --git a/app/models/participation.rb b/app/models/participation.rb new file mode 100644 index 000000000..45ef129a6 --- /dev/null +++ b/app/models/participation.rb @@ -0,0 +1,3 @@ +class Participation < FederatedRelayable + +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 3fa47a371..6bafb452c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -294,6 +294,16 @@ class User < ActiveRecord::Base end end + def participate!(target, opts={}) + participation = build_participation(opts.merge!(:target => target)) + if participation.save + dispatch_post(participation) + participation + else + false + end + end + def like!(target, opts={}) like = build_like(opts.merge!(:target => target, :positive => true)) if like.save @@ -311,12 +321,14 @@ class User < ActiveRecord::Base r end - ######## Commenting ######## def build_comment(options = {}) build_relayable(Comment, options) end - ######## Liking ######## + def build_participation(options = {}) + build_relayable(Participation, options) + end + def build_like(options = {}) build_relayable(Like, options) end diff --git a/db/migrate/20120208231253_create_participations.rb b/db/migrate/20120208231253_create_participations.rb new file mode 100644 index 000000000..62f840bc6 --- /dev/null +++ b/db/migrate/20120208231253_create_participations.rb @@ -0,0 +1,17 @@ +class CreateParticipations < ActiveRecord::Migration + def self.up + create_table "participations", :force => true do |t| + t.string "guid" + t.integer "target_id" + t.string "target_type", :limit => 60, :null => false + t.integer "author_id" + t.text "author_signature" + t.text "parent_author_signature" + t.timestamps + end + end + + def self.down + drop_table :participations + end +end diff --git a/db/schema.rb b/db/schema.rb index b863d086e..c7d72dccb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120203220932) do +ActiveRecord::Schema.define(:version => 20120208231253) do create_table "account_deletions", :force => true do |t| t.string "diaspora_handle" @@ -244,6 +244,17 @@ ActiveRecord::Schema.define(:version => 20120203220932) do add_index "oauth_clients", ["name"], :name => "index_oauth_clients_on_name", :unique => true add_index "oauth_clients", ["nonce"], :name => "index_oauth_clients_on_nonce", :unique => true + create_table "participations", :force => true do |t| + t.string "guid" + t.integer "target_id" + t.string "target_type", :limit => 60, :null => false + t.integer "author_id" + t.text "author_signature" + t.text "parent_author_signature" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "people", :force => true do |t| t.string "guid", :null => false t.text "url", :null => false diff --git a/spec/models/like_spec.rb b/spec/models/like_spec.rb index 568701874..7e8bedfc9 100644 --- a/spec/models/like_spec.rb +++ b/spec/models/like_spec.rb @@ -7,8 +7,7 @@ require File.join(Rails.root, "spec", "shared_behaviors", "relayable") describe Like do before do - bobs_aspect = bob.aspects.first - @status = bob.post(:status_message, :text => "hello", :to => bobs_aspect.id) + @status = bob.post(:status_message, :text => "hello", :to => bob.aspects.first.id) end it 'has a valid factory' do @@ -94,5 +93,4 @@ describe Like do let(:build_object) { alice.build_like(:target => @status, :positive => true) } it_should_behave_like 'it is relayable' end - end diff --git a/spec/models/participation_spec.rb b/spec/models/participation_spec.rb new file mode 100644 index 000000000..7214c3e69 --- /dev/null +++ b/spec/models/participation_spec.rb @@ -0,0 +1,22 @@ +require "spec_helper" + +describe Participation do + describe 'it is relayable' do + before do + @status = bob.post(:status_message, :text => "hello", :to => bob.aspects.first.id) + + @local_luke, @local_leia, @remote_raphael = set_up_friends + @remote_parent = Factory(:status_message, :author => @remote_raphael) + @local_parent = @local_luke.post :status_message, :text => "foobar", :to => @local_luke.aspects.first + + @object_by_parent_author = @local_luke.participate!(@local_parent) + @object_by_recipient = @local_leia.participate!(@local_parent) + @dup_object_by_parent_author = @object_by_parent_author.dup + + @object_on_remote_parent = @local_luke.participate!(@remote_parent) + end + + let(:build_object) { alice.build_participation(:target => @status) } + it_should_behave_like 'it is relayable' + end +end \ No newline at end of file From f3c1eff3e9be33cecc043a63c62606091e4e6f5c Mon Sep 17 00:00:00 2001 From: Dennis Collinson Date: Thu, 9 Feb 2012 00:05:47 -0800 Subject: [PATCH 2/5] Refactor Relayable Creation --- app/models/comment.rb | 15 +++++++++++ app/models/federated_relayable.rb | 42 ----------------------------- app/models/like.rb | 12 ++++++++- app/models/participation.rb | 10 ++++++- app/models/user.rb | 43 ++++-------------------------- lib/federated/generator.rb | 32 ++++++++++++++++++++++ lib/federated/relayable.rb | 44 +++++++++++++++++++++++++++++++ spec/models/like_spec.rb | 2 +- spec/models/participation_spec.rb | 3 ++- 9 files changed, 119 insertions(+), 84 deletions(-) delete mode 100644 app/models/federated_relayable.rb create mode 100644 lib/federated/generator.rb create mode 100644 lib/federated/relayable.rb diff --git a/app/models/comment.rb b/app/models/comment.rb index b4e42f929..a19b09cb9 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -84,4 +84,19 @@ class Comment < ActiveRecord::Base def parent= parent self.post = parent end + + class Generator < Federated::Generator + def self.federated_class + Comment + end + + def initialize(person, target, text) + @text = text + super(person, target) + end + + def relayable_options + {:post => @target, :text => @text} + end + end end diff --git a/app/models/federated_relayable.rb b/app/models/federated_relayable.rb deleted file mode 100644 index 540ee0967..000000000 --- a/app/models/federated_relayable.rb +++ /dev/null @@ -1,42 +0,0 @@ -class FederatedRelayable < ActiveRecord::Base - self.abstract_class = true - - #crazy ordering issues - DEATH TO ROXML - include ROXML - - include Diaspora::Webhooks - include Diaspora::Guid - - #seriously, don't try to move this shit around until you have killed ROXML - xml_attr :target_type - include Diaspora::Relayable - - xml_attr :diaspora_handle - - belongs_to :target, :polymorphic => true - belongs_to :author, :class_name => 'Person' - #end crazy ordering issues - - validates_uniqueness_of :target_id, :scope => [:target_type, :author_id] - validates :parent, :presence => true #should be in relayable (pending on fixing Message) - - def diaspora_handle - self.author.diaspora_handle - end - - def diaspora_handle=(nh) - self.author = Webfinger.new(nh).fetch - end - - def parent_class - self.target_type.constantize - end - - def parent - self.target - end - - def parent= parent - self.target = parent - end -end \ No newline at end of file diff --git a/app/models/like.rb b/app/models/like.rb index 07dc4e2ea..af85c8d70 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -2,7 +2,17 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -class Like < FederatedRelayable +class Like < Federated::Relayable + class Generator < Federated::Generator + def self.federated_class + Like + end + + def relayable_options + {:target => @target, :positive => true} + end + end + after_create do self.parent.update_likes_counter end diff --git a/app/models/participation.rb b/app/models/participation.rb index 45ef129a6..229d1afc9 100644 --- a/app/models/participation.rb +++ b/app/models/participation.rb @@ -1,3 +1,11 @@ -class Participation < FederatedRelayable +class Participation < Federated::Relayable + class Generator < Federated::Generator + def self.federated_class + Participation + end + def relayable_options + {:target => @target} + end + end end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 6bafb452c..ebbed7f7c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -285,52 +285,19 @@ class User < ActiveRecord::Base end def comment!(post, text, opts={}) - comment = build_comment(opts.merge!(:post => post, :text => text)) - if comment.save - dispatch_post(comment) - comment - else - false - end + Comment::Generator.new(self.person, post, text).create!(opts) end def participate!(target, opts={}) - participation = build_participation(opts.merge!(:target => target)) - if participation.save - dispatch_post(participation) - participation - else - false - end + Participation::Generator.new(self.person, target).create!(opts) end def like!(target, opts={}) - like = build_like(opts.merge!(:target => target, :positive => true)) - if like.save - dispatch_post(like) - like - else - false - end + Like::Generator.new(self.person, target).create!(opts) end - def build_relayable(model, options = {}) - r = model.new(options.merge(:author_id => self.person.id)) - r.set_guid - r.initialize_signatures - r - end - - def build_comment(options = {}) - build_relayable(Comment, options) - end - - def build_participation(options = {}) - build_relayable(Participation, options) - end - - def build_like(options = {}) - build_relayable(Like, options) + def build_comment(options={}) + Comment::Generator.new(self.person, options.delete(:post), options.delete(:text)).build(options) end # Check whether the user has liked a post. diff --git a/lib/federated/generator.rb b/lib/federated/generator.rb new file mode 100644 index 000000000..f9dd2d265 --- /dev/null +++ b/lib/federated/generator.rb @@ -0,0 +1,32 @@ +module Federated + class Generator + def initialize(person, target) + @person = person + @target = target + end + + def build(options={}) + options.merge!(relayable_options) + relayable = self.class.federated_class.new(options.merge(:author_id => @person.id)) + relayable.set_guid + relayable.initialize_signatures + relayable + end + + def create!(options={}) + relayable = build(options) + if relayable.save + Postzord::Dispatcher.defer_build_and_post(@person, relayable) + relayable + else + false + end + end + + protected + + def relayable_options + {} + end + end +end \ No newline at end of file diff --git a/lib/federated/relayable.rb b/lib/federated/relayable.rb new file mode 100644 index 000000000..618c24820 --- /dev/null +++ b/lib/federated/relayable.rb @@ -0,0 +1,44 @@ +module Federated + class Relayable < ActiveRecord::Base + self.abstract_class = true + + #crazy ordering issues - DEATH TO ROXML + include ROXML + + include Diaspora::Webhooks + include Diaspora::Guid + + #seriously, don't try to move this shit around until you have killed ROXML + xml_attr :target_type + include Diaspora::Relayable + + xml_attr :diaspora_handle + + belongs_to :target, :polymorphic => true + belongs_to :author, :class_name => 'Person' + #end crazy ordering issues + + validates_uniqueness_of :target_id, :scope => [:target_type, :author_id] + validates :parent, :presence => true #should be in relayable (pending on fixing Message) + + def diaspora_handle + self.author.diaspora_handle + end + + def diaspora_handle=(nh) + self.author = Webfinger.new(nh).fetch + end + + def parent_class + self.target_type.constantize + end + + def parent + self.target + end + + def parent= parent + self.target = parent + end + end +end \ No newline at end of file diff --git a/spec/models/like_spec.rb b/spec/models/like_spec.rb index 7e8bedfc9..e9461192c 100644 --- a/spec/models/like_spec.rb +++ b/spec/models/like_spec.rb @@ -90,7 +90,7 @@ describe Like do @object_on_remote_parent = @local_luke.like!(@remote_parent) end - let(:build_object) { alice.build_like(:target => @status, :positive => true) } + let(:build_object) { Like::Generator.new(alice.person, @status).build } it_should_behave_like 'it is relayable' end end diff --git a/spec/models/participation_spec.rb b/spec/models/participation_spec.rb index 7214c3e69..12a1da5a0 100644 --- a/spec/models/participation_spec.rb +++ b/spec/models/participation_spec.rb @@ -16,7 +16,8 @@ describe Participation do @object_on_remote_parent = @local_luke.participate!(@remote_parent) end - let(:build_object) { alice.build_participation(:target => @status) } + let(:build_object) { Participation::Generator.new(alice.person, @status).build } + it_should_behave_like 'it is relayable' end end \ No newline at end of file From 14b9f5dc5bbb9ce85c431dd809921d157a71f07d Mon Sep 17 00:00:00 2001 From: Dennis Collinson Date: Thu, 9 Feb 2012 14:19:14 -0800 Subject: [PATCH 3/5] move user modules into user namespace. --- app/models/account_deleter.rb | 2 +- app/models/person.rb | 1 + app/models/post.rb | 2 + app/models/user.rb | 24 +--- app/models/user/connecting.rb | 70 ++++++++++ app/models/user/querying.rb | 164 +++++++++++++++++++++++ app/models/user/social_actions.rb | 19 +++ lib/diaspora/user.rb | 9 -- lib/diaspora/user/connecting.rb | 74 ----------- lib/diaspora/user/querying.rb | 169 ------------------------ lib/evil_query.rb | 1 + spec/lib/evil_query_spec.rb | 4 +- spec/models/user/connecting_spec.rb | 2 +- spec/models/user/querying_spec.rb | 3 +- spec/models/user/social_actions_spec.rb | 27 ++++ spec/models/user_spec.rb | 25 ---- 16 files changed, 294 insertions(+), 302 deletions(-) create mode 100644 app/models/user/connecting.rb create mode 100644 app/models/user/querying.rb create mode 100644 app/models/user/social_actions.rb delete mode 100644 lib/diaspora/user.rb delete mode 100644 lib/diaspora/user/connecting.rb delete mode 100644 lib/diaspora/user/querying.rb create mode 100644 spec/models/user/social_actions_spec.rb diff --git a/app/models/account_deleter.rb b/app/models/account_deleter.rb index f57b01775..f6d8bf45d 100644 --- a/app/models/account_deleter.rb +++ b/app/models/account_deleter.rb @@ -103,7 +103,7 @@ class AccountDeleter end def normal_ar_person_associates_to_delete - [:posts, :photos, :mentions] + [:posts, :photos, :mentions, :participations] end def ignored_or_special_ar_person_associations diff --git a/app/models/person.rb b/app/models/person.rb index a056decc2..a2fa97ec0 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -44,6 +44,7 @@ class Person < ActiveRecord::Base has_many :posts, :foreign_key => :author_id, :dependent => :destroy # This person's own posts has_many :photos, :foreign_key => :author_id, :dependent => :destroy # This person's own photos has_many :comments, :foreign_key => :author_id, :dependent => :destroy # This person's own comments + has_many :participations, :through => :posts, :foreign_key => :author_id, :dependent => :destroy belongs_to :owner, :class_name => 'User' diff --git a/app/models/post.rb b/app/models/post.rb index 2ed1617b5..769e3522d 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -9,6 +9,8 @@ class Post < ActiveRecord::Base include Diaspora::Commentable include Diaspora::Shareable + has_many :participations, :dependent => :delete_all, :as => :target + attr_accessor :user_like # NOTE API V1 to be extracted diff --git a/app/models/user.rb b/app/models/user.rb index ebbed7f7c..7c5ce1c59 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,15 +2,17 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -require File.join(Rails.root, 'lib/diaspora/user') require File.join(Rails.root, 'lib/salmon/salmon') require File.join(Rails.root, 'lib/postzord/dispatcher') require 'rest-client' class User < ActiveRecord::Base - include Diaspora::UserModules include Encryptor::Private + include Connecting + include Querying + include SocialActions + devise :invitable, :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :timeoutable, :token_authenticatable, :lockable, @@ -33,7 +35,7 @@ class User < ActiveRecord::Base serialize :hidden_shareables, Hash has_one :person, :foreign_key => :owner_id - delegate :public_key, :posts, :photos, :owns?, :diaspora_handle, :name, :public_url, :profile, :first_name, :last_name, :to => :person + delegate :public_key, :posts, :photos, :owns?, :diaspora_handle, :name, :public_url, :profile, :first_name, :last_name, :participations, :to => :person has_many :invitations_from_me, :class_name => 'Invitation', :foreign_key => :sender_id has_many :invitations_to_me, :class_name => 'Invitation', :foreign_key => :recipient_id @@ -284,22 +286,6 @@ class User < ActiveRecord::Base Salmon::EncryptedSlap.create_by_user_and_activity(self, post.to_diaspora_xml) end - def comment!(post, text, opts={}) - Comment::Generator.new(self.person, post, text).create!(opts) - end - - def participate!(target, opts={}) - Participation::Generator.new(self.person, target).create!(opts) - end - - def like!(target, opts={}) - Like::Generator.new(self.person, target).create!(opts) - end - - def build_comment(options={}) - Comment::Generator.new(self.person, options.delete(:post), options.delete(:text)).build(options) - end - # Check whether the user has liked a post. # @param [Post] post def liked?(target) diff --git a/app/models/user/connecting.rb b/app/models/user/connecting.rb new file mode 100644 index 000000000..5fa7588d1 --- /dev/null +++ b/app/models/user/connecting.rb @@ -0,0 +1,70 @@ +# Copyright (c) 2010-2011, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3 or later. See +# the COPYRIGHT file. + +module User::Connecting + # This will create a contact on the side of the sharer and the sharee. + # @param [Person] person The person to start sharing with. + # @param [Aspect] aspect The aspect to add them to. + # @return [Contact] The newly made contact for the passed in person. + def share_with(person, aspect) + contact = self.contacts.find_or_initialize_by_person_id(person.id) + return false unless contact.valid? + + unless contact.receiving? + contact.dispatch_request + contact.receiving = true + end + + contact.aspects << aspect + contact.save + + if notification = Notification.where(:target_id => person.id).first + notification.update_attributes(:unread=>false) + end + + register_share_visibilities(contact) + contact + end + + # This puts the last 100 public posts by the passed in contact into the user's stream. + # @param [Contact] contact + # @return [void] + def register_share_visibilities(contact) + #should have select here, but proven hard to test + posts = Post.where(:author_id => contact.person_id, :public => true).limit(100) + p = posts.map do |post| + ShareVisibility.new(:contact_id => contact.id, :shareable_id => post.id, :shareable_type => 'Post') + end + ShareVisibility.import(p) unless posts.empty? + nil + end + + def remove_contact(contact, opts={:force => false}) + posts = contact.posts.all + + if !contact.mutual? || opts[:force] + contact.destroy + else + contact.update_attributes(:receiving => false) + end + end + + def disconnect(bad_contact, opts={}) + person = bad_contact.person + Rails.logger.info("event=disconnect user=#{diaspora_handle} target=#{person.diaspora_handle}") + retraction = Retraction.for(self) + retraction.subscribers = [person]#HAX + Postzord::Dispatcher.build(self, retraction).post + + AspectMembership.where(:contact_id => bad_contact.id).delete_all + remove_contact(bad_contact, opts) + end + + def disconnected_by(person) + Rails.logger.info("event=disconnected_by user=#{diaspora_handle} target=#{person.diaspora_handle}") + if contact = self.contact_for(person) + remove_contact(contact) + end + end +end diff --git a/app/models/user/querying.rb b/app/models/user/querying.rb new file mode 100644 index 000000000..d4c7da6c3 --- /dev/null +++ b/app/models/user/querying.rb @@ -0,0 +1,164 @@ +# Copyright (c) 2010-2011, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3 or later. See +# the COPYRIGHT file. + +require File.join(Rails.root, 'lib', 'evil_query') + + +#TODO: THIS FILE SHOULD NOT EXIST, EVIL SQL SHOULD BE ENCAPSULATED IN EvilQueries, +#throwing all of this stuff in user violates demeter like WHOA +module User::Querying + def find_visible_shareable_by_id(klass, id, opts={} ) + key = (opts.delete(:key) || :id) + ::EvilQuery::VisibleShareableById.new(self, klass, key, id, opts).post! + end + + def visible_shareables(klass, opts={}) + opts = prep_opts(klass, opts) + shareable_ids = visible_shareable_ids(klass, opts) + klass.where(:id => shareable_ids).select('DISTINCT '+klass.to_s.tableize+'.*').limit(opts[:limit]).order(opts[:order_with_table]) + end + + def visible_shareable_ids(klass, opts={}) + opts = prep_opts(klass, opts) + visible_ids_from_sql(klass, opts) + end + + # @return [Array] + def visible_ids_from_sql(klass, opts={}) + opts = prep_opts(klass, opts) + opts[:klass] = klass + opts[:by_members_of] ||= self.aspect_ids + + post_ids = klass.connection.select_values(visible_shareable_sql(klass, opts)).map { |id| id.to_i } + post_ids += klass.connection.select_values(construct_public_followings_sql(opts).to_sql).map {|id| id.to_i } + end + + def visible_shareable_sql(klass, opts={}) + table = klass.table_name + opts = prep_opts(klass, opts) + opts[:klass] = klass + + shareable_from_others = construct_shareable_from_others_query(opts) + shareable_from_self = construct_shareable_from_self_query(opts) + + "(#{shareable_from_others.to_sql} LIMIT #{opts[:limit]}) UNION ALL (#{shareable_from_self.to_sql} LIMIT #{opts[:limit]}) ORDER BY #{opts[:order]} LIMIT #{opts[:limit]}" + end + + def ugly_select_clause(query, opts) + klass = opts[:klass] + select_clause ='DISTINCT %s.id, %s.updated_at AS updated_at, %s.created_at AS created_at' % [klass.table_name, klass.table_name, klass.table_name] + query.select(select_clause).order(opts[:order_with_table]).where(klass.arel_table[opts[:order_field]].lt(opts[:max_time])) + end + + def construct_shareable_from_others_query(opts) + conditions = { + :pending => false, + :share_visibilities => {:hidden => opts[:hidden]}, + :contacts => {:user_id => self.id, :receiving => true} + } + + conditions[:type] = opts[:type] if opts.has_key?(:type) + + query = opts[:klass].joins(:contacts).where(conditions) + + if opts[:by_members_of] + query = query.joins(:contacts => :aspect_memberships).where( + :aspect_memberships => {:aspect_id => opts[:by_members_of]}) + end + + ugly_select_clause(query, opts) + end + + def construct_public_followings_sql(opts) + aspects = Aspect.where(:id => opts[:by_members_of]) + person_ids = Person.connection.select_values(people_in_aspects(aspects).select("people.id").to_sql) + + query = opts[:klass].where(:author_id => person_ids, :public => true, :pending => false) + + unless(opts[:klass] == Photo) + query = query.where(:type => opts[:type]) + end + + ugly_select_clause(query, opts) + end + + def construct_shareable_from_self_query(opts) + conditions = {:pending => false } + conditions[:type] = opts[:type] if opts.has_key?(:type) + query = self.person.send(opts[:klass].to_s.tableize).where(conditions) + + if opts[:by_members_of] + query = query.joins(:aspect_visibilities).where(:aspect_visibilities => {:aspect_id => opts[:by_members_of]}) + end + + ugly_select_clause(query, opts) + end + + def contact_for(person) + return nil unless person + contact_for_person_id(person.id) + end + + def aspects_with_shareable(base_class_name_or_class, shareable_id) + base_class_name = base_class_name_or_class + base_class_name = base_class_name_or_class.base_class.to_s if base_class_name_or_class.is_a?(Class) + self.aspects.joins(:aspect_visibilities).where(:aspect_visibilities => {:shareable_id => shareable_id, :shareable_type => base_class_name}) + end + + def contact_for_person_id(person_id) + Contact.where(:user_id => self.id, :person_id => person_id).includes(:person => :profile).first + end + + # @param [Person] person + # @return [Boolean] whether person is a contact of this user + def has_contact_for?(person) + Contact.exists?(:user_id => self.id, :person_id => person.id) + end + + def people_in_aspects(requested_aspects, opts={}) + allowed_aspects = self.aspects & requested_aspects + aspect_ids = allowed_aspects.map(&:id) + + people = Person.in_aspects(aspect_ids) + + if opts[:type] == 'remote' + people = people.where(:owner_id => nil) + elsif opts[:type] == 'local' + people = people.where('people.owner_id IS NOT NULL') + end + people + end + + def aspects_with_person person + contact_for(person).aspects + end + + def posts_from(person) + ::EvilQuery::ShareablesFromPerson.new(self, Post, person).make_relation! + end + + def photos_from(person) + ::EvilQuery::ShareablesFromPerson.new(self, Photo, person).make_relation! + end + + protected + + # @return [Hash] + def prep_opts(klass, opts) + defaults = { + :order => 'created_at DESC', + :limit => 15, + :hidden => false + } + defaults[:type] = Stream::Base::TYPES_OF_POST_IN_STREAM if klass == Post + opts = defaults.merge(opts) + + opts[:order_field] = opts[:order].split.first.to_sym + opts[:order_with_table] = klass.table_name + '.' + opts[:order] + + opts[:max_time] = Time.at(opts[:max_time]) if opts[:max_time].is_a?(Integer) + opts[:max_time] ||= Time.now + 1 + opts + end +end diff --git a/app/models/user/social_actions.rb b/app/models/user/social_actions.rb new file mode 100644 index 000000000..fbc0640a5 --- /dev/null +++ b/app/models/user/social_actions.rb @@ -0,0 +1,19 @@ +module User::SocialActions + def comment!(post, text, opts={}) + participations.where(:target_id => post).first || participate!(post) + Comment::Generator.new(self.person, post, text).create!(opts) + end + + def participate!(target, opts={}) + Participation::Generator.new(self.person, target).create!(opts) + end + + def like!(target, opts={}) + participations.where(:target_id => target).first || participate!(target) + Like::Generator.new(self.person, target).create!(opts) + end + + def build_comment(options={}) + Comment::Generator.new(self.person, options.delete(:post), options.delete(:text)).build(options) + end +end \ No newline at end of file diff --git a/lib/diaspora/user.rb b/lib/diaspora/user.rb deleted file mode 100644 index 6c346dabc..000000000 --- a/lib/diaspora/user.rb +++ /dev/null @@ -1,9 +0,0 @@ -require File.join(Rails.root, 'lib/diaspora/user/connecting') -require File.join(Rails.root, 'lib/diaspora/user/querying') - -module Diaspora - module UserModules - include Connecting - include Querying - end -end diff --git a/lib/diaspora/user/connecting.rb b/lib/diaspora/user/connecting.rb deleted file mode 100644 index c52dea5f7..000000000 --- a/lib/diaspora/user/connecting.rb +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2010-2011, Diaspora Inc. This file is -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. - -module Diaspora - module UserModules - module Connecting - # This will create a contact on the side of the sharer and the sharee. - # @param [Person] person The person to start sharing with. - # @param [Aspect] aspect The aspect to add them to. - # @return [Contact] The newly made contact for the passed in person. - def share_with(person, aspect) - contact = self.contacts.find_or_initialize_by_person_id(person.id) - return false unless contact.valid? - - unless contact.receiving? - contact.dispatch_request - contact.receiving = true - end - - contact.aspects << aspect - contact.save - - if notification = Notification.where(:target_id => person.id).first - notification.update_attributes(:unread=>false) - end - - register_share_visibilities(contact) - contact - end - - # This puts the last 100 public posts by the passed in contact into the user's stream. - # @param [Contact] contact - # @return [void] - def register_share_visibilities(contact) - #should have select here, but proven hard to test - posts = Post.where(:author_id => contact.person_id, :public => true).limit(100) - p = posts.map do |post| - ShareVisibility.new(:contact_id => contact.id, :shareable_id => post.id, :shareable_type => 'Post') - end - ShareVisibility.import(p) unless posts.empty? - nil - end - - def remove_contact(contact, opts={:force => false}) - posts = contact.posts.all - - if !contact.mutual? || opts[:force] - contact.destroy - else - contact.update_attributes(:receiving => false) - end - end - - def disconnect(bad_contact, opts={}) - person = bad_contact.person - Rails.logger.info("event=disconnect user=#{diaspora_handle} target=#{person.diaspora_handle}") - retraction = Retraction.for(self) - retraction.subscribers = [person]#HAX - Postzord::Dispatcher.build(self, retraction).post - - AspectMembership.where(:contact_id => bad_contact.id).delete_all - remove_contact(bad_contact, opts) - end - - def disconnected_by(person) - Rails.logger.info("event=disconnected_by user=#{diaspora_handle} target=#{person.diaspora_handle}") - if contact = self.contact_for(person) - remove_contact(contact) - end - end - end - end -end diff --git a/lib/diaspora/user/querying.rb b/lib/diaspora/user/querying.rb deleted file mode 100644 index 61665561b..000000000 --- a/lib/diaspora/user/querying.rb +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) 2010-2011, Diaspora Inc. This file is -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. - -require File.join(Rails.root, 'lib', 'evil_query') - - -#TODO: THIS FILE SHOULD NOT EXIST, EVIL SQL SHOULD BE ENCAPSULATED IN EvilQueries, -#throwing all of this stuff in user violates demeter like WHOA - -module Diaspora - module UserModules - module Querying - def find_visible_shareable_by_id(klass, id, opts={} ) - key = (opts.delete(:key) || :id) - ::EvilQuery::VisibleShareableById.new(self, klass, key, id, opts).post! - end - - def visible_shareables(klass, opts={}) - opts = prep_opts(klass, opts) - shareable_ids = visible_shareable_ids(klass, opts) - klass.where(:id => shareable_ids).select('DISTINCT '+klass.to_s.tableize+'.*').limit(opts[:limit]).order(opts[:order_with_table]) - end - - def visible_shareable_ids(klass, opts={}) - opts = prep_opts(klass, opts) - visible_ids_from_sql(klass, opts) - end - - # @return [Array] - def visible_ids_from_sql(klass, opts={}) - opts = prep_opts(klass, opts) - opts[:klass] = klass - opts[:by_members_of] ||= self.aspect_ids - - post_ids = klass.connection.select_values(visible_shareable_sql(klass, opts)).map { |id| id.to_i } - post_ids += klass.connection.select_values(construct_public_followings_sql(opts).to_sql).map {|id| id.to_i } - end - - def visible_shareable_sql(klass, opts={}) - table = klass.table_name - opts = prep_opts(klass, opts) - opts[:klass] = klass - - shareable_from_others = construct_shareable_from_others_query(opts) - shareable_from_self = construct_shareable_from_self_query(opts) - - "(#{shareable_from_others.to_sql} LIMIT #{opts[:limit]}) UNION ALL (#{shareable_from_self.to_sql} LIMIT #{opts[:limit]}) ORDER BY #{opts[:order]} LIMIT #{opts[:limit]}" - end - - def ugly_select_clause(query, opts) - klass = opts[:klass] - select_clause ='DISTINCT %s.id, %s.updated_at AS updated_at, %s.created_at AS created_at' % [klass.table_name, klass.table_name, klass.table_name] - query.select(select_clause).order(opts[:order_with_table]).where(klass.arel_table[opts[:order_field]].lt(opts[:max_time])) - end - - def construct_shareable_from_others_query(opts) - conditions = { - :pending => false, - :share_visibilities => {:hidden => opts[:hidden]}, - :contacts => {:user_id => self.id, :receiving => true} - } - - conditions[:type] = opts[:type] if opts.has_key?(:type) - - query = opts[:klass].joins(:contacts).where(conditions) - - if opts[:by_members_of] - query = query.joins(:contacts => :aspect_memberships).where( - :aspect_memberships => {:aspect_id => opts[:by_members_of]}) - end - - ugly_select_clause(query, opts) - end - - def construct_public_followings_sql(opts) - aspects = Aspect.where(:id => opts[:by_members_of]) - person_ids = Person.connection.select_values(people_in_aspects(aspects).select("people.id").to_sql) - - query = opts[:klass].where(:author_id => person_ids, :public => true, :pending => false) - - unless(opts[:klass] == Photo) - query = query.where(:type => opts[:type]) - end - - ugly_select_clause(query, opts) - end - - def construct_shareable_from_self_query(opts) - conditions = {:pending => false } - conditions[:type] = opts[:type] if opts.has_key?(:type) - query = self.person.send(opts[:klass].to_s.tableize).where(conditions) - - if opts[:by_members_of] - query = query.joins(:aspect_visibilities).where(:aspect_visibilities => {:aspect_id => opts[:by_members_of]}) - end - - ugly_select_clause(query, opts) - end - - def contact_for(person) - return nil unless person - contact_for_person_id(person.id) - end - - def aspects_with_shareable(base_class_name_or_class, shareable_id) - base_class_name = base_class_name_or_class - base_class_name = base_class_name_or_class.base_class.to_s if base_class_name_or_class.is_a?(Class) - self.aspects.joins(:aspect_visibilities).where(:aspect_visibilities => {:shareable_id => shareable_id, :shareable_type => base_class_name}) - end - - def contact_for_person_id(person_id) - Contact.where(:user_id => self.id, :person_id => person_id).includes(:person => :profile).first - end - - # @param [Person] person - # @return [Boolean] whether person is a contact of this user - def has_contact_for?(person) - Contact.exists?(:user_id => self.id, :person_id => person.id) - end - - def people_in_aspects(requested_aspects, opts={}) - allowed_aspects = self.aspects & requested_aspects - aspect_ids = allowed_aspects.map(&:id) - - people = Person.in_aspects(aspect_ids) - - if opts[:type] == 'remote' - people = people.where(:owner_id => nil) - elsif opts[:type] == 'local' - people = people.where('people.owner_id IS NOT NULL') - end - people - end - - def aspects_with_person person - contact_for(person).aspects - end - - def posts_from(person) - ::EvilQuery::ShareablesFromPerson.new(self, Post, person).make_relation! - end - - def photos_from(person) - ::EvilQuery::ShareablesFromPerson.new(self, Photo, person).make_relation! - end - - protected - - # @return [Hash] - def prep_opts(klass, opts) - defaults = { - :order => 'created_at DESC', - :limit => 15, - :hidden => false - } - defaults[:type] = Stream::Base::TYPES_OF_POST_IN_STREAM if klass == Post - opts = defaults.merge(opts) - - opts[:order_field] = opts[:order].split.first.to_sym - opts[:order_with_table] = klass.table_name + '.' + opts[:order] - - opts[:max_time] = Time.at(opts[:max_time]) if opts[:max_time].is_a?(Integer) - opts[:max_time] ||= Time.now + 1 - opts - end - end - end -end diff --git a/lib/evil_query.rb b/lib/evil_query.rb index e507c78ad..0b91d6793 100644 --- a/lib/evil_query.rb +++ b/lib/evil_query.rb @@ -17,6 +17,7 @@ module EvilQuery end def posts +# Post.joins(:participations).where(:participations => {:author_id => @user.id}).order("posts.interacted_at DESC") liked_post_ids = fetch_ids!(LikedPosts.new(@user).posts, "posts.id") commented_post_ids = fetch_ids!(CommentedPosts.new(@user).posts, "posts.id") Post.where(:id => liked_post_ids + commented_post_ids).order("posts.interacted_at DESC") diff --git a/spec/lib/evil_query_spec.rb b/spec/lib/evil_query_spec.rb index 10ee9ffe4..68cd11199 100644 --- a/spec/lib/evil_query_spec.rb +++ b/spec/lib/evil_query_spec.rb @@ -6,7 +6,7 @@ describe EvilQuery::Participation do end it "includes posts liked by the user" do - Factory(:like, :target => @status_message, :author => alice.person) + alice.like!(@status_message) EvilQuery::Participation.new(alice).posts.should include(@status_message) end @@ -35,7 +35,7 @@ describe EvilQuery::Participation do alice.comment!(@status_messageB, "party") Timecop.travel time += 1.month - Factory(:like, :target => @status_messageA, :author => alice.person) + alice.like!(@status_messageA) Timecop.travel time += 1.month alice.comment!(@photoC, "party") diff --git a/spec/models/user/connecting_spec.rb b/spec/models/user/connecting_spec.rb index 1329120cf..e1114ee12 100644 --- a/spec/models/user/connecting_spec.rb +++ b/spec/models/user/connecting_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' -describe Diaspora::UserModules::Connecting do +describe User::Connecting do let(:aspect) { alice.aspects.first } let(:aspect1) { alice.aspects.create(:name => 'other') } diff --git a/spec/models/user/querying_spec.rb b/spec/models/user/querying_spec.rb index b9cb377fd..36b9b4d02 100644 --- a/spec/models/user/querying_spec.rb +++ b/spec/models/user/querying_spec.rb @@ -4,8 +4,7 @@ require 'spec_helper' -describe User do - +describe User::Querying do before do @alices_aspect = alice.aspects.where(:name => "generic").first @eves_aspect = eve.aspects.where(:name => "generic").first diff --git a/spec/models/user/social_actions_spec.rb b/spec/models/user/social_actions_spec.rb new file mode 100644 index 000000000..d300a14c7 --- /dev/null +++ b/spec/models/user/social_actions_spec.rb @@ -0,0 +1,27 @@ +require "spec_helper" + +describe User::SocialActions do + describe 'User#like!' do + before do + @bobs_aspect = bob.aspects.where(:name => "generic").first + @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id) + end + + it "should be able to like on one's own status" do + like = alice.like!(@status) + @status.reload.likes.first.should == like + end + + it "should be able to like on a contact's status" do + like = bob.like!(@status) + @status.reload.likes.first.should == like + end + + it "does not allow multiple likes" do + alice.like!(@status) + lambda { + alice.like!(@status) + }.should_not change(@status, :likes) + end + end +end \ No newline at end of file diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index e7c765965..f4f286622 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -5,7 +5,6 @@ require 'spec_helper' describe User do - describe "private key" do it 'has a key' do alice.encryption_key.should_not be nil @@ -688,30 +687,6 @@ describe User do @like2 = bob.like!(@message) end - describe 'User#like' do - before do - @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id) - end - - it "should be able to like on one's own status" do - like = alice.like!(@status) - @status.reload.likes.first.should == like - end - - it "should be able to like on a contact's status" do - like = bob.like!(@status) - @status.reload.likes.first.should == like - end - - it "does not allow multiple likes" do - alice.like!(@status) - - lambda { - alice.like!(@status) - }.should_not change(@status, :likes) - end - end - describe '#like_for' do it 'returns the correct like' do alice.like_for(@message).should == @like From 5e26a7e6bb5ac2f78a27cc01c298dfd4564ffd0b Mon Sep 17 00:00:00 2001 From: Dennis Collinson Date: Thu, 9 Feb 2012 16:42:26 -0800 Subject: [PATCH 4/5] Participate stream query uses participations --- app/models/person.rb | 2 +- lib/evil_query.rb | 5 +-- spec/models/user/social_actions_spec.rb | 58 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/app/models/person.rb b/app/models/person.rb index a2fa97ec0..48b768f08 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -44,7 +44,7 @@ class Person < ActiveRecord::Base has_many :posts, :foreign_key => :author_id, :dependent => :destroy # This person's own posts has_many :photos, :foreign_key => :author_id, :dependent => :destroy # This person's own photos has_many :comments, :foreign_key => :author_id, :dependent => :destroy # This person's own comments - has_many :participations, :through => :posts, :foreign_key => :author_id, :dependent => :destroy + has_many :participations, :foreign_key => :author_id, :dependent => :destroy belongs_to :owner, :class_name => 'User' diff --git a/lib/evil_query.rb b/lib/evil_query.rb index 0b91d6793..113890c3b 100644 --- a/lib/evil_query.rb +++ b/lib/evil_query.rb @@ -17,10 +17,7 @@ module EvilQuery end def posts -# Post.joins(:participations).where(:participations => {:author_id => @user.id}).order("posts.interacted_at DESC") - liked_post_ids = fetch_ids!(LikedPosts.new(@user).posts, "posts.id") - commented_post_ids = fetch_ids!(CommentedPosts.new(@user).posts, "posts.id") - Post.where(:id => liked_post_ids + commented_post_ids).order("posts.interacted_at DESC") + Post.joins(:participations).where(:participations => {:author_id => @user.person.id}).order("posts.interacted_at DESC") end end diff --git a/spec/models/user/social_actions_spec.rb b/spec/models/user/social_actions_spec.rb index d300a14c7..a9a88078b 100644 --- a/spec/models/user/social_actions_spec.rb +++ b/spec/models/user/social_actions_spec.rb @@ -1,12 +1,70 @@ require "spec_helper" describe User::SocialActions do + before do + @bobs_aspect = bob.aspects.where(:name => "generic").first + @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id) + end + + describe 'User#comment!' do + it "sets the comment text" do + alice.comment!(@status, "unicorn_mountain").text.should == "unicorn_mountain" + end + + it "creates a partcipation" do + lambda{ alice.comment!(@status, "bro") }.should change(Participation, :count).by(1) + alice.participations.last.target.should == @status + end + + it "creates the like" do + lambda{ alice.comment!(@status, "bro") }.should change(Comment, :count).by(1) + end + + it "federates" do + Participation::Generator.any_instance.stub(:create!) + Postzord::Dispatcher.should_receive(:defer_build_and_post) + alice.comment!(@status, "omg") + end + end + + describe 'User#like!' do + it "creates a partcipation" do + lambda{ alice.like!(@status) }.should change(Participation, :count).by(1) + alice.participations.last.target.should == @status + end + + it "creates the like" do + lambda{ alice.like!(@status) }.should change(Like, :count).by(1) + end + + it "federates" do + #participation and like + Participation::Generator.any_instance.stub(:create!) + Postzord::Dispatcher.should_receive(:defer_build_and_post) + alice.like!(@status) + end + end + describe 'User#like!' do before do @bobs_aspect = bob.aspects.where(:name => "generic").first @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id) end + it "creates a partcipation" do + lambda{ alice.like!(@status) }.should change(Participation, :count).by(1) + end + + it "creates the like" do + lambda{ alice.like!(@status) }.should change(Like, :count).by(1) + end + + it "federates" do + #participation and like + Postzord::Dispatcher.should_receive(:defer_build_and_post).twice + alice.like!(@status) + end + it "should be able to like on one's own status" do like = alice.like!(@status) @status.reload.likes.first.should == like From 04bd507025dd4764c4a58952ec94a164e03d78f3 Mon Sep 17 00:00:00 2001 From: Dennis Collinson Date: Thu, 9 Feb 2012 18:06:02 -0800 Subject: [PATCH 5/5] federated generators take a user --- app/models/user/social_actions.rb | 12 ++++++------ lib/federated/generator.rb | 22 +++++++++++----------- spec/models/like_spec.rb | 2 +- spec/models/participation_spec.rb | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/models/user/social_actions.rb b/app/models/user/social_actions.rb index fbc0640a5..3244b9bad 100644 --- a/app/models/user/social_actions.rb +++ b/app/models/user/social_actions.rb @@ -1,19 +1,19 @@ module User::SocialActions - def comment!(post, text, opts={}) - participations.where(:target_id => post).first || participate!(post) - Comment::Generator.new(self.person, post, text).create!(opts) + def comment!(target, text, opts={}) + participations.where(:target_id => target).first || participate!(target) + Comment::Generator.new(self, target, text).create!(opts) end def participate!(target, opts={}) - Participation::Generator.new(self.person, target).create!(opts) + Participation::Generator.new(self, target).create!(opts) end def like!(target, opts={}) participations.where(:target_id => target).first || participate!(target) - Like::Generator.new(self.person, target).create!(opts) + Like::Generator.new(self, target).create!(opts) end def build_comment(options={}) - Comment::Generator.new(self.person, options.delete(:post), options.delete(:text)).build(options) + Comment::Generator.new(self, options.delete(:post), options.delete(:text)).build(options) end end \ No newline at end of file diff --git a/lib/federated/generator.rb b/lib/federated/generator.rb index f9dd2d265..68f95e292 100644 --- a/lib/federated/generator.rb +++ b/lib/federated/generator.rb @@ -1,28 +1,28 @@ module Federated class Generator - def initialize(person, target) - @person = person + def initialize(user, target) + @user = user @target = target end - def build(options={}) - options.merge!(relayable_options) - relayable = self.class.federated_class.new(options.merge(:author_id => @person.id)) - relayable.set_guid - relayable.initialize_signatures - relayable - end - def create!(options={}) relayable = build(options) if relayable.save - Postzord::Dispatcher.defer_build_and_post(@person, relayable) + Postzord::Dispatcher.defer_build_and_post(@user, relayable) relayable else false end end + def build(options={}) + options.merge!(relayable_options) + relayable = self.class.federated_class.new(options.merge(:author_id => @user.person.id)) + relayable.set_guid + relayable.initialize_signatures + relayable + end + protected def relayable_options diff --git a/spec/models/like_spec.rb b/spec/models/like_spec.rb index e9461192c..46d676b76 100644 --- a/spec/models/like_spec.rb +++ b/spec/models/like_spec.rb @@ -90,7 +90,7 @@ describe Like do @object_on_remote_parent = @local_luke.like!(@remote_parent) end - let(:build_object) { Like::Generator.new(alice.person, @status).build } + let(:build_object) { Like::Generator.new(alice, @status).build } it_should_behave_like 'it is relayable' end end diff --git a/spec/models/participation_spec.rb b/spec/models/participation_spec.rb index 12a1da5a0..61a8fdac8 100644 --- a/spec/models/participation_spec.rb +++ b/spec/models/participation_spec.rb @@ -16,7 +16,7 @@ describe Participation do @object_on_remote_parent = @local_luke.participate!(@remote_parent) end - let(:build_object) { Participation::Generator.new(alice.person, @status).build } + let(:build_object) { Participation::Generator.new(alice, @status).build } it_should_behave_like 'it is relayable' end