Merge branch 'tag_stream_refactor'

This commit is contained in:
Maxwell Salzberg 2011-10-03 15:41:07 -07:00
commit 6653896b31
32 changed files with 501 additions and 158 deletions

View file

@ -137,4 +137,21 @@ class ApplicationController < ActionController::Base
@tags ||= current_user.followed_tags
end
def save_sort_order
if params[:sort_order].present?
session[:sort_order] = (params[:sort_order] == 'created_at') ? 'created_at' : 'updated_at'
elsif session[:sort_order].blank?
session[:sort_order] = 'updated_at'
else
session[:sort_order] = (session[:sort_order] == 'created_at') ? 'created_at' : 'updated_at'
end
end
def sort_order
is_mobile_device? ? 'created_at' : session[:sort_order]
end
def max_time
params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now
end
end

View file

@ -1,12 +1,8 @@
class AppsController < ApplicationController
def show
@app = 'cubbies'
@posts = ActivityStreams::Photo
max_time = params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now
@posts = @posts.where(ActivityStreams::Photo.arel_table[:created_at].lt(max_time)
).where(:public => true
).order('posts.created_at DESC'
).includes(:author => :profile).limit(30)
@posts = ActivityStreams::Photo.where(:public => true).for_a_stream(max_time, 'created_at')
@commenting_disabled = true
@people = []
@people_count = 0

View file

@ -2,7 +2,7 @@
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
require File.join(Rails.root, "lib", "aspect_stream")
require File.join(Rails.root, "lib", 'stream', "aspect_stream")
class AspectsController < ApplicationController
before_filter :authenticate_user!
@ -138,18 +138,4 @@ class AspectsController < ApplicationController
end
private
def save_sort_order
if params[:sort_order].present?
session[:sort_order] = (params[:sort_order] == 'created_at') ? 'created_at' : 'updated_at'
elsif session[:sort_order].blank?
session[:sort_order] = 'created_at'
else
session[:sort_order] = (session[:sort_order] == 'created_at') ? 'created_at' : 'updated_at'
end
end
def sort_order
is_mobile_device? ? 'created_at' : session[:sort_order]
end
end

View file

@ -0,0 +1,20 @@
# 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_stream')
class MentionsController < ApplicationController
before_filter :authenticate_user!
before_filter :save_sort_order, :only => :index
def index
@stream = MentionStream.new(current_user, :max_time => params[:max_time], :order => sort_order)
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @stream.posts}
else
render 'aspects/index'
end
end
end

View file

@ -1,12 +1,23 @@
require File.join(Rails.root, '/lib/tag_stream')
# 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', 'tag_stream')
class TagFollowingsController < ApplicationController
before_filter :authenticate_user!
before_filter :save_sort_order, :only => :index
def index
@stream = TagStream.new(current_user)
@stream = TagStream.new(current_user, :max_time => params[:max_time], :order => sort_order)
render 'aspects/index', :locals => {:posts => @stream.posts}
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @stream.posts}
else
render 'aspects/index'
end
end
# POST /tag_followings
# POST /tag_followings.xml
def create

View file

@ -47,27 +47,17 @@ class TagsController < ApplicationController
def show
params[:name].downcase!
@aspect = :tag
if current_user
@posts = StatusMessage.
joins("LEFT OUTER JOIN post_visibilities ON post_visibilities.post_id = posts.id").
joins("LEFT OUTER JOIN contacts ON contacts.id = post_visibilities.contact_id").
where(Contact.arel_table[:user_id].eq(current_user.id).or(
StatusMessage.arel_table[:public].eq(true).or(
StatusMessage.arel_table[:author_id].eq(current_user.person.id)
)
)).select('DISTINCT posts.*')
@posts = StatusMessage.owned_or_visible_by_user(current_user)
else
@posts = StatusMessage.all_public
end
params[:prefill] = "##{params[:name]} "
@posts = @posts.tagged_with(params[:name])
max_time = params[:max_time] ? Time.at(params[:max_time].to_i) : Time.now
@posts = @posts.where(StatusMessage.arel_table[:created_at].lt(max_time))
@posts = @posts.includes({:author => :profile}, :comments, :photos).order('posts.created_at DESC').limit(15)
@posts = @posts.tagged_with(params[:name]).for_a_stream(max_time, 'created_at')
@commenting_disabled = true
params[:prefill] = "##{params[:name]} "
if params[:only_posts]
render :partial => 'shared/stream', :locals => {:posts => @posts}
@ -84,4 +74,5 @@ class TagsController < ApplicationController
end
@tag_followed
end
end

View file

@ -11,20 +11,24 @@ module StreamHelper
elsif controller.instance_of?(PeopleController)
person_path(@person, :max_time => @posts.last.created_at.to_i)
elsif controller.instance_of?(TagFollowingsController)
tag_followings_path(:max_time => @stream.posts.last.created_at.to_i)
tag_followings_path(:max_time => time_for_scroll(opts[:ajax_stream], @stream), :sort_order => session[:sort_order])
elsif controller.instance_of?(MentionsController)
mentions_path(:max_time => time_for_scroll(opts[:ajax_stream], @stream), :sort_order => session[:sort_order])
elsif controller.instance_of?(AspectsController)
if opts[:ajax_stream]
time = (Time.now() + 1).to_i
else
time = @stream.posts.last.send(@stream.order.to_sym).to_i
end
aspects_path(:max_time => time, :sort_order => session[:sort_order], :a_ids => @stream.aspect_ids)
aspects_path(:max_time => time_for_scroll(opts[:ajax_stream], @stream), :a_ids => @stream.aspect_ids, :sort_order => session[:sort_order])
else
raise 'in order to use pagination for this new controller, update next_page_path in stream helper'
end
end
def time_for_scroll(ajax_stream, stream)
if ajax_stream || stream.posts.empty?
(Time.now() + 1).to_i
else
stream.posts.last.send(stream.order.to_sym).to_i
end
end
def time_for_sort post
if controller.instance_of?(AspectsController)
post.send(session[:sort_order].to_sym)

View file

@ -32,7 +32,20 @@ class Post < ActiveRecord::Base
validates :guid, :uniqueness => true
#scopes
scope :all_public, where(:public => true, :pending => false)
scope :includes_for_a_stream, includes({:author => :profile}, :mentions => {:person => :profile}) #note should include root and photos, but i think those are both on status_message
def self.for_a_stream(max_time, order)
by_max_time(max_time, order).
includes_for_a_stream.
limit(15)
end
def self.by_max_time(max_time, order='created_at')
where("posts.#{order} < ?", max_time).order("posts.#{order} desc")
end
#############
def diaspora_handle
read_attribute(:diaspora_handle) || self.author.diaspora_handle
@ -140,4 +153,3 @@ class Post < ActiveRecord::Base
update_all(:comments_count => self.comments.count)
end
end

View file

@ -26,6 +26,19 @@ class StatusMessage < Post
after_create :create_mentions
#scopes
scope :where_person_is_mentioned, lambda{|person| joins(:mentions).where(:mentions => {:person_id => person.id})}
def self.owned_or_visible_by_user(user)
joins("LEFT OUTER JOIN post_visibilities ON post_visibilities.post_id = posts.id").
joins("LEFT OUTER JOIN contacts ON contacts.id = post_visibilities.contact_id").
where(Contact.arel_table[:user_id].eq(user.id).or(
StatusMessage.arel_table[:public].eq(true).or(
StatusMessage.arel_table[:author_id].eq(user.person.id)
)
)).select('DISTINCT posts.*')
end
def text(opts = {})
self.formatted_message(opts)
end

View file

