Merge branch 'block-user'

This commit is contained in:
danielgrippi 2011-11-03 12:31:32 -07:00
commit 10ce4426a9
59 changed files with 483 additions and 103 deletions

View file

@ -154,7 +154,7 @@ class ApplicationController < ActionController::Base
@stream = stream_klass.new(current_user, :max_time => max_time, :order => sort_order)
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @stream.posts}
render :partial => 'shared/stream', :locals => {:posts => @stream.stream_posts}
else
render 'aspects/index'
end

View file

@ -46,12 +46,11 @@ class AspectMembershipsController < ApplicationController
@aspect = current_user.aspects.where(:id => params[:aspect_id]).first
if @contact = current_user.share_with(@person, @aspect)
flash.now[:notice] = I18n.t 'aspects.add_to_aspect.success'
flash.now[:notice] = I18n.t('aspects.add_to_aspect.success')
respond_with AspectMembership.where(:contact_id => @contact.id, :aspect_id => @aspect.id).first
else
flash[:error] = I18n.t 'contacts.create.failure'
#TODO(dan) take this out once the .js template is removed
render :nothing => true
flash.now[:error] = I18n.t('contacts.create.failure')
render :nothing => true, :status => 409
end
end

View file

@ -20,7 +20,7 @@ class AspectsController < ApplicationController
:max_time => params[:max_time].to_i)
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @stream.posts}
render :partial => 'shared/stream', :locals => {:posts => @stream.stream_posts}
end
end

View file

@ -0,0 +1,32 @@
class BlocksController < ApplicationController
before_filter :authenticate_user!
def create
block = current_user.blocks.new(params[:block])
if block.save
disconnect_if_contact(block.person)
notice = {:notice => t('blocks.create.success')}
else
notice = {:error => t('blocks.create.failure')}
end
redirect_to :back, notice
end
def destroy
if current_user.blocks.find(params[:id]).delete
notice = {:notice => t('blocks.destroy.success')}
else
notice = {:error => t('blocks.destroy.failure')}
end
redirect_to :back, notice
end
protected
def disconnect_if_contact(person)
if contact = current_user.contact_for(person)
current_user.disconnect(contact, :force => true)
end
end
end

View file

@ -95,6 +95,7 @@ class PeopleController < ApplicationController
unless params[:format] == "json" # hovercard
if current_user
@block = current_user.blocks.where(:person_id => @person.id).first
@contact = current_user.contact_for(@person)
@aspects_with_person = []
if @contact && !params[:only_posts]
@ -112,7 +113,7 @@ class PeopleController < ApplicationController
end
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @stream.posts}
render :partial => 'shared/stream', :locals => {:posts => @stream.stream_posts}
else
respond_to do |format|
format.all { respond_with @person, :locals => {:post_type => :all} }

View file

@ -38,7 +38,7 @@ class TagsController < ApplicationController
@stream = Stream::Tag.new(current_user, params[:name], :max_time => max_time, :page => params[:page])
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @stream.posts}
render :partial => 'shared/stream', :locals => {:posts => @stream.stream_posts}
return
end
end

View file

@ -20,6 +20,10 @@ class UsersController < ApplicationController
end
end
def privacy_settings
@blocks = current_user.blocks.includes(:person)
end
def update
password_changed = false
@user = current_user

View file

@ -0,0 +1,19 @@
module StreamElementHelper
def block_user_control(author)
if user_signed_in? && current_user.person.id != author.id
link_to image_tag('deletelabel.png'), blocks_path(:block => {:person_id => author.id}),
:class => 'block_user delete',
:confirm => t('.ignore_user_description'),
:title => t('.ignore_user', :name => author.first_name),
:method => :post
end
end
def delete_or_hide_button(post)
if user_signed_in? && current_user.owns?(post)
link_to image_tag('deletelabel.png'), post_path(post), :confirm => t('are_you_sure'), :method => :delete, :remote => true, :class => "delete remove_post", :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 remove_post vis_hide", :title => t('.hide_and_mute')
end
end
end

View file

@ -28,15 +28,14 @@ module StreamHelper
end
def time_for_scroll(ajax_stream, stream)
if ajax_stream || stream.posts.empty?
if ajax_stream || stream.stream_posts.empty?
(Time.now() + 1).to_i
else
stream.posts.last.send(stream.order.to_sym).to_i
stream.stream_posts.last.send(stream.order.to_sym).to_i
end
end
def time_for_sort post
def time_for_sort(post)
if controller.instance_of?(AspectsController)
post.send(session[:sort_order].to_sym)
else

