From bfe0b7129c57e177e5b4767fc9d497638e788f11 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Mon, 16 Jan 2012 19:33:47 -0800 Subject: [PATCH 01/35] move all stream actions into PostController --- app/controllers/application_controller.rb | 4 +- app/controllers/aspects_controller.rb | 28 ------- app/controllers/comment_stream_controller.rb | 19 ----- app/controllers/home_controller.rb | 2 +- app/controllers/like_stream_controller.rb | 19 ----- app/controllers/mentions_controller.rb | 19 ----- app/controllers/multis_controller.rb | 20 ----- app/controllers/notifications_controller.rb | 2 +- app/controllers/posts_controller.rb | 74 +++++++++++++++++-- app/controllers/status_messages_controller.rb | 2 +- app/controllers/tag_followings_controller.rb | 12 +-- app/controllers/users_controller.rb | 10 +-- app/controllers/vanna_controller.rb | 2 +- app/helpers/stream_helper.rb | 22 ++---- app/views/aspects/index.html.haml | 8 +- app/views/layouts/application.mobile.haml | 2 +- app/views/tags/_followed_tags_listings.haml | 2 +- app/views/users/logged_out.haml | 7 +- config/routes.rb | 31 ++++---- features/accepts_invitation.feature | 4 +- features/change_password.feature | 2 +- features/follows_tags.feature | 4 +- features/logs_in_and_out.feature | 4 +- features/signs_up.feature | 6 +- features/support/paths.rb | 2 +- lib/stream/multi.rb | 2 +- public/javascripts/app/router.js | 6 +- spec/controllers/admins_controller_spec.rb | 4 +- spec/controllers/aspects_controller_spec.rb | 68 +---------------- spec/controllers/home_controller_spec.rb | 2 +- .../jasmine_fixtures/aspects_spec.rb | 22 +++--- .../jasmine_fixtures/stream_spec.rb | 6 +- .../like_stream_controller_spec.rb | 23 ------ spec/controllers/posts_controller_spec.rb | 66 ++++++++++++++--- .../registrations_controller_spec.rb | 2 +- spec/controllers/sessions_controller_spec.rb | 4 +- 36 files changed, 200 insertions(+), 312 deletions(-) delete mode 100644 app/controllers/comment_stream_controller.rb delete mode 100644 app/controllers/like_stream_controller.rb delete mode 100644 app/controllers/mentions_controller.rb delete mode 100644 app/controllers/multis_controller.rb delete mode 100644 spec/controllers/like_stream_controller_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c46581f80..52bda40bc 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -83,7 +83,7 @@ class ApplicationController < ActionController::Base def redirect_unless_admin unless current_user.admin? - redirect_to multi_url, :notice => 'you need to be an admin to do that' + redirect_to multi_stream_url, :notice => 'you need to be an admin to do that' return end end @@ -111,7 +111,7 @@ class ApplicationController < ActionController::Base end def after_sign_in_path_for(resource) - stored_location_for(:user) || (current_user.getting_started? ? getting_started_path : multi_path) + stored_location_for(:user) || (current_user.getting_started? ? getting_started_path : multi_stream_path) end def tag_followings diff --git a/app/controllers/aspects_controller.rb b/app/controllers/aspects_controller.rb index 2fcc10c31..1873cd635 100644 --- a/app/controllers/aspects_controller.rb +++ b/app/controllers/aspects_controller.rb @@ -2,29 +2,13 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -require File.join(Rails.root, "lib", 'stream', "aspect") - class AspectsController < ApplicationController before_filter :authenticate_user! - before_filter :save_selected_aspects, :only => :index - before_filter :ensure_page, :only => :index respond_to :html, :js, :json - def index - stream_klass = Stream::Aspect - aspect_ids = (session[:a_ids] ? session[:a_ids] : []) - @stream = Stream::Aspect.new(current_user, aspect_ids, - :max_time => params[:max_time].to_i) - - respond_with do |format| - format.html { render 'aspects/index' } - format.json{ render_for_api :backbone, :json => @stream.stream_posts, :root => :posts } - end - end - def create @aspect = current_user.aspects.create(params[:aspect]) @@ -132,16 +116,4 @@ class AspectsController < ApplicationController end @aspect.save end - - def ensure_page - params[:max_time] ||= Time.now + 1 - end - - private - - def save_selected_aspects - if params[:a_ids].present? - session[:a_ids] = params[:a_ids] - end - end end diff --git a/app/controllers/comment_stream_controller.rb b/app/controllers/comment_stream_controller.rb deleted file mode 100644 index f478a6d20..000000000 --- a/app/controllers/comment_stream_controller.rb +++ /dev/null @@ -1,19 +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','stream', 'comments') - -class CommentStreamController < ApplicationController - - respond_to :html, :json - - def index - stream_klass = Stream::Comments - - respond_with do |format| - format.html{ default_stream_action(stream_klass) } - format.json{ stream_json(stream_klass) } - end - end -end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 5376bc8ab..e33d51656 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -6,7 +6,7 @@ class HomeController < ApplicationController def show if current_user - redirect_to multi_path if current_user + redirect_to multi_stream_path if current_user elsif is_mobile_device? redirect_to user_session_path else diff --git a/app/controllers/like_stream_controller.rb b/app/controllers/like_stream_controller.rb deleted file mode 100644 index 5fd8fc631..000000000 --- a/app/controllers/like_stream_controller.rb +++ /dev/null @@ -1,19 +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','stream', 'likes') - -class LikeStreamController < ApplicationController - - respond_to :html, :json - - def index - stream_klass = Stream::Likes - - respond_with do |format| - format.html{ default_stream_action(stream_klass) } - format.json{ stream_json(stream_klass) } - end - end -end diff --git a/app/controllers/mentions_controller.rb b/app/controllers/mentions_controller.rb deleted file mode 100644 index 87e2f37f7..000000000 --- a/app/controllers/mentions_controller.rb +++ /dev/null @@ -1,19 +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','stream', 'mention') - -class MentionsController < ApplicationController - - respond_to :html, :json - - def index - stream_klass = Stream::Mention - - respond_with do |format| - format.html{ default_stream_action(stream_klass) } - format.json{ stream_json(stream_klass) } - end - end -end diff --git a/app/controllers/multis_controller.rb b/app/controllers/multis_controller.rb deleted file mode 100644 index 9eb042503..000000000 --- a/app/controllers/multis_controller.rb +++ /dev/null @@ -1,20 +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', 'stream', 'multi') - -class MultisController < ApplicationController - - respond_to :html, :json - - def index - stream_klass = Stream::Multi - - respond_with do |format| - format.html{ default_stream_action(stream_klass) } - format.mobile{ default_stream_action(stream_klass) } - format.json{ stream_json(stream_klass) } - end - end -end diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index c27df96c7..b51d7e470 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -50,7 +50,7 @@ class NotificationsController < VannaController post_process :html do def post_read_all(json) - Response.new(:status => 302, :location => multi_path) + Response.new(:status => 302, :location => multi_stream_path) end end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 1a44a8f26..c58f3944b 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -2,12 +2,21 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -require File.join(Rails.root, 'lib', 'stream', 'public') +require File.join(Rails.root, "lib", "stream", "aspect") +require File.join(Rails.root, "lib", "stream", "multi") +require File.join(Rails.root, "lib", "stream", "comments") +require File.join(Rails.root, "lib", "stream", "likes") +require File.join(Rails.root, "lib", "stream", "mention") +require File.join(Rails.root, "lib", "stream", "followed_tag") class PostsController < ApplicationController before_filter :authenticate_user!, :except => :show before_filter :set_format_if_malformed_from_status_net, :only => :show - before_filter :redirect_unless_admin, :only => :index + + before_filter :redirect_unless_admin, :only => :public + + before_filter :save_selected_aspects, :only => :aspects + before_filter :ensure_page, :only => :aspects respond_to :html, :mobile, @@ -54,7 +63,7 @@ class PostsController < ApplicationController respond_to do |format| format.js {render 'destroy'} format.json { render :nothing => true, :status => 204 } - format.all {redirect_to multi_path} + format.all {redirect_to multi_stream_path} end else Rails.logger.info "event=post_destroy status=failure user=#{current_user.diaspora_handle} reason='User does not own post'" @@ -62,16 +71,57 @@ class PostsController < ApplicationController end end - def index - default_stream_action(Stream::Public) + # streams + def aspects + stream_klass = Stream::Aspect + aspect_ids = (session[:a_ids] ? session[:a_ids] : []) + @stream = Stream::Aspect.new(current_user, aspect_ids, + :max_time => params[:max_time].to_i) + + respond_with do |format| + format.html { render 'aspects/index' } + format.json{ render_for_api :backbone, :json => @stream.stream_posts, :root => :posts } + end + end + + def public + stream_responder(Stream::Public) + end + + def multi + stream_responder(Stream::Multi) + end + + def commented + stream_responder(Stream::Comments) + end + + def liked + stream_responder(Stream::Likes) + end + + def mentioned + stream_responder(Stream::Mention) + end + + def followed_tags + stream_responder(Stream::FollowedTag) + end + + private + + def stream_responder(stream_klass) + respond_with do |format| + format.html{ default_stream_action(stream_klass) } + format.mobile{ default_stream_action(stream_klass) } + format.json{ stream_json(stream_klass) } + end end def set_format_if_malformed_from_status_net request.format = :html if request.format == 'application/html+xml' end - private - def user_can_not_comment_on_post? if @post.public && @post.author.local? false @@ -83,4 +133,14 @@ class PostsController < ApplicationController true end end + + def save_selected_aspects + if params[:a_ids].present? + session[:a_ids] = params[:a_ids] + end + end + + def ensure_page + params[:max_time] ||= Time.now + 1 + end end diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index 3717cd472..726835961 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -70,7 +70,7 @@ class StatusMessagesController < ApplicationController respond_to do |format| format.html { redirect_to :back} - format.mobile{ redirect_to multi_path} + format.mobile{ redirect_to multi_stream_path} format.json{ render :json => @status_message.as_api_response(:backbone), :status => 201 } end else diff --git a/app/controllers/tag_followings_controller.rb b/app/controllers/tag_followings_controller.rb index b99e00a22..f9a0e7b63 100644 --- a/app/controllers/tag_followings_controller.rb +++ b/app/controllers/tag_followings_controller.rb @@ -2,22 +2,12 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. # -require File.join(Rails.root, 'lib', 'stream', 'followed_tag') class TagFollowingsController < ApplicationController before_filter :authenticate_user! respond_to :html, :json - def index - stream_klass = Stream::FollowedTag - - respond_with do |format| - format.html{ default_stream_action(stream_klass) } - format.json{ stream_json(stream_klass) } - end - end - # POST /tag_followings # POST /tag_followings.xml def create @@ -73,6 +63,6 @@ class TagFollowingsController < ApplicationController @tag_following = current_user.tag_followings.create(:tag_id => @tag.id) end end - redirect_to multi_path + redirect_to multi_stream_path end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 56a26bab8..72c1ccbd7 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -87,7 +87,7 @@ class UsersController < ApplicationController if params[:user] && params[:user][:current_password] && current_user.valid_password?(params[:user][:current_password]) current_user.close_account! sign_out current_user - redirect_to(multi_path, :notice => I18n.t('users.destroy.success')) + redirect_to(multi_stream_path, :notice => I18n.t('users.destroy.success')) else if params[:user].present? && params[:user][:current_password].present? flash[:error] = t 'users.destroy.wrong_password' @@ -111,7 +111,7 @@ class UsersController < ApplicationController format.any { redirect_to person_path(user.person.id) } end else - redirect_to multi_path, :error => I18n.t('users.public.does_not_exist', :username => params[:username]) + redirect_to multi_stream_path, :error => I18n.t('users.public.does_not_exist', :username => params[:username]) end end @@ -127,14 +127,14 @@ class UsersController < ApplicationController def logged_out @page = :logged_out if user_signed_in? - redirect_to multi_path + redirect_to multi_stream_path end end def getting_started_completed user = current_user user.update_attributes(:getting_started => false) - redirect_to multi_path + redirect_to multi_stream_path end def export @@ -150,7 +150,7 @@ class UsersController < ApplicationController def user_photo username = params[:username].split('@')[0] user = User.find_by_username(username) - if user.present? + if user.present? redirect_to user.profile.image_url else render :nothing => true, :status => 404 diff --git a/app/controllers/vanna_controller.rb b/app/controllers/vanna_controller.rb index 3ae86330c..693f10dc9 100644 --- a/app/controllers/vanna_controller.rb +++ b/app/controllers/vanna_controller.rb @@ -83,7 +83,7 @@ class VannaController < Vanna::Base def redirect_unless_admin unless current_user.admin? - redirect_to multi_path, :notice => 'you need to be an admin to do that' + redirect_to multi_stream_path, :notice => 'you need to be an admin to do that' return end end diff --git a/app/helpers/stream_helper.rb b/app/helpers/stream_helper.rb index 44b882380..f18654525 100644 --- a/app/helpers/stream_helper.rb +++ b/app/helpers/stream_helper.rb @@ -10,25 +10,19 @@ module StreamHelper "/apps/1?#{{:max_time => @posts.last.created_at.to_i}.to_param}" elsif controller.instance_of?(PeopleController) local_or_remote_person_path(@person, :max_time => time_for_scroll(@stream)) - elsif controller.instance_of?(TagFollowingsController) - tag_followings_path(:max_time => time_for_scroll(@stream)) - elsif controller.instance_of?(MentionsController) - mentions_path(:max_time => time_for_scroll(@stream)) - elsif controller.instance_of?(MultisController) - multi_path(:max_time => time_for_scroll(@stream)) elsif controller.instance_of?(PostsController) public_stream_path(:max_time => time_for_scroll(@stream)) - elsif controller.instance_of?(AspectsController) - aspects_path(:max_time => time_for_scroll(@stream), :a_ids => @stream.aspect_ids) - elsif controller.instance_of?(LikeStreamController) - like_stream_path(:max_time => time_for_scroll(@stream)) - elsif controller.instance_of?(CommentStreamController) - comment_stream_path(:max_time => time_for_scroll(@stream)) else raise 'in order to use pagination for this new controller, update next_page_path in stream helper' end end + def reshare?(post) + post.instance_of?(Reshare) + end + + private + def time_for_scroll(stream) if stream.stream_posts.empty? (Time.now() + 1).to_i @@ -36,8 +30,4 @@ module StreamHelper stream.stream_posts.last.send(stream.order.to_sym).to_i end end - - def reshare?(post) - post.instance_of?(Reshare) - end end diff --git a/app/views/aspects/index.html.haml b/app/views/aspects/index.html.haml index bd1039821..313e83e8b 100644 --- a/app/views/aspects/index.html.haml +++ b/app/views/aspects/index.html.haml @@ -31,21 +31,21 @@ .section %ul.left_nav %li - = link_to t("streams.multi.title"), multi_path, :class => 'home_selector', :rel => 'backbone' + = link_to t("streams.multi.title"), multi_stream_path, :class => 'home_selector', :rel => 'backbone' = render 'aspects/aspect_listings', :stream => @stream %ul.left_nav %li - = link_to t('streams.mentions.title'), mentions_path, :class => 'home_selector', :rel => 'backbone' + = link_to t('streams.mentions.title'), mentioned_stream_path, :class => 'home_selector', :rel => 'backbone' %ul.left_nav %li - = link_to t('streams.comment_stream.title'), comment_stream_path, :class => 'home_selector', :rel => 'backbone' + = link_to t('streams.comment_stream.title'), commented_stream_path, :class => 'home_selector', :rel => 'backbone' %ul.left_nav %li - = link_to t('streams.like_stream.title'), like_stream_path, :class => 'home_selector', :rel => 'backbone' + = link_to t('streams.like_stream.title'), liked_stream_path, :class => 'home_selector', :rel => 'backbone' #followed_tags_listing = render 'tags/followed_tags_listings' diff --git a/app/views/layouts/application.mobile.haml b/app/views/layouts/application.mobile.haml index 89601a4c5..b574203bd 100644 --- a/app/views/layouts/application.mobile.haml +++ b/app/views/layouts/application.mobile.haml @@ -50,7 +50,7 @@ = yield %header - = link_to(image_tag('white@2x.png', :height => 20, :width => 127, :id => 'header_title'), multi_path) + = link_to(image_tag('white@2x.png', :height => 20, :width => 127, :id => 'header_title'), multi_stream_path) - if user_signed_in? - if yield(:header_action).present? = yield(:header_action) diff --git a/app/views/tags/_followed_tags_listings.haml b/app/views/tags/_followed_tags_listings.haml index 30bed3e9f..3ed55ada3 100644 --- a/app/views/tags/_followed_tags_listings.haml +++ b/app/views/tags/_followed_tags_listings.haml @@ -5,7 +5,7 @@ - if user_signed_in? %ul.left_nav %li - %b=link_to t('streams.followed_tag.title'), tag_followings_path, :class => 'home_selector' + %b=link_to t('streams.followed_tag.title'), followed_tags_stream_path, :class => 'home_selector' - if @stream.is_a?(Stream::FollowedTag) %ul.sub_nav diff --git a/app/views/users/logged_out.haml b/app/views/users/logged_out.haml index b0ae96e93..9ca4a458b 100644 --- a/app/views/users/logged_out.haml +++ b/app/views/users/logged_out.haml @@ -4,10 +4,7 @@ - content_for :head do :css - body { - margin-top: 220px; - } - + body { margin-top: 220px; } #grey_header .row @@ -25,7 +22,7 @@ %h4 = t('.simply_visit') %strong - = link_to AppConfig[:pod_url], multi_path + = link_to AppConfig[:pod_url], multi_stream_path = t('.on_your_mobile_device') %p.dull diff --git a/config/routes.rb b/config/routes.rb index e85117ea5..4ce940862 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,15 +4,10 @@ Diaspora::Application.routes.draw do - # Posting and Reading resources :reshares - resources :aspects do - put :toggle_contact_visibility - end - resources :status_messages, :only => [:new, :create] resources :posts, :only => [:show, :destroy] do @@ -20,12 +15,23 @@ Diaspora::Application.routes.draw do resources :comments, :only => [:new, :create, :destroy, :index] end get 'p/:id' => 'posts#show', :as => 'short_post' - get 'public_stream' => 'posts#index', :as => 'public_stream' # roll up likes into a nested resource above resources :comments, :only => [:create, :destroy] do resources :likes, :only => [:create, :destroy, :index] end + # Streams + get "public" => "posts#public", :as => "public_stream" + get "stream" => "posts#multi", :as => "multi_stream" + get "followed_tags" => "posts#followed_tags", :as => "followed_tags_stream" + get "mentions" => "posts#mentioned", :as => "mentioned_stream" + get "liked" => "posts#liked", :as => "liked_stream" + get "commented" => "posts#commented", :as => "commented_stream" + get "aspects" => "posts#aspects", :as => "aspects_stream" + + resources :aspects do + put :toggle_contact_visibility + end get 'bookmarklet' => 'status_messages#bookmarklet' @@ -50,26 +56,19 @@ Diaspora::Application.routes.draw do resources :tags, :only => [:index] scope "tags/:name" do post "tag_followings" => "tag_followings#create", :as => 'tag_tag_followings' - delete "tag_followings" => "tag_followings#destroy" + delete "tag_followings" => "tag_followings#destroy", :as => 'tag_tag_followings' end post "multiple_tag_followings" => "tag_followings#create_multiple", :as => 'multiple_tag_followings' - - get "tag_followings" => "tag_followings#index", :as => 'tag_followings' - resources :mentions, :only => [:index] resources "tag_followings", :only => [:create] - get 'comment_stream' => 'comment_stream#index', :as => 'comment_stream' - - get 'like_stream' => 'like_stream#index', :as => 'like_stream' - get 'tags/:name' => 'tags#show', :as => 'tag' resources :apps, :only => [:show] #Cubbies info page - resource :token, :only => :show + resource :token, :only => :show # Users and people @@ -120,8 +119,6 @@ Diaspora::Application.routes.draw do get 'community_spotlight' => "contacts#spotlight", :as => 'community_spotlight' - get 'stream' => "multis#index", :as => 'multi' - resources :people, :except => [:edit, :update] do resources :status_messages resources :photos diff --git a/features/accepts_invitation.feature b/features/accepts_invitation.feature index d675f1c00..3971078ce 100644 --- a/features/accepts_invitation.feature +++ b/features/accepts_invitation.feature @@ -16,7 +16,7 @@ Feature: invitation acceptance And I preemptively confirm the alert And I follow "awesome_button" - Then I should be on the multi page + Then I should be on the multi stream page Scenario: accept invitation from user Given I have been invited by a user @@ -34,7 +34,7 @@ Feature: invitation acceptance And I preemptively confirm the alert And I follow "awesome_button" - Then I should be on the multi page + Then I should be on the multi stream page Scenario: sends an invitation Given a user with email "bob@bob.bob" diff --git a/features/change_password.feature b/features/change_password.feature index 1115741f9..6bb646c91 100644 --- a/features/change_password.feature +++ b/features/change_password.feature @@ -11,7 +11,7 @@ Feature: Change password Then I should see "Password changed" Then I should be on the new user session page When I sign in with password "newsecret" - Then I should be on the multi page + Then I should be on the multi stream page Scenario: Reset my password Given a user with email "forgetful@users.net" diff --git a/features/follows_tags.feature b/features/follows_tags.feature index 01f09e88f..f305e32d7 100644 --- a/features/follows_tags.feature +++ b/features/follows_tags.feature @@ -29,11 +29,11 @@ Feature: posting Scenario: can stop following a tag from the tag page When I press "Following #boss" - And I go to the tag_followings page + And I go to the followed tags stream page Then I should not see "#boss" within ".left_nav" Scenario: can stop following a tag from the homepage - When I go to the tag_followings page + When I go to the followed tags stream page And I preemptively confirm the alert And I hover over the "li.unfollow#tag-following-boss" And I follow "unfollow_boss" diff --git a/features/logs_in_and_out.feature b/features/logs_in_and_out.feature index f5017bdcd..cc01930c1 100644 --- a/features/logs_in_and_out.feature +++ b/features/logs_in_and_out.feature @@ -6,7 +6,7 @@ Feature: user authentication And I fill in "Username" with "ohai" And I fill in "Password" with "secret" And I press "Sign in" - Then I should be on the multi page + Then I should be on the multi stream page @javascript Scenario: user logs out @@ -19,5 +19,5 @@ Feature: user authentication Scenario: user uses token auth Given a user with username "ohai" and password "secret" When I post a photo with a token - And I go to the multi page + And I go to the multi stream page Then I should be on the new user session page diff --git a/features/signs_up.feature b/features/signs_up.feature index cd0e9e24e..8cdd51e87 100644 --- a/features/signs_up.feature +++ b/features/signs_up.feature @@ -19,18 +19,18 @@ Feature: new user registration And I preemptively confirm the alert And I follow "awesome_button" - Then I should be on the multi page + Then I should be on the multi stream page And I should not see "awesome_button" Scenario: new user skips the setup wizard When I preemptively confirm the alert And I follow "awesome_button" - Then I should be on the multi page + Then I should be on the multi stream page Scenario: closing a popover clears getting started When I preemptively confirm the alert And I follow "awesome_button" - Then I should be on the multi page + Then I should be on the multi stream page And I have turned off jQuery effects And I wait for the popovers to appear And I click close on all the popovers diff --git a/features/support/paths.rb b/features/support/paths.rb index cf0166ca1..ce6ccb3dc 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -2,7 +2,7 @@ module NavigationHelpers def path_to(page_name) case page_name when /^the home(?: )?page$/ - multi_path + multi_stream_path when /^step (\d)$/ if $1.to_i == 1 getting_started_path diff --git a/lib/stream/multi.rb b/lib/stream/multi.rb index 8e6e62cde..0dc9efaa1 100644 --- a/lib/stream/multi.rb +++ b/lib/stream/multi.rb @@ -2,7 +2,7 @@ class Stream::Multi < Stream::Base # @return [String] URL def link(opts) - Rails.application.routes.url_helpers.multi_path(opts) + Rails.application.routes.url_helpers.multi_stream_path(opts) end # @return [String] diff --git a/public/javascripts/app/router.js b/public/javascripts/app/router.js index dde392e68..ab7234f59 100644 --- a/public/javascripts/app/router.js +++ b/public/javascripts/app/router.js @@ -2,12 +2,12 @@ app.Router = Backbone.Router.extend({ routes: { "stream": "stream", "aspects:query": "stream", - "comment_stream": "stream", - "like_stream": "stream", + "commented": "stream", + "liked": "stream", "mentions": "stream", "people/:id": "stream", "u/:name": "stream", - "tag_followings": "stream", + "followed_tags": "stream", "tags/:name": "stream", "posts/:id": "stream" }, diff --git a/spec/controllers/admins_controller_spec.rb b/spec/controllers/admins_controller_spec.rb index 776a54e80..165103df0 100644 --- a/spec/controllers/admins_controller_spec.rb +++ b/spec/controllers/admins_controller_spec.rb @@ -14,7 +14,7 @@ describe AdminsController do context 'admin not signed in' do it 'is behind redirect_unless_admin' do get :user_search - response.should redirect_to multi_path + response.should redirect_to multi_stream_path end end @@ -64,7 +64,7 @@ describe AdminsController do context 'admin not signed in' do it 'is behind redirect_unless_admin' do get :admin_inviter - response.should redirect_to multi_path + response.should redirect_to multi_stream_path end end diff --git a/spec/controllers/aspects_controller_spec.rb b/spec/controllers/aspects_controller_spec.rb index 97e3cabf5..697670fc4 100644 --- a/spec/controllers/aspects_controller_spec.rb +++ b/spec/controllers/aspects_controller_spec.rb @@ -35,52 +35,6 @@ describe AspectsController do end end - describe "#index" do - it 'assigns an Stream::Aspect' do - get :index - assigns(:stream).class.should == Stream::Aspect - end - - describe 'filtering by aspect' do - before do - @aspect1 = alice.aspects.create(:name => "test aspect") - @stream = Stream::Aspect.new(alice, []) - @stream.stub(:posts).and_return([]) - end - - it 'respects a single aspect' do - Stream::Aspect.should_receive(:new).with(alice, [@aspect1.id], anything).and_return(@stream) - get :index, :a_ids => [@aspect1.id] - end - - it 'respects multiple aspects' do - aspect2 = alice.aspects.create(:name => "test aspect two") - Stream::Aspect.should_receive(:new).with(alice, [@aspect1.id, aspect2.id], anything).and_return(@stream) - get :index, :a_ids => [@aspect1.id, aspect2.id] - end - end - - describe 'performance', :performance => true do - before do - require 'benchmark' - 8.times do |n| - user = Factory.create(:user) - aspect = user.aspects.create(:name => 'people') - connect_users(alice, @alices_aspect_1, user, aspect) - post = alice.post(:status_message, :text => "hello#{n}", :to => @alices_aspect_2.id) - 8.times do |n| - user.comment "yo#{post.text}", :post => post - end - end - end - it 'takes time' do - Benchmark.realtime { - get :index - }.should < 1.5 - end - end - end - describe "#show" do it "succeeds" do get :show, 'id' => @alices_aspect_1.id.to_s @@ -124,6 +78,7 @@ describe AspectsController do end end end + context "with invalid params" do it "does not create an aspect" do alice.aspects.count.should == 2 @@ -232,25 +187,4 @@ describe AspectsController do end end end - - describe "mobile site" do - before do - ap = alice.person - posts = [] - posts << alice.post(:reshare, :root_guid => Factory(:status_message, :public => true).guid, :to => 'all') - posts << alice.post(:status_message, :text => 'foo', :to => alice.aspects) - photo = Factory(:activity_streams_photo, :public => true, :author => ap) - posts << photo - posts.each do |p| - alice.build_like(:positive => true, :target => p).save - end - alice.add_to_streams(photo, alice.aspects) - sign_in alice - end - - it 'should not 500' do - get :index, :format => :mobile - response.should be_success - end - end end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index 0ef0f07aa..f9e950357 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -14,7 +14,7 @@ describe HomeController do it 'redirects to multis index if user is logged in' do sign_in alice get :show, :home => true - response.should redirect_to(multi_path) + response.should redirect_to(multi_stream_path) end end end diff --git a/spec/controllers/jasmine_fixtures/aspects_spec.rb b/spec/controllers/jasmine_fixtures/aspects_spec.rb index 0092b431e..32811ed3c 100644 --- a/spec/controllers/jasmine_fixtures/aspects_spec.rb +++ b/spec/controllers/jasmine_fixtures/aspects_spec.rb @@ -4,8 +4,8 @@ require 'spec_helper' -describe AspectsController do - describe '#index' do +describe PostsController do + describe '#aspects' do before do sign_in :user, alice @alices_aspect_2 = alice.aspects.create(:name => "another aspect") @@ -19,19 +19,19 @@ describe AspectsController do end it "generates a jasmine fixture", :fixture => true do - get :index + get :aspects save_fixture(html_for("body"), "aspects_index") end it "generates a jasmine fixture with a prefill", :fixture => true do - get :index, :prefill => "reshare things" + get :aspects, :prefill => "reshare things" save_fixture(html_for("body"), "aspects_index_prefill") end it 'generates a jasmine fixture with services', :fixture => true do alice.services << Services::Facebook.create(:user_id => alice.id) alice.services << Services::Twitter.create(:user_id => alice.id) - get :index, :prefill => "reshare things" + get :aspects, :prefill => "reshare things" save_fixture(html_for("body"), "aspects_index_services") end @@ -39,14 +39,14 @@ describe AspectsController do bob.post(:status_message, :text => "Is anyone out there?", :to => @bob.aspects.where(:name => "generic").first.id) message = alice.post(:status_message, :text => "hello "*800, :to => @alices_aspect_2.id) 5.times { bob.comment("what", :post => message) } - get :index + get :aspects save_fixture(html_for("body"), "aspects_index_with_posts") end it 'generates a jasmine fixture with only posts', :fixture => true do 2.times { bob.post(:status_message, :text => "Is anyone out there?", :to => @bob.aspects.where(:name => "generic").first.id) } - get :index, :only_posts => true + get :aspects, :only_posts => true save_fixture(response.body, "aspects_index_only_posts") end @@ -54,14 +54,14 @@ describe AspectsController do it "generates a jasmine fixture with a post with comments", :fixture => true do message = bob.post(:status_message, :text => "HALO WHIRLED", :to => @bob.aspects.where(:name => "generic").first.id) 5.times { bob.comment("what", :post => message) } - get :index + get :aspects save_fixture(html_for("body"), "aspects_index_post_with_comments") end it 'generates a jasmine fixture with a followed tag', :fixture => true do @tag = ActsAsTaggableOn::Tag.create!(:name => "partytimeexcellent") TagFollowing.create!(:tag => @tag, :user => alice) - get :index + get :aspects save_fixture(html_for("body"), "aspects_index_with_one_followed_tag") end @@ -89,7 +89,7 @@ describe AspectsController do ) alice.post(:status_message, :text => "http://www.youtube.com/watch?v=UYrkQL1bX4A", :to => @alices_aspect_2.id) - get :index + get :aspects save_fixture(html_for("body"), "aspects_index_with_video_post") end @@ -98,7 +98,7 @@ describe AspectsController do alice.build_like(:positive => true, :target => message).save bob.build_like(:positive => true, :target => message).save - get :index + get :aspects save_fixture(html_for("body"), "aspects_index_with_a_post_with_likes") end end diff --git a/spec/controllers/jasmine_fixtures/stream_spec.rb b/spec/controllers/jasmine_fixtures/stream_spec.rb index 27f71b9c6..fd9fa7d13 100644 --- a/spec/controllers/jasmine_fixtures/stream_spec.rb +++ b/spec/controllers/jasmine_fixtures/stream_spec.rb @@ -4,8 +4,8 @@ require 'spec_helper' -describe MultisController do - describe '#index' do +describe PostsController do + describe '#multi' do before do sign_in :user, alice end @@ -27,7 +27,7 @@ describe MultisController do end end - get :index, :format => :json + get :multi, :format => :json response.should be_success save_fixture(response.body, "multi_stream_json") diff --git a/spec/controllers/like_stream_controller_spec.rb b/spec/controllers/like_stream_controller_spec.rb deleted file mode 100644 index 9dfddce4d..000000000 --- a/spec/controllers/like_stream_controller_spec.rb +++ /dev/null @@ -1,23 +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 'spec_helper' - -describe LikeStreamController do - before do - sign_in :user, alice - end - - describe 'index' do - it 'succeeds' do - get :index - response.should be_success - end - - it 'assigns a stream' do - get :index - assigns[:stream].should be_a Stream::Likes - end - end -end diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb index 5141ee383..42fc96bce 100644 --- a/spec/controllers/posts_controller_spec.rb +++ b/spec/controllers/posts_controller_spec.rb @@ -138,22 +138,70 @@ describe PostsController do end end - describe '#index' do + context 'streams' do before do sign_in alice end - it 'will succeed if admin' do - AppConfig[:admins] = [alice.username] - get :index - response.should be_success + describe "#public" do + it 'will succeed if admin' do + AppConfig[:admins] = [alice.username] + get :public + response.should be_success + end + + it 'will redirect if not' do + AppConfig[:admins] = [] + get :public + response.should be_redirect + end end - it 'will redirect if not' do - AppConfig[:admins] = [] - get :index - response.should be_redirect + describe '#multi' do + before do + @old_spotlight_value = AppConfig[:community_spotlight] + end + + after do + AppConfig[:community_spotlight] = @old_spotlight_value + end + + it 'succeeds' do + AppConfig[:community_spotlight] = [bob.person.diaspora_handle] + get :multi + response.should be_success + end + + it 'succeeds without AppConfig[:community_spotlight]' do + AppConfig[:community_spotlight] = nil + get :multi + response.should be_success + end + + it 'succeeds on mobile' do + get :multi, :format => :mobile + response.should be_success + end end + streams = [ + {:path => :liked, :type => Stream::Likes}, + {:path => :mentioned, :type => Stream::Mention}, + {:path => :followed_tags, :type => Stream::FollowedTag} + ] + + streams.each do |s| + describe "##{s[:path]}" do + it 'succeeds' do + get s[:path] + response.should be_success + end + + it 'assigns a stream' do + get s[:path] + assigns[:stream].should be_a s[:type] + end + end + end end end diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index b647895fd..b7338ce4a 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -67,7 +67,7 @@ describe RegistrationsController do it "redirects to the home path" do get :create, @valid_params response.should be_redirect - response.location.should match /^#{multi_url}\??$/ + response.location.should match /^#{multi_stream_url}\??$/ end end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index cabf39664..38c203e6e 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -27,14 +27,14 @@ describe SessionsController do it "redirects to /stream for a non-mobile user" do post :create, {"user" => {"remember_me" => "0", "username" => @user.username, "password" => "evankorth"}} response.should be_redirect - response.location.should match /^#{multi_url}\??$/ + response.location.should match /^#{multi_stream_url}\??$/ end it "redirects to /stream for a mobile user" do @request.env['HTTP_USER_AGENT'] = 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7' post :create, {"user" => {"remember_me" => "0", "username" => @user.username, "password" => "evankorth"}} response.should be_redirect - response.location.should match /^#{multi_url}\??$/ + response.location.should match /^#{multi_stream_url}\??$/ end it 'queues up an update job' do From 339c47d7821a577f901f509ba5976ae30434044d Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Tue, 17 Jan 2012 15:52:15 -0800 Subject: [PATCH 02/35] moved stream logic into its own controller (StreamsController) --- app/controllers/application_controller.rb | 16 -- app/controllers/posts_controller.rb | 67 ------ app/controllers/streams_controller.rb | 71 +++++++ .../main_stream.html.haml} | 4 +- app/views/layouts/main_stream.mobile.haml | 18 ++ config/routes.rb | 14 +- features/oembed.feature | 1 + features/photo_lightbox.feature | 1 - features/posts_from_main_page.feature | 2 + .../jasmine_fixtures/aspects_spec.rb | 2 +- .../{stream_spec.rb => streams_spec.rb} | 2 +- spec/controllers/multis_controller_spec.rb | 35 ---- spec/controllers/posts_controller_spec.rb | 67 ------ spec/controllers/streams_controller_spec.rb | 72 +++++++ .../tag_followings_controller_spec.rb | 195 ------------------ 15 files changed, 175 insertions(+), 392 deletions(-) create mode 100644 app/controllers/streams_controller.rb rename app/views/{aspects/index.html.haml => layouts/main_stream.html.haml} (92%) create mode 100644 app/views/layouts/main_stream.mobile.haml rename spec/controllers/jasmine_fixtures/{stream_spec.rb => streams_spec.rb} (97%) delete mode 100644 spec/controllers/multis_controller_spec.rb create mode 100644 spec/controllers/streams_controller_spec.rb delete mode 100644 spec/controllers/tag_followings_controller_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 52bda40bc..3afefd3c2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -127,22 +127,6 @@ class ApplicationController < ActionController::Base @tags ||= current_user.followed_tags end - # @param stream_klass [Constant] - # @return [String] JSON representation of posts given a [Stream] constant. - def stream_json(stream_klass) - render_for_api :backbone, :json => stream(stream_klass).stream_posts, :root => :posts - end - - def stream(stream_klass) - authenticate_user! - stream_klass.new(current_user, :max_time => max_time) - end - - def default_stream_action(stream_klass) - @stream = stream(stream_klass) - render 'aspects/index' - end - def max_time params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index c58f3944b..856dcc104 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -2,22 +2,10 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -require File.join(Rails.root, "lib", "stream", "aspect") -require File.join(Rails.root, "lib", "stream", "multi") -require File.join(Rails.root, "lib", "stream", "comments") -require File.join(Rails.root, "lib", "stream", "likes") -require File.join(Rails.root, "lib", "stream", "mention") -require File.join(Rails.root, "lib", "stream", "followed_tag") - class PostsController < ApplicationController before_filter :authenticate_user!, :except => :show before_filter :set_format_if_malformed_from_status_net, :only => :show - before_filter :redirect_unless_admin, :only => :public - - before_filter :save_selected_aspects, :only => :aspects - before_filter :ensure_page, :only => :aspects - respond_to :html, :mobile, :json, @@ -71,53 +59,8 @@ class PostsController < ApplicationController end end - # streams - def aspects - stream_klass = Stream::Aspect - aspect_ids = (session[:a_ids] ? session[:a_ids] : []) - @stream = Stream::Aspect.new(current_user, aspect_ids, - :max_time => params[:max_time].to_i) - - respond_with do |format| - format.html { render 'aspects/index' } - format.json{ render_for_api :backbone, :json => @stream.stream_posts, :root => :posts } - end - end - - def public - stream_responder(Stream::Public) - end - - def multi - stream_responder(Stream::Multi) - end - - def commented - stream_responder(Stream::Comments) - end - - def liked - stream_responder(Stream::Likes) - end - - def mentioned - stream_responder(Stream::Mention) - end - - def followed_tags - stream_responder(Stream::FollowedTag) - end - private - def stream_responder(stream_klass) - respond_with do |format| - format.html{ default_stream_action(stream_klass) } - format.mobile{ default_stream_action(stream_klass) } - format.json{ stream_json(stream_klass) } - end - end - def set_format_if_malformed_from_status_net request.format = :html if request.format == 'application/html+xml' end @@ -133,14 +76,4 @@ class PostsController < ApplicationController true end end - - def save_selected_aspects - if params[:a_ids].present? - session[:a_ids] = params[:a_ids] - end - end - - def ensure_page - params[:max_time] ||= Time.now + 1 - end end diff --git a/app/controllers/streams_controller.rb b/app/controllers/streams_controller.rb new file mode 100644 index 000000000..50a240f37 --- /dev/null +++ b/app/controllers/streams_controller.rb @@ -0,0 +1,71 @@ +# 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", "stream", "aspect") +require File.join(Rails.root, "lib", "stream", "multi") +require File.join(Rails.root, "lib", "stream", "comments") +require File.join(Rails.root, "lib", "stream", "likes") +require File.join(Rails.root, "lib", "stream", "mention") +require File.join(Rails.root, "lib", "stream", "followed_tag") + +class StreamsController < ApplicationController + before_filter :authenticate_user! + before_filter :save_selected_aspects, :only => :aspects + before_filter :redirect_unless_admin, :only => :public + + respond_to :html, + :mobile, + :json + + def aspects + aspect_ids = (session[:a_ids] ? session[:a_ids] : []) + @stream = Stream::Aspect.new(current_user, aspect_ids, + :max_time => max_time) + stream_responder + end + + def public + stream_responder(Stream::Public) + end + + def multi + stream_responder(Stream::Multi) + end + + def commented + stream_responder(Stream::Comments) + end + + def liked + stream_responder(Stream::Likes) + end + + def mentioned + stream_responder(Stream::Mention) + end + + def followed_tags + stream_responder(Stream::FollowedTag) + end + + private + + def stream_responder(stream_klass=nil) + if stream_klass.present? + @stream ||= stream_klass.new(current_user, :max_time => max_time) + end + + respond_with do |format| + format.html { render 'layouts/main_stream' } + format.mobile { render 'layouts/main_stream' } + format.json { render_for_api :backbone, :json => @stream.stream_posts, :root => :posts } + end + end + + def save_selected_aspects + if params[:a_ids].present? + session[:a_ids] = params[:a_ids] + end + end +end diff --git a/app/views/aspects/index.html.haml b/app/views/layouts/main_stream.html.haml similarity index 92% rename from app/views/aspects/index.html.haml rename to app/views/layouts/main_stream.html.haml index 313e83e8b..fad1427e9 100644 --- a/app/views/aspects/index.html.haml +++ b/app/views/layouts/main_stream.html.haml @@ -13,9 +13,9 @@ = link_to image_tag('close_label.png'), getting_started_completed_path, :id => "gs-skip-x" .span-23 %h1 - = t('.welcome_to_diaspora', :name => current_user.first_name) + = t('aspects.index.welcome_to_diaspora', :name => current_user.first_name) %h3 - = t('.introduce_yourself') + = t('aspects.index.introduce_yourself') %br %br %br diff --git a/app/views/layouts/main_stream.mobile.haml b/app/views/layouts/main_stream.mobile.haml new file mode 100644 index 000000000..4c5ab0cb9 --- /dev/null +++ b/app/views/layouts/main_stream.mobile.haml @@ -0,0 +1,18 @@ +-# Copyright (c) 2010-2011, Diaspora Inc. This file is +-# licensed under the Affero General Public License version 3 or later. See +-# the COPYRIGHT file. + +%h2{:style => "padding:0 10px;display:none;"} + - if @stream.for_all_aspects? + = t('all_aspects') + - else + = @stream.aspect + +#main_stream.stream + = render 'shared/stream', :posts => @stream.stream_posts + -if @stream.stream_posts.length > 0 + #pagination + %a.more-link.paginate{:href => next_page_path} + %h1 + = t("more") + diff --git a/config/routes.rb b/config/routes.rb index 4ce940862..de5a45cfa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -21,13 +21,13 @@ Diaspora::Application.routes.draw do end # Streams - get "public" => "posts#public", :as => "public_stream" - get "stream" => "posts#multi", :as => "multi_stream" - get "followed_tags" => "posts#followed_tags", :as => "followed_tags_stream" - get "mentions" => "posts#mentioned", :as => "mentioned_stream" - get "liked" => "posts#liked", :as => "liked_stream" - get "commented" => "posts#commented", :as => "commented_stream" - get "aspects" => "posts#aspects", :as => "aspects_stream" + get "public" => "streams#public", :as => "public_stream" + get "stream" => "streams#multi", :as => "multi_stream" + get "followed_tags" => "streams#followed_tags", :as => "followed_tags_stream" + get "mentions" => "streams#mentioned", :as => "mentioned_stream" + get "liked" => "streams#liked", :as => "liked_stream" + get "commented" => "streams#commented", :as => "commented_stream" + get "aspects" => "streams#aspects", :as => "aspects_stream" resources :aspects do put :toggle_contact_visibility diff --git a/features/oembed.feature b/features/oembed.feature index 6aefc2a18..9fdf31c9b 100644 --- a/features/oembed.feature +++ b/features/oembed.feature @@ -22,6 +22,7 @@ Feature: oembed Given I expand the publisher When I fill in "status_message_fake_text" with "http://mytube.com/watch?v=M3r2XDceM6A&format=json" And I press "Share" + And I wait for the ajax to finish And I follow "Your Aspects" Then I should not see a video player diff --git a/features/photo_lightbox.feature b/features/photo_lightbox.feature index de908ec35..1b13de22d 100644 --- a/features/photo_lightbox.feature +++ b/features/photo_lightbox.feature @@ -12,7 +12,6 @@ Feature: viewing the photo lightbox And I fill in "status_message_fake_text" with "Look at this dog" And I press "Share" And I wait for the ajax to finish - And I am on the aspects page Scenario: viewing a photo Then I should see an image attached to the post diff --git a/features/posts_from_main_page.feature b/features/posts_from_main_page.feature index 251b782aa..fffe3073c 100644 --- a/features/posts_from_main_page.feature +++ b/features/posts_from_main_page.feature @@ -19,6 +19,8 @@ Feature: posting from the main page Given I expand the publisher When I fill in "status_message_fake_text" with "I am eating a yogurt" And I press "Share" + And I wait for the ajax to finish + And I go to the aspects page Then I should see "I am eating a yogurt" within ".stream_element" diff --git a/spec/controllers/jasmine_fixtures/aspects_spec.rb b/spec/controllers/jasmine_fixtures/aspects_spec.rb index 32811ed3c..2dace2747 100644 --- a/spec/controllers/jasmine_fixtures/aspects_spec.rb +++ b/spec/controllers/jasmine_fixtures/aspects_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' -describe PostsController do +describe StreamsController do describe '#aspects' do before do sign_in :user, alice diff --git a/spec/controllers/jasmine_fixtures/stream_spec.rb b/spec/controllers/jasmine_fixtures/streams_spec.rb similarity index 97% rename from spec/controllers/jasmine_fixtures/stream_spec.rb rename to spec/controllers/jasmine_fixtures/streams_spec.rb index fd9fa7d13..95f3ed476 100644 --- a/spec/controllers/jasmine_fixtures/stream_spec.rb +++ b/spec/controllers/jasmine_fixtures/streams_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' -describe PostsController do +describe StreamsController do describe '#multi' do before do sign_in :user, alice diff --git a/spec/controllers/multis_controller_spec.rb b/spec/controllers/multis_controller_spec.rb deleted file mode 100644 index 874b18608..000000000 --- a/spec/controllers/multis_controller_spec.rb +++ /dev/null @@ -1,35 +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 'spec_helper' - -describe MultisController do - describe '#index' do - before do - @old_spotlight_value = AppConfig[:community_spotlight] - sign_in :user, alice - end - - after do - AppConfig[:community_spotlight] = @old_spotlight_value - end - - it 'succeeds' do - AppConfig[:community_spotlight] = [bob.person.diaspora_handle] - get :index - response.should be_success - end - - it 'succeeds without AppConfig[:community_spotlight]' do - AppConfig[:community_spotlight] = nil - get :index - response.should be_success - end - - it 'succeeds on mobile' do - get :index, :format => :mobile - response.should be_success - end - end -end diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb index 42fc96bce..ffe8e6d65 100644 --- a/spec/controllers/posts_controller_spec.rb +++ b/spec/controllers/posts_controller_spec.rb @@ -137,71 +137,4 @@ describe PostsController do StatusMessage.exists?(message.id).should be_true end end - - context 'streams' do - before do - sign_in alice - end - - describe "#public" do - it 'will succeed if admin' do - AppConfig[:admins] = [alice.username] - get :public - response.should be_success - end - - it 'will redirect if not' do - AppConfig[:admins] = [] - get :public - response.should be_redirect - end - end - - describe '#multi' do - before do - @old_spotlight_value = AppConfig[:community_spotlight] - end - - after do - AppConfig[:community_spotlight] = @old_spotlight_value - end - - it 'succeeds' do - AppConfig[:community_spotlight] = [bob.person.diaspora_handle] - get :multi - response.should be_success - end - - it 'succeeds without AppConfig[:community_spotlight]' do - AppConfig[:community_spotlight] = nil - get :multi - response.should be_success - end - - it 'succeeds on mobile' do - get :multi, :format => :mobile - response.should be_success - end - end - - streams = [ - {:path => :liked, :type => Stream::Likes}, - {:path => :mentioned, :type => Stream::Mention}, - {:path => :followed_tags, :type => Stream::FollowedTag} - ] - - streams.each do |s| - describe "##{s[:path]}" do - it 'succeeds' do - get s[:path] - response.should be_success - end - - it 'assigns a stream' do - get s[:path] - assigns[:stream].should be_a s[:type] - end - end - end - end end diff --git a/spec/controllers/streams_controller_spec.rb b/spec/controllers/streams_controller_spec.rb new file mode 100644 index 000000000..6b713e06d --- /dev/null +++ b/spec/controllers/streams_controller_spec.rb @@ -0,0 +1,72 @@ +# 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 'spec_helper' + +describe StreamsController do + before do + sign_in alice + end + + describe "#public" do + it 'will succeed if admin' do + AppConfig[:admins] = [alice.username] + get :public + response.should be_success + end + + it 'will redirect if not' do + AppConfig[:admins] = [] + get :public + response.should be_redirect + end + end + + describe '#multi' do + before do + @old_spotlight_value = AppConfig[:community_spotlight] + end + + after do + AppConfig[:community_spotlight] = @old_spotlight_value + end + + it 'succeeds' do + AppConfig[:community_spotlight] = [bob.person.diaspora_handle] + get :multi + response.should be_success + end + + it 'succeeds without AppConfig[:community_spotlight]' do + AppConfig[:community_spotlight] = nil + get :multi + response.should be_success + end + + it 'succeeds on mobile' do + get :multi, :format => :mobile + response.should be_success + end + end + + streams = [ + {:path => :liked, :type => Stream::Likes}, + {:path => :mentioned, :type => Stream::Mention}, + {:path => :followed_tags, :type => Stream::FollowedTag} + ] + + streams.each do |s| + describe "##{s[:path]}" do + it 'succeeds' do + get s[:path] + response.should be_success + end + + it 'assigns a stream' do + get s[:path] + assigns[:stream].should be_a s[:type] + end + end + end +end diff --git a/spec/controllers/tag_followings_controller_spec.rb b/spec/controllers/tag_followings_controller_spec.rb deleted file mode 100644 index 9717aa9a1..000000000 --- a/spec/controllers/tag_followings_controller_spec.rb +++ /dev/null @@ -1,195 +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 'spec_helper' - -describe TagFollowingsController do - - def valid_attributes - {:name => "partytimeexcellent"} - end - - before do - @tag = ActsAsTaggableOn::Tag.create!(:name => "partytimeexcellent") - sign_in :user, bob - bob.followed_tags.create(:name => "testing") - end - - describe 'index' do - it 'succeeds' do - get :index - response.should be_success - end - - it 'assigns a stream' do - get :index - assigns[:stream].should be_a Stream::FollowedTag - end - - describe 'if empty' do - it 'succeeds' do - bob.followed_tags.delete_all - get :index - response.should be_success - end - - it 'assigns a stream' do - bob.followed_tags.delete_all - get :index - assigns[:stream].should be_a Stream::FollowedTag - end - end - end - - - describe "create" do - describe "successfully" do - it "creates a new TagFollowing" do - expect { - post :create, valid_attributes - response.should be_redirect - }.to change(TagFollowing, :count).by(1) - end - - it "associates the tag following with the currently-signed-in user" do - expect { - post :create, valid_attributes - response.should be_redirect - }.to change(bob.tag_followings, :count).by(1) - end - - it "assigns a newly created tag_following as @tag_following" do - post :create, valid_attributes - response.should be_redirect - assigns(:tag_following).should be_a(TagFollowing) - assigns(:tag_following).should be_persisted - end - - it "creates the tag IFF it doesn't already exist" do - ActsAsTaggableOn::Tag.find_by_name('tomcruisecontrol').should be_nil - expect { - post :create, :name => "tomcruisecontrol" - }.to change(ActsAsTaggableOn::Tag, :count).by(1) - end - - it "flashes success to the tag page" do - post :create, valid_attributes - flash[:notice].should include(valid_attributes[:name]) - end - - it "flashes error if you already have a tag" do - TagFollowing.any_instance.stub(:save).and_return(false) - post :create, valid_attributes - flash[:error].should include(valid_attributes[:name]) - end - - it 'squashes the tag' do - ActsAsTaggableOn::Tag.find_by_name('somestuff').should be_nil - post :create, :name => "some stuff" - assigns[:tag].name.should == "somestuff" - ActsAsTaggableOn::Tag.find_by_name('somestuff').should_not be_nil - end - - it 'downcases the tag name' do - ActsAsTaggableOn::Tag.find_by_name('somestuff').should be_nil - post :create, :name => "SOMESTUFF" - response.should be_redirect - assigns[:tag].name.should == "somestuff" - ActsAsTaggableOn::Tag.find_by_name('somestuff').should_not be_nil - end - - it "normalizes the tag name" do - ActsAsTaggableOn::Tag.find_by_name('foobar').should be_nil - post :create, :name => "foo:bar" - assigns[:tag].name.should == "foobar" - ActsAsTaggableOn::Tag.find_by_name('foobar').should_not be_nil - end - end - - describe 'fails to' do - it "create the tag if it already exists" do - ActsAsTaggableOn::Tag.find_by_name('tomcruisecontrol').should be_nil - expect { - post :create, :name => "tomcruisecontrol" - }.to change(ActsAsTaggableOn::Tag, :count).by(1) - ActsAsTaggableOn::Tag.find_by_name('tomcruisecontrol').should_not be_nil - - expect { - post :create, :name => "tomcruisecontrol" - }.to change(ActsAsTaggableOn::Tag, :count).by(0) - expect { - post :create, :name => "tom cruise control" - }.to change(ActsAsTaggableOn::Tag, :count).by(0) - expect { - post :create, :name => "TomCruiseControl" - }.to change(ActsAsTaggableOn::Tag, :count).by(0) - expect { - post :create, :name => "tom:cruise:control" - }.to change(ActsAsTaggableOn::Tag, :count).by(0) - end - - it "create a tag following for a user other than the currently signed in user" do - expect { - expect { - post :create, valid_attributes.merge(:user_id => alice.id) - }.not_to change(alice.tag_followings, :count).by(1) - }.to change(bob.tag_followings, :count).by(1) - end - end - end - - describe "DELETE destroy" do - before do - TagFollowing.create!(:tag => @tag, :user => bob ) - TagFollowing.create!(:tag => @tag, :user => alice ) - end - - it "destroys the requested tag_following" do - expect { - delete :destroy, valid_attributes - }.to change(TagFollowing, :count).by(-1) - end - - it "redirects and flashes error if you already don't follow the tag" do - delete :destroy, valid_attributes - - response.should redirect_to(tag_path(:name => valid_attributes[:name])) - flash[:notice].should include(valid_attributes[:name]) - end - - it "redirects and flashes error if you already don't follow the tag" do - TagFollowing.any_instance.stub(:destroy).and_return(false) - delete :destroy, valid_attributes - - response.should redirect_to(tag_path(:name => valid_attributes[:name])) - flash[:error].should include(valid_attributes[:name]) - end - end - - describe "#create_multiple" do - it "redirects" do - post :create_multiple, :tags => "#foo,#bar" - response.should be_redirect - end - - it "handles no tags parameter" do - expect { post :create_multiple, :name => 'not tags' }.to_not raise_exception - end - - it "adds multiple tags" do - expect { post :create_multiple, :tags => "#tags,#cats,#bats," }.to change{ bob.followed_tags.count }.by(3) - end - - it "adds non-followed tags" do - TagFollowing.create!(:tag => @tag, :user => bob ) - expect { post :create_multiple, :tags => "#partytimeexcellent,#a,#b," }.to change{ bob.followed_tags.count }.by(2) - end - - it "normalizes the tag names" do - bob.followed_tags.delete_all - post :create_multiple, :tags => "#foo:bar,#bar#foo" - bob.followed_tags(true).map(&:name).should =~ ["foobar", "barfoo"] - end - end -end From fdc0b681ebc8f6ada1c55cb01f4549a269840a08 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Tue, 17 Jan 2012 16:03:24 -0800 Subject: [PATCH 03/35] remove unused api serializers (cruft) --- app/controllers/api/v0/tags_controller.rb | 9 -------- app/controllers/api/v0/users_controller.rb | 13 ----------- app/models/api/v0/serializers/tag.rb | 19 --------------- app/models/api/v0/serializers/user.rb | 20 ---------------- .../api/v0/tags_controller_spec.rb | 20 ---------------- .../api/v0/users_controller_spec.rb | 23 ------------------- 6 files changed, 104 deletions(-) delete mode 100644 app/controllers/api/v0/tags_controller.rb delete mode 100644 app/controllers/api/v0/users_controller.rb delete mode 100644 app/models/api/v0/serializers/tag.rb delete mode 100644 app/models/api/v0/serializers/user.rb delete mode 100644 spec/controllers/api/v0/tags_controller_spec.rb delete mode 100644 spec/controllers/api/v0/users_controller_spec.rb diff --git a/app/controllers/api/v0/tags_controller.rb b/app/controllers/api/v0/tags_controller.rb deleted file mode 100644 index 1ce401b1c..000000000 --- a/app/controllers/api/v0/tags_controller.rb +++ /dev/null @@ -1,9 +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. - -class Api::V0::TagsController < ApplicationController - def show - render :json => Api::V0::Serializers::Tag.new(params[:name]) - end -end diff --git a/app/controllers/api/v0/users_controller.rb b/app/controllers/api/v0/users_controller.rb deleted file mode 100644 index 5328a63c3..000000000 --- a/app/controllers/api/v0/users_controller.rb +++ /dev/null @@ -1,13 +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. - -class Api::V0::UsersController < ApplicationController - def show - if user = User.find_by_username(params[:username]) - render :json => Api::V0::Serializers::User.new(user) - else - head :not_found - end - end -end diff --git a/app/models/api/v0/serializers/tag.rb b/app/models/api/v0/serializers/tag.rb deleted file mode 100644 index bd378607d..000000000 --- a/app/models/api/v0/serializers/tag.rb +++ /dev/null @@ -1,19 +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. - -class Api::V0::Serializers::Tag - - def initialize(tag) - @stream = Stream::Tag.new(nil, tag) - end - - def as_json(opts={}) - { - "name" => @stream.tag_name, - "person_count" => @stream.tagged_people_count, - "followed_count" => @stream.tag_follow_count, - "posts" => [] - } - end -end diff --git a/app/models/api/v0/serializers/user.rb b/app/models/api/v0/serializers/user.rb deleted file mode 100644 index 2dc94fc07..000000000 --- a/app/models/api/v0/serializers/user.rb +++ /dev/null @@ -1,20 +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. - -class Api::V0::Serializers::User - def initialize(user) - @person = user.person - @profile = @person.profile - end - - def as_json(opts={}) - { - "diaspora_id" => @person.diaspora_handle, - "first_name" => @profile.first_name, - "last_name" => @profile.last_name, - "image_url" => @profile.image_url, - "searchable" => @profile.searchable - } - end -end diff --git a/spec/controllers/api/v0/tags_controller_spec.rb b/spec/controllers/api/v0/tags_controller_spec.rb deleted file mode 100644 index 1fd9867a4..000000000 --- a/spec/controllers/api/v0/tags_controller_spec.rb +++ /dev/null @@ -1,20 +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 'spec_helper' - -describe Api::V0::TagsController do - describe '#show' do - it 'succeeds' do - get :show, :name => 'alice' - response.should be_success - end - - it "returns the basic tag data" do - get :show, :name => 'alice' - parsed_json = JSON.parse(response.body) - parsed_json.keys.should =~ %w(name person_count followed_count posts) - end - end -end diff --git a/spec/controllers/api/v0/users_controller_spec.rb b/spec/controllers/api/v0/users_controller_spec.rb deleted file mode 100644 index 1fc3e8e7b..000000000 --- a/spec/controllers/api/v0/users_controller_spec.rb +++ /dev/null @@ -1,23 +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 'spec_helper' - -describe Api::V0::UsersController do - describe '#show' do - it 'succeeds' do - get :show, :username => 'alice' - response.should be_success - end - it "404s if there's no such user" do - get :show, :username => "*****" - response.should be_not_found - end - it "returns the public profile data" do - get :show, :username => 'alice' - parsed_json = JSON.parse(response.body) - parsed_json.keys.should =~ %w( diaspora_id first_name last_name image_url searchable ) - end - end -end From 86c8f9918827fdbe120d90dff186ade195b3f4b8 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Tue, 17 Jan 2012 17:13:24 -0800 Subject: [PATCH 04/35] update the .example, which unfortunatly i think will make travis happier and avoid some loading bs --- config/application.yml.example | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/application.yml.example b/config/application.yml.example index 3a7c99c40..4eadcf13c 100644 --- a/config/application.yml.example +++ b/config/application.yml.example @@ -15,7 +15,7 @@ defaults: &defaults # However changing http to https is okay and has no consquences. If you do change it # you have to start over as it's hardcoded into the database. # For development and testing, you can leave this as is. - pod_url: "http://localhost:3000" + pod_url: "http://localhost:3000/" # Websocket host - leave as 0.0.0.0 unless you know what you are doing socket_host: 0.0.0.0 @@ -239,17 +239,17 @@ production: test: <<: *defaults - pod_url: "http://localhost:9887" + pod_url: "http://localhost:9887/" socket_port: 8081 open_invitations: true serve_static_assets: true integration_1: <<: *defaults - pod_url: "http://localhost:45789" + pod_url: "http://localhost:45789/" serve_static_assets: true integration_2: <<: *defaults - pod_url: "http://localhost:34658" + pod_url: "http://localhost:34658/" serve_static_assets: true From 9cde06a6289e78ba6dd9faee28b6bfed106008ce Mon Sep 17 00:00:00 2001 From: Dennis Collinson Date: Tue, 17 Jan 2012 17:22:44 -0800 Subject: [PATCH 05/35] You can now like "reshares", stream is polymorphic --- public/javascripts/app/collections/stream.js | 5 ++- public/javascripts/app/models/like.js | 3 +- public/javascripts/app/models/post.js | 36 +++++++------------ public/javascripts/app/models/reshare.js | 12 +++++-- .../javascripts/app/models/status_message.js | 4 +-- public/javascripts/app/views/feedback_view.js | 15 ++++---- public/javascripts/app/views/post_view.js | 7 +--- .../app/views/reshare_feedback_view.js | 6 ---- spec/javascripts/app/models/post_spec.js | 32 ----------------- spec/javascripts/app/models/reshare_spec.js | 16 ++++++--- .../app/views/feedback_view_spec.js | 11 ++---- spec/javascripts/app/views/post_view_spec.js | 8 ----- .../app/views/reshare_feedback_view_spec.js | 24 ------------- 13 files changed, 51 insertions(+), 128 deletions(-) delete mode 100644 public/javascripts/app/views/reshare_feedback_view.js delete mode 100644 spec/javascripts/app/views/reshare_feedback_view_spec.js diff --git a/public/javascripts/app/collections/stream.js b/public/javascripts/app/collections/stream.js index 70fe1b5da..b16e137e1 100644 --- a/public/javascripts/app/collections/stream.js +++ b/public/javascripts/app/collections/stream.js @@ -9,7 +9,10 @@ app.collections.Stream = Backbone.Collection.extend({ return path; }, - model: app.models.Post, + model: function(attrs, options) { + var modelClass = app.models[attrs.post_type] || app.models.Post + return new modelClass(attrs, options); + }, parse: function(resp){ return resp.posts; diff --git a/public/javascripts/app/models/like.js b/public/javascripts/app/models/like.js index d18d96685..534317c8a 100644 --- a/public/javascripts/app/models/like.js +++ b/public/javascripts/app/models/like.js @@ -1,2 +1 @@ -app.models.Like = Backbone.Model.extend({ -}) +app.models.Like = Backbone.Model.extend({ }) diff --git a/public/javascripts/app/models/post.js b/public/javascripts/app/models/post.js index f5d707bc4..4cabdaa1b 100644 --- a/public/javascripts/app/models/post.js +++ b/public/javascripts/app/models/post.js @@ -15,14 +15,13 @@ app.models.Post = Backbone.Model.extend({ } }, + reshareUrl : "reshares/", reshare : function(){ - var reshare = new app.models.Reshare(); - reshare.save({root_guid : this.baseGuid()}, { - success : function(){ - app.stream.collection.add(reshare.toJSON()); - } - }); - return reshare; + return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")}); + }, + + reshareAuthor : function(){ + return this.get("author") }, toggleLike : function() { @@ -35,23 +34,16 @@ app.models.Post = Backbone.Model.extend({ }, createdAt : function() { - return +new Date(this.get("created_at")) / 1000; + return new Date(this.get("created_at")) / 1000; }, - baseGuid : function() { - if(this.get("root")){ - return this.get("root").guid; - } else { - return this.get("guid"); - } + + likeUrl : function(){ + return this.url() + "/likes" }, - baseAuthor : function() { - if(this.get("root")){ - return this.get("root").author; - } else { - return this.get("author"); - } + like : function() { + this.set({ user_like : this.likes.create({}, {url : this.likeUrl()}) }); }, unlike : function() { @@ -60,9 +52,5 @@ app.models.Post = Backbone.Model.extend({ likeModel.destroy(); this.set({ user_like : null }); - }, - - like : function() { - this.set({ user_like : this.likes.create() }); } }); diff --git a/public/javascripts/app/models/reshare.js b/public/javascripts/app/models/reshare.js index a88f62538..c1c5105c8 100644 --- a/public/javascripts/app/models/reshare.js +++ b/public/javascripts/app/models/reshare.js @@ -1,8 +1,14 @@ app.models.Reshare = app.models.Post.extend({ - url : function() { return "/reshares"; }, - rootPost : function(){ this._rootPost = this._rootPost || new app.models.Post(this.get("root")) - return this._rootPost + return this._rootPost + }, + + reshare : function(){ + this.rootPost().reshare() + }, + + reshareAuthor : function(){ + return this.rootPost().reshareAuthor() } }); diff --git a/public/javascripts/app/models/status_message.js b/public/javascripts/app/models/status_message.js index fb73daad4..7a2c8120a 100644 --- a/public/javascripts/app/models/status_message.js +++ b/public/javascripts/app/models/status_message.js @@ -1,3 +1 @@ -app.models.StatusMessage = app.models.Post.extend({ - url : function() { return "/status_messages"; } -}); +app.models.StatusMessage = app.models.Post.extend({ }); diff --git a/public/javascripts/app/views/feedback_view.js b/public/javascripts/app/views/feedback_view.js index c45dbdbf8..68dc013a1 100644 --- a/public/javascripts/app/views/feedback_view.js +++ b/public/javascripts/app/views/feedback_view.js @@ -13,14 +13,15 @@ app.views.Feedback = app.views.StreamObject.extend({ this.model.toggleLike(); }, - initialize: function(options){ - this.setupRenderEvents(); - this.reshareablePost = options.model; - }, - resharePost : function(evt){ if(evt) { evt.preventDefault(); } - if(!window.confirm("Reshare " + this.reshareablePost.baseAuthor().name + "'s post?")) { return } - this.reshareablePost.reshare(); + if(!window.confirm("Reshare " + this.model.reshareAuthor().name + "'s post?")) { return } + var reshare = this.model.reshare() + reshare.save({}, { + url: this.model.reshareUrl, + success : function(){ + app.stream.collection.add(reshare); + } + }); } }) diff --git a/public/javascripts/app/views/post_view.js b/public/javascripts/app/views/post_view.js index 0fb51bb57..adb46d6b8 100644 --- a/public/javascripts/app/views/post_view.js +++ b/public/javascripts/app/views/post_view.js @@ -35,12 +35,7 @@ app.views.Post = app.views.StreamObject.extend({ feedbackView : function(){ if(!window.app.user().current_user ) { return null } - var feedbackViewClass = this.resharedContent() ? app.views.ReshareFeedback : app.views.Feedback - return new feedbackViewClass({model : this.model}); - }, - - resharedContent : function(){ - return this.model.get('root') + return new app.views.Feedback({model : this.model}); }, postContentView: function(){ diff --git a/public/javascripts/app/views/reshare_feedback_view.js b/public/javascripts/app/views/reshare_feedback_view.js deleted file mode 100644 index 3c89e5f2d..000000000 --- a/public/javascripts/app/views/reshare_feedback_view.js +++ /dev/null @@ -1,6 +0,0 @@ -app.views.ReshareFeedback = app.views.Feedback.extend({ - initialize : function(){ - this.reshareablePost = (this.model instanceof app.models.Reshare) ? this.model.rootPost() : new app.models.Reshare(this.model.attributes).rootPost(); - this.setupRenderEvents(); - } -}); diff --git a/spec/javascripts/app/models/post_spec.js b/spec/javascripts/app/models/post_spec.js index d0c3c5191..ed5aede9f 100644 --- a/spec/javascripts/app/models/post_spec.js +++ b/spec/javascripts/app/models/post_spec.js @@ -13,22 +13,6 @@ describe("app.models.Post", function() { }); }); - describe("baseGuid", function(){ - it("returns the post's guid if the post does not have a root", function() { - this.post.attributes.root = null; - this.post.attributes.guid = "abcd"; - - expect(this.post.baseGuid()).toBe("abcd") - }) - - it("returns the post's root guid if the post has a root", function() { - this.post.attributes.root = {guid : "1234"} - this.post.attributes.guid = "abcd"; - - expect(this.post.baseGuid()).toBe("1234") - }) - }) - describe("toggleLike", function(){ it("calls unliked when the user_like exists", function(){ this.post.set({user_like : "123"}); @@ -67,20 +51,4 @@ describe("app.models.Post", function() { expect(app.models.Like.prototype.destroy).toHaveBeenCalled(); }) }) - - describe("baseAuthor", function(){ - it("returns the post's guid if the post does not have a root", function() { - this.post.attributes.root = null; - this.post.attributes.author = "abcd"; - - expect(this.post.baseAuthor()).toBe("abcd") - }) - - it("returns the post's root guid if the post has a root", function() { - this.post.attributes.root = {author : "1234"} - this.post.attributes.author = "abcd"; - - expect(this.post.baseAuthor()).toBe("1234") - }) - }) }); diff --git a/spec/javascripts/app/models/reshare_spec.js b/spec/javascripts/app/models/reshare_spec.js index 5181f8f8f..5f61f0ad7 100644 --- a/spec/javascripts/app/models/reshare_spec.js +++ b/spec/javascripts/app/models/reshare_spec.js @@ -1,9 +1,9 @@ describe("app.models.Reshare", function(){ - describe("rootPost", function(){ - beforeEach(function(){ - this.reshare = new app.models.Reshare({root: {a:"namaste", be : "aloha", see : "community"}}) - }); + beforeEach(function(){ + this.reshare = new app.models.Reshare({root: {a:"namaste", be : "aloha", see : "community"}}) + }); + describe("rootPost", function(){ it("should be the root attrs", function(){ expect(this.reshare.rootPost().get("be")).toBe("aloha") }); @@ -16,5 +16,13 @@ describe("app.models.Reshare", function(){ expect(this.reshare.rootPost()).toBe(this.reshare.rootPost()) }); }); + + describe(".reshare", function(){ + it("reshares the root post", function(){ + spyOn(this.reshare.rootPost(), "reshare") + this.reshare.reshare() + expect(this.reshare.rootPost().reshare).toHaveBeenCalled() + }) + }) }); diff --git a/spec/javascripts/app/views/feedback_view_spec.js b/spec/javascripts/app/views/feedback_view_spec.js index 8f060bc54..070b0822c 100644 --- a/spec/javascripts/app/views/feedback_view_spec.js +++ b/spec/javascripts/app/views/feedback_view_spec.js @@ -15,11 +15,6 @@ describe("app.views.Feedback", function(){ this.view = new app.views.Feedback({model: this.post}); }); - describe("initialization", function(){ - it("sets the model as the reshareable post", function(){ - expect(this.view.reshareablePost).toBe(this.post); - }) - }) describe(".render", function(){ beforeEach(function(){ @@ -130,11 +125,11 @@ describe("app.views.Feedback", function(){ expect(window.confirm).toHaveBeenCalled(); }) - it("reshares the reshareablePost", function(){ + it("reshares the model", function(){ spyOn(window, "confirm").andReturn(true); - spyOn(this.view.reshareablePost, "reshare") + spyOn(this.view.model.reshare(), "save") this.view.$(".reshare_action").first().click(); - expect(this.view.reshareablePost.reshare).toHaveBeenCalled(); + expect(this.view.model.reshare().save).toHaveBeenCalled(); }) }) }) diff --git a/spec/javascripts/app/views/post_view_spec.js b/spec/javascripts/app/views/post_view_spec.js index d775005b4..790913afd 100644 --- a/spec/javascripts/app/views/post_view_spec.js +++ b/spec/javascripts/app/views/post_view_spec.js @@ -18,14 +18,6 @@ describe("app.views.Post", function(){ this.reshare = this.collection.models[1]; }) - context("for a reshare", function(){ - it("should display ReshareFeedback", function(){ - spyOn(app.views, "ReshareFeedback").andReturn(stubView("these are special reshare actions")); - var view = new app.views.Post({model : this.reshare}).render(); - expect(view.$(".feedback").text().trim()).toBe("these are special reshare actions"); - }) - }) - it("displays a reshare count", function(){ this.statusMessage.set({reshares_count : 2}) var view = new app.views.Post({model : this.statusMessage}).render(); diff --git a/spec/javascripts/app/views/reshare_feedback_view_spec.js b/spec/javascripts/app/views/reshare_feedback_view_spec.js deleted file mode 100644 index 5bcbc0fb2..000000000 --- a/spec/javascripts/app/views/reshare_feedback_view_spec.js +++ /dev/null @@ -1,24 +0,0 @@ -describe("app.views.ReshareFeedback", function(){ - beforeEach(function(){ - var posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"]; - this.reshare = new app.models.Reshare(_.extend(posts[1], {public : true})); - this.view = new app.views.ReshareFeedback({model : this.reshare }).render() - }) - - it("inherits from feedback view", function(){ - expect(this.view instanceof app.views.Feedback).toBeTruthy() - }) - - it("sets Up the root Post as the reshareable post", function(){ - expect(this.view.reshareablePost).toBe(this.reshare.rootPost()) - }) - - it("reshares the rootPost", function(){ - spyOn(window, "confirm").andReturn(true); - spyOn(this.reshare.rootPost(), "reshare") - console.log(this.view.el) - this.view.$(".reshare_action").first().click(); - expect(this.reshare.rootPost().reshare).toHaveBeenCalled(); - }) - -}) From 30947778f9915f4f0536d799ef4314edc70ef1e4 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Tue, 17 Jan 2012 17:33:55 -0800 Subject: [PATCH 06/35] remove stray api feature --- features/api.feature | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 features/api.feature diff --git a/features/api.feature b/features/api.feature deleted file mode 100644 index 423b425ee..000000000 --- a/features/api.feature +++ /dev/null @@ -1,11 +0,0 @@ -Feature: API - In order to use a client application - as an epic developer - I need to get user's info - - Scenario: Getting a users public profile - Given a user named "Maxwell S" with email "maxwell@example.com" - And I send and accept JSON - When I send a GET request for "/api/v0/users/maxwell_s" - Then the response status should be "200" - And the JSON response should have "first_name" with the text "Maxwell" From b09e76a0ceae15d44312c8d35b6686bc55c0bd37 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Tue, 17 Jan 2012 17:34:42 -0800 Subject: [PATCH 07/35] introduce base_pod_uri, so we can support domains that use www and [bare] with webfinger --- app/helpers/application_helper.rb | 4 ++++ app/models/app_config.rb | 4 ++++ app/models/user.rb | 8 ++++++-- app/views/invitations/edit.html.haml | 2 +- app/views/publics/host_meta.erb | 2 +- app/views/registrations/new.html.haml | 2 +- app/views/registrations/new.mobile.haml | 2 +- spec/factories.rb | 2 +- spec/models/app_config_spec.rb | 8 ++++++++ spec/models/person_spec.rb | 8 ++++++++ spec/models/user_spec.rb | 2 +- 11 files changed, 36 insertions(+), 8 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 21752935c..d0f12da91 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -32,6 +32,10 @@ module ApplicationHelper without_close_html + link_to(image_tag('deletelabel.png'), "#", :class => 'close') end + def diaspora_id_host + User.diaspora_id_host + end + def jquery_include_tag javascript_include_tag('//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js') + content_tag(:script) do diff --git a/app/models/app_config.rb b/app/models/app_config.rb index 12e266bac..40866429a 100644 --- a/app/models/app_config.rb +++ b/app/models/app_config.rb @@ -103,6 +103,10 @@ HELP end end + def self.bare_pod_uri + self[:pod_uri].authority.gsub('www.', '') + end + def self.normalize_admins self[:admins] ||= [] self[:admins].collect! { |username| username.downcase } diff --git a/app/models/user.rb b/app/models/user.rb index 7c91f29bd..49e681187 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -377,10 +377,14 @@ class User < ActiveRecord::Base def set_person(person) person.url = AppConfig[:pod_url] - person.diaspora_handle = "#{self.username}@#{AppConfig[:pod_uri].authority}" + person.diaspora_handle = "#{self.username}#{User.diaspora_id_host}" self.person = person end + def self.diaspora_id_host + "@#{AppConfig.bare_pod_uri}" + end + def seed_aspects self.aspects.create(:name => I18n.t('aspects.seed.family')) self.aspects.create(:name => I18n.t('aspects.seed.friends')) @@ -476,7 +480,7 @@ class User < ActiveRecord::Base end def no_person_with_same_username - diaspora_id = "#{self.username}@#{AppConfig[:pod_uri].host}" + diaspora_id = "#{self.username}#{User.diaspora_id_host}" if self.username_changed? && Person.exists?(:diaspora_handle => diaspora_id) errors[:base] << 'That username has already been taken' end diff --git a/app/views/invitations/edit.html.haml b/app/views/invitations/edit.html.haml index ca4047ff3..e208b613f 100644 --- a/app/views/invitations/edit.html.haml +++ b/app/views/invitations/edit.html.haml @@ -27,7 +27,7 @@ = t('username') = f.text_field :username, :title => t('registrations.new.enter_username') %span.host_uri - = "@#{AppConfig[:pod_uri].host}" + = diaspora_id_host .clearfix %b = t('email') diff --git a/app/views/publics/host_meta.erb b/app/views/publics/host_meta.erb index fa8cd9879..bc7b16d4c 100644 --- a/app/views/publics/host_meta.erb +++ b/app/views/publics/host_meta.erb @@ -1,7 +1,7 @@ - <%= AppConfig[:pod_uri].authority %> + <%= AppConfig[:pod_bare_domain] %> Resource Descriptor diff --git a/app/views/registrations/new.html.haml b/app/views/registrations/new.html.haml index 012aa79be..b4a27188e 100644 --- a/app/views/registrations/new.html.haml +++ b/app/views/registrations/new.html.haml @@ -28,7 +28,7 @@ = t('username') = f.text_field :username, :title => t('registrations.new.enter_username') %span.host_uri - = "@#{AppConfig[:pod_uri].host}" + = diaspora_id_host .clearfix %b = t('email') diff --git a/app/views/registrations/new.mobile.haml b/app/views/registrations/new.mobile.haml index 17f0d5f5a..60b23c1f4 100644 --- a/app/views/registrations/new.mobile.haml +++ b/app/views/registrations/new.mobile.haml @@ -16,7 +16,7 @@ .centered = f.text_field :username %span.host_uri - = "@#{AppConfig[:pod_uri].host}" + = diaspora_id_host .row .row = f.label :email, t('email') diff --git a/spec/factories.rb b/spec/factories.rb index 284d1e67a..1a64e2b1c 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -66,7 +66,7 @@ Factory.define :user do |u| user.person = Factory.build(:person, :profile => Factory.build(:profile), :owner_id => user.id, :serialized_public_key => user.encryption_key.public_key.export, - :diaspora_handle => "#{user.username}@#{AppConfig[:pod_url].gsub(/(https?:|www\.)\/\//, '').chop!}") + :diaspora_handle => "#{user.username}#{User.diaspora_id_host}") end u.after_create do |user| user.person.save diff --git a/spec/models/app_config_spec.rb b/spec/models/app_config_spec.rb index 7ba7180ba..56e03df95 100644 --- a/spec/models/app_config_spec.rb +++ b/spec/models/app_config_spec.rb @@ -142,6 +142,14 @@ describe AppConfig do AppConfig.normalize_pod_url AppConfig[:pod_url].should == "https://example.org/" end + + end + + describe '.bare_pod_uri' do + it 'is AppConfig[:pod_uri].authority stripping www.' do + AppConfig[:pod_url] = "https://www.example.org/" + AppConfig.bare_pod_uri.should == 'example.org' + end end describe ".pod_uri" do diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index f37f80c51..dc3c835b8 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -132,6 +132,14 @@ describe Person do new_person = User.build(:username => "foo123", :email => "foo123@example.com", :password => "password", :password_confirmation => "password").person new_person.diaspora_handle.should == "foo123@#{AppConfig[:pod_uri].authority}" end + + it 'does not include www if it is set in app config' do + old_url = AppConfig[:pod_url] + AppConfig[:pod_url] = 'https://www.foobar.com/' + new_person = User.build(:username => "foo123", :email => "foo123@example.com", :password => "password", :password_confirmation => "password").person + new_person.diaspora_handle.should == "foo123@foobar.com" + AppConfig[:pod_url] = old_url + end end context 'remote people' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c2b513d19..a18974173 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -111,7 +111,7 @@ describe User do end it 'requires uniqueness also amount Person objects with diaspora handle' do - p = Factory(:person, :diaspora_handle => "jimmy@#{AppConfig[:pod_uri].host}") + p = Factory(:person, :diaspora_handle => "jimmy#{User.diaspora_id_host}") alice.username = 'jimmy' alice.should_not be_valid From 641ca9fdd2deede13fb525140ee80695e213eb91 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Tue, 17 Jan 2012 17:39:12 -0800 Subject: [PATCH 08/35] we want to POST to /status_messages on Publisher submit --- app/controllers/application_controller.rb | 2 +- public/javascripts/app/views/publisher_view.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3afefd3c2..cce1e7772 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -128,6 +128,6 @@ class ApplicationController < ActionController::Base end def max_time - params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now + params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now + 1 end end diff --git a/public/javascripts/app/views/publisher_view.js b/public/javascripts/app/views/publisher_view.js index 2315b8c3d..989d2ce9a 100644 --- a/public/javascripts/app/views/publisher_view.js +++ b/public/javascripts/app/views/publisher_view.js @@ -31,6 +31,7 @@ app.views.Publisher = Backbone.View.extend({ "photos" : serializedForm["photos[]"], "services" : serializedForm["services[]"] }, { + url : "/status_messages", success : function() { app.stream.collection.add(statusMessage.toJSON()); } From 880efd3e72c9ac06b0f26502cdaa91ec363b6ce1 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Tue, 17 Jan 2012 17:53:02 -0800 Subject: [PATCH 09/35] use '/reshare' instead of 'reshare/' to ensure the correct path (js) --- public/javascripts/app/models/post.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/javascripts/app/models/post.js b/public/javascripts/app/models/post.js index 4cabdaa1b..b9641156d 100644 --- a/public/javascripts/app/models/post.js +++ b/public/javascripts/app/models/post.js @@ -15,7 +15,7 @@ app.models.Post = Backbone.Model.extend({ } }, - reshareUrl : "reshares/", + reshareUrl : "/reshares", reshare : function(){ return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")}); }, From a658552c3fbf8bddd8bcfa1bf5d67c06b58edc83 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Tue, 17 Jan 2012 19:21:36 -0800 Subject: [PATCH 10/35] fix stream helper for mobile --- app/helpers/stream_helper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/helpers/stream_helper.rb b/app/helpers/stream_helper.rb index f18654525..10a6e27b0 100644 --- a/app/helpers/stream_helper.rb +++ b/app/helpers/stream_helper.rb @@ -12,6 +12,8 @@ module StreamHelper local_or_remote_person_path(@person, :max_time => time_for_scroll(@stream)) elsif controller.instance_of?(PostsController) public_stream_path(:max_time => time_for_scroll(@stream)) + elsif controller.instance_of?(StreamsController) + multi_stream_path(:max_time => time_for_scroll(@stream)) else raise 'in order to use pagination for this new controller, update next_page_path in stream helper' end From 254860bddc1f68f96430019f96d1b94e92977572 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Sat, 7 Jan 2012 17:52:35 -0800 Subject: [PATCH 11/35] SM MS; Read email sent to diaspora-dev for more information about this commit. Add migration and rake task to copy hidden information from share_visibilities to users. see: http://devblog.joindiaspora.com/?p=44 --- .../share_visibilities_controller.rb | 31 ++------ app/models/notification.rb | 18 ++--- app/models/post.rb | 27 +++++-- app/models/user.rb | 52 ++++++++++++++ ...0942_move_recently_hidden_posts_to_user.rb | 28 ++++++++ db/schema.rb | 1 + lib/diaspora/redis_cache.rb | 12 ++++ lib/share_visibility_converter.rb | 24 +++++++ lib/tasks/db.rake | 11 ++- lib/tasks/migrations.rake | 7 ++ .../share_visibilities_controller_spec.rb | 62 ++-------------- spec/factories.rb | 1 + spec/lib/diaspora/redis_cache_spec.rb | 26 +++++++ spec/models/notification_spec.rb | 12 ---- spec/models/post_spec.rb | 22 ++++++ spec/models/user_spec.rb | 71 +++++++++++++++++++ 16 files changed, 291 insertions(+), 114 deletions(-) create mode 100644 db/migrate/20120107220942_move_recently_hidden_posts_to_user.rb create mode 100644 lib/share_visibility_converter.rb diff --git a/app/controllers/share_visibilities_controller.rb b/app/controllers/share_visibilities_controller.rb index 1c6cb9a8e..49c7ead7c 100644 --- a/app/controllers/share_visibilities_controller.rb +++ b/app/controllers/share_visibilities_controller.rb @@ -11,37 +11,14 @@ class ShareVisibilitiesController < ApplicationController params[:shareable_id] ||= params[:post_id] params[:shareable_type] ||= 'Post' - @post = accessible_post - @contact = current_user.contact_for(@post.author) - - if @contact && @vis = ShareVisibility.where(:contact_id => @contact.id, - :shareable_id => params[:shareable_id], - :shareable_type => params[:shareable_type]).first - @vis.hidden = !@vis.hidden - if @vis.save - update_cache(@vis) - render :nothing => true, :status => 200 - return - end - end - render :nothing => true, :status => 403 + vis = current_user.toggle_hidden_shareable(accessible_post) + RedisCache.update_cache_for(current_user, accessible_post, vis) + render :nothing => true, :status => 200 end protected - def update_cache(visibility) - return unless RedisCache.configured? - - cache = RedisCache.new(current_user, 'created_at') - - if visibility.hidden? - cache.remove(accessible_post.id) - else - cache.add(accessible_post.created_at.to_i, accessible_post.id) - end - end - def accessible_post - @post ||= Post.where(:id => params[:post_id]).select("id, guid, author_id, created_at").first + @post ||= params[:shareable_type].constantize.where(:id => params[:post_id]).select("id, guid, author_id, created_at").first end end diff --git a/app/models/notification.rb b/app/models/notification.rb index 547899379..a15711c31 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -22,6 +22,7 @@ class Notification < ActiveRecord::Base else n = note_type.make_notification(recipient, target, actor, note_type) end + if n n.email_the_user(target, actor) n @@ -43,7 +44,8 @@ class Notification < ActiveRecord::Base private def self.concatenate_or_create(recipient, target, actor, notification_type) - return nil if share_visiblity_is_hidden?(recipient, target) + return nil if suppress_notification?(recipient, target) + if n = notification_type.where(:target_id => target.id, :target_type => target.class.base_class, :recipient_id => recipient.id, @@ -64,22 +66,16 @@ private def self.make_notification(recipient, target, actor, notification_type) - return nil if share_visiblity_is_hidden?(recipient, target) + return nil if suppress_notification?(recipient, target) n = notification_type.new(:target => target, - :recipient_id => recipient.id) + :recipient_id => recipient.id) n.actors = n.actors | [actor] n.unread = false if target.is_a? Request n.save! n end - #horrible hack that should not be here! - def self.share_visiblity_is_hidden?(recipient, post) - return false unless post.is_a?(Post) - - contact = recipient.contact_for(post.author) - return false unless contact && recipient && post - pv = ShareVisibility.where(:contact_id => contact.id, :shareable_id => post.id, :shareable_type => post.class.base_class.to_s).first - pv.present? ? pv.hidden? : false + def self.suppress_notification?(recipient, post) + post.is_a?(Post) && recipient.is_shareable_hidden?(post) end end diff --git a/app/models/post.rb b/app/models/post.rb index 4e066b635..dc656e672 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -71,27 +71,40 @@ class Post < ActiveRecord::Base end def self.excluding_blocks(user) - people = user.blocks.includes(:person).map{|b| b.person} + people = user.blocks.map{|b| b.person_id} + scope = scoped - if people.present? - where("posts.author_id NOT IN (?)", people.map { |person| person.id }) - else - scoped + if people.any? + scope = scope.where("posts.author_id NOT IN (?)", people) end + + scope + end + + def self.excluding_hidden_shareables(user) + scope = scoped + if user.has_hidden_shareables_of_type? + scope = scope.where('posts.id NOT IN (?)', user.hidden_shareables["#{self.base_class}"]) + end + scope + end + + def self.excluding_hidden_content(user) + excluding_blocks(user).excluding_hidden_shareables(user) 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 = scope.excluding_hidden_content(user) if user.present? scope end ############# - def self.diaspora_initialize params + def self.diaspora_initialize(params) new_post = self.new params.to_hash new_post.author = params[:author] new_post.public = params[:public] if params[:public] diff --git a/app/models/user.rb b/app/models/user.rb index 49e681187..3ba7864fc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,6 +30,8 @@ class User < ActiveRecord::Base validates_associated :person validate :no_person_with_same_username + 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 @@ -99,6 +101,56 @@ class User < ActiveRecord::Base end end + def hidden_shareables + self[:hidden_shareables] ||= {} + end + + def add_hidden_shareable(key, share_id, opts={}) + if self.hidden_shareables.has_key?(key) + self.hidden_shareables[key] << share_id + else + self.hidden_shareables[key] = [share_id] + end + self.save unless opts[:batch] + self.hidden_shareables + end + + def remove_hidden_shareable(key, share_id) + if self.hidden_shareables.has_key?(key) + self.hidden_shareables[key].delete(share_id) + end + end + + def is_shareable_hidden?(shareable) + shareable_type = shareable.class.base_class.name + if self.hidden_shareables.has_key?(shareable_type) + self.hidden_shareables[shareable_type].include?(shareable.id.to_s) + else + false + end + end + + + def toggle_hidden_shareable(share) + share_id = share.id.to_s + key = share.class.base_class.to_s + if self.hidden_shareables.has_key?(key) && self.hidden_shareables[key].include?(share_id) + self.remove_hidden_shareable(key, share_id) + self.save + false + else + self.add_hidden_shareable(key, share_id) + self.save + true + end + end + + def has_hidden_shareables_of_type?(t = Post) + share_type = t.base_class.to_s + self.hidden_shareables[share_type].present? + end + + def self.create_from_invitation!(invitation) user = User.new user.generate_keys diff --git a/db/migrate/20120107220942_move_recently_hidden_posts_to_user.rb b/db/migrate/20120107220942_move_recently_hidden_posts_to_user.rb new file mode 100644 index 000000000..bac3a2e78 --- /dev/null +++ b/db/migrate/20120107220942_move_recently_hidden_posts_to_user.rb @@ -0,0 +1,28 @@ +class Person < ActiveRecord::Base + belongs_to :owner, :class_name => 'User' +end + +class User < ActiveRecord::Base + serialize :hidden_shareables, Hash +end + +class Contact < ActiveRecord::Base + belongs_to :user +end + +class ShareVisibility < ActiveRecord::Base + belongs_to :contact +end + +require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'share_visibility_converter') + +class MoveRecentlyHiddenPostsToUser < ActiveRecord::Migration + def self.up + add_column :users, :hidden_shareables, :text + ShareVisibilityConverter.copy_hidden_share_visibilities_to_users(true) + end + + def self.down + remove_column :users, :hidden_shareables + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index f41d0de14..62ec26489 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -463,6 +463,7 @@ ActiveRecord::Schema.define(:version => 20120114191018) do t.boolean "show_community_spotlight_in_stream", :default => true, :null => false t.boolean "auto_follow_back", :default => false t.integer "auto_follow_back_aspect_id" + t.text "hidden_shareables" end add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true diff --git a/lib/diaspora/redis_cache.rb b/lib/diaspora/redis_cache.rb index 8f5ceb672..636c90e9d 100644 --- a/lib/diaspora/redis_cache.rb +++ b/lib/diaspora/redis_cache.rb @@ -19,6 +19,18 @@ class RedisCache AppConfig[:redis_cache].present? end + def self.update_cache_for(user, post, post_was_hidden) + return unless RedisCache.configured? + + cache = RedisCache.new(user, 'created_at') + + if post_was_hidden + cache.remove(post.id) + else + cache.add(post.created_at.to_i, post.id) + end + end + # @return [Boolean] def cache_exists? self.redis.exists(set_key) diff --git a/lib/share_visibility_converter.rb b/lib/share_visibility_converter.rb new file mode 100644 index 000000000..c8f6dff30 --- /dev/null +++ b/lib/share_visibility_converter.rb @@ -0,0 +1,24 @@ +class ShareVisibilityConverter + RECENT = 2 # number of weeks to do in the migration + def self.copy_hidden_share_visibilities_to_users(only_recent = false) + query = ShareVisibility.where(:hidden => true).includes(:contact => :user) + query = query.where('share_visibilities.updated_at > ?', RECENT.weeks.ago) if only_recent + count = query.count + puts "Updating #{count} records in batches of 1000..." + + batch_count = 1 + query.find_in_batches do |visibilities| + puts "Updating batch ##{batch_count} of #{(count/1000)+1}..." + batch_count += 1 + visibilities.each do |visibility| + type = visibility.shareable_type + id = visibility.shareable_id.to_s + u = visibility.contact.user + u.hidden_shareables ||= {} + u.hidden_shareables[type] ||= [] + u.hidden_shareables[type] << id unless u.hidden_shareables[type].include?(id) + u.save!(:validate => false) + end + end + end +end \ No newline at end of file diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 15fd9fda2..9f9e069c9 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -4,7 +4,16 @@ namespace :db do desc "rebuild and prepare test db" - task :rebuild => [:drop, :drop_integration, :create, :migrate, :seed, 'db:test:prepare'] + task :rebuild do + Rake::Task['db:drop'].invoke + Rake::Task['db:drop_integration'].invoke + Rake::Task['db:create'].invoke + Rake::Task['db:migrate'].invoke + puts "seeding users, this will take awhile" + `rake db:seed` #ghetto hax as we have active record garbage in our models + puts "seeded!" + Rake::Task['db:test:prepare'].invoke + end namespace :integration do # desc 'Check for pending migrations and load the integration schema' diff --git a/lib/tasks/migrations.rake b/lib/tasks/migrations.rake index 4cd77c89f..ab445085d 100644 --- a/lib/tasks/migrations.rake +++ b/lib/tasks/migrations.rake @@ -3,6 +3,13 @@ # the COPYRIGHT file. namespace :migrations do + + desc 'copy all hidden share visibilities from share_visibilities to users. Can be run with the site still up.' + task :copy_hidden_share_visibilities_to_users => [:environment] do + require File.join(Rails.root, 'lib', 'share_visibility_converter') + ShareVisibilityConverter.copy_hidden_share_visibilities_to_users + end + desc 'absolutify all existing image references' task :absolutify_image_references do require File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment') diff --git a/spec/controllers/share_visibilities_controller_spec.rb b/spec/controllers/share_visibilities_controller_spec.rb index a7634c37a..b22535e21 100644 --- a/spec/controllers/share_visibilities_controller_spec.rb +++ b/spec/controllers/share_visibilities_controller_spec.rb @@ -7,7 +7,6 @@ require 'spec_helper' describe ShareVisibilitiesController do before do @status = alice.post(:status_message, :text => "hello", :to => alice.aspects.first) - @vis = @status.share_visibilities.first sign_in :user, bob end @@ -23,72 +22,23 @@ describe ShareVisibilitiesController do end it 'calls #update_cache' do - @controller.should_receive(:update_cache).with(an_instance_of(ShareVisibility)) + RedisCache.should_receive(:update_cache_for).with(an_instance_of(User), an_instance_of(Post), true) put :update, :format => :js, :id => 42, :post_id => @status.id end - it 'marks hidden if visible' do + it 'it calls toggle_hidden_shareable' do + @controller.current_user.should_receive(:toggle_hidden_shareable).with(an_instance_of(Post)) put :update, :format => :js, :id => 42, :post_id => @status.id - @vis.reload.hidden.should be_true - end - - it 'marks visible if hidden' do - @vis.update_attributes(:hidden => true) - - put :update, :format => :js, :id => 42, :post_id => @status.id - @vis.reload.hidden.should be_false - end - end - - context "post you do not see" do - before do - sign_in :user, eve - end - - it 'does not let a user destroy a visibility that is not theirs' do - lambda { - put :update, :format => :js, :id => 42, :post_id => @status.id - }.should_not change(@vis.reload, :hidden).to(true) - end - - it 'does not succeed' do - put :update, :format => :js, :id => 42, :post_id => @status.id - response.should_not be_success end end end - - describe '#update_cache' do - before do - @controller.params[:post_id] = @status.id - @cache = RedisCache.new(bob, 'created_at') - RedisCache.stub(:new).and_return(@cache) - RedisCache.stub(:configured?).and_return(true) - end - - it 'does nothing if cache is not configured' do - RedisCache.stub(:configured?).and_return(false) - RedisCache.should_not_receive(:new) - @controller.send(:update_cache, @vis) - end - - it 'removes the post from the cache if visibility is marked as hidden' do - @vis.hidden = true - @cache.should_receive(:remove).with(@vis.shareable_id) - @controller.send(:update_cache, @vis) - end - - it 'adds the post from the cache if visibility is marked as hidden' do - @vis.hidden = false - @cache.should_receive(:add).with(@status.created_at.to_i, @vis.shareable_id) - @controller.send(:update_cache, @vis) - end - end - + describe "#accessible_post" do it "memoizes a query for a post given a post_id param" do id = 1 @controller.params[:post_id] = id + @controller.params[:shareable_type] = 'Post' + Post.should_receive(:where).with(hash_including(:id => id)).once.and_return(stub.as_null_object) 2.times do |n| @controller.send(:accessible_post) diff --git a/spec/factories.rb b/spec/factories.rb index 1a64e2b1c..e2cba1be7 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -100,6 +100,7 @@ end Factory.define(:photo) do |p| p.sequence(:random_string) {|n| ActiveSupport::SecureRandom.hex(10) } + p.association :author, :factory => :person p.after_build do |p| p.unprocessed_image.store! File.open(File.join(File.dirname(__FILE__), 'fixtures', 'button.png')) p.update_remote_path diff --git a/spec/lib/diaspora/redis_cache_spec.rb b/spec/lib/diaspora/redis_cache_spec.rb index 27dd9d6dd..da56a2354 100644 --- a/spec/lib/diaspora/redis_cache_spec.rb +++ b/spec/lib/diaspora/redis_cache_spec.rb @@ -220,4 +220,30 @@ describe RedisCache do RedisCache.acceptable_types.should =~ Stream::Base::TYPES_OF_POST_IN_STREAM end end + + describe '#update_cache' do + before do + @cache = RedisCache.new(bob, 'created_at') + RedisCache.stub(:new).and_return(@cache) + RedisCache.stub(:configured?).and_return(true) + @post = Factory(:status_message) + end + + it 'does nothing if cache is not configured' do + RedisCache.stub(:configured?).and_return(false) + RedisCache.should_not_receive(:new) + RedisCache.update_cache_for(bob, @post, true) + end + + it 'removes the post from the cache if visibility is marked as hidden' do + @cache.should_receive(:remove).with(@post.id) + RedisCache.update_cache_for(bob, @post, true) + end + + it 'adds the post from the cache if visibility is unmarked as hidden' do + @cache.should_receive(:add).with(@post.created_at.to_i, @post.id) + RedisCache.update_cache_for(bob, @post, false) + end + end + end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index a619bb7ef..b6b973124 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -50,18 +50,6 @@ describe Notification do end end describe '.notify' do - it 'does not call Notification.create if the object does not have a notification_type' do - Notification.should_not_receive(:make_notificatin) - Notification.notify(@user, @sm, @person) - end - - it 'does not create a notification if the post visibility is hidden' do - Notification.stub(:share_visiblity_is_hidden).and_return(true) - expect{ - Notification.notify(@user, @sm, @person) - }.to change(Notification, :count).by(0) - end - context 'with a request' do before do @request = Request.diaspora_initialize(:from => @user.person, :to => @user2.person, :into => @aspect) diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index 4d6a2fdcc..a93e7d7d6 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -87,6 +87,28 @@ describe Post do end end + describe '.excluding_hidden_shareables' do + before do + @post = Factory(:status_message, :author => alice.person) + @other_post = Factory(:status_message, :author => eve.person) + bob.toggle_hidden_shareable(@post) + end + it 'excludes posts the user has hidden' do + Post.excluding_hidden_shareables(bob).should_not include(@post) + end + it 'includes posts the user has not hidden' do + Post.excluding_hidden_shareables(bob).should include(@other_post) + end + end + + describe '.excluding_hidden_content' do + it 'calls excluding_blocks and excluding_hidden_shareables' do + Post.should_receive(:excluding_blocks).and_return(Post) + Post.should_receive(:excluding_hidden_shareables) + Post.excluding_hidden_content(bob) + end + end + context 'having some posts' do before do time_interval = 1000 diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a18974173..e0a3633c6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -58,6 +58,76 @@ describe User do end end + describe 'hidden_shareables' do + before do + @sm = Factory(:status_message) + @sm_id = @sm.id.to_s + @sm_class = @sm.class.base_class.to_s + end + + it 'is a hash' do + alice.hidden_shareables.should == {} + end + + describe '#add_hidden_shareable' do + it 'adds the share id to an array which is keyed by the objects class' do + alice.add_hidden_shareable(@sm_class, @sm_id) + alice.hidden_shareables['Post'].should == [@sm_id] + end + + it 'handles having multiple posts' do + sm2 = Factory(:status_message) + alice.add_hidden_shareable(@sm_class, @sm_id) + alice.add_hidden_shareable(sm2.class.base_class.to_s, sm2.id.to_s) + + alice.hidden_shareables['Post'].should =~ [@sm_id, sm2.id.to_s] + end + + it 'handles having multiple shareable types' do + photo = Factory(:photo) + alice.add_hidden_shareable(photo.class.base_class.to_s, photo.id.to_s) + alice.add_hidden_shareable(@sm_class, @sm_id) + + alice.hidden_shareables['Photo'].should == [photo.id.to_s] + end + end + + describe '#remove_hidden_shareable' do + it 'removes the id from the hash if it is there' do + alice.add_hidden_shareable(@sm_class, @sm_id) + alice.remove_hidden_shareable(@sm_class, @sm_id) + alice.hidden_shareables['Post'].should == [] + end + end + + describe 'toggle_hidden_shareable' do + it 'calls add_hidden_shareable if the key does not exist, and returns true' do + alice.should_receive(:add_hidden_shareable).with(@sm_class, @sm_id) + alice.toggle_hidden_shareable(@sm).should be_true + end + + it 'calls remove_hidden_shareable if the key exists' do + alice.should_receive(:remove_hidden_shareable).with(@sm_class, @sm_id) + alice.add_hidden_shareable(@sm_class, @sm_id) + alice.toggle_hidden_shareable(@sm).should be_false + end + end + + describe '#is_shareable_hidden?' do + it 'returns true if the shareable is hidden' do + post = Factory(:status_message) + bob.toggle_hidden_shareable(post) + bob.is_shareable_hidden?(post).should be_true + end + + it 'returns false if the shareable is not present' do + post = Factory(:status_message) + bob.is_shareable_hidden?(post).should be_false + end + end + end + + describe 'overwriting people' do it 'does not overwrite old users with factory' do lambda { @@ -1037,6 +1107,7 @@ describe User do current_sign_in_at last_sign_in_at current_sign_in_ip + hidden_shareables last_sign_in_ip invitation_service invitation_identifier From 22bd70664f5742a6c154f3ae4ec29e829101e7b4 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Tue, 17 Jan 2012 21:12:47 -0800 Subject: [PATCH 12/35] fix post spec --- spec/models/post_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index a93e7d7d6..7d17c437a 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -60,9 +60,8 @@ describe Post do 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) + Post.should_receive(:excluding_blocks).with(alice).and_return(Post) + Post.for_a_stream(stub, stub, alice) end end From bfde0514bfd426718e81adb4ac2269441a010be6 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Tue, 17 Jan 2012 21:43:46 -0800 Subject: [PATCH 13/35] fix webfinger specs --- spec/lib/webfinger_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/lib/webfinger_spec.rb b/spec/lib/webfinger_spec.rb index 87e7b74be..b11df3cb7 100644 --- a/spec/lib/webfinger_spec.rb +++ b/spec/lib/webfinger_spec.rb @@ -7,7 +7,7 @@ require 'spec_helper' require File.join(Rails.root, 'lib/webfinger') describe Webfinger do - let(:host_with_port) { "#{AppConfig.pod_uri.host}:#{AppConfig.pod_uri.port}" } + let(:host_with_port) { AppConfig.bare_pod_uri } let(:user1) { alice } let(:user2) { eve } @@ -45,7 +45,7 @@ describe Webfinger do describe '#webfinger_profile_url' do it 'parses out the webfinger template' do finger.send(:webfinger_profile_url, diaspora_xrd).should == - "http://#{host_with_port}/webfinger?q=foo@tom.joindiaspora.com" + "http://#{AppConfig[:pod_uri].authority}/webfinger?q=foo@tom.joindiaspora.com" end it 'should return nil if not an xrd' do From 392e317962101c436f40e5b891440a7044901888 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Tue, 17 Jan 2012 22:10:03 -0800 Subject: [PATCH 14/35] fix person spec --- spec/models/person_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index dc3c835b8..ee2043ff2 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -130,7 +130,7 @@ describe Person do context 'local people' do it 'uses the pod config url to set the diaspora_handle' do new_person = User.build(:username => "foo123", :email => "foo123@example.com", :password => "password", :password_confirmation => "password").person - new_person.diaspora_handle.should == "foo123@#{AppConfig[:pod_uri].authority}" + new_person.diaspora_handle.should == "foo123#{User.diaspora_id_host}" end it 'does not include www if it is set in app config' do From 38ad76d9c7dbdc55ce3766af1346f2018f17a883 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Wed, 18 Jan 2012 01:21:28 -0800 Subject: [PATCH 15/35] rewrite webfinger client and specs; now this is much easier to maintain. --- lib/webfinger.rb | 156 +++++++++----------- spec/lib/webfinger_spec.rb | 290 +++++++++++++++++++++++-------------- 2 files changed, 253 insertions(+), 193 deletions(-) diff --git a/lib/webfinger.rb b/lib/webfinger.rb index 975557b40..83c3df20d 100644 --- a/lib/webfinger.rb +++ b/lib/webfinger.rb @@ -2,126 +2,110 @@ require File.join(Rails.root, 'lib/hcard') require File.join(Rails.root, 'lib/webfinger_profile') class Webfinger - class WebfingerFailedError < RuntimeError; end + attr_accessor :host_meta_xrd, :webfinger_profile_xrd, + :webfinger_profile, :hcard, :hcard_xrd, :person, + :account, :ssl + def initialize(account) - @account = account.strip.gsub('acct:','').to_s.downcase - @ssl = true + self.account = account + self.ssl = true Rails.logger.info("event=webfinger status=initialized target=#{account}") end + + def fetch + return person if existing_person_with_profile? + create_or_update_person_from_webfinger_profile! + end + def self.in_background(account, opts={}) Resque.enqueue(Jobs::FetchWebfinger, account) end - def fetch - begin - person = Person.by_account_identifier(@account) - if person - if person.profile - Rails.logger.info("event=webfinger status=success route=local target=#{@account}") - return person - end - end + #everything below should be private I guess + def account=(str) + @account = str.strip.gsub('acct:','').to_s.downcase + end - profile_url = get_xrd - webfinger_profile = get_webfinger_profile(profile_url) - if person - person.assign_new_profile_from_hcard(get_hcard(webfinger_profile)) - fingered_person = person - else - fingered_person = make_person_from_webfinger(webfinger_profile) - end - - if fingered_person - Rails.logger.info("event=webfinger status=success route=remote target=#{@account}") - fingered_person - else - Rails.logger.info("event=webfinger status=failure route=remote target=#{@account}") - raise WebfingerFailedError.new(@account) - end + def get(url) + Rails.logger.info("Getting: #{url} for #{account}") + begin + Faraday.get(url).body rescue Exception => e - Rails.logger.info("event=receive status=abort recipient=#{@account} reason='#{e.message}'") - nil + Rails.logger.info("Failed to fetch: #{url} for #{account}; #{e.message}") + raise e end end - private - def get_xrd - begin - http = Faraday.get xrd_url + def existing_person_with_profile? + cached_person.present? && cached_person.profile.present? + end - profile_url = webfinger_profile_url(http.body) - if profile_url - return profile_url - else - raise "no profile URL" - end + def cached_person + self.person ||= Person.by_account_identifier(account) + end + + def create_or_update_person_from_webfinger_profile! + if person #update my profile please + person.assign_new_profile_from_hcard(self.hcard) + else + person = make_person_from_webfinger + end + Rails.logger.info("event=webfinger status=success route=remote target=#{@account}") + person + end + + #this tries the xrl url with https first, then falls back to http + def host_meta_xrd + begin + get(host_meta_url) rescue Exception => e - if @ssl - @ssl = false + if self.ssl + self.ssl = false retry else - raise e - raise I18n.t('webfinger.xrd_fetch_failed', :account => @account) + raise I18n.t('webfinger.xrd_fetch_failed', :account => account) end end end - def get_webfinger_profile(profile_url) - begin - http = Faraday.get(profile_url) + def hcard + @hcard ||= HCard.build(hcard_xrd) + end - rescue - raise I18n.t('webfinger.fetch_failed', :profile_url => profile_url) - end - return http.body + def webfinger_profile + @webfinger_profile ||= WebfingerProfile.new(account, webfinger_profile_xrd) end def hcard_url - @wf_profile.hcard + self.webfinger_profile.hcard end - def get_hcard(webfinger_profile) - unless webfinger_profile.strip == "" - - @wf_profile = WebfingerProfile.new(@account, webfinger_profile) - - begin - hcard = Faraday.get(hcard_url) - rescue - return I18n.t('webfinger.hcard_fetch_failed', :account => @account) - end - - HCard.build hcard.body - else - nil - end - end - - def make_person_from_webfinger(webfinger_profile) - card = get_hcard(webfinger_profile) - if card && @wf_profile - Person.create_from_webfinger(@wf_profile, card) - end - end - - - ##helpers - private - - def webfinger_profile_url(xrd_response) - doc = Nokogiri::XML::Document.parse(xrd_response) + def webfinger_profile_url + doc = Nokogiri::XML::Document.parse(self.host_meta_xrd) return nil if doc.namespaces["xmlns"] != "http://docs.oasis-open.org/ns/xri/xrd-1.0" swizzle doc.at('Link[rel=lrdd]').attribute('template').value end - def xrd_url - domain = @account.split('@')[1] - "http#{'s' if @ssl}://#{domain}/.well-known/host-meta" + def webfinger_profile_xrd + @webfinger_profile_xrd ||= get(webfinger_profile_url) + end + + def hcard_xrd + @hcard_xrd ||= get(hcard_url) + end + + def make_person_from_webfinger + Person.create_from_webfinger(webfinger_profile, hcard) + end + + def host_meta_url + domain = account.split('@')[1] + "http#{'s' if self.ssl}://#{domain}/.well-known/host-meta" end def swizzle(template) - template.gsub '{uri}', @account + template.gsub('{uri}', account) end end diff --git a/spec/lib/webfinger_spec.rb b/spec/lib/webfinger_spec.rb index b11df3cb7..f82ed53fa 100644 --- a/spec/lib/webfinger_spec.rb +++ b/spec/lib/webfinger_spec.rb @@ -4,125 +4,201 @@ require 'spec_helper' -require File.join(Rails.root, 'lib/webfinger') - describe Webfinger do - let(:host_with_port) { AppConfig.bare_pod_uri } - let(:user1) { alice } - let(:user2) { eve } - - let(:account) { "foo@tom.joindiaspora.com" } - let(:person) { Factory(:person, :diaspora_handle => account) } - let(:finger) { Webfinger.new(account) } - - let(:good_request) { FakeHttpRequest.new(:success) } - - let(:diaspora_xrd) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'host-meta.fixture.html')).read } - let(:diaspora_finger) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'webfinger.fixture.html')).read } + let(:host_meta_xrd) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'host-meta.fixture.html')).read } + let(:webfinger_xrd) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'webfinger.fixture.html')).read } let(:hcard_xml) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'hcard.fixture.html')).read } + let(:account){'foo@bar.com'} + let(:account_in_fixtures){"alice@localhost:9887"} + let(:finger){Webfinger.new(account)} + let(:host_meta_url){"http://#{AppConfig[:pod_uri].authority}/webfinger?q="} - context 'setup' do - - describe '#intialize' do - it 'sets account ' do - n = Webfinger.new("mbs348@gmail.com") - n.instance_variable_get(:@account).should_not be nil - end - - it 'downcases account' do - account = "BIGBOY@Example.Org" - n = Webfinger.new(account) - n.instance_variable_get(:@account).should == account.downcase - end - - it 'should set ssl as the default' do - foo = Webfinger.new(account) - foo.instance_variable_get(:@ssl).should be true - end + describe '#intialize' do + it 'sets account ' do + n = Webfinger.new("mbs348@gmail.com") + n.account.should_not be nil end - context 'webfinger query chain processing' do - describe '#webfinger_profile_url' do - it 'parses out the webfinger template' do - finger.send(:webfinger_profile_url, diaspora_xrd).should == - "http://#{AppConfig[:pod_uri].authority}/webfinger?q=foo@tom.joindiaspora.com" - end - - it 'should return nil if not an xrd' do - finger.send(:webfinger_profile_url, '').should be nil - end - end - - describe '#xrd_url' do - it 'should return canonical host-meta url for http' do - finger.instance_variable_set(:@ssl, false) - finger.send(:xrd_url).should == "http://tom.joindiaspora.com/.well-known/host-meta" - end - - it 'can return the https version' do - finger.send(:xrd_url).should == "https://tom.joindiaspora.com/.well-known/host-meta" - end - end + it "downcases account and strips whitespace, and gsub 'acct:'" do + n = Webfinger.new("acct:BIGBOY@Example.Org ") + n.account.should == 'bigboy@example.org' end - describe '#get_xrd' do - it 'follows redirects' do - redirect_url = "http://whereami.whatisthis/host-meta" - stub_request(:get, "https://tom.joindiaspora.com/.well-known/host-meta"). - to_return(:status => 302, :headers => { 'Location' => redirect_url }) - stub_request(:get, redirect_url). - to_return(:status => 200, :body => diaspora_xrd) - begin - finger.send :get_xrd - rescue; end - a_request(:get, redirect_url).should have_been_made - end + it 'should set ssl as the default' do + foo = Webfinger.new(account) + foo.ssl.should be true end + end - - context 'webfingering local people' do - it 'should return a person from the database if it matches its handle' do - person.save - finger.fetch.id.should == person.id - end + describe '.in_background' do + it 'enqueues a Jobs::FetchWebfinger job' do + Resque.should_receive(:enqueue).with(Jobs::FetchWebfinger, account) + Webfinger.in_background(account) end - it 'should fetch a diaspora webfinger and make a person for them' do - User.delete_all; Person.delete_all; Profile.delete_all - hcard_url = "http://google-1655890.com/hcard/users/29a9d5ae5169ab0b" - - f = Webfinger.new("alice@#{host_with_port}") - stub_request(:get, f.send(:xrd_url)). - to_return(:status => 200, :body => diaspora_xrd, :headers => {}) - stub_request(:get, f.send(:webfinger_profile_url, diaspora_xrd)). - to_return(:status => 200, :body => diaspora_finger, :headers => {}) - f.should_receive(:hcard_url).and_return(hcard_url) - - stub_request(:get, hcard_url). - to_return(:status => 200, :body => hcard_xml, :headers => {}) - - person = f.fetch - - WebMock.should have_requested(:get, f.send(:xrd_url)) - WebMock.should have_requested(:get, f.send(:webfinger_profile_url, diaspora_xrd)) - WebMock.should have_requested(:get, hcard_url) + end + + describe '#fetch' do + it 'works' do + finger = Webfinger.new(account_in_fixtures) + finger.stub(:host_meta_xrd).and_return(host_meta_xrd) + finger.stub(:hcard_xrd).and_return(hcard_xml) + finger.stub(:webfinger_profile_xrd).and_return(webfinger_xrd) + person = finger.fetch person.should be_valid - end - - it 'should retry with http if https fails' do - f = Webfinger.new("tom@tom.joindiaspora.com") - xrd_url = "://tom.joindiaspora.com/.well-known/host-meta" - - stub_request(:get, "https#{xrd_url}"). - to_return(:status => 503, :body => "", :headers => {}) - stub_request(:get, "http#{xrd_url}"). - to_return(:status => 200, :body => diaspora_xrd, :headers => {}) - - #Faraday::Connection.any_instance.should_receive(:get).twice.and_return(nil, diaspora_xrd) - f.send(:get_xrd) - WebMock.should have_requested(:get,"https#{xrd_url}") - WebMock.should have_requested(:get,"http#{xrd_url}") - f.instance_variable_get(:@ssl).should == false + person.should be_a Person end end + + describe '#get' do + it 'makes a request and grabs the body' do + url ="https://bar.com/.well-known/host-meta" + stub_request(:get, url). + to_return(:status => 200, :body => host_meta_xrd) + + finger.get(url).should == host_meta_xrd + end + + it 'follows redirects' do + redirect_url = "http://whereami.whatisthis/host-meta" + + stub_request(:get, "https://bar.com/.well-known/host-meta"). + to_return(:status => 302, :headers => { 'Location' => redirect_url }) + + stub_request(:get, redirect_url). + to_return(:status => 200, :body => host_meta_xrd) + + finger.host_meta_xrd + + a_request(:get, redirect_url).should have_been_made + end + end + + describe 'existing_person_with_profile?' do + it 'returns true if cached_person is present and has a profile' do + finger.should_receive(:cached_person).twice.and_return(Factory(:person)) + finger.existing_person_with_profile?.should be_true + end + + it 'returns false if it has no person' do + finger.stub(:cached_person).and_return false + finger.existing_person_with_profile?.should be_false + end + + it 'returns false if the person has no profile' do + p = Factory(:person) + p.profile = nil + finger.stub(:cached_person).and_return(p) + finger.existing_person_with_profile?.should be_false + end + end + + describe 'cached_person' do + it 'sets the person by looking up the account from Person.by_account_identifier' do + person = stub + Person.should_receive(:by_account_identifier).with(account).and_return(person) + finger.cached_person.should == person + finger.person.should == person + end + end + + + describe 'create_or_update_person_from_webfinger_profile!' do + context 'with a cached_person' do + it 'calls Person#assign_new_profile_from_hcard with the fetched hcard' do + finger.hcard_xrd = hcard_xml + finger.stub(:person).and_return(bob.person) + bob.person.should_receive(:assign_new_profile_from_hcard).with(finger.hcard) + finger.create_or_update_person_from_webfinger_profile! + end + end + + context 'with no cached person' do + it 'sets person based on make_person_from_webfinger' do + finger.stub(:person).and_return(nil) + finger.should_receive(:make_person_from_webfinger) + finger.create_or_update_person_from_webfinger_profile! + end + end + end + + describe '#host_meta_xrd' do + it 'calls #get with host_meta_url' do + finger.stub(:host_meta_url).and_return('meta') + finger.should_receive(:get).with('meta') + finger.host_meta_xrd + end + + it 'should retry with ssl off a second time' do + finger.should_receive(:get).and_raise + finger.should_receive(:get) + finger.host_meta_xrd + finger.ssl.should be false + end + end + + describe '#hcard' do + it 'calls HCard.build' do + finger.stub(:hcard_xrd).and_return(hcard_xml) + HCard.should_receive(:build).with(hcard_xml).and_return true + finger.hcard.should_not be_nil + end + end + + describe '#webfinger_profile' do + it 'constructs a new WebfingerProfile object' do + finger.stub(:webfinger_profile_xrd).and_return(webfinger_xrd) + WebfingerProfile.should_receive(:new).with(account, webfinger_xrd) + finger.webfinger_profile + end + end + + describe '#webfinger_profile_url' do + it 'returns the llrd link for a valid host meta' do + finger.stub(:host_meta_xrd).and_return(host_meta_xrd) + finger.webfinger_profile_url.should_not be_nil + end + + it 'returns nil if no link is found' do + finger.stub(:host_meta_xrd).and_return(nil) + finger.webfinger_profile_url.should be_nil + end + end + + describe '#webfinger_profile_xrd' do + it 'calls #get with the hcard_url' do + finger.stub(:hcard_url).and_return("url") + finger.should_receive(:get).with("url") + finger.hcard_xrd + end + end + + describe '#make_person_from_webfinger' do + it 'with an hcard and a webfinger_profile, it calls Person.create_from_webfinger' do + finger.stub(:hcard).and_return("hcard") + finger.stub(:webfinger_profile).and_return("webfinger_profile") + Person.should_receive(:create_from_webfinger).with("webfinger_profile", "hcard") + finger.make_person_from_webfinger + end + end + + + + describe '#host_meta_url' do + it 'should return canonical host-meta url for http' do + finger.ssl = false + finger.host_meta_url.should == "http://bar.com/.well-known/host-meta" + end + + it 'can return the https version' do + finger.host_meta_url.should == "https://bar.com/.well-known/host-meta" + end + end + + describe 'swizzle' do + it 'gsubs out {uri} for the account' do + string = "{uri} is the coolest" + finger.swizzle(string).should == "#{finger.account} is the coolest" + end + end end From 0edb06eef7ba54224232b82a46cd69641c76d170 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Wed, 18 Jan 2012 09:29:00 -0800 Subject: [PATCH 16/35] fix for the migration for some linux users, which the AR stubs were not carring over from the migration file to the ShareVisibilityConverter --- lib/share_visibility_converter.rb | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/share_visibility_converter.rb b/lib/share_visibility_converter.rb index c8f6dff30..b8b0e7aa1 100644 --- a/lib/share_visibility_converter.rb +++ b/lib/share_visibility_converter.rb @@ -1,3 +1,28 @@ +#we dont have the enviroment, and it is not carring over from the migration +unless defined?(Person) + class Person < ActiveRecord::Base + belongs_to :owner, :class_name => 'User' + end +end + +unless defined?(User) + class User < ActiveRecord::Base + serialize :hidden_shareables, Hash + end +end + +unless defined?(Contact) + class Contact < ActiveRecord::Base + belongs_to :user + end +end + +unless defined?(ShareVisibility) + class ShareVisibility < ActiveRecord::Base + belongs_to :contact + end +end + class ShareVisibilityConverter RECENT = 2 # number of weeks to do in the migration def self.copy_hidden_share_visibilities_to_users(only_recent = false) @@ -21,4 +46,4 @@ class ShareVisibilityConverter end end end -end \ No newline at end of file +end From 0a40cdf28830811cde63f1a9b59eff98372c9ae6 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Wed, 18 Jan 2012 11:48:23 -0800 Subject: [PATCH 17/35] MS DG make share_visibility_converter really defensive :( --- lib/share_visibility_converter.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/share_visibility_converter.rb b/lib/share_visibility_converter.rb index b8b0e7aa1..6847c7b47 100644 --- a/lib/share_visibility_converter.rb +++ b/lib/share_visibility_converter.rb @@ -36,13 +36,17 @@ class ShareVisibilityConverter puts "Updating batch ##{batch_count} of #{(count/1000)+1}..." batch_count += 1 visibilities.each do |visibility| - type = visibility.shareable_type - id = visibility.shareable_id.to_s - u = visibility.contact.user - u.hidden_shareables ||= {} - u.hidden_shareables[type] ||= [] - u.hidden_shareables[type] << id unless u.hidden_shareables[type].include?(id) - u.save!(:validate => false) + begin + type = visibility.shareable_type + id = visibility.shareable_id.to_s + u = visibility.contact.user + u.hidden_shareables ||= {} + u.hidden_shareables[type] ||= [] + u.hidden_shareables[type] << id unless u.hidden_shareables[type].include?(id) + u.save!(:validate => false) + rescue Exception =>e + puts "ERROR: #{e.message} skipping pv with id: #{visibility.id}" + end end end end From c82ac5f3e218e976535cc10abb8e7655fdc4405e Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Wed, 18 Jan 2012 12:40:14 -0800 Subject: [PATCH 18/35] fix collapsing of posts [ci skip] --- app/views/templates/comment.jst | 4 +++- app/views/templates/status_message.jst | 7 ++++--- public/javascripts/app/views/stream_object_view.js | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/views/templates/comment.jst b/app/views/templates/comment.jst index e42f601a7..7397726dd 100644 --- a/app/views/templates/comment.jst +++ b/app/views/templates/comment.jst @@ -18,7 +18,9 @@ - <%= text %> +
+ <%= text %> +