@ -6,15 +6,12 @@
#sort_by
= t('.recently')
%span.controls
= link_to_if(session[:sort_order] == 'updated_at', t('.posted'), aspects_path(:a_ids => stream.aspect_ids, :sort_order => 'created_at' ))
= link_to_if(session[:sort_order] == 'created_at', t('.commented_on'), stream.link(:sort_order => 'updated_at'))
·
= link_to_if(session[:sort_order] == 'created_at', t('.commented_on'), aspects_path(:a_ids => stream.aspect_ids, :sort_order => 'updated_at'))
= link_to_if(session[:sort_order] == 'updated_at', t('.posted'), stream.link(:sort_order => 'created_at' ))
%h3
- if stream.for_all_aspects?
= t('.stream')
- else
= stream.aspects.to_sentence
= stream.title
= render 'shared/publisher', :selected_aspects => stream.aspects, :aspect_ids => stream.aspect_ids, :for_all_aspects => stream.for_all_aspects?, :aspect => stream.aspect
= render 'aspects/no_posts_message'
@ -23,11 +20,7 @@
= render 'aspects/no_contacts_message'
#main_stream.stream{:data => {:guids => stream.aspect_ids.join(',')}}
- if stream.ajax_stream?
#pagination
=link_to(t('more'), next_page_path(:ajax_stream => true), :class => 'paginate')
- elsif stream.posts.length > 0
- if !stream.ajax_stream? && stream.posts.length > 0
= render 'shared/stream', :posts => stream.posts
#pagination
=link_to(t('more'), next_page_path, :class => 'paginate')
#pagination
=link_to(t('more'), next_page_path(:ajax_stream => stream.ajax_stream?), :class => 'paginate')

View file

@ -1,23 +1,13 @@
#selected_aspect_contacts.section
.title.no_icon
%h5
- if @stream.for_all_aspects? || @stream.aspect_ids.size > 1
= "#{t('_contacts')}"
- else
= @stream.aspect.name
= "(#{@stream.people.size})"
= @stream.contacts_title
.content
- if @stream.people.size > 0
- for person in @stream.people.sample(15)
= person_image_link(person)
- if @stream.for_all_aspects? || @stream.aspect_ids.size > 1
= link_to t('.view_all_contacts'), contacts_link, :id => "view_all_contacts_link"
- else
= link_to t('.view_all_contacts'), contacts_path(:a_id => @stream.aspect.id), :id => "view_all_contacts_link"
= link_to t('.view_all_contacts'), @stream.contacts_link, :id => "view_all_contacts_link"
- else
= t('.no_contacts')
= link_to t('.manage_your_aspects'), contacts_link

View file

@ -21,6 +21,11 @@
.section
= render 'aspects/aspect_listings'
.section
%ul.left_nav
.li
%b= link_to t('.mentions'), mentions_path, :class => 'home_selector'
.section#followed_tags_listing
= render 'tags/followed_tags_listings'

View file

@ -5,8 +5,7 @@
- if user_signed_in?
%ul.left_nav
%li
%div.root_element
= t('aspects.index.tags_following')
%b=link_to t('aspects.index.tags_following'), tag_followings_path, :class => 'home_selector'
%ul.sub_nav
- if tags.size > 0

View file

@ -21,7 +21,6 @@ Diaspora::Application.configure do
config.action_mailer.raise_delivery_errors = false
config.active_support.deprecation = :log
#config.threadsafe!
# Monkeypatch around the nasty "2.5MB exception page" issue, caused by very large environment vars
# This snippet via: http://stackoverflow.com/questions/3114993/exception-pages-in-development-mode-take-upwards-of-15-30-seconds-to-render-why
# Relevant Rails ticket: https://rails.lighthouseapp.com/projects/8994/tickets/5027-_request_and_responseerb-and-diagnosticserb-take-an-increasingly-long-time-to-render-in-development-with-multiple-show-tables-calls

View file

@ -106,6 +106,7 @@ en:
done_editing: "done editing"
aspect_stream:
stream: "Stream"
mentions: "Mentions"
recently: "recently:"
commented_on: "commented on"
posted: "posted"
@ -155,6 +156,7 @@ en:
acquaintances: "Acquaintances"
friends: "Friends"
index:
mentions: "Mentions"
donate: "Donate"
keep_us_running: "Keep %{pod} running fast and buy servers their coffee fix with a monthly donation!"
your_aspects: "Your Aspects"
@ -824,7 +826,15 @@ en:
index:
revoke_access: "Revoke Access"
no_applications: "You haven't registered any applications yet."
streams:
mentions:
title: "Your Mentions"
contacts_title: "People who mentioned you"
tags:
title: "Posts tagged: %{tags}"
contacts_title: "People who dig these tags"
users:
logged_out:

View file

@ -53,7 +53,8 @@ Diaspora::Application.routes.draw do
end
# get "tag_followings" => "tag_followings#index", :as => 'tag_followings'
get "tag_followings" => "tag_followings#index", :as => 'tag_followings'
resources :mentions, :only => [:index]
get 'tags/:name' => 'tags#show', :as => 'tag'

View file

@ -181,6 +181,7 @@ And /^I scroll down$/ do
evaluate_script("window.scrollBy(0,3000000)")
sleep 1
wait_until(30) { evaluate_script('$("#infscr-loading:visible").length') == 0 }
And "I wait for the ajax to finish"
end
Then /^the notification dropdown should be visible$/ do

View file

@ -25,6 +25,7 @@ When /^I sign in as "([^"]*)"$/ do |email|
@me = User.find_by_email(email)
@me.password ||= 'password'
Given 'I am signed in'
And 'I wait for the ajax to finish'
end
When /^I sign in with password "([^"]*)"$/ do |password|

70
lib/base_stream.rb Normal file
View file

@ -0,0 +1,70 @@
class BaseStream
attr_accessor :max_time, :order, :user
def initialize(user, opts={})
self.user = user
self.max_time = opts[:max_time]
self.order = opts[:order]
end
#requied to implement said stream
def link(opts={})
Rails.application.routes.url_helpers.mentions_path(opts)
end
def title
'a title'
end
def posts
[]
end
def people
[]
end
def contacts_title
"title for a stream"
end
def contacts_link
'#'
end
#helpers
def ajax_stream?
false
end
def for_all_aspects?
true
end
#NOTE: MBS bad bad methods the fact we need these means our views are foobared. please kill them and make them
#private methods on the streams that need them
def aspects
@user.aspects
end
def aspect
aspects.first
end
def aspect_ids
aspects.map{|x| x.id}
end
def max_time=(time_string)
@max_time = Time.at(time_string.to_i) unless time_string.blank?
@max_time ||= (Time.now + 1)
end
def order=(order_string)
@order = order_string
@order ||= 'created_at'
end
end

View file

