Merge branch 'master' of git://github.com/diaspora/diaspora into input-placeholders
This commit is contained in:
commit
ad5a17776f
113 changed files with 1199 additions and 1507 deletions
6
Gemfile
6
Gemfile
|
|
@ -32,6 +32,7 @@ group :production do # we don't install these on travis to speed up test runs
|
|||
gem 'newrelic_rpm'
|
||||
gem 'rack-google-analytics', :require => 'rack/google-analytics'
|
||||
gem 'rack-piwik', :require => 'rack/piwik'
|
||||
gem 'rack-ssl', :require => 'rack/ssl'
|
||||
end
|
||||
|
||||
# configuration
|
||||
|
|
@ -116,7 +117,7 @@ gem 'jasmine', '~> 1.1.2'
|
|||
|
||||
group :test do
|
||||
gem 'capybara', '~> 1.1.2'
|
||||
gem 'cucumber-rails', '1.2.1'
|
||||
gem 'cucumber-rails', '1.2.1', :require => false
|
||||
gem 'cucumber-api-steps', '0.6', :require => false
|
||||
gem 'database_cleaner', '0.7.1'
|
||||
gem 'diaspora-client', :git => 'git://github.com/diaspora/diaspora-client.git'
|
||||
|
|
@ -149,4 +150,7 @@ group :development do
|
|||
gem 'ruby-debug19', :platforms => :ruby_19
|
||||
gem 'ruby-debug', :platforms => :mri_18
|
||||
gem 'yard', :require => false
|
||||
|
||||
# speed up development requests (already pulled into rails 3.2)
|
||||
gem 'active_reload'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ GEM
|
|||
rack-mount (~> 0.6.14)
|
||||
rack-test (~> 0.5.7)
|
||||
tzinfo (~> 0.3.23)
|
||||
active_reload (0.6.1)
|
||||
activemodel (3.0.11)
|
||||
activesupport (= 3.0.11)
|
||||
builder (~> 2.1.2)
|
||||
|
|
@ -147,7 +148,7 @@ GEM
|
|||
abstract (>= 1.0.0)
|
||||
eventmachine (0.12.10)
|
||||
excon (0.9.4)
|
||||
factory_girl (2.4.0)
|
||||
factory_girl (2.4.2)
|
||||
activesupport
|
||||
factory_girl_rails (1.5.0)
|
||||
factory_girl (~> 2.4.0)
|
||||
|
|
@ -292,6 +293,8 @@ GEM
|
|||
rack-mount (0.6.14)
|
||||
rack (>= 1.0.0)
|
||||
rack-piwik (0.1.2)
|
||||
rack-ssl (1.3.2)
|
||||
rack
|
||||
rack-test (0.5.7)
|
||||
rack (>= 1.0)
|
||||
rails (3.0.11)
|
||||
|
|
@ -416,6 +419,7 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
SystemTimer (= 1.2.3)
|
||||
active_reload
|
||||
activerecord-import
|
||||
acts-as-taggable-on!
|
||||
acts_as_api
|
||||
|
|
@ -471,6 +475,7 @@ DEPENDENCIES
|
|||
pg
|
||||
rack-google-analytics
|
||||
rack-piwik
|
||||
rack-ssl
|
||||
rails (= 3.0.11)
|
||||
rails-i18n
|
||||
redcarpet (= 2.0.1)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -127,23 +127,7 @@ 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
|
||||
params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now + 1
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@
|
|||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require File.join(Rails.root, 'lib', 'stream', 'public')
|
||||
|
||||
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
|
||||
|
||||
respond_to :html,
|
||||
:mobile,
|
||||
|
|
@ -54,7 +51,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 +59,12 @@ class PostsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def index
|
||||
default_stream_action(Stream::Public)
|
||||
end
|
||||
private
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
71
app/controllers/streams_controller.rb
Normal file
71
app/controllers/streams_controller.rb
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -10,25 +10,21 @@ 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))
|
||||
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
|
||||
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 +32,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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ class Person < ActiveRecord::Base
|
|||
|
||||
has_many :mentions, :dependent => :destroy
|
||||
|
||||
before_destroy :remove_all_traces
|
||||
before_validation :clean_url
|
||||
|
||||
validates :url, :presence => true
|
||||
|
|
@ -322,10 +321,6 @@ class Person < ActiveRecord::Base
|
|||
end
|
||||
|
||||
private
|
||||
def remove_all_traces
|
||||
Notification.joins(:notification_actors).where(:notification_actors => {:person_id => self.id}).all.each{ |n| n.destroy}
|
||||
end
|
||||
|
||||
def fix_profile
|
||||
Webfinger.new(self.diaspora_handle).fetch
|
||||
self.reload
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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,55 @@ 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
|
||||
|
|
@ -114,7 +165,6 @@ class User < ActiveRecord::Base
|
|||
Resque.enqueue(Jobs::ResetPassword, self.id)
|
||||
end
|
||||
|
||||
|
||||
def update_user_preferences(pref_hash)
|
||||
if self.disable_mail
|
||||
UserPreference::VALID_EMAIL_TYPES.each{|x| self.user_preferences.find_or_create_by_email_type(x)}
|
||||
|
|
@ -377,10 +427,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'))
|
||||
|
|
@ -394,7 +448,6 @@ class User < ActiveRecord::Base
|
|||
aq
|
||||
end
|
||||
|
||||
|
||||
def encryption_key
|
||||
OpenSSL::PKey::RSA.new(serialized_private_key)
|
||||
end
|
||||
|
|
@ -403,32 +456,6 @@ class User < ActiveRecord::Base
|
|||
AppConfig[:admins].present? && AppConfig[:admins].include?(self.username)
|
||||
end
|
||||
|
||||
def remove_all_traces
|
||||
disconnect_everyone
|
||||
remove_mentions
|
||||
remove_person
|
||||
end
|
||||
|
||||
def remove_person
|
||||
self.person.destroy
|
||||
end
|
||||
|
||||
def disconnect_everyone
|
||||
self.contacts.each do |contact|
|
||||
if contact.person.remote?
|
||||
self.disconnect(contact)
|
||||
else
|
||||
contact.person.owner.disconnected_by(self.person)
|
||||
remove_contact(contact, :force => true)
|
||||
end
|
||||
end
|
||||
self.aspects.destroy_all
|
||||
end
|
||||
|
||||
def remove_mentions
|
||||
Mention.where( :person_id => self.person.id).delete_all
|
||||
end
|
||||
|
||||
def guard_unconfirmed_email
|
||||
self.unconfirmed_email = nil if unconfirmed_email.blank? || unconfirmed_email == email
|
||||
|
||||
|
|
@ -445,7 +472,6 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
# Generate public/private keys for User and associated Person
|
||||
def generate_keys
|
||||
key_size = (Rails.env == 'test' ? 512 : 4096)
|
||||
|
|
@ -476,7 +502,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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
18
app/views/layouts/main_stream.mobile.haml
Normal file
18
app/views/layouts/main_stream.mobile.haml
Normal file
|
|
@ -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")
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'
|
||||
xmlns:hm='http://host-meta.net/xrd/1.0'>
|
||||
<hm:Host><%= AppConfig[:pod_uri].authority %></hm:Host>
|
||||
<hm:Host><%= AppConfig[:pod_bare_domain] %></hm:Host>
|
||||
<Link rel='lrdd'
|
||||
template='<%= AppConfig[:pod_url] %>webfinger?q={uri}'>
|
||||
<Title>Resource Descriptor</Title>
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
</a>
|
||||
</span>
|
||||
|
||||
<%= text %>
|
||||
<div class="collapsible">
|
||||
<%= text %>
|
||||
</div>
|
||||
|
||||
<div class="comment_info">
|
||||
<time class="timeago" datetime="<%= created_at %>"/>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<%= text %>
|
||||
|
||||
<%= o_embed_html %>
|
||||
<div class="collapsible">
|
||||
<%= text %>
|
||||
<%= o_embed_html %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -15,30 +15,38 @@ 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"
|
||||
|
||||
# Websocket host - leave as 0.0.0.0 unless you know what you are doing
|
||||
socket_host: 0.0.0.0
|
||||
|
||||
# Websocket port - should normally be 8080 or 8081.
|
||||
socket_port: 8080
|
||||
pod_url: "http://localhost:3000/"
|
||||
|
||||
# Setting the root certificate bundle (this is operating system specific). Examples, uncomment one:
|
||||
ca_file: '/etc/pki/tls/certs/ca-bundle.crt' # CentOS
|
||||
#ca_file: '/etc/ssl/certs/ca-certificates.crt' # Debian
|
||||
#ca_file: '/etc/ssl/certs/ca-certificates.crt' # Gentoo
|
||||
|
||||
# Secure websocket confguration (wss://).
|
||||
# Requires SSL cert and key
|
||||
socket_secure: false
|
||||
socket_cert_chain_location: '/full/path/to/cert_chain.crt'
|
||||
socket_private_key_location: '/full/path/to/file.key'
|
||||
|
||||
|
||||
# URL for a remote redis, on the default port. Don't forget to restrict IP access!
|
||||
# leave it empty for the default (localhost)
|
||||
redis_url: ''
|
||||
|
||||
# Redis cache
|
||||
|
||||
# Enable the cache layer (Redis)
|
||||
# If you expect to have thousands of users on your pod,
|
||||
# we *highly* suggest you enable this.
|
||||
# IMPORTANT: THE CACHE REQUIRES REDIS 2.4 OR LATER.
|
||||
#
|
||||
# By default, the cache layer will piggyback off of the Redis
|
||||
# database used by your Resque workers.
|
||||
redis_cache: false
|
||||
|
||||
# The location of your redis cache.
|
||||
# IMPORTANT: DO NOT CHANGE THIS IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||
#
|
||||
# Leave this blank to use the same Redis database
|
||||
# that your Resque workers use (happy path).
|
||||
#
|
||||
# This takes an ip (or DNS record). It assumes that your Redis database
|
||||
# is running on the default Redis port.
|
||||
redis_location: ''
|
||||
|
||||
# Amazon S3 for photos
|
||||
|
||||
# s3 config - if set, carrierwave will store your photos on s3. Otherwise they're on the filesystem.
|
||||
|
|
@ -90,9 +98,6 @@ defaults: &defaults
|
|||
# Enable extensive logging to log/{development,test,production}.log
|
||||
debug: false
|
||||
|
||||
# Enable extensive logging to websocket server.
|
||||
socket_debug : false
|
||||
|
||||
# Hoptoad api key, send failures to Hoptoad
|
||||
hoptoad_api_key: ''
|
||||
|
||||
|
|
@ -105,6 +110,7 @@ defaults: &defaults
|
|||
|
||||
tumblr_consumer_key: ''
|
||||
tumblr_consumer_secret: ''
|
||||
|
||||
# Miscellaneous
|
||||
|
||||
NEW_RELIC_LICENSE_KEY: ''
|
||||
|
|
@ -116,12 +122,6 @@ defaults: &defaults
|
|||
# will be disabled.
|
||||
single_process_mode: false
|
||||
|
||||
# File containing pid of running script/websocket_server.rb
|
||||
socket_pidfile: "log/diaspora-wsd.pid"
|
||||
|
||||
# Do not touch unless you know what you're doing
|
||||
socket_collection_name: 'websocket'
|
||||
|
||||
# Diaspora is only tested against this default pubsub server. You probably don't want to change this.
|
||||
pubsub_server: 'https://pubsubhubbub.appspot.com/'
|
||||
|
||||
|
|
@ -175,27 +175,10 @@ defaults: &defaults
|
|||
# Sender address in Diaspora's outgoing mail.
|
||||
smtp_sender_address: 'no-reply@joindiaspora.com'
|
||||
|
||||
# Redis cache
|
||||
|
||||
# Enable the cache layer (Redis)
|
||||
# If you expect to have thousands of users on your pod,
|
||||
# we *highly* suggest you enable this.
|
||||
# IMPORTANT: THE CACHE REQUIRES REDIS 2.4 OR LATER.
|
||||
#
|
||||
# By default, the cache layer will piggyback off of the Redis
|
||||
# database used by your Resque workers.
|
||||
redis_cache: false
|
||||
|
||||
# The location of your redis cache.
|
||||
# IMPORTANT: DO NOT CHANGE THIS IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||
#
|
||||
# Leave this blank to use the same Redis database
|
||||
# that your Resque workers use (happy path).
|
||||
#
|
||||
# This takes an ip (or DNS record). It assumes that your Redis database
|
||||
# is running on the default Redis port.
|
||||
redis_location: ''
|
||||
|
||||
#when set, your pod will not force you to use https in production
|
||||
#NOTE: not all features of Diaspora work without SSL, and you may have trouble federating
|
||||
# with other pods
|
||||
circumvent_ssl_requirement: false
|
||||
|
||||
# Web tracking
|
||||
|
||||
|
|
@ -216,12 +199,6 @@ defaults: &defaults
|
|||
cloudfiles_db_container: 'Database Backup'
|
||||
cloudfiles_images_container: 'Image Backup'
|
||||
|
||||
# Donations
|
||||
|
||||
# Leave this blank to not show the request for donations
|
||||
# Use paypal for recurring donations
|
||||
paypal_hosted_button_id: ""
|
||||
|
||||
#
|
||||
# Use this section to override default settings in specific environments
|
||||
#
|
||||
|
|
@ -239,17 +216,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
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ Diaspora::Application.configure do
|
|||
# In production, Apache or nginx will already do this
|
||||
config.serve_static_assets = false
|
||||
|
||||
|
||||
# Enable serving of images, stylesheets, and javascripts from an asset server
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
|
||||
|
|
|
|||
4
config/initializers/enforce_ssl.rb
Normal file
4
config/initializers/enforce_ssl.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
if EnviromentConfiguration.enforce_ssl?
|
||||
Rails.application.config.middleware.insert_before HoptoadNotifier::UserInformer, Rack::SSL
|
||||
puts "Rack::SSL is enabled"
|
||||
end
|
||||
|
|
@ -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" => "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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
module EnviromentConfiguration
|
||||
ARRAY_SEPERATOR = '%|%'
|
||||
|
||||
def self.heroku?
|
||||
ENV['HEROKU']
|
||||
end
|
||||
|
|
@ -29,6 +29,13 @@ module EnviromentConfiguration
|
|||
end
|
||||
end
|
||||
|
||||
def self.enforce_ssl?
|
||||
return false unless Rails.env == 'production'
|
||||
return false if ENV['NO_SSL']
|
||||
return false if AppConfig[:circumvent_ssl_requirement].present?
|
||||
true
|
||||
end
|
||||
|
||||
def self.ca_cert_file_location
|
||||
if self.heroku?
|
||||
"/usr/lib/ssl/certs/ca-certificates.crt"
|
||||
|
|
|
|||
53
lib/share_visibility_converter.rb
Normal file
53
lib/share_visibility_converter.rb
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#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)
|
||||
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|
|
||||
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
|
||||
end
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
156
lib/webfinger.rb
156
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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
app.collections.Comments = Backbone.Collection.extend({
|
||||
model: app.models.Comment
|
||||
model: app.models.Comment,
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/comments" //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
app.collections.Likes = Backbone.Collection.extend({
|
||||
model: app.models.Like
|
||||
model: app.models.Like,
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/likes" //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
}
|
||||
});
|
||||
|
|
|
|||
16
public/javascripts/app/collections/posts.js
Normal file
16
public/javascripts/app/collections/posts.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
app.collections.Posts = Backbone.Collection.extend({
|
||||
url : "/posts",
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
comparator : function(post) {
|
||||
return -post.createdAt();
|
||||
}
|
||||
});
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
app.collections.Stream = Backbone.Collection.extend({
|
||||
url: function() {
|
||||
var path = document.location.pathname;
|
||||
|
||||
if(this.models.length) {
|
||||
path += "?max_time=" + _.last(this.models).createdAt();
|
||||
}
|
||||
|
||||
return path;
|
||||
},
|
||||
|
||||
model: app.models.Post,
|
||||
|
||||
parse: function(resp){
|
||||
return resp.posts;
|
||||
},
|
||||
|
||||
comparator : function(post) {
|
||||
return -post.createdAt();
|
||||
}
|
||||
});
|
||||
|
|
@ -1,2 +1 @@
|
|||
app.models.Like = Backbone.Model.extend({
|
||||
})
|
||||
app.models.Like = Backbone.Model.extend({ })
|
||||
|
|
|
|||
|
|
@ -1,28 +1,22 @@
|
|||
app.models.Post = Backbone.Model.extend({
|
||||
urlRoot : "/posts",
|
||||
initialize : function() {
|
||||
this.comments = new app.collections.Comments(this.get("last_three_comments"));
|
||||
this.comments.url = this.url() + '/comments';
|
||||
|
||||
this.likes = new app.collections.Likes(this.get("user_like")); // load in the user like initially
|
||||
this.likes.url = this.url() + '/likes';
|
||||
this.comments = new app.collections.Comments(this.get("last_three_comments"), {post : this});
|
||||
this.likes = new app.collections.Likes(this.get("user_like"), { post : this}); // load in the user like initially
|
||||
},
|
||||
|
||||
url : function() {
|
||||
if(this.id) {
|
||||
return "/posts/" + this.id;
|
||||
} else {
|
||||
return "/posts"
|
||||
}
|
||||
createdAt : function() {
|
||||
return new Date(this.get("created_at")) / 1000;
|
||||
},
|
||||
|
||||
createReshareUrl : "/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() {
|
||||
|
|
@ -34,24 +28,8 @@ app.models.Post = Backbone.Model.extend({
|
|||
}
|
||||
},
|
||||
|
||||
createdAt : function() {
|
||||
return +new Date(this.get("created_at")) / 1000;
|
||||
},
|
||||
|
||||
baseGuid : function() {
|
||||
if(this.get("root")){
|
||||
return this.get("root").guid;
|
||||
} else {
|
||||
return this.get("guid");
|
||||
}
|
||||
},
|
||||
|
||||
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() });
|
||||
},
|
||||
|
||||
unlike : function() {
|
||||
|
|
@ -60,9 +38,5 @@ app.models.Post = Backbone.Model.extend({
|
|||
|
||||
likeModel.destroy();
|
||||
this.set({ user_like : null });
|
||||
},
|
||||
|
||||
like : function() {
|
||||
this.set({ user_like : this.likes.create() });
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1 @@
|
|||
app.models.StatusMessage = app.models.Post.extend({
|
||||
url : function() { return "/status_messages"; }
|
||||
});
|
||||
app.models.StatusMessage = app.models.Post.extend({ });
|
||||
|
|
|
|||
36
public/javascripts/app/models/stream.js
Normal file
36
public/javascripts/app/models/stream.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
app.models.Stream = Backbone.Collection.extend({
|
||||
initialize : function(){
|
||||
this.posts = new app.collections.Posts();
|
||||
},
|
||||
|
||||
url : function(){
|
||||
return _.any(this.posts.models) ? this.timeFilteredPath() : this.basePath()
|
||||
},
|
||||
|
||||
fetch: function() {
|
||||
var self = this
|
||||
|
||||
this.posts
|
||||
.fetch({
|
||||
add : true,
|
||||
url : self.url()
|
||||
})
|
||||
.done(
|
||||
function(){
|
||||
self.trigger("fetched", self);
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
basePath : function(){
|
||||
return document.location.pathname;
|
||||
},
|
||||
|
||||
timeFilteredPath : function(){
|
||||
return this.basePath() + "?max_time=" + _.last(this.posts.models).createdAt();
|
||||
},
|
||||
|
||||
add : function(models){
|
||||
this.posts.add(models)
|
||||
}
|
||||
})
|
||||
|
|
@ -2,21 +2,22 @@ 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"
|
||||
},
|
||||
|
||||
stream : function() {
|
||||
app.stream = new app.views.Stream().render();
|
||||
$("#main_stream").html(app.stream.el);
|
||||
app.stream = new app.models.Stream()
|
||||
app.page = new app.views.Stream().render();
|
||||
$("#main_stream").html(app.page.el);
|
||||
|
||||
var streamFacesView = new app.views.StreamFaces({collection : app.stream.collection}).render();
|
||||
var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts}).render();
|
||||
$('#selected_aspect_contacts .content').html(streamFacesView.el);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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.createReshareUrl,
|
||||
success : function(){
|
||||
app.stream.add(reshare);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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(){
|
||||
|
|
@ -68,9 +63,9 @@ app.views.Post = app.views.StreamObject.extend({
|
|||
success : function(){
|
||||
if(!app.stream) { return }
|
||||
|
||||
_.each(app.stream.collection.models, function(model){
|
||||
_.each(app.stream.posts.models, function(model){
|
||||
if(model.get("author").id == personId) {
|
||||
app.stream.collection.remove(model);
|
||||
app.stream.posts.remove(model);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ app.views.Publisher = Backbone.View.extend({
|
|||
},
|
||||
|
||||
initialize : function(){
|
||||
this.collection = this.collection || new app.collections.Stream;
|
||||
this.collection = this.collection || new app.collections.Posts;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -31,8 +31,9 @@ app.views.Publisher = Backbone.View.extend({
|
|||
"photos" : serializedForm["photos[]"],
|
||||
"services" : serializedForm["services[]"]
|
||||
}, {
|
||||
url : "/status_messages",
|
||||
success : function() {
|
||||
app.stream.collection.add(statusMessage.toJSON());
|
||||
app.stream.posts.add(statusMessage.toJSON());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
@ -8,7 +8,7 @@ app.views.StreamFaces = app.views.Base.extend({
|
|||
|
||||
initialize : function(){
|
||||
this.updatePeople()
|
||||
this.collection.bind("add", this.updatePeople, this)
|
||||
app.stream.posts.bind("add", this.updatePeople, this)
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ app.views.StreamObject = app.views.Base.extend({
|
|||
this.$(".collapsible").expander({
|
||||
slicePoint: 400,
|
||||
widow: 12,
|
||||
expandPrefix: "",
|
||||
expandText: Diaspora.I18n.t("show_more"),
|
||||
userCollapse: false
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,25 +3,86 @@ app.views.Stream = Backbone.View.extend({
|
|||
"click #paginate": "render"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.collection = this.collection || new app.collections.Stream;
|
||||
this.collection.bind("add", this.addPost, this);
|
||||
|
||||
initialize: function(options) {
|
||||
this.stream = app.stream || new app.models.Stream()
|
||||
this.collection = this.stream.posts
|
||||
this.publisher = new app.views.Publisher({collection : this.collection});
|
||||
|
||||
// inf scroll
|
||||
// we're using this._loading to keep track of backbone's collection
|
||||
// fetching state... is there a better way to do this?
|
||||
var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200);
|
||||
$(window).scroll(throttledScroll);
|
||||
this.stream.bind("fetched", this.collectionFetched, this)
|
||||
this.collection.bind("add", this.addPost, this);
|
||||
this.setupInfiniteScroll()
|
||||
this.setupLightbox()
|
||||
},
|
||||
|
||||
// lightbox delegation
|
||||
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
|
||||
$(this.el).delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked);
|
||||
addPost : function(post) {
|
||||
var postView = new app.views.Post({ model: post });
|
||||
|
||||
$(this.el)[
|
||||
(this.collection.at(0).id == post.id)
|
||||
? "prepend"
|
||||
: "append"
|
||||
](postView.render().el);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
isLoading : function(){
|
||||
return this._loading && !this._loading.isResolved();
|
||||
},
|
||||
|
||||
allContentLoaded : false,
|
||||
|
||||
|
||||
collectionFetched: function(collection, response) {
|
||||
this.removeLoader()
|
||||
if(!collection.parse(response).length || collection.parse(response).length == 0) {
|
||||
this.allContentLoaded = true;
|
||||
$(window).unbind('scroll')
|
||||
return
|
||||
}
|
||||
|
||||
$(this.el).append($("<a>", {
|
||||
href: this.stream.url(),
|
||||
id: "paginate"
|
||||
}).text('Load more posts'));
|
||||
},
|
||||
|
||||
render : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
|
||||
this.addLoader();
|
||||
this._loading = this.stream.fetch();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addLoader: function(){
|
||||
if(this.$("#paginate").length == 0) {
|
||||
$(this.el).append($("<div>", {
|
||||
"id" : "paginate"
|
||||
}));
|
||||
}
|
||||
|
||||
this.$("#paginate").html($("<img>", {
|
||||
src : "/images/static-loader.png",
|
||||
"class" : "loader"
|
||||
}));
|
||||
},
|
||||
|
||||
removeLoader : function(){
|
||||
this.$("#paginate").remove();
|
||||
},
|
||||
|
||||
setupLightbox : function(){
|
||||
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
|
||||
$(this.el).delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked);
|
||||
},
|
||||
|
||||
setupInfiniteScroll : function() {
|
||||
var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200);
|
||||
$(window).scroll(throttledScroll);
|
||||
},
|
||||
|
||||
infScroll : function() {
|
||||
if(this.allContentLoaded || this.isLoading()) { return }
|
||||
|
||||
|
|
@ -36,64 +97,4 @@ app.views.Stream = Backbone.View.extend({
|
|||
|
||||
return this;
|
||||
},
|
||||
|
||||
isLoading : function(){
|
||||
return this._loading && !this._loading.isResolved();
|
||||
},
|
||||
|
||||
allContentLoaded : false,
|
||||
|
||||
addPost : function(post) {
|
||||
var postView = new app.views.Post({ model: post });
|
||||
|
||||
$(this.el)[
|
||||
(this.collection.at(0).id == post.id)
|
||||
? "prepend"
|
||||
: "append"
|
||||
](postView.render().el);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
collectionFetched: function(collection, response) {
|
||||
this.$("#paginate").remove();
|
||||
|
||||
if(!collection.parse(response).length || collection.parse(response).length == 0) {
|
||||
this.allContentLoaded = true;
|
||||
$(window).unbind('scroll')
|
||||
return
|
||||
}
|
||||
|
||||
$(this.el).append($("<a>", {
|
||||
href: this.collection.url(),
|
||||
id: "paginate"
|
||||
}).text('Load more posts'));
|
||||
},
|
||||
|
||||
render : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
|
||||
var self = this;
|
||||
self.addLoader();
|
||||
|
||||
this._loading = self.collection.fetch({
|
||||
add: true,
|
||||
success: $.proxy(this.collectionFetched, self)
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addLoader: function(){
|
||||
if(this.$("#paginate").length == 0) {
|
||||
$(this.el).append($("<div>", {
|
||||
"id" : "paginate"
|
||||
}));
|
||||
}
|
||||
|
||||
this.$("#paginate").html($("<img>", {
|
||||
src : "/images/static-loader.png",
|
||||
"class" : "loader"
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe AspectsController do
|
||||
describe '#index' do
|
||||
describe StreamsController 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
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe MultisController do
|
||||
describe '#index' do
|
||||
describe StreamsController 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")
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -137,23 +137,4 @@ describe PostsController do
|
|||
StatusMessage.exists?(message.id).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before do
|
||||
sign_in alice
|
||||
end
|
||||
|
||||
it 'will succeed if admin' do
|
||||
AppConfig[:admins] = [alice.username]
|
||||
get :index
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it 'will redirect if not' do
|
||||
AppConfig[:admins] = []
|
||||
get :index
|
||||
response.should be_redirect
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
72
spec/controllers/streams_controller_spec.rb
Normal file
72
spec/controllers/streams_controller_spec.rb
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
10
spec/javascripts/app/collections/comments_collection_spec.js
Normal file
10
spec/javascripts/app/collections/comments_collection_spec.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
describe("app.collections.comments", function(){
|
||||
describe("url", function(){
|
||||
it("should user the post id", function(){
|
||||
var post =new app.models.Post({id : 5})
|
||||
var collection = new app.collections.Comments([], {post : post})
|
||||
expect(collection.url).toBe("/posts/5/comments")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
10
spec/javascripts/app/collections/likes_collections_spec.js
Normal file
10
spec/javascripts/app/collections/likes_collections_spec.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
describe("app.collections.Likes", function(){
|
||||
describe("url", function(){
|
||||
it("should user the post id", function(){
|
||||
var post =new app.models.Post({id : 5})
|
||||
var collection = new app.collections.Likes([], {post : post})
|
||||
expect(collection.url).toBe("/posts/5/likes")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
describe("app.collections.Stream", function() {
|
||||
describe("url", function() {
|
||||
var stream = new app.collections.Stream(),
|
||||
expectedPath = document.location.pathname;
|
||||
|
||||
it("returns the correct path", function() {
|
||||
expect(stream.url()).toEqual(expectedPath);
|
||||
});
|
||||
|
||||
it("returns the json path with max_time if the collection has models", function() {
|
||||
var post = new app.models.Post();
|
||||
spyOn(post, "createdAt").andReturn(1234);
|
||||
|
||||
stream.add(post);
|
||||
|
||||
expect(stream.url()).toEqual(expectedPath + "?max_time=1234");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,15 @@ describe("app.models.Post", function() {
|
|||
this.post = new app.models.Post();
|
||||
})
|
||||
|
||||
describe("url", function(){
|
||||
it("should be /posts when it doesn't have an id", function(){
|
||||
expect(new app.models.Post().url()).toBe("/posts")
|
||||
})
|
||||
|
||||
it("should be /posts/id when it doesn't have an id", function(){
|
||||
expect(new app.models.Post({id: 5}).url()).toBe("/posts/5")
|
||||
})
|
||||
})
|
||||
describe("createdAt", function() {
|
||||
it("returns the post's created_at as an integer", function() {
|
||||
var date = new Date;
|
||||
|
|
@ -13,22 +22,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 +60,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")
|
||||
})
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue