diff --git a/app/controllers/aspects_controller.rb b/app/controllers/aspects_controller.rb
index 2f4317195..ec8af115d 100644
--- a/app/controllers/aspects_controller.rb
+++ b/app/controllers/aspects_controller.rb
@@ -38,7 +38,7 @@ class AspectsController < ApplicationController
:type => ['StatusMessage','ActivityStreams::Photo'],
:order => session[:sort_order] + ' DESC',
:max_time => params[:max_time].to_i
- ).includes(:likes, {:comments => {:author => :profile}}, {:mentions => {:person => :profile}})
+ ).includes({:comments => {:author => :profile}}, {:mentions => {:person => :profile}})
@posts = PostsFake.new(posts)
if params[:only_posts]
diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb
index b008dc41a..696a0ba3c 100644
--- a/app/controllers/likes_controller.rb
+++ b/app/controllers/likes_controller.rb
@@ -9,7 +9,7 @@ class LikesController < ApplicationController
respond_to :html, :mobile, :json
def create
- target = current_user.find_visible_post_by_id params[:post_id]
+ target = current_user.find_visible_post_by_id params[:status_message_id]
positive = (params[:positive] == 'true') ? true : false
if target
@like = current_user.build_like(:positive => positive, :post => target)
@@ -32,7 +32,7 @@ class LikesController < ApplicationController
end
def destroy
- if @like = Like.where(:id => params[:id], :author_id => current_user.person.id).first
+ if @like = Like.where(:id => params[:id], :author_id => current_user.person.id, :post_id => params[:status_message_id]).first
current_user.retract(@like)
else
respond_to do |format|
@@ -41,4 +41,13 @@ class LikesController < ApplicationController
end
end
end
+
+ def index
+ if target = current_user.find_visible_post_by_id(params[:status_message_id])
+ @likes = target.likes.includes(:author => :profile)
+ render :layout => false
+ else
+ render :nothing => true, :status => 404
+ end
+ end
end
diff --git a/app/helpers/aspect_global_helper.rb b/app/helpers/aspect_global_helper.rb
index dac264005..4398183f5 100644
--- a/app/helpers/aspect_global_helper.rb
+++ b/app/helpers/aspect_global_helper.rb
@@ -9,35 +9,6 @@ module AspectGlobalHelper
end
end
- def aspect_badges(aspects, opts={})
- str = ''
- aspects.each do |aspect|
- str << aspect_badge(aspect, opts)
- end
- str.html_safe
- end
-
- def aspect_badge(aspect, opts={})
- str = ""
- link = opts.delete(:link)
- if !link
- str << link_to(aspect.name, "#", 'data-guid' => aspect.id, :class => 'hard_aspect_link').html_safe
- else
- str << link_for_aspect(aspect).html_safe
- end
- str << ""
- end
-
- def aspect_links(aspects, opts={})
- str = ""
- aspects.each do |aspect|
- str << '
'
- str << link_for_aspect(aspect, :params => opts, 'data-guid' => aspect.id, :class => 'hard_aspect_link').html_safe
- str << ''
- end
- str.html_safe
- end
-
def link_for_aspect(aspect, opts={})
opts[:params] ||= {}
params ||= {}
diff --git a/app/helpers/likes_helper.rb b/app/helpers/likes_helper.rb
index c9f9b3801..0648bed4e 100644
--- a/app/helpers/likes_helper.rb
+++ b/app/helpers/likes_helper.rb
@@ -10,9 +10,9 @@ module LikesHelper
def like_action(post, current_user=current_user)
if current_user.liked?(post)
- link_to t('shared.stream_element.unlike'), like_path(current_user.like_for(post)), :method => :delete, :class => 'unlike', :remote => true
+ link_to t('shared.stream_element.unlike'), status_message_like_path(post, current_user.like_for(post)), :method => :delete, :class => 'unlike', :remote => true
else
- link_to t('shared.stream_element.like'), likes_path(:positive => 'true', :post_id => post.id ), :method => :post, :class => 'like', :remote => true
+ link_to t('shared.stream_element.like'), status_message_likes_path(post, :positive => 'true'), :method => :post, :class => 'like', :remote => true
end
end
end
diff --git a/app/models/like.rb b/app/models/like.rb
index 156775e44..9d549e909 100644
--- a/app/models/like.rb
+++ b/app/models/like.rb
@@ -15,7 +15,7 @@ class Like < ActiveRecord::Base
xml_attr :positive
xml_attr :diaspora_handle
- belongs_to :post
+ belongs_to :post, :counter_cache => true
belongs_to :author, :class_name => 'Person'
validates_uniqueness_of :post_id, :scope => :author_id
diff --git a/app/models/user.rb b/app/models/user.rb
index 9a2173f8d..0bab1c58e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -182,10 +182,14 @@ class User < ActiveRecord::Base
# Check whether the user has liked a post. Extremely inefficient if the post's likes are not loaded.
# @param [Post] post
def liked?(post)
- if self.like_for(post)
- return true
+ if post.likes.loaded?
+ if self.like_for(post)
+ return true
+ else
+ return false
+ end
else
- return false
+ Like.exists?(:author_id => self.person.id, :post_id => post.id)
end
end
@@ -193,10 +197,11 @@ class User < ActiveRecord::Base
# @param [Post] post
# @return [Like]
def like_for(post)
- post.likes.each do |like|
- return like if like.author_id == self.person.id
+ if post.likes.loaded?
+ return post.likes.detect{ |like| like.author_id == self.person.id }
+ else
+ return Like.where(:author_id => self.person.id, :post_id => post.id).first
end
- return nil
end
######### Mailer #######################
diff --git a/app/views/aspects/index.html.haml b/app/views/aspects/index.html.haml
index 0df73cd20..26824860d 100644
--- a/app/views/aspects/index.html.haml
+++ b/app/views/aspects/index.html.haml
@@ -6,7 +6,7 @@
- content_for :head do
= include_javascripts :home
-.span-5.leftNavBar
+.span-5.leftNavBar.fixed
#home_user_badge
= owner_image_link
%h3
@@ -15,7 +15,7 @@
.section
= render 'aspects/aspect_listings'
-.span-13.append-1
+.span-13.append-1.prepend-5
#aspect_stream_container.stream_container
= render 'aspect_stream',
:aspect => @aspect,
diff --git a/app/views/likes/_likes.haml b/app/views/likes/_likes.haml
index 2d0bd5fae..6536917c0 100644
--- a/app/views/likes/_likes.haml
+++ b/app/views/likes/_likes.haml
@@ -2,11 +2,5 @@
-# licensed under the Affero General Public License version 3 or later. See
-# the COPYRIGHT file.
-- if likes.size > 0
- .likes_container
- .likes
- = image_tag('icons/heart.svg')
- = link_to t('.people_like_this', :count => likes.length), "#", :class => "expand_likes"
- %span.hidden.likes_list
- = notification_people_link(nil, likes.map{|x| x.author})
+= notification_people_link(nil, likes.map{|x| x.author})
diff --git a/app/views/likes/_likes_container.haml b/app/views/likes/_likes_container.haml
new file mode 100644
index 000000000..eb39d2136
--- /dev/null
+++ b/app/views/likes/_likes_container.haml
@@ -0,0 +1,12 @@
+-# Copyright (c) 2010, Diaspora Inc. This file is
+-# licensed under the Affero General Public License version 3 or later. See
+-# the COPYRIGHT file.
+
+- if likes_count > 0
+ .likes_container
+ .likes
+ = image_tag('icons/heart.svg')
+ = link_to t('likes.likes.people_like_this', :count => likes_count), status_message_likes_path(post_id), :class => "expand_likes"
+ %span.hidden.likes_list
+ /= render 'likes/likes', :likes => likes
+
diff --git a/app/views/likes/create.js.erb b/app/views/likes/create.js.erb
index 67b90b85d..ff6f0ef63 100644
--- a/app/views/likes/create.js.erb
+++ b/app/views/likes/create.js.erb
@@ -1,4 +1,4 @@
$(".like_action", ".stream_element[data-guid=<%=@like.post_id%>]").html("<%= escape_javascript(like_action(@like.post))%>");
-WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes", :post_id => @like.post_id, :likes => @like.post.likes)) %>");
+WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes_container", :post_id => @like.post_id, :likes_count => @like.post.likes.count)) %>");
diff --git a/app/views/likes/destroy.js.erb b/app/views/likes/destroy.js.erb
index 2c9e5e9a4..0f9663348 100644
--- a/app/views/likes/destroy.js.erb
+++ b/app/views/likes/destroy.js.erb
@@ -1,3 +1,3 @@
$(".like_action", ".stream_element[data-guid=<%=@like.post_id%>]").html("<%= escape_javascript(like_action(@like.post))%>");
-WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes", :post_id => @like.post_id, :likes => @like.post.likes)) %>");
+WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes_container", :post_id => @like.post_id, :likes_count => @like.post.likes.count)) %>");
diff --git a/app/views/likes/index.html.haml b/app/views/likes/index.html.haml
new file mode 100644
index 000000000..3fe13daaa
--- /dev/null
+++ b/app/views/likes/index.html.haml
@@ -0,0 +1 @@
+= render 'likes', :likes => @likes
diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml
index 8fb5000b3..dfc4d5dba 100644
--- a/app/views/photos/show.html.haml
+++ b/app/views/photos/show.html.haml
@@ -65,5 +65,5 @@
#photo_stream.stream.show
%div{:data=>{:guid=>parent.id}}
.likes_container
- = render "likes/likes", :post_id => parent.id, :likes => parent.likes
+ = render "likes/likes_container", :post_id => parent.id, :likes_count => parent.likes_count
= render "comments/comments", :post => parent, :comments => parent.comments, :always_expanded => true
diff --git a/app/views/shared/_stream_element.html.haml b/app/views/shared/_stream_element.html.haml
index 82e708778..4933e2c38 100644
--- a/app/views/shared/_stream_element.html.haml
+++ b/app/views/shared/_stream_element.html.haml
@@ -32,26 +32,31 @@
.info
- if post.public?
- %span.aspect_badges
- %span.aspect_badge.public
- = t('the_world')
- - elsif post.author.owner_id == current_user.id
- %span.aspect_badges
- = aspect_badges(aspects_with_post(all_aspects, post), :link => true)
+ %span.post_scope{:title => t('.viewable_to_anyone')}
+ = t('public')
+ ·
+ - else
+ - if post.author.owner_id == current_user.id
+ %span.post_scope{:title => t('.shared_with', :aspect_names => aspects_with_post(all_aspects, post).map!{|a| a.name}.join(', '))}
+ = t('limited')
+ - else
+ %span.post_scope
+ = t('limited')
+ ·
%span.via
- if post.activity_streams?
= t('.via', :link => link_to("#{post.provider_display_name}", post.actor_url)).html_safe
+ ·
- unless (defined?(@commenting_disabled) && @commenting_disabled)
- ·
%span.like_action
= like_action(post, current_user)
·
= link_to t('comments.new_comment.comment'), '#', :class => 'focus_comment_textarea'
.likes
- - if post.likes.size > 0
- = render "likes/likes", :post_id => post.id, :likes => post.likes, :current_user => current_user
+ - if post.likes_count > 0
+ = render "likes/likes_container", :post_id => post.id, :likes_count => post.likes_count, :current_user => current_user
= render "comments/comments", :post => post, :comments => post.comments, :current_user => current_user, :condensed => true, :commenting_disabled => (defined?(@commenting_disabled) && @commenting_disabled)
diff --git a/app/views/tokens/show.html.haml b/app/views/tokens/show.html.haml
index 7add09dca..4b9ef98c5 100644
--- a/app/views/tokens/show.html.haml
+++ b/app/views/tokens/show.html.haml
@@ -14,7 +14,7 @@
%hr
.cubbies_infographic.span-24{:style => "text-align:left;position:relative;"}
- = image_tag '/images/cubbies_screenshot2.png', :height => 452, :class => "cubbies_screenshot"
+ = image_tag '/images/cubbies_screenshot2.png', :height => 452, :width => 600, :class => "cubbies_screenshot"
= image_tag '/images/cubbies_collage.png', :class => "cubbies_collage"
.span-24.last{:style => "text-align:right;"}
diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml
index 57586a2df..d3ec11df4 100644
--- a/config/locales/diaspora/en.yml
+++ b/config/locales/diaspora/en.yml
@@ -26,7 +26,8 @@ en:
are_you_sure: "Are you sure?"
fill_me_out: "Fill me out"
back: "Back"
- the_world: "the world"
+ public: "Public"
+ limited: "Limited"
search: "Search"
find_people: "Find people"
_home: "Home"
@@ -657,10 +658,12 @@ en:
contact_list:
all_contacts: "All contacts"
stream_element:
+ viewable_to_anyone: "This post is viewable to anyone on the web"
via: "via %{link}"
like: "Like"
unlike: "Unlike"
dislike: "Dislike"
+ shared_with: "Shared with: %{aspect_names}"
footer:
logged_in_as: "logged in as %{name}"
your_aspects: "your aspects"
diff --git a/config/routes.rb b/config/routes.rb
index d3895c5b9..7627953bd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -10,7 +10,10 @@ Diaspora::Application.routes.draw do
put 'toggle_contact_visibility' => :toggle_contact_visibility
end
- resources :status_messages, :only => [:new, :create, :destroy, :show]
+ resources :status_messages, :only => [:new, :create, :destroy, :show] do
+ resources :likes, :only => [:create, :destroy, :index]
+ end
+
get 'bookmarklet' => 'status_messages#bookmarklet'
get 'p/:id' => 'posts#show', :as => 'post'
@@ -20,7 +23,6 @@ Diaspora::Application.routes.draw do
resources :comments, :only => [:create, :destroy]
- resources :likes, :only => [:create, :destroy]
resources :conversations do
resources :messages, :only => [:create, :show]
diff --git a/db/migrate/20110705003445_counter_cache_on_post_likes.rb b/db/migrate/20110705003445_counter_cache_on_post_likes.rb
new file mode 100644
index 000000000..2d4f55f4c
--- /dev/null
+++ b/db/migrate/20110705003445_counter_cache_on_post_likes.rb
@@ -0,0 +1,9 @@
+class CounterCacheOnPostLikes < ActiveRecord::Migration
+ def self.up
+ add_column :posts, :likes_count, :integer, :default => 0
+ end
+
+ def self.down
+ remove_column :posts, :likes_count
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 86ba0bfe0..085facef9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20110623210918) do
+ActiveRecord::Schema.define(:version => 20110705003445) do
create_table "aspect_memberships", :force => true do |t|
t.integer "aspect_id", :null => false
@@ -266,6 +266,7 @@ ActiveRecord::Schema.define(:version => 20110623210918) do
t.string "actor_url"
t.integer "objectId"
t.string "status_message_guid"
+ t.integer "likes_count", :default => 0
end
add_index "posts", ["author_id"], :name => "index_posts_on_person_id"
diff --git a/lib/tasks/cruise.rake b/lib/tasks/cruise.rake
index 1e2a31cbf..ccc3e1b5f 100644
--- a/lib/tasks/cruise.rake
+++ b/lib/tasks/cruise.rake
@@ -16,7 +16,7 @@ namespace :cruise do
end
task :migrate do
- system('bundle exec rake db:migrate')
+ system('bundle exec rake db:schema:load')
exit_status = $?.exitstatus
raise "db:migrate failed!" unless exit_status == 0
end
diff --git a/public/images/cubbies_screenshot.png b/public/images/cubbies_screenshot.png
deleted file mode 100644
index 7dad8817e..000000000
Binary files a/public/images/cubbies_screenshot.png and /dev/null differ
diff --git a/public/images/cubbies_screenshot2.png b/public/images/cubbies_screenshot2.png
index d8347fc6c..573e88b23 100644
Binary files a/public/images/cubbies_screenshot2.png and b/public/images/cubbies_screenshot2.png differ
diff --git a/public/images/cubbies_settings.png b/public/images/cubbies_settings.png
deleted file mode 100644
index ca9bef480..000000000
Binary files a/public/images/cubbies_settings.png and /dev/null differ
diff --git a/public/javascripts/widgets/post.js b/public/javascripts/widgets/post.js
index 79bd975c8..14bd300fb 100644
--- a/public/javascripts/widgets/post.js
+++ b/public/javascripts/widgets/post.js
@@ -20,11 +20,7 @@
};
this.setUpLikes = function() {
- $(this.expandLikesSelector).live("click", function(evt) {
- evt.preventDefault();
- $(this).siblings(".likes_list")
- .fadeToggle("fast");
- });
+ $(this.expandLikesSelector).live("click", this.expandLikes);
var likeIt = $(this.likesSelector);
@@ -37,7 +33,24 @@
$(this).parent().fadeIn("fast");
});
};
+ this.expandLikes = function(evt){
+ evt.preventDefault();
+ var likesList = $(this).siblings(".likes_list");
+ if(likesList.children().length == 0){
+ likesList.append("
");
+ $.ajax({
+ url: this.href,
+ success: function(data){
+ likesList.html(data);
+ likesList.fadeToggle("fast");
+ }
+ });
+ }else {
+ likesList
+ .fadeToggle("fast");
+ }
+ };
};
Diaspora.widgets.add("post", Post);
-})();
\ No newline at end of file
+})();
diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass
index 0182bf439..853ac3ea9 100644
--- a/public/stylesheets/sass/application.sass
+++ b/public/stylesheets/sass/application.sass
@@ -386,7 +386,7 @@ ul.dropdown
p
:margin
- :top 4px
+ :top 0
:bottom 10px
:font
:size 12px
@@ -476,10 +476,14 @@ ul.dropdown
:margin
:bottom 5px
-
.post_initial_info
.details
:color #aaa
+ :margin
+ :bottom 5px
+
+.post_scope
+ :cursor default
.time,
.timeago,
@@ -2085,22 +2089,11 @@ h3,h4
.stream
.avatar
:float left
- .arrow,
-
- .stream_element
- .aspect_badges
- @include opacity(0.5)
-
- &:hover
- .aspect_badges
- @include opacity(1)
.aspect_badge
:position relative
:margin
:bottom 0
- .arrow
- :top -0.1em
.aspect_badge
:top -0.2em
@@ -3058,3 +3051,6 @@ ul.left_nav
:height 450px
:margin
:top 30px
+
+.fixed
+ :position fixed
diff --git a/spec/controllers/likes_controller_spec.rb b/spec/controllers/likes_controller_spec.rb
index 8ec331a08..b5e37fb42 100644
--- a/spec/controllers/likes_controller_spec.rb
+++ b/spec/controllers/likes_controller_spec.rb
@@ -12,18 +12,17 @@ describe LikesController do
@aspect1 = @user1.aspects.first
@aspect2 = @user2.aspects.first
- @controller.stub(:current_user).and_return(alice)
sign_in :user, @user1
end
describe '#create' do
let(:like_hash) {
{:positive => 1,
- :post_id => "#{@post.id}"}
+ :status_message_id => "#{@post.id}"}
}
let(:dislike_hash) {
{:positive => 0,
- :post_id => "#{@post.id}"}
+ :status_message_id => "#{@post.id}"}
}
context "on my own post" do
@@ -72,6 +71,29 @@ describe LikesController do
end
end
+ describe '#index' do
+ before do
+ @message = alice.post(:status_message, :text => "hey", :to => @aspect1.id)
+ end
+ it 'returns a 404 for a post not visible to the user' do
+ sign_in eve
+ get :index, :status_message_id => @message.id
+ end
+
+ it 'returns an array of likes for a post' do
+ like = bob.build_like(:positive => true, :post => @message)
+ like.save!
+
+ get :index, :status_message_id => @message.id
+ assigns[:likes].map(&:id).should == @message.likes.map(&:id)
+ end
+
+ it 'returns an empty array for a post with no likes' do
+ get :index, :status_message_id => @message.id
+ assigns[:likes].should == []
+ end
+ end
+
describe '#destroy' do
before do
@message = bob.post(:status_message, :text => "hey", :to => @aspect1.id)
@@ -81,7 +103,7 @@ describe LikesController do
it 'lets a user destroy their like' do
expect {
- delete :destroy, :format => "js", :post_id => @like.post_id, :id => @like.id
+ delete :destroy, :format => "js", :status_message_id => @like.post_id, :id => @like.id
}.should change(Like, :count).by(-1)
response.status.should == 200
end
@@ -91,7 +113,7 @@ describe LikesController do
like2.save
expect {
- delete :destroy, :format => "js", :post_id => like2.post_id, :id => like2.id
+ delete :destroy, :format => "js", :status_message_id => like2.post_id, :id => like2.id
}.should_not change(Like, :count)
response.status.should == 403
diff --git a/spec/models/like_spec.rb b/spec/models/like_spec.rb
index 19c0b4963..ade64c299 100644
--- a/spec/models/like_spec.rb
+++ b/spec/models/like_spec.rb
@@ -56,6 +56,14 @@ describe Like do
end
end
+ describe 'counter cache' do
+ it 'increments the counter cache on its post' do
+ lambda {
+ @alice.like(1, :post => @status)
+ }.should change{ @status.reload.likes_count }.by(1)
+ end
+ end
+
describe 'xml' do
before do
@liker = Factory.create(:user)