@ -2,9 +2,8 @@
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
class AspectStream
attr_reader :max_time, :order
class AspectStream < BaseStream
TYPES_OF_POST_IN_STREAM = ['StatusMessage', 'Reshare', 'ActivityStreams::Photo']
# @param user [User]
# @param inputted_aspect_ids [Array<Integer>] Ids of aspects for given stream
@ -13,10 +12,8 @@ class AspectStream
# @opt order [String] Order of posts (i.e. 'created_at', 'updated_at')
# @return [void]
def initialize(user, inputted_aspect_ids, opts={})
@user = user
super(user, opts)
@inputted_aspect_ids = inputted_aspect_ids
@max_time = opts[:max_time]
@order = opts[:order]
end
# Filters aspects given the stream's aspect ids on initialization and the user.
@ -26,7 +23,7 @@ class AspectStream
# @return [ActiveRecord::Association<Aspect>] Filtered aspects given the stream's user
def aspects
@aspects ||= lambda do
a = @user.aspects
a = user.aspects
a = a.where(:id => @inputted_aspect_ids) if @inputted_aspect_ids.length > 0
a
end.call
@ -42,16 +39,20 @@ class AspectStream
# @return [ActiveRecord::Association<Post>] AR association of posts
def posts
# NOTE(this should be something like Post.all_for_stream(@user, aspect_ids, {}) that calls visible_posts
@posts ||= @user.visible_posts(:by_members_of => aspect_ids,
:type => ['StatusMessage', 'Reshare', 'ActivityStreams::Photo'],
:order => "#{@order} DESC",
:max_time => @max_time
).includes(:mentions => {:person => :profile}, :author => :profile)
@posts ||= user.visible_posts(:by_members_of => aspect_ids,
:type => TYPES_OF_POST_IN_STREAM,
:order => "#{order} DESC",
:max_time => max_time
).for_a_stream(max_time, order)
end
# @return [ActiveRecord::Association<Person>] AR association of people within stream's given aspects
def people
@people ||= Person.all_from_aspects(aspect_ids, @user).includes(:profile)
@people ||= Person.all_from_aspects(aspect_ids, user).includes(:profile)
end
def link(opts={})
Rails.application.routes.url_helpers.aspects_path(opts.merge(:a_ids => aspect_ids))
end
# The first aspect in #aspects, given the stream is not for all aspects, or #aspects size is 1
@ -67,11 +68,35 @@ class AspectStream
for_all_aspects?
end
def title
if self.for_all_aspects?
I18n.t('aspects.aspect_stream.stream')
else
self.aspects.to_sentence
end
end
# Determine whether or not the stream is displaying across
# all of the user's aspects.
#
# @return [Boolean]
def for_all_aspects?
@all_aspects ||= aspect_ids.length == @user.aspects.size
@all_aspects ||= aspect_ids.length == user.aspects.size
end
def contacts_title
if self.for_all_aspects? || self.aspect_ids.size > 1
I18n.t('_contacts')
else
"#{self.aspect.name}(#{self.people.size})"
end
end
def contacts_link
if for_all_aspects? || aspect_ids.size > 1
Rails.application.routes.url_helpers.contacts_path
else
Rails.application.routes.url_helpers.contacts_path(:a_id => aspect.id)
end
end
end

View file

@ -0,0 +1,28 @@
# 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 MentionStream< BaseStream
def link(opts={})
Rails.application.routes.url_helpers.mentions_path(opts)
end
def title
I18n.translate("streams.mentions.title")
end
# @return [ActiveRecord::Association<Post>] AR association of posts
def posts
@posts ||= StatusMessage.where_person_is_mentioned(self.user.person).for_a_stream(max_time, order)
end
# @return [ActiveRecord::Association<Person>] AR association of people within stream's given aspects
def people
@people ||= posts.map{|p| p.author}.uniq
end
def contacts_title
I18n.translate('streams.mentions.contacts_title')
end
end

49
lib/stream/tag_stream.rb Normal file
View file

@ -0,0 +1,49 @@
# 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 TagStream < BaseStream
def link(opts={})
Rails.application.routes.url_helpers.tag_followings_path(opts)
end
def title
tags_titleized
end
# @return [ActiveRecord::Association<Post>] AR association of posts
def posts
if tag_string.empty?
[]
else
@posts ||= StatusMessage.owned_or_visible_by_user(user).
tagged_with([tag_string], :any => true).
where(:public => true).
for_a_stream(@max_time, @order)
end
end
# @return [ActiveRecord::Association<Person>] AR association of people within stream's given aspects
def people
@people ||= posts.map{|p| p.author}.uniq
end
def contacts_title
I18n.translate('streams.tags.contacts_title')
end
private
def tag_string
@tag_string ||= tags.join(', '){|tag| tag.name}.to_s
end
def tags
@tags = user.followed_tags
end
def tags_titleized
tag_string.split(',').map{|x| "##{x.strip}"}.to_sentence
end
end

View file