15
app/models/block.rb Normal file
View file

@ -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

View file

@ -15,11 +15,13 @@ class Contact < ActiveRecord::Base
has_many :share_visibilities, :source => :shareable, :source_type => 'Post'
has_many :posts, :through => :share_visibilities, :source => :shareable, :source_type => 'Post'
validate :not_contact_for_self
validate :not_contact_for_self,
:not_blocked_user
validates_uniqueness_of :person_id, :scope => :user_id
before_destroy :destroy_notifications
before_destroy :destroy_notifications,
:repopulate_cache!
# contact.sharing is true when contact.person is sharing with contact.user
scope :sharing, lambda {
@ -39,7 +41,14 @@ class Contact < ActiveRecord::Base
Notification.where(:target_type => "Person",
:target_id => person_id,
:recipient_id => user_id,
:type => "Notifications::StartedSharing").delete_all
:type => "Notifications::StartedSharing").delete_all
end
def repopulate_cache!
if RedisCache.configured?
cache = RedisCache.new(self.user)
cache.repopulate!
end
end
def dispatch_request
@ -90,5 +99,14 @@ class Contact < ActiveRecord::Base
errors[:base] << 'Cannot create self-contact'
end
end
def not_blocked_user
if user.blocks.where(:person_id => person_id).exists?
errors[:base] << 'Cannot connect to an ignored user'
false
else
true
end
end
end

View file

@ -21,11 +21,25 @@ class Post < ActiveRecord::Base
after_create :cache_for_author
#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
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.includes(:person).map{|b| b.person}
if people.present?
where("posts.author_id NOT IN (?)", people.map { |person| person.id })
else
scoped
end
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
#############

View file

@ -37,8 +37,7 @@ class StatusMessage < Post
def self.tag_stream(user, tag_array, max_time, order)
owned_or_visible_by_user(user).
joins(:tags).where(:tags => {:name => tag_array}).
for_a_stream(max_time, order)
joins(:tags).where(:tags => {:name => tag_array})
end
def text(opts = {})

View file

@ -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

View file

@ -19,8 +19,8 @@
#gs-shim{:title => "3. #{t('.stay_updated')}", 'data-content' => t('.stay_updated_explanation')}
#main_stream.stream{:data => {:guids => stream.aspect_ids.join(','), :time_for_scroll => time_for_scroll(stream.ajax_stream?, stream)}}
- if !stream.ajax_stream? && stream.posts.length > 0
= render 'shared/stream', :posts => stream.posts
- if !stream.ajax_stream? && stream.stream_posts.length > 0
= render 'shared/stream', :posts => stream.stream_posts
#pagination
=link_to(t('more'), next_page_path(:ajax_stream => stream.ajax_stream?), :class => 'paginate')

View file

@ -9,8 +9,8 @@
= @stream.aspect
#main_stream.stream
= render 'shared/stream', :posts => @stream.posts
-if @stream.posts.length > 0
= render 'shared/stream', :posts => @stream.stream_posts
-if @stream.stream_posts.length > 0
#pagination
%a.more-link.paginate{:href => next_page_path}
%h1

View file

@ -1,7 +1,13 @@
#author_info
.right
- if user_signed_in? && current_user.person != person
= aspect_membership_dropdown(contact, person, 'right')
- if @block.present?
= link_to t('users.privacy_settings.stop_ignoring'), block_path(@block),
:method => :delete,
:class => "button"
- else
= aspect_membership_dropdown(contact, person, 'right')
- elsif user_signed_in? && current_user.person == person
= link_to t('people.profile_sidebar.edit_my_profile'), edit_profile_path, :class => 'button creation'

View file

@ -27,17 +27,20 @@
= render 'people/sub_header', :person => @person, :contact => @contact
/ hackity hack until we get a photo stream
- if (@posts && @posts.length > 0) || (defined?(@stream) && @stream.posts.length > 0)
- if (@posts && @posts.length > 0) || @stream.stream_posts.length > 0
-if @post_type == :photos
= render 'photos/index', :photos => @posts
- else
#main_stream.stream
= render 'shared/stream', :posts => @stream.posts
= render 'shared/stream', :posts => @stream.stream_posts
#pagination
=link_to(t('more'), next_page_path, :class => 'paginate')
- else
#main_stream
%div{:style=>"text-align:center;", :class => "dull"}
= t('.has_not_shared_with_you_yet', :name => @person.first_name)
- if @block.present?
= t('.ignoring', :name => @person.first_name)
- else
= t('.has_not_shared_with_you_yet', :name => @person.first_name)

