diff --git a/Changelog.md b/Changelog.md index 27c81bb94..4a5e58a58 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ ## Refactor ## Bug fixes +* Fix fetching comments after fetching likes [#7167](https://github.com/diaspora/diaspora/pull/7167) ## Features diff --git a/app/assets/javascripts/app/collections/reshares.js b/app/assets/javascripts/app/collections/reshares.js index 1aee51053..ab7bb9173 100644 --- a/app/assets/javascripts/app/collections/reshares.js +++ b/app/assets/javascripts/app/collections/reshares.js @@ -2,6 +2,9 @@ app.collections.Reshares = Backbone.Collection.extend({ model: app.models.Reshare, - url : "/reshares" + + initialize: function(models, options) { + this.url = "/posts/" + options.post.id + "/reshares"; + } }); // @license-end diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js index 28d6f3a57..51b40227e 100644 --- a/app/assets/javascripts/app/models/post/interactions.js +++ b/app/assets/javascripts/app/models/post/interactions.js @@ -70,6 +70,7 @@ app.models.Post.Interactions = Backbone.Model.extend({ self.post.set({participation: true}); self.trigger("change"); self.set({"likes_count" : self.get("likes_count") + 1}); + self.likes.trigger("change"); }, error: function() { app.flashMessages.error(Diaspora.I18n.t("failed_to_like")); @@ -84,6 +85,7 @@ app.models.Post.Interactions = Backbone.Model.extend({ this.userLike().destroy({success : function() { self.trigger('change'); self.set({"likes_count" : self.get("likes_count") - 1}); + self.likes.trigger("change"); }}); app.instrument("track", "Unlike"); @@ -116,6 +118,8 @@ app.models.Post.Interactions = Backbone.Model.extend({ app.stream.addNow(reshare); } interactions.trigger("change"); + interactions.set({"reshares_count": interactions.get("reshares_count") + 1}); + interactions.reshares.trigger("change"); }) .fail(function(){ app.flashMessages.error(Diaspora.I18n.t("reshares.duplicate")); diff --git a/app/assets/javascripts/app/views/likes_info_view.js b/app/assets/javascripts/app/views/likes_info_view.js index 9300ac9ad..d511c2ef9 100644 --- a/app/assets/javascripts/app/views/likes_info_view.js +++ b/app/assets/javascripts/app/views/likes_info_view.js @@ -11,7 +11,7 @@ app.views.LikesInfo = app.views.Base.extend({ tooltipSelector : ".avatar", initialize : function() { - this.model.interactions.bind('change', this.render, this); + this.model.interactions.likes.on("change", this.render, this); this.displayAvatars = false; }, @@ -19,18 +19,16 @@ app.views.LikesInfo = app.views.Base.extend({ return _.extend(this.defaultPresenter(), { likes : this.model.interactions.likes.toJSON(), likesCount : this.model.interactions.likesCount(), - displayAvatars : this.model.interactions.get("fetched") && this.displayAvatars + displayAvatars: this.displayAvatars }); }, showAvatars : function(evt){ if(evt) { evt.preventDefault() } this.displayAvatars = true; - if(!this.model.interactions.get("fetched")){ - this.model.interactions.fetch(); - } else { - this.model.interactions.trigger("change"); - } + this.model.interactions.likes.fetch({success: function() { + this.model.interactions.likes.trigger("change"); + }.bind(this)}); } }); // @license-end diff --git a/app/assets/javascripts/app/views/reshares_info_view.js b/app/assets/javascripts/app/views/reshares_info_view.js index b91027e84..a1d985dd4 100644 --- a/app/assets/javascripts/app/views/reshares_info_view.js +++ b/app/assets/javascripts/app/views/reshares_info_view.js @@ -11,7 +11,7 @@ app.views.ResharesInfo = app.views.Base.extend({ tooltipSelector : ".avatar", initialize : function() { - this.model.interactions.bind("change", this.render, this); + this.model.interactions.reshares.bind("change", this.render, this); this.displayAvatars = false; }, @@ -19,18 +19,16 @@ app.views.ResharesInfo = app.views.Base.extend({ return _.extend(this.defaultPresenter(), { reshares : this.model.interactions.reshares.toJSON(), resharesCount : this.model.interactions.resharesCount(), - displayAvatars : this.model.interactions.get("fetched") && this.displayAvatars + displayAvatars: this.displayAvatars }); }, showAvatars : function(evt){ if(evt) { evt.preventDefault() } this.displayAvatars = true; - if(!this.model.interactions.get("fetched")){ - this.model.interactions.fetch(); - } else { - this.model.interactions.trigger("change"); - } + this.model.interactions.reshares.fetch({success: function() { + this.model.interactions.reshares.trigger("change"); + }.bind(this)}); } }); // @license-end diff --git a/app/controllers/reshares_controller.rb b/app/controllers/reshares_controller.rb index 22915891a..385e6acfc 100644 --- a/app/controllers/reshares_controller.rb +++ b/app/controllers/reshares_controller.rb @@ -17,4 +17,16 @@ class ResharesController < ApplicationController render :nothing => true, :status => 422 end end + + def index + @reshares = target.reshares.includes(author: :profile) + render json: @reshares.as_api_response(:backbone) + end + + private + + def target + @target ||= current_user.find_visible_shareable_by_id(Post, params[:post_id]) || + raise(ActiveRecord::RecordNotFound.new) + end end diff --git a/app/models/reshare.rb b/app/models/reshare.rb index bb914d401..a88208248 100644 --- a/app/models/reshare.rb +++ b/app/models/reshare.rb @@ -21,6 +21,14 @@ class Reshare < Post self.root.update_reshares_counter if self.root.present? end + acts_as_api + api_accessible :backbone do |t| + t.add :id + t.add :guid + t.add :author + t.add :created_at + end + def root_diaspora_id root.try(:author).try(:diaspora_handle) end diff --git a/config/routes.rb b/config/routes.rb index 02b15089c..190ad6b98 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,6 +38,7 @@ Diaspora::Application.routes.draw do resources :poll_participations, only: :create resources :likes, only: %i(create destroy index) resources :comments, only: %i(new create destroy index) + resources :reshares, only: :index end get 'p/:id' => 'posts#show', :as => 'short_post' diff --git a/features/desktop/comments.feature b/features/desktop/comments.feature index 3b9fb1aa2..0ef2ca6c8 100644 --- a/features/desktop/comments.feature +++ b/features/desktop/comments.feature @@ -73,3 +73,16 @@ Feature: commenting When I follow "less than a minute ago" within ".comments .comment:last-child" Then I should see "I think that’s a cat" within ".comments .comment .highlighted" And I should have scrolled down + + Scenario: Show more comments after loading likes + When "alice@alice.alice" has commented a lot on "Look at this dog" + And "alice@alice.alice" has liked the post "Look at this dog" + And I am on "alice@alice.alice"'s page + Then I should see "Look at this dog" + And I should not see "Comment 2" + + When I follow "1 Like" + Then I should not see "1 Like" + + When I click on selector ".toggle_post_comments" + Then I should see "Comment 2" diff --git a/features/step_definitions/like_steps.rb b/features/step_definitions/like_steps.rb new file mode 100644 index 000000000..e0670e7c8 --- /dev/null +++ b/features/step_definitions/like_steps.rb @@ -0,0 +1,5 @@ +Given /^"([^"]*)" has liked the post "([^"]*)"$/ do |email, post_text| + user = User.find_by(email: email) + post = StatusMessage.find_by(text: post_text) + user.like!(post) +end diff --git a/spec/controllers/likes_controller_spec.rb b/spec/controllers/likes_controller_spec.rb index 066bdc01a..606cf69db 100644 --- a/spec/controllers/likes_controller_spec.rb +++ b/spec/controllers/likes_controller_spec.rb @@ -101,12 +101,6 @@ describe LikesController, :type => :controller do @message = alice.comment!(@message, "hey") if class_const == Comment end - it 'generates a jasmine fixture', :fixture => true do - get :index, id_field => @message.id - - save_fixture(response.body, "ajax_likes_on_#{class_const.to_s.underscore}") - end - it 'returns a 404 for a post not visible to the user' do sign_in eve expect{get :index, id_field => @message.id}.to raise_error(ActiveRecord::RecordNotFound) diff --git a/spec/controllers/reshares_controller_spec.rb b/spec/controllers/reshares_controller_spec.rb index cc4b7e9ec..571f5651b 100644 --- a/spec/controllers/reshares_controller_spec.rb +++ b/spec/controllers/reshares_controller_spec.rb @@ -64,4 +64,44 @@ describe ResharesController, :type => :controller do end end end + + describe "#index" do + context "with a private post" do + before do + @alices_aspect = alice.aspects.where(name: "generic").first + @post = alice.post(:status_message, text: "hey", to: @alices_aspect.id) + end + + it "returns a 404 for a post not visible to the user" do + sign_in(eve, scope: :user) + expect { + get :index, post_id: @post.id, format: :json + }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "returns an empty array for a post visible to the user" do + sign_in(bob, scope: :user) + get :index, post_id: @post.id, format: :json + expect(JSON.parse(response.body)).to eq([]) + end + end + + context "with a public post" do + before do + sign_in(alice, scope: :user) + @post = alice.post(:status_message, text: "hey", public: true) + end + + it "returns an array of reshares for a post" do + bob.reshare!(@post) + get :index, post_id: @post.id, format: :json + expect(JSON.parse(response.body).map {|h| h["id"] }).to eq(@post.reshares.map(&:id)) + end + + it "returns an empty array for a post with no reshares" do + get :index, post_id: @post.id, format: :json + expect(JSON.parse(response.body)).to eq([]) + end + end + end end diff --git a/spec/javascripts/app/models/post/interacations_spec.js b/spec/javascripts/app/models/post/interacations_spec.js index 6b2b66e37..0f7b9926c 100644 --- a/spec/javascripts/app/models/post/interacations_spec.js +++ b/spec/javascripts/app/models/post/interacations_spec.js @@ -40,6 +40,13 @@ describe("app.models.Post.Interactions", function(){ jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess); expect(this.post.get("participation")).toBeTruthy(); }); + + it("triggers a change on the likes collection", function() { + spyOn(this.interactions.likes, "trigger"); + this.interactions.like(); + jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess); + expect(this.interactions.likes.trigger).toHaveBeenCalledWith("change"); + }); }); describe("unlike", function(){ @@ -56,7 +63,7 @@ describe("app.models.Post.Interactions", function(){ this.reshare = this.interactions.post.reshare(); }); - it("triggers a change on the model", function() { + it("triggers a change on the interactions model", function() { spyOn(this.interactions, "trigger"); this.interactions.reshare(); @@ -65,6 +72,13 @@ describe("app.models.Post.Interactions", function(){ expect(this.interactions.trigger).toHaveBeenCalledWith("change"); }); + it("triggers a change on the reshares collection", function() { + spyOn(this.interactions.reshares, "trigger"); + this.interactions.reshare(); + jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess); + expect(this.interactions.reshares.trigger).toHaveBeenCalledWith("change"); + }); + it("adds the reshare to the default, activity and aspects stream", function() { app.stream = { addNow: $.noop }; spyOn(app.stream, "addNow"); diff --git a/spec/javascripts/app/views/likes_info_view_spec.js b/spec/javascripts/app/views/likes_info_view_spec.js index f0848675d..6166bfc82 100644 --- a/spec/javascripts/app/views/likes_info_view_spec.js +++ b/spec/javascripts/app/views/likes_info_view_spec.js @@ -21,19 +21,23 @@ describe("app.views.LikesInfo", function(){ it("fires on a model change", function(){ spyOn(this.view, "postRenderTemplate"); - this.view.model.interactions.trigger('change'); + this.view.model.interactions.likes.trigger("change"); expect(this.view.postRenderTemplate).toHaveBeenCalled(); }); }); describe("showAvatars", function(){ - beforeEach(function(){ - spyOn(this.post.interactions, "fetch").and.callThrough(); + it("calls fetch on the model's like collection", function() { + spyOn(this.post.interactions.likes, "fetch").and.callThrough(); + this.view.showAvatars(); + expect(this.post.interactions.likes.fetch).toHaveBeenCalled(); }); - it("calls fetch on the model's like collection", function(){ + it("triggers 'change' on the likes collection", function() { + spyOn(this.post.interactions.likes, "trigger"); this.view.showAvatars(); - expect(this.post.interactions.fetch).toHaveBeenCalled(); + jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: "{\"id\": 1}"}); + expect(this.post.interactions.likes.trigger).toHaveBeenCalledWith("change"); }); it("sets 'displayAvatars' to true", function(){ diff --git a/spec/javascripts/app/views/reshares_info_view_spec.js b/spec/javascripts/app/views/reshares_info_view_spec.js index b36853cc0..f5e6bf0db 100644 --- a/spec/javascripts/app/views/reshares_info_view_spec.js +++ b/spec/javascripts/app/views/reshares_info_view_spec.js @@ -22,19 +22,23 @@ describe("app.views.ResharesInfo", function(){ it("fires on a model change", function(){ spyOn(this.view, "postRenderTemplate"); - this.view.model.interactions.trigger("change"); + this.view.model.interactions.reshares.trigger("change"); expect(this.view.postRenderTemplate).toHaveBeenCalled(); }); }); describe("showAvatars", function(){ - beforeEach(function(){ - spyOn(this.post.interactions, "fetch").and.callThrough(); + it("calls fetch on the model's reshare collection", function() { + spyOn(this.post.interactions.reshares, "fetch").and.callThrough(); + this.view.showAvatars(); + expect(this.post.interactions.reshares.fetch).toHaveBeenCalled(); }); - it("calls fetch on the model's reshare collection", function(){ + it("triggers 'change' on the reshares collection", function() { + spyOn(this.post.interactions.reshares, "trigger"); this.view.showAvatars(); - expect(this.post.interactions.fetch).toHaveBeenCalled(); + jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: "{\"id\": 1}"}); + expect(this.post.interactions.reshares.trigger).toHaveBeenCalledWith("change"); }); it("sets 'displayAvatars' to true", function(){