@ -1,66 +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 TagStream
attr_reader :max_time, :order
# @param user [User]
# @param inputted_aspect_ids [Array<Integer>] Ids of aspects for given stream
# @param aspect_ids [Array<Integer>] Aspects this stream is responsible for
# @opt max_time [Integer] Unix timestamp of stream's post ceiling
# @opt order [String] Order of posts (i.e. 'created_at', 'updated_at')
# @return [void]
def initialize(user, opts={})
@tags = user.followed_tags
@tag_string = @tags.join(', '){|tag| tag.name}.to_sym
@user = user
@max_time = opts[:max_time]
@order = opts[:order]
end
# Filters aspects given the stream's aspect ids on initialization and the user.
# Will disclude aspects from inputted aspect ids if user is not associated with their
# target aspects.
#
# @return [ActiveRecord::Association<Aspect>] Filtered aspects given the stream's user
def aspects
[@tag_string]
end
# Maps ids into an array from #aspects
#
# @return [Array<Integer>] Aspect ids
def aspect_ids
[]
end
# @return [ActiveRecord::Association<Post>] AR association of posts
def posts
# NOTE(this should be something like Post.all_for_stream(@user, aspect_ids, {}) that calls visible_posts
@posts ||= StatusMessage.tagged_with([@tag_string], :any => true)
end
# @return [ActiveRecord::Association<Person>] AR association of people within stream's given aspects
def people
@people ||= posts.map{|p| p.author}.uniq
end
# The first aspect in #aspects, given the stream is not for all aspects, or #aspects size is 1
# @note aspects.first is used for mobile. NOTE(this is a hack and should be fixed)
# @return [Aspect,Symbol]
def aspect
@tags_string
end
# Determine whether or not the stream is displaying across
# all of the user's aspects.
#
# @return [Boolean]
def for_all_aspects?
true
end
end

View file

@ -0,0 +1,8 @@
Diaspora.Pages.MentionsIndex = function() {
var self = this;
this.subscribe("page/ready", function(evt, document) {
self.stream = self.instantiate("Stream", document.find("#aspect_stream_container"));
self.infiniteScroll = self.instantiate("InfiniteScroll");
});
};

View file

@ -0,0 +1,8 @@
Diaspora.Pages.TagFollowingsIndex = function() {
var self = this;
this.subscribe("page/ready", function(evt, document) {
self.stream = self.instantiate("Stream", document.find("#aspect_stream_container"));
self.infiniteScroll = self.instantiate("InfiniteScroll");
});
};

View file

@ -0,0 +1,11 @@
require 'spec_helper'
require File.join(Rails.root, 'spec', 'shared_behaviors', 'stream')
describe BaseStream do
before do
@stream = BaseStream.new(stub)
end
describe 'shared behaviors' do
it_should_behave_like 'it is a stream'
end
end

View file

@ -2,7 +2,7 @@
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
require 'aspect_stream'
require 'spec_helper'
describe AspectStream do
describe '#aspects' do
@ -70,7 +70,7 @@ describe AspectStream do
it 'respects max_time' do
stream = AspectStream.new(@alice, [1,2], :max_time => 123)
@alice.should_receive(:visible_posts).with(hash_including(:max_time => 123)).and_return(stub.as_null_object)
@alice.should_receive(:visible_posts).with(hash_including(:max_time => instance_of(Time))).and_return(stub.as_null_object)
stream.posts
end
end
@ -138,4 +138,10 @@ describe AspectStream do
@stream.ajax_stream?.should be_false
end
end
describe 'shared behaviors' do
before do
@stream = AspectStream.new(alice, alice.aspects.map(&:id))
end
it_should_behave_like 'it is a stream'
end
end

View file

@ -0,0 +1,12 @@
require 'spec_helper'
require File.join(Rails.root, 'spec', 'shared_behaviors', 'stream')
describe MentionStream do
before do
@stream = MentionStream.new(Factory(:user), :max_time => Time.now, :order => 'updated_at')
end
describe 'shared behaviors' do
it_should_behave_like 'it is a stream'
end
end

View file

@ -0,0 +1,12 @@
require 'spec_helper'
require File.join(Rails.root, 'spec', 'shared_behaviors', 'stream')
describe TagStream do
before do
@stream = TagStream.new(Factory(:user), :max_time => Time.now, :order => 'updated_at')
end
describe 'shared behaviors' do
it_should_behave_like 'it is a stream'
end
end

View file