View file

@ -20,12 +20,12 @@
= link_to t('.return_to_aspects'), aspects_manage_path
= t('.to_accept_or_ignore')
- if @stream.posts.length > 0
- if @stream.stream_posts.length > 0
-if @post_type == :photos
= render 'photos/index', :photos => @stream.posts
= render 'photos/index', :photos => @stream.stream_posts
- else
#main_stream.stream
= render 'shared/stream', :posts => @stream.posts
= render 'shared/stream', :posts => @stream.stream_posts
#pagination
=link_to(t('more'), next_page_path, :class => 'paginate')
- else

View file

@ -1,5 +1,6 @@
%ul#settings_nav
%li= link_to_unless_current t('profile'), edit_profile_path
%li= link_to_unless_current t('account'), edit_user_path
%li= link_to_unless_current t('privacy'), privacy_settings_path
%li= link_to_unless_current t('_services'), services_path
%li= link_to_unless_current t('_applications'), authorizations_path

View file

@ -5,10 +5,9 @@
.stream_element{:id => post.guid, :class => from_group(post)}
.right.controls
- if current_user && post.author.owner_id == current_user.id
= 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)
= delete_or_hide_button(post)
= image_tag 'ajax-loader.gif', :class => "hide_loader hidden"
.undo_text.hidden

View file

@ -67,8 +67,8 @@
%hr
#main_stream.stream
- if @stream.posts.length > 0
= render 'shared/stream', :posts => @stream.posts
- if @stream.stream_posts.length > 0
= render 'shared/stream', :posts => @stream.stream_posts
#pagination
=link_to(t('more'), next_page_path, :class => 'paginate')
- else

View file

@ -6,8 +6,8 @@
= @stream.display_tag_name
#main_stream.stream
= render 'shared/stream', :posts => @stream.posts
-if @stream.posts.length > 0
= render 'shared/stream', :posts => @stream.stream_posts
-if @stream.stream_posts.length > 0
#pagination
%a.more-link.paginate{:href => next_page_path}
%h1

View file

@ -0,0 +1,23 @@
-# Copyright (c) 2010-2011, Diaspora Inc. This file is
-# licensed under the Affero General Public License version 3 or later. See
-# the COPYRIGHT file.
- content_for :page_title do
= t('.title')
#section_header
%h2
= t('privacy')
= render 'shared/settings_nav'
.span-12.prepend-5.last
%h3
= t('.ignored_users')
- @blocks.each do |block|
= block.person.name
\-
= link_to t('.stop_ignoring'), block_path(block),
:method => :delete
%br

View file

@ -9,6 +9,7 @@ en:
settings: "Settings"
profile: "Profile"
account: "Account"
privacy: "Privacy"
_services: "Services"
_applications: "Applications"
_photos: "photos"
@ -543,6 +544,7 @@ en:
start_sharing: "start sharing"
message: "Message"
mention: "Mention"
ignoring: "You are ignoring all posts from %{name}."
sub_header:
you_have_no_tags: "you have no tags!"
add_some: "add some"
@ -605,7 +607,7 @@ en:
permalink: "permalink"
not_found: "Sorry, we couldn't find that post."
post_visibilites:
share_visibilites:
update:
post_hidden_and_muted: "%{name}'s post has been hidden, and notifications have been muted."
see_it_on_their_profile: "If you want to see updates on this post, visit %{name}'s profile page."
@ -722,6 +724,14 @@ en:
invite: "invite"
not_on_diaspora: "Not yet on Diaspora"
blocks:
create:
success: "Alright, you won't see that user in your stream again. #silencio!"
failure: "I couldn't ignore that user. #evasion"
destroy:
success: "Let's see what they have to say! #sayhello"
failure: "I couldn't stop ignoring that user. #evasion"
shared:
aspect_dropdown:
add_to_aspect: "Add contact"
@ -767,7 +777,6 @@ en:
reshare:
reshare: "Reshare"
public_explain:
control_your_audience: "Control your Audience"
new_user_welcome_message: "Use #hashtags to classify your posts and find people who share your interests. Call out awesome people with @Mentions"
visibility_dropdown: "Use this dropdown to change visibility of your post. (We suggest you make this first one public.)"
@ -785,7 +794,9 @@ en:
connect_to_comment: "Connect to this user to comment on their post"
currently_unavailable: 'commenting currently unavailable'
via: "via %{link}"
hide_and_mute: "Hide and Mute"
ignore_user: "Ignore %{name}"
ignore_user_description: "Ignore and remove user from all aspects?"
hide_and_mute: "Hide and mute post"
like: "Like"
unlike: "Unlike"
dislike: "Dislike"
@ -891,6 +902,7 @@ en:
simply_visit: "Simply visit"
on_your_mobile_device: "on your mobile device to access Diaspora* mobile."
works_on_modern: "Works on all modern smartphones"
edit:
export_data: "Export Data"
photo_export_unavailable: "Photo exporting currently unavailable"
@ -919,6 +931,12 @@ en:
show_community_spotlight: "Show Community Spotlight in Stream?"
show_getting_started: 'Re-enable Getting Started'
getting_started: 'New User Prefrences'
privacy_settings:
title: "Privacy Settings"
ignored_users: "Ignored Users"
stop_ignoring: "Stop ignoring"
destroy: "Your account has been locked. It may take 20 minutes for us to finish closing your account. Thank you for trying Diaspora."
getting_started:
well_hello_there: "Well, hello there!"

