diff --git a/app/controllers/blocks_controller.rb b/app/controllers/blocks_controller.rb new file mode 100644 index 000000000..c8c82217b --- /dev/null +++ b/app/controllers/blocks_controller.rb @@ -0,0 +1,9 @@ +class BlocksController < ApplicationController + before_filter :authenticate_user! + + def create + current_user.blocks.create(params[:block]) + + redirect_to :back, :notice => "that person sucked anyways..." + end +end \ No newline at end of file diff --git a/app/helpers/stream_element_helper.rb b/app/helpers/stream_element_helper.rb new file mode 100644 index 000000000..67856a182 --- /dev/null +++ b/app/helpers/stream_element_helper.rb @@ -0,0 +1,7 @@ +module StreamElementHelper + def block_user_control(author) + if user_signed_in? + link_to block_path(author), :class => "block_button" + end + end +end \ No newline at end of file diff --git a/app/models/block.rb b/app/models/block.rb new file mode 100644 index 000000000..2409a9d3b --- /dev/null +++ b/app/models/block.rb @@ -0,0 +1,15 @@ +class Block < ActiveRecord::Base + belongs_to :person + belongs_to :user + + validates :user_id, :presence => true + validates :person_id, :presence => true, :uniqueness => { :scope => :user_id } + + validate :not_blocking_yourself + + def not_blocking_yourself + if self.user.person.id == self.person_id + errors[:person_id] << "stop blocking yourself!" + end + end +end \ No newline at end of file diff --git a/app/models/post.rb b/app/models/post.rb index 559564e69..feb1f7504 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -23,9 +23,19 @@ class Post < ActiveRecord::Base #scopes scope :includes_for_a_stream, includes(:o_embed_cache, {:author => :profile}, :mentions => {:person => :profile}) #note should include root and photos, but i think those are both on status_message - def self.for_a_stream(max_time, order) - self.for_visible_shareable_sql(max_time, order). - includes_for_a_stream + def self.excluding_blocks(user) + people = user.blocks.map { |x| x.person_id } + + where("posts.author_id NOT IN (?)", people) + end + + def self.for_a_stream(max_time, order, user=nil) + scope = self.for_visible_shareable_sql(max_time, order). + includes_for_a_stream + + scope = scope.excluding_blocks(user) if user.present? + + scope end ############# diff --git a/app/models/user.rb b/app/models/user.rb index 96cd712fb..69f888618 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -43,6 +43,7 @@ class User < ActiveRecord::Base has_many :user_preferences, :dependent => :destroy has_many :tag_followings, :dependent => :destroy has_many :followed_tags, :through => :tag_followings, :source => :tag, :order => 'tags.name' + has_many :blocks has_many :authorizations, :class_name => 'OAuth2::Provider::Models::ActiveRecord::Authorization', :foreign_key => :resource_owner_id has_many :applications, :through => :authorizations, :source => :client diff --git a/app/views/shared/_stream_element.html.haml b/app/views/shared/_stream_element.html.haml index 9babe8298..59689c821 100644 --- a/app/views/shared/_stream_element.html.haml +++ b/app/views/shared/_stream_element.html.haml @@ -9,6 +9,9 @@ = 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 = link_to image_tag('deletelabel.png'), share_visibility_path(:id => "42", :post_id => post.id), :method => :put, :remote => true, :class => "delete stream_element_delete vis_hide", :title => t('.hide_and_mute') + + = block_user_control(post.author) + = image_tag 'ajax-loader.gif', :class => "hide_loader hidden" .undo_text.hidden diff --git a/config/routes.rb b/config/routes.rb index 2b37f97bf..4f3299818 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -111,6 +111,7 @@ Diaspora::Application.routes.draw do end resources :aspect_memberships, :only => [:destroy, :create, :update] resources :share_visibilities, :only => [:update] + resources :blocks, :only => :create get 'spotlight' => 'community_spotlight#index', :as => 'spotlight' diff --git a/db/migrate/20111101202137_create_blocks.rb b/db/migrate/20111101202137_create_blocks.rb new file mode 100644 index 000000000..31e451740 --- /dev/null +++ b/db/migrate/20111101202137_create_blocks.rb @@ -0,0 +1,12 @@ +class CreateBlocks < ActiveRecord::Migration + def self.up + create_table :blocks do |t| + t.integer :user_id + t.integer :person_id + end + end + + def self.down + drop_table :blocks + end +end diff --git a/db/schema.rb b/db/schema.rb index a2b1512c2..1e4c27f76 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20111026173547) do +ActiveRecord::Schema.define(:version => 20111101202137) do create_table "aspect_memberships", :force => true do |t| t.integer "aspect_id", :null => false @@ -47,6 +47,11 @@ ActiveRecord::Schema.define(:version => 20111026173547) do add_index "aspects", ["user_id", "contacts_visible"], :name => "index_aspects_on_user_id_and_contacts_visible" add_index "aspects", ["user_id"], :name => "index_aspects_on_user_id" + create_table "blocks", :force => true do |t| + t.integer "user_id" + t.integer "person_id" + end + create_table "comments", :force => true do |t| t.text "text", :null => false t.integer "commentable_id", :null => false @@ -247,7 +252,6 @@ ActiveRecord::Schema.define(:version => 20111026173547) do add_index "people", ["owner_id"], :name => "index_people_on_owner_id", :unique => true create_table "photos", :force => true do |t| - t.integer "tmp_old_id" t.integer "author_id", :null => false t.boolean "public", :default => false, :null => false t.string "diaspora_handle" diff --git a/features/blocks_user.feature b/features/blocks_user.feature new file mode 100644 index 000000000..fd47a4f93 --- /dev/null +++ b/features/blocks_user.feature @@ -0,0 +1,20 @@ +@javascript +Feature: Blocking a user from the stream + Background: + Given a user with username "bob" + And a user with username "alice" + And a user with username "alice" is connected with "bob" + + When I sign in as "bob@bob.bob" + And I post a status with the text "I am da #boss" + And I am on the home page + When I go to the destroy user session page + + + Scenario: Blocking a user + When I sign in as "alice@alice.alice" + And I am on the home page + Then I should see "I am da #boss" + When I click on bob's block button + And I am on the home page + Then I should not see "I am da #boss" \ No newline at end of file diff --git a/features/step_definitions/posts_steps.rb b/features/step_definitions/posts_steps.rb index 5bd2ff50a..bdf830c8a 100644 --- a/features/step_definitions/posts_steps.rb +++ b/features/step_definitions/posts_steps.rb @@ -26,3 +26,7 @@ end When /^The user deletes their first post$/ do @me.posts.first.destroy end + +When /^I click on bob's block button/ do + find(".block_button").first.click +end \ No newline at end of file diff --git a/lib/stream/aspect.rb b/lib/stream/aspect.rb index 0cf4ce668..33cd3a662 100644 --- a/lib/stream/aspect.rb +++ b/lib/stream/aspect.rb @@ -43,7 +43,7 @@ class Stream::Aspect < Stream::Base :type => TYPES_OF_POST_IN_STREAM, :order => "#{order} DESC", :max_time => max_time - ).for_a_stream(max_time, order) + ).for_a_stream(max_time, order, user) end # @return [ActiveRecord::Association] AR association of people within stream's given aspects diff --git a/lib/stream/public.rb b/lib/stream/public.rb index a9056795e..74872a903 100644 --- a/lib/stream/public.rb +++ b/lib/stream/public.rb @@ -13,7 +13,7 @@ class Stream::Public < Stream::Base # @return [ActiveRecord::Association] AR association of posts def posts - @posts ||= Post.all_public.for_a_stream(max_time, order) + @posts ||= Post.all_public.for_a_stream(max_time, order) end diff --git a/spec/controllers/blocks_controller_spec.rb b/spec/controllers/blocks_controller_spec.rb new file mode 100644 index 000000000..445cfb482 --- /dev/null +++ b/spec/controllers/blocks_controller_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe BlocksController do + describe "#create" do + before do + sign_in alice + end + + it "should create a block" do + expect { + post :create, :block => { :person_id => 2 } + }.should change { alice.blocks.count }.by(1) + end + + it "should redirect to back" do + post :create, :block => { :person_id => 2 } + + response.should be_redirect + end + + it "notifies the user" do + post :create, :block => { :person_id => 2 } + + flash.should_not be_empty + end + end +end \ No newline at end of file diff --git a/spec/models/block_spec.rb b/spec/models/block_spec.rb new file mode 100644 index 000000000..a6b598c06 --- /dev/null +++ b/spec/models/block_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Block do + describe 'validations' do + it 'doesnt allow you to block yourself' do + block = alice.blocks.create(:person => alice.person) + + block.should have(1).error_on(:person_id) + end + end +end \ No newline at end of file diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index 648a0c24b..0804064db 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -58,6 +58,29 @@ describe Post do Post.should_receive(:includes_for_a_stream) Post.for_a_stream(stub, stub) end + + it 'calls excluding_blocks if a user is present' do + user = stub + Post.should_receive(:excluding_blocks).with(user) + Post.for_a_stream(stub, stub, user) + end + end + + describe '.excluding_blocks' do + before do + @post = Factory(:status_message, :author => alice.person) + @other_post = Factory(:status_message, :author => eve.person) + + bob.blocks.create(:person => alice.person) + end + + it 'does not included blocked users posts' do + Post.excluding_blocks(bob).should_not include(@post) + end + + it 'includes not blocked users posts' do + Post.excluding_blocks(bob).should include(@other_post) + end end context 'having some posts' do