@ -10,6 +10,47 @@ describe Post do
@aspect = @user.aspects.create(:name => "winners")
end
describe 'scopes' do
describe '.for_a_stream' do
before do
time_interval = 1000
time_past = 1000000
@posts = (1..3).map do |n|
aspect_to_post = alice.aspects.where(:name => "generic").first
post = alice.post :status_message, :text => "#{alice.username} - #{n}", :to => aspect_to_post.id
post.created_at = (post.created_at-time_past) - time_interval
post.updated_at = (post.updated_at-time_past) + time_interval
post.save
time_interval += 1000
post
end
end
it 'returns the posts ordered and limited by unix time' do
Post.for_a_stream(Time.now + 1, "created_at").should == @posts
Post.for_a_stream(Time.now + 1, "updated_at").should == @posts.reverse
end
it 'includes everything in .includes_for_a_stream' do
Post.should_receive(:includes_for_a_stream)
Post.for_a_stream(Time.now + 1, "created_at")
end
it 'is limited to 15 posts' do
Post.stub(:by_max_time).and_return(Post)
Post.stub(:includes_for_a_stream).and_return(Post)
Post.should_receive(:limit)
Post.for_a_stream(Time.now + 1, "created_at")
end
end
describe 'includes for a stream' do
it 'inclues author profile and mentions'
it 'should include photos and root of reshares(but does not)'
end
end
describe 'validations' do
it 'validates uniqueness of guid and does not throw a db error' do
message = Factory(:status_message)

View file

@ -17,6 +17,51 @@ describe StatusMessage do
@aspect = @user.aspects.first
end
describe 'scopes' do
describe '.where_person_is_mentioned' do
it 'returns status messages where the given person is mentioned' do
@bo = bob.person
@test_string = "@{Daniel; #{@bo.diaspora_handle}} can mention people like Raph"
Factory.create(:status_message, :text => @test_string )
Factory.create(:status_message, :text => @test_string )
Factory(:status_message)
StatusMessage.where_person_is_mentioned(@bo).count.should == 2
end
end
describe '.owned_or_visible_by_user' do
before do
@you = bob
@public_post = Factory(:status_message, :public => true)
@your_post = Factory(:status_message, :author => @you.person)
@post_from_contact = eve.post(:status_message, :text => 'wooo', :to => eve.aspects.where(:name => 'generic').first)
@post_from_stranger = Factory(:status_message, :public => false)
end
it 'returns post from your contacts' do
StatusMessage.owned_or_visible_by_user(@you).should include(@post_from_contact)
end
it 'returns your posts' do
StatusMessage.owned_or_visible_by_user(@you).should include(@your_post)
end
it 'returns public posts' do
StatusMessage.owned_or_visible_by_user(@you).should include(@public_post)
end
it 'does not return non contacts, non-public post' do
StatusMessage.owned_or_visible_by_user(@you).should_not include(@post_from_stranger)
end
it 'should return the three visible posts' do
StatusMessage.owned_or_visible_by_user(@you).count.should == 3
end
end
end
describe '.before_create' do
it 'calls build_tags' do
status = Factory.build(:status_message)

View file

@ -0,0 +1,45 @@
require 'spec_helper'
describe 'Streams' do
shared_examples_for 'it is a stream' do
context 'required methods for display' do
it '#title' do
@stream.title.should_not be_nil
end
it '#posts' do
@stream.posts.should_not be_nil
end
it '#people' do
@stream.people.should_not be_nil
end
it 'has a #contacts title' do
@stream.contacts_title.should_not be_nil
end
it 'has a contacts link' do
@stream.contacts_link.should_not be_nil
end
it 'responds to ajax_stream' do
@stream.ajax_stream?.should_not be_nil
end
it 'responds to ajax_stream' do
@stream.ajax_stream?.should_not be_nil
end
it 'should make the stream a time object' do
@stream.max_time = 123
@stream.max_time.should be_a(Time)
end
it 'should default order to created_at' do
@stream.order=nil
@stream.order.should == 'created_at'
end
end
end
end