View file

@ -40,6 +40,7 @@ en:
all_aspects: "All aspects"
stopped_sharing_with: "You have stopped sharing with {{name}}."
started_sharing_with: "You have started sharing with {{name}}!"
error: "Couldn't start sharing with {{name}}. Are you ignoring them?"
toggle:
zero: "Select aspects"
one: "In {{count}} aspect"

View file

@ -76,10 +76,11 @@ Diaspora::Application.routes.draw do
end
controller :users do
get 'public/:username' => :public, :as => 'users_public'
match 'getting_started' => :getting_started, :as => 'getting_started'
get 'public/:username' => :public, :as => 'users_public'
match 'getting_started' => :getting_started, :as => 'getting_started'
match 'privacy' => :privacy_settings, :as => 'privacy_settings'
get 'getting_started_completed' => :getting_started_completed
get 'confirm_email/:token' => :confirm_email, :as => 'confirm_email'
get 'confirm_email/:token' => :confirm_email, :as => 'confirm_email'
end
# This is a hack to overide a route created by devise.
@ -109,8 +110,9 @@ Diaspora::Application.routes.draw do
resources :contacts, :except => [:update, :create] do
get :sharing, :on => :collection
end
resources :aspect_memberships, :only => [:destroy, :create, :update]
resources :share_visibilities, :only => [:update]
resources :aspect_memberships, :only => [:destroy, :create, :update]
resources :share_visibilities, :only => [:update]
resources :blocks, :only => [:create, :destroy]
get 'spotlight' => 'community_spotlight#index', :as => 'spotlight'

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,18 @@
@javascript
Feature: Blocking a user from the stream
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 Alice has a post mentioning Bob
Scenario: Blocking a user
When I sign in as "bob@bob.bob"
And I am on the home page
And I preemptively confirm the alert
And I wait for the ajax to finish
When I click on the first block button
And I am on the home page
And I wait for the ajax to finish
Then I should not see any posts in my stream

View file

@ -52,7 +52,6 @@ Feature: commenting
And I preemptively confirm the alert
And I click to delete the first comment
And I wait for the ajax to finish
And I wait for 2 seconds
Then I should not see "is that a poodle?"
Scenario: expand the comment form in the main stream and an individual aspect stream

View file

@ -7,7 +7,7 @@ Feature: new user registration
And I fill in "user_email" with "ohai@example.com"
And I fill in "user_password" with "secret"
And I fill in "user_password_confirmation" with "secret"
And I press "Create my account"
And I press "Create my account!"
Then I should be on the getting started page
And I should see "Well, hello there!"
And I should see "Who are you?"

View file

@ -58,7 +58,7 @@ And /^I hover over the "([^"]+)"$/ do |element|
end
When /^I click to delete the first post$/ do
page.execute_script('$(".stream_element").first().find(".stream_element_delete").first().click()')
page.execute_script('$(".stream_element").first().find(".remove_post").first().click()')
end
When /^I click to delete the first comment$/ do

View file

@ -13,6 +13,10 @@ Then /^I should not see an uploaded image within the photo drop zone$/ do
find("#photodropzone img").should be_nil
end
Then /^I should not see any posts in my stream$/ do
find(".stream_element").should be_nil
end
Given /^"([^"]*)" has a public post with text "([^"]*)"$/ do |email, text|
user = User.find_by_email(email)
user.post(:status_message, :text => text, :public => true, :to => user.aspects)
@ -26,3 +30,7 @@ end
When /^The user deletes their first post$/ do
@me.posts.first.destroy
end
When /^I click on the first block button/ do
find(".block_user").click
end

View file

@ -4,10 +4,10 @@
class RedisCache
SUPPORTED_CACHES = [:created_at] #['updated_at',
SUPPORTED_CACHES = [:created_at]
CACHE_LIMIT = 100
def initialize(user, order_field)
def initialize(user, order_field=:created_at)
@user = user
@order_field = order_field.to_s
end

View file

@ -11,6 +11,8 @@ module Diaspora
# @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
@ -56,7 +58,7 @@ module Diaspora
end
end
def disconnect(bad_contact)
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)
@ -64,7 +66,7 @@ module Diaspora
Postzord::Dispatcher.build(self, retraction).post
AspectMembership.where(:contact_id => bad_contact.id).delete_all
remove_contact(bad_contact)
remove_contact(bad_contact, opts)
end
def disconnected_by(person)

View file

@ -141,7 +141,7 @@ module Diaspora
end
def shareables_from(klass, person)
return self.person.send(klass.table_name).where(:pending => false).order("created_at DESC") if person == self.person
return self.person.send(klass.table_name).where(:pending => false).order("#{klass.table_name}.created_at DESC") if person == self.person
con = Contact.arel_table
p = klass.arel_table
shareable_ids = []

View file

@ -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)
)
end
# @return [ActiveRecord::Association<Person>] AR association of people within stream's given aspects

View file

@ -43,13 +43,19 @@ class Stream::Base
# @return [ActiveRecord::Relation<Post>]
def posts
[]
Post.scoped
end
# @return [ActiveRecord::Relation<Post>]
def stream_posts
self.posts.for_a_stream(max_time, order, self.user)
end
# @return [ActiveRecord::Association<Person>] AR association of people within stream's given aspects
def people
people_ids = posts.map{|x| x.author_id}
Person.where(:id => people_ids).includes(:profile)
people_ids = self.stream_posts.map{|x| x.author_id}
Person.where(:id => people_ids).
includes(:profile)
end
# @return [String]

View file

@ -20,7 +20,7 @@ class Stream::CommunitySpotlight < Stream::Base
end
def posts
Post.all_public.where(:author_id => people.map{|x| x.id}).for_a_stream(max_time, order)
Post.all_public.where(:author_id => people.map{|x| x.id})
end
def people

View file

@ -13,7 +13,7 @@ class Stream::Mention < Stream::Base
# @return [ActiveRecord::Association<Post>] AR association of posts
def posts
@posts ||= StatusMessage.where_person_is_mentioned(self.user.person).for_a_stream(max_time, order)
@posts ||= StatusMessage.where_person_is_mentioned(self.user.person)
end
def contacts_title

View file

@ -19,13 +19,13 @@ class Stream::Multi < Stream::Base
@posts ||= lambda do
post_ids = aspects_post_ids + followed_tags_post_ids + mentioned_post_ids
post_ids += community_spotlight_post_ids if include_community_spotlight?
Post.where(:id => post_ids).for_a_stream(max_time, order)
Post.where(:id => post_ids)
end.call
end
# @return [Boolean]
def ajax_stream?
false
true
end
#emits an enum of the groups which the post appeared

View file

@ -15,9 +15,9 @@ class Stream::Person < Stream::Base
def posts
@posts ||= lambda do
if user
posts = self.user.posts_from(@person).for_a_stream(max_time, order)
posts = self.user.posts_from(@person)
else
posts = @person.posts.where(:public => true).for_a_stream(max_time, order)
posts = @person.posts.where(:public => true)
end
posts
end.call

View file

@ -13,7 +13,7 @@ class Stream::Public < Stream::Base
# @return [ActiveRecord::Association<Post>] AR association of posts
def posts
@posts ||= Post.all_public.for_a_stream(max_time, order)
@posts ||= Post.all_public
end

View file

@ -52,6 +52,6 @@ class Stream::Tag < Stream::Base
else
posts = posts.all_public
end
posts.tagged_with(tag_name).for_a_stream(max_time, 'created_at')
posts.tagged_with(tag_name)
end
end

