diff --git a/app/controllers/aspects_controller.rb b/app/controllers/aspects_controller.rb index ad4958ae335c868e69e33be94fb57ff67af9b342..c2051bef8ec4d048a99521fcaca1eabf7af3f348 100644 --- a/app/controllers/aspects_controller.rb +++ b/app/controllers/aspects_controller.rb @@ -44,7 +44,7 @@ class AspectsController < ApplicationController @aspect_ids = @aspects.map { |a| a.id } posts = current_user.visible_posts(:by_members_of => @aspect_ids, - :type => ['StatusMessage','ActivityStreams::Photo'], + :type => ['StatusMessage','Reshare', 'ActivityStreams::Photo'], :order => session[:sort_order] + ' DESC', :max_time => params[:max_time].to_i ).includes(:mentions => {:person => :profile}) diff --git a/app/controllers/reshares_controller.rb b/app/controllers/reshares_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..d28a0c0a5fffe14725a0c0c88ba0b5093f5e0cc1 --- /dev/null +++ b/app/controllers/reshares_controller.rb @@ -0,0 +1,13 @@ +class ResharesController < ApplicationController + before_filter :authenticate_user! + respond_to :js + + def create + @reshare = current_user.build_post(:reshare, :root_id => params[:root_id]) + if @reshare.save! + current_user.add_to_streams(@reshare, current_user.aspects) + end + + respond_with @reshare + end +end diff --git a/app/helpers/reshares_helper.rb b/app/helpers/reshares_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..f1b23f5220dbb59409cfd1a4afe5c6ffa92a4aaf --- /dev/null +++ b/app/helpers/reshares_helper.rb @@ -0,0 +1,2 @@ +module ResharesHelper +end diff --git a/app/models/reshare.rb b/app/models/reshare.rb new file mode 100644 index 0000000000000000000000000000000000000000..2b0366518e848a0e425d54a7c37daf4beaea4d5a --- /dev/null +++ b/app/models/reshare.rb @@ -0,0 +1,19 @@ +class Reshare < Post + belongs_to :root, :class_name => 'Post' + validate :root_must_be_public + attr_accessible :root_id, + + before_validation do + self.public = true + end + + delegate :photos, :text, :comments, :to => :root + private + + def root_must_be_public + if self.root.nil? || !self.root.public + errors[:base] << "you must reshare public posts" + return false + end + end +end diff --git a/app/views/reshares/create.js.erb b/app/views/reshares/create.js.erb new file mode 100644 index 0000000000000000000000000000000000000000..f25d9629f2be8cb910b3e59c95ceda3443956400 --- /dev/null +++ b/app/views/reshares/create.js.erb @@ -0,0 +1 @@ +$('.stream_element[data-guid=<%=params[:root_id]%>]').addClass('reshared'); diff --git a/app/views/shared/_stream.haml b/app/views/shared/_stream.haml index 95ee72a0f5eaa58665d3c453b2bd1470dd80db14..1d79fb636c05752b22c2e5464d814c9c8d90be49 100644 --- a/app/views/shared/_stream.haml +++ b/app/views/shared/_stream.haml @@ -3,7 +3,7 @@ -# the COPYRIGHT file. -= render :partial => 'shared/stream_element', += render :partial => 'shared/stream_element_shim', :collection => posts, :as => :post, :locals => { :commenting_disabled => defined?(@commenting_disabled)} diff --git a/app/views/shared/_stream_element.html.haml b/app/views/shared/_stream_element.html.haml index 55f27f1efe94eb3f58a7cdd9ae2dd24d4fa49883..0a2049f31ea09c7fafc40a9f98699823962b99e4 100644 --- a/app/views/shared/_stream_element.html.haml +++ b/app/views/shared/_stream_element.html.haml @@ -4,11 +4,18 @@ .stream_element{:id => post.guid} - if current_user && post.author.owner_id == current_user.id + - if reshare + .reshare_attribution + = "reshared by #{reshare.author.name}" .right.controls = link_to image_tag('deletelabel.png'), post_path(post), :confirm => t('are_you_sure'), :method => :delete, :remote => true, :class => "delete stream_element_delete", :title => t('delete') + - else - .right.controls - = link_to image_tag('deletelabel.png'), post_visibility_path(:id => "42", :post_id => post.id), :method => :put, :remote => true, :class => "delete stream_element_delete", :title => t('hide') + .right + - if reshare + .reshare_attribution= "reshared by #{reshare.author.name}" + .controls + = link_to image_tag('deletelabel.png'), post_visibility_path(:id => "42", :post_id => post.id), :method => :put, :remote => true, :class => "delete stream_element_delete", :title => t('hide') .undo_text.hidden = t('post_visibilites.update.post_hidden', :name => post.author.name) = link_to t('undo'), post_visibility_path(:id => "42", :post_id => post.id), :method => :put, :remote => true, :class => "delete stream_element_delete" diff --git a/app/views/shared/_stream_element_shim.haml b/app/views/shared/_stream_element_shim.haml new file mode 100644 index 0000000000000000000000000000000000000000..a5dd321c44720faa55cef8d5f5bb676e14b83f75 --- /dev/null +++ b/app/views/shared/_stream_element_shim.haml @@ -0,0 +1,5 @@ + +-if post.model.is_a?(Reshare) + = render 'shared/stream_element', :post => post.root, :all_aspects => all_aspects, :commenting_disabled => commenting_disabled, :reshare => post +- else + = render 'shared/stream_element', :post => post, :all_aspects => all_aspects, :commenting_disabled => commenting_disabled, :reshare => nil diff --git a/db/migrate/20110525213325_add_root_id_to_posts.rb b/db/migrate/20110525213325_add_root_id_to_posts.rb new file mode 100644 index 0000000000000000000000000000000000000000..7f6969b54db4e0f79834bdfcbebe5189112057bf --- /dev/null +++ b/db/migrate/20110525213325_add_root_id_to_posts.rb @@ -0,0 +1,9 @@ +class AddRootIdToPosts < ActiveRecord::Migration + def self.up + add_column :posts, :root_id, :integer + end + + def self.down + remove_column :posts, :root_id + end +end diff --git a/features/repost.feature b/features/repost.feature new file mode 100644 index 0000000000000000000000000000000000000000..1be45daaf04f9b2789da959d5d50ae215e6d0169 --- /dev/null +++ b/features/repost.feature @@ -0,0 +1,29 @@ +@javascript +Feature: public repost + In order to make Diaspora more viral + As a User + I want to reshare my friends post + + Background: + Given a user named "Bob Jones" with email "bob@bob.bob" + And a user named "Alice Smith" with email "alice@alice.alice" + And a user with email "bob@bob.bob" is connected with "alice@alice.alice" + And "bob@bob.bob" has a public post with text "reshare this!" + And I sign in as "alice@alice.alice" + And I preemptively confirm the alert + And I follow "Reshare" + And I wait for the ajax to finish + + Scenario: shows up on the profile page + Then I should see a ".reshared" + And I am on "alice@alice.alice"'s page + Then I should see "reshare this!" + Then I should see a ".reshared" + And I should see "Bob" + + Scenario: shows up on the aspects page + Then I should see a ".reshared" + And I follow "All Aspects" + Then I should see "reshare this!" + Then I should see a ".reshared" + And I should see "Bob" diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass index b02d1881e5227178df0b816369dc7b7ee277c865..d3d462a100d10353a08780431f5da4faa1466e00 100644 --- a/public/stylesheets/sass/application.sass +++ b/public/stylesheets/sass/application.sass @@ -376,6 +376,10 @@ ul.as-selections &:hover :text :decoration none +.reshare_attribution + :font-size smaller +.reshared + :background-color #eee .stream_element :position relative diff --git a/spec/controllers/aspects_controller_spec.rb b/spec/controllers/aspects_controller_spec.rb index 792ac7a9edf895dbd21e4e38d399f67b99c0acb0..f0a2794a6cfe23de05816ca6f3105796732fce76 100644 --- a/spec/controllers/aspects_controller_spec.rb +++ b/spec/controllers/aspects_controller_spec.rb @@ -179,6 +179,12 @@ describe AspectsController do assigns(:posts).models.length.should == 2 end + it "posts include reshares" do + reshare = alice.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id, :to => alice.aspects) + get :index + assigns[:posts].post_fakes.map{|x| x.id}.should include(reshare.id) + end + it "can filter to a single aspect" do get :index, :a_ids => [@alices_aspect_2.id.to_s] assigns(:posts).models.length.should == 1 diff --git a/spec/controllers/people_controller_spec.rb b/spec/controllers/people_controller_spec.rb index f6aea62460b9d43f85ce13308f0e5552c800f614..7feb2b478ec415ca6e3d26fc447d038b0a1fd3f7 100644 --- a/spec/controllers/people_controller_spec.rb +++ b/spec/controllers/people_controller_spec.rb @@ -206,7 +206,7 @@ describe PeopleController do end it "posts include reshares" do - reshare = @user.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id) + reshare = @user.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id, :to => alice.aspects) get :show, :id => @user.person.id assigns[:posts].post_fakes.map{|x| x.id}.should include(reshare.id) end @@ -259,7 +259,7 @@ describe PeopleController do end it "posts include reshares" do - reshare = @user.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id) + reshare = @user.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id, :to => alice.aspects) get :show, :id => @user.person.id assigns[:posts].post_fakes.map{|x| x.id}.should include(reshare.id) end @@ -297,7 +297,7 @@ describe PeopleController do end it "posts include reshares" do - reshare = @user.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id) + reshare = @user.post(:reshare, :public => true, :root_id => Factory(:status_message, :public => true).id, :to => alice.aspects) get :show, :id => @user.person.id assigns[:posts].post_fakes.map{|x| x.id}.should include(reshare.id) end diff --git a/spec/controllers/reshares_controller_spec.rb b/spec/controllers/reshares_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9a780a9057847de3640470016f4b6aab40edbe2a --- /dev/null +++ b/spec/controllers/reshares_controller_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' +describe ResharesController do + + describe '#create' do + + it 'requires authentication' do + post :create, :format => :js + response.should_not be_success + end + + context 'with an authenticated user' do + + before do + + sign_in :user, bob + @post_id = Factory(:status_message, :public => true).id + @controller.stub(:current_user).and_return(bob) + end + + it 'succeeds' do + post :create, :format => :js, :root_id => @post_id + puts response.code + response.should be_success + end + + it 'creates a reshare' do + expect{ + post :create, :format => :js, :root_id => @post_id + }.should change(Reshare, :count).by(1) + end + + it 'after save, calls add to streams' do + bob.should_receive(:add_to_streams) + post :create, :format => :js, :root_id => @post_id + end + end + end +end diff --git a/spec/helpers/reshares_helper_spec.rb b/spec/helpers/reshares_helper_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..524a2bd0c79fb734a1b52833371ccfc1d513b07b --- /dev/null +++ b/spec/helpers/reshares_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the ResharesHelper. For example: +# +# describe ResharesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe ResharesHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/reshare_spec.rb b/spec/models/reshare_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..7fcd620ae80986fbf2e73c97588f1e756561c55f --- /dev/null +++ b/spec/models/reshare_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe Reshare do + it 'has a valid Factory' do + Factory(:reshare).should be_valid + end + + it 'requires root' do + reshare = Factory.build(:reshare, :root => nil) + reshare.should_not be_valid + end + + it 'require public root' do + Factory.build(:reshare, :root => Factory.build(:status_message, :public => false)).should_not be_valid + end + + it 'forces public' do + Factory(:reshare, :public => false).public.should be_true + end +end