View file

@ -6,7 +6,6 @@ var ContactEdit = {
init: function(){
$.extend(ContactEdit, AspectsDropdown);
$('.dropdown.aspect_membership .dropdown_list > li, .dropdown.inviter .dropdown_list > li').live('click', function(evt){
ContactEdit.processClick($(this), evt);
});
},
@ -64,7 +63,10 @@ var ContactEdit = {
},
toggleAspectMembership: function(li, evt) {
var button = li.find('.button');
var button = li.find('.button'),
dropdown = li.closest('.dropdown'),
dropdownList = li.parent('.dropdown_list');
if(button.hasClass('disabled') || li.hasClass('newItem')){ return; }
var selected = li.hasClass("selected"),
@ -75,12 +77,19 @@ var ContactEdit = {
"person_id": li.parent().data("person_id"),
"_method": (selected) ? "DELETE" : "POST"
}, function(aspectMembership) {
li.removeClass("loading");
ContactEdit.toggleCheckbox(li);
ContactEdit.updateNumber(li.closest(".dropdown_list"), li.parent().data("person_id"), aspectMembership.aspect_ids.length, 'in_aspects');
Diaspora.page.publish("aspectDropdown/updated", [li.parent().data("person_id"), li.parents(".dropdown").parent(".right").html()]);
});
})
.error(function() {
var message = Diaspora.I18n.t("aspect_dropdown.error", {name: dropdownList.data('person-short-name')});
Diaspora.page.flashMessages.render({success: false, notice: message});
dropdown.removeClass('active');
})
.complete(function() {
li.removeClass("loading");
});
}
};

View file

@ -13,7 +13,8 @@
timeAgo: self.instantiate("TimeAgo", element.find(".timeago a abbr.timeago")),
content: element.find(".content .collapsible"),
deletePostLink: element.find("a.stream_element_delete"),
blockUserLink: element.find(".block_user"),
deletePostLink: element.find(".remove_post"),
focusCommentLink: element.find("a.focus_comment_textarea"),
hidePostLoader: element.find("img.hide_loader"),
hidePostUndo: element.find("a.stream_element_hide_undo"),
@ -22,8 +23,11 @@
});
// twipsy tooltips
self.deletePostLink.twipsy();
self.postScope.twipsy();
$([
self.blockUserLink,
self.deletePostLink,
self.postScope
]).map(function() { this.twipsy(); });
// collapse long posts
self.content.expander({
@ -40,8 +44,10 @@
self.deletePostLink.click(function(evt) {
evt.preventDefault();
self.deletePostLink.toggleClass("hidden");
self.hidePostLoader.toggleClass("hidden");
$([
self.deletePostLink,
self.hidePostLoader
]).toggleClass("hidden");
});
self.focusCommentLink.click(function(evt) {

View file

@ -96,6 +96,8 @@ form
:padding
:top 45px
:bottom 8px
:left 12px
:right 12px
#flash_notice
.message
@ -791,9 +793,6 @@ a.paginate, #infscr-loading
:text-align center
:width 100%
&:hover
:border 1px solid #1C6D99
#main_stream
:position relative
:z-index 0

View file

@ -0,0 +1,67 @@
require 'spec_helper'
describe BlocksController do
before do
sign_in alice
end
describe "#create" do
it "creates a block" do
expect {
post :create, :block => {:person_id => eve.person.id}
}.should change { alice.blocks.count }.by(1)
end
it "redirects 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
it "calls #disconnect_if_contact" do
@controller.should_receive(:disconnect_if_contact).with(bob.person)
post :create, :block => {:person_id => bob.person.id}
end
end
describe "#destroy" do
before do
@block = alice.blocks.create(:person => eve.person)
end
it "redirects back" do
delete :destroy, :id => @block.id
response.should be_redirect
end
it "removes a block" do
expect {
delete :destroy, :id => @block.id
}.should change { alice.blocks.count }.by(-1)
end
end
describe "#disconnect_if_contact" do
before do
@controller.stub(:current_user).and_return(alice)
end
it "calls disconnect with the force option if there is a contact for a given user" do
contact = alice.contact_for(bob.person)
alice.stub(:contact_for).and_return(contact)
alice.should_receive(:disconnect).with(contact, hash_including(:force => true))
@controller.send(:disconnect_if_contact, bob.person)
end
it "doesn't call disconnect if there is a contact for a given user" do
alice.should_not_receive(:disconnect)
@controller.send(:disconnect_if_contact, eve.person)
end
end
end

View file

@ -242,7 +242,7 @@ describe PeopleController do
it 'is sorted by created_at desc' do
get :show, :id => @person.id
assigns[:stream].posts.should == @public_posts.sort_by{|p| p.created_at}.reverse
assigns[:stream].stream_posts.should == @public_posts.sort_by{|p| p.created_at}.reverse
end
end

View file

@ -13,6 +13,7 @@ describe TagFollowingsController do
before do
@tag = ActsAsTaggableOn::Tag.create!(:name => "partytimeexcellent")
sign_in :user, bob
bob.followed_tags.create(:name => "testing")
end
describe 'index' do

View file

@ -159,6 +159,13 @@ describe UsersController do
end
end
describe '#privacy_settings' do
it "returns a 200" do
get 'privacy_settings'
response.status.should == 200
end
end
describe '#edit' do
it "returns a 200" do
get 'edit', :id => @user.id
@ -220,15 +227,13 @@ describe UsersController do
describe 'getting_started' do
it 'does not fail miserably' do
get :getting_started
response.should be_success
get :getting_started
response.should be_success
end
it 'does not fail miserably on mobile' do
get :getting_started, :format => :mobile
response.should be_success
get :getting_started, :format => :mobile
response.should be_success
end
end
end

View file

@ -43,6 +43,13 @@ describe Stream::Base do
end
end
describe '#people' do
it 'excludes blocked people' do
@stream.should_receive(:stream_posts).and_return(stub.as_null_object)
@stream.people
end
end
describe 'shared behaviors' do
it_should_behave_like 'it is a stream'
end

View file

@ -3,7 +3,7 @@ require File.join(Rails.root, 'spec', 'shared_behaviors', 'stream')
describe Stream::Public do
before do
@stream = Stream::Public.new(stub)
@stream = Stream::Public.new(alice)
end
describe 'shared behaviors' do

11
spec/models/block_spec.rb Normal file
View file

@ -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

View file

@ -174,4 +174,52 @@ describe Contact do
end
end
end
describe "#repopulate_cache" do
before do
@contact = bob.contact_for(alice.person)
end
it "repopulates the cache if the cache exists" do
cache = stub(:repopulate!)
RedisCache.stub(:configured? => true, :new => cache)
cache.should_receive(:repopulate!)
@contact.repopulate_cache!
end
it "does not touch the cache if it is not configured" do
RedisCache.stub(:configured?).and_return(false)
RedisCache.should_not_receive(:new)
@contact.repopulate_cache!
end
it "gets called on destroy" do
@contact.should_receive(:repopulate_cache!)
@contact.destroy
end
end
describe "#not_blocked_user" do
before do
@contact = alice.contact_for(bob.person)
end
it "is called on validate" do
@contact.should_receive(:not_blocked_user)
@contact.valid?
end
it "adds to errors if potential contact is blocked by user" do
person = eve.person
block = alice.blocks.create(:person => person)
bad_contact = alice.contacts.create(:person => person)
bad_contact.send(:not_blocked_user).should be_false
end
it "does not add to errors" do
@contact.send(:not_blocked_user).should be_true
end
end
end

View file

@ -58,6 +58,33 @@ 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
it 'returns posts if you dont have any blocks' do
Post.excluding_blocks(alice).count.should == 2
end
end
context 'having some posts' do

View file

@ -52,8 +52,8 @@ describe Diaspora::UserModules::Connecting do
it 'calls remove contact' do
contact = bob.contact_for(alice.person)
bob.should_receive(:remove_contact).with(contact)
bob.disconnect contact
bob.should_receive(:remove_contact).with(contact, {})
bob.disconnect(contact)
end
it 'dispatches a retraction' do

View file

@ -382,9 +382,7 @@ describe User do
end
end
describe '.find_or_create_by_invitation' do
end
describe '.find_or_create_by_invitation'
describe '.create_from_invitation!' do
before do
@ -400,7 +398,6 @@ describe User do
it 'sets the email if the service is email' do
@user.email.should == @inv.identifier
end
end
describe 'update_user_preferences' do
@ -551,7 +548,6 @@ describe User do
alice.remove_all_traces
end
it 'should remove mentions' do
alice.should_receive(:remove_mentions)
alice.remove_all_traces