diff --git a/app/assets/javascripts/app/collections/comments.js b/app/assets/javascripts/app/collections/comments.js
index 9ecf4f047..55ffcd425 100644
--- a/app/assets/javascripts/app/collections/comments.js
+++ b/app/assets/javascripts/app/collections/comments.js
@@ -12,12 +12,17 @@ app.collections.Comments = Backbone.Collection.extend({
make : function(text) {
var self = this;
- var comment = new app.models.Comment({ "text": text });
+ var comment = new app.models.Comment({"text": text}, {post: this.post});
var deferred = comment.save({}, {
url: "/posts/"+ this.post.id +"/comments",
success: function() {
comment.set({author: app.currentUser.toJSON(), parent: self.post });
+
+ // Need interactions after make
+ comment.interactions = new app.models.Post.LikeInteractions(
+ _.extend({comment: comment, post: self.post}, comment.get("interactions"))
+ );
self.add(comment);
}
});
diff --git a/app/assets/javascripts/app/collections/likes.js b/app/assets/javascripts/app/collections/likes.js
index 7eabdc6e4..7f42f9eaf 100644
--- a/app/assets/javascripts/app/collections/likes.js
+++ b/app/assets/javascripts/app/collections/likes.js
@@ -4,10 +4,11 @@ app.collections.Likes = Backbone.Collection.extend({
model: app.models.Like,
initialize : function(models, options) {
- this.url = (options.post != null) ?
+ // A comment- like has a post reference and a comment reference
+ this.url = (options.comment != null) ?
// not delegating to post.url() because when it is in a stream collection it delegates to that url
- "/posts/" + options.post.id + "/likes" :
- "/comments/" + options.comment.id + "/likes";
+ "/comments/" + options.comment.id + "/likes" :
+ "/posts/" + options.post.id + "/likes";
}
});
// @license-end
diff --git a/app/assets/javascripts/app/models/comment.js b/app/assets/javascripts/app/models/comment.js
index da1e017b5..fb4c268f5 100644
--- a/app/assets/javascripts/app/models/comment.js
+++ b/app/assets/javascripts/app/models/comment.js
@@ -3,51 +3,15 @@
app.models.Comment = Backbone.Model.extend({
urlRoot: "/comments",
- initialize: function() {
- this.likes = new app.collections.Likes(this.get("likes"), {comment: this});
- },
-
- // Copied from Post.Interaction. To be merged in an "interactable" class once comments can be commented too
- likesCount: function() {
- return this.get("likes_count");
- },
-
- userLike: function() {
- return this.likes.select(function(like) {
- return like.get("author") && like.get("author").guid === app.currentUser.get("guid");
- })[0];
- },
-
- toggleLike: function() {
- if (this.userLike()) {
- this.unlike();
- } else {
- this.like();
- }
- },
-
- like: function() {
- var self = this;
- this.likes.create({}, {
- success: function() {
- self.post.set({participation: true});
- self.trigger("change");
- self.set({"likes_count": self.get("likes_count") + 1});
- self.likes.trigger("change");
- },
- error: function(model, response) {
- app.flashMessages.handleAjaxError(response);
- }
- });
- },
-
- unlike: function() {
- var self = this;
- this.userLike().destroy({success: function() {
- self.trigger("change");
- self.set({"likes_count": self.get("likes_count") - 1});
- self.likes.trigger("change");
- }});
+ initialize: function(model, options) {
+ options = options || {};
+ this.post = model.post || options.post || this.collection.post;
+ this.interactions = new app.models.Post.LikeInteractions(
+ _.extend({comment: this, post: this.post}, this.get("interactions"))
+ );
+ this.likes = this.interactions.likes;
+ this.likesCount = this.attributes.likes_count;
+ this.userLike = this.interactions.userLike();
}
});
// @license-end
diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js
index 572375c73..d07f075bc 100644
--- a/app/assets/javascripts/app/models/post/interactions.js
+++ b/app/assets/javascripts/app/models/post/interactions.js
@@ -1,75 +1,29 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
-//require ../post
+//= require ./like_interactions
-app.models.Post.Interactions = Backbone.Model.extend({
- initialize : function(options){
+app.models.Post.Interactions = app.models.Post.LikeInteractions.extend({
+ initialize: function(options) {
+ app.models.Post.LikeInteractions.prototype.initialize.apply(this, arguments);
this.post = options.post;
- this.comments = new app.collections.Comments(this.get("comments"), {post : this.post});
- this.likes = new app.collections.Likes(this.get("likes"), {post : this.post});
- this.reshares = new app.collections.Reshares(this.get("reshares"), {post : this.post});
+ this.comments = new app.collections.Comments(this.get("comments"), {post: this.post});
+ this.reshares = new app.collections.Reshares(this.get("reshares"), {post: this.post});
},
- likesCount : function(){
- return this.get("likes_count");
- },
-
- resharesCount : function(){
+ resharesCount: function() {
return this.get("reshares_count");
},
- commentsCount : function(){
+ commentsCount: function() {
return this.get("comments_count");
},
- userLike : function(){
- return this.likes.select(function(like){
- return like.get("author") && like.get("author").guid === app.currentUser.get("guid");
- })[0];
- },
-
- userReshare : function(){
+ userReshare: function() {
return this.reshares.select(function(reshare){
return reshare.get("author") && reshare.get("author").guid === app.currentUser.get("guid");
})[0];
},
- toggleLike : function() {
- if(this.userLike()) {
- this.unlike();
- } else {
- this.like();
- }
- },
-
- like : function() {
- var self = this;
- this.likes.create({}, {
- success: function() {
- self.post.set({participation: true});
- self.trigger("change");
- self.set({"likes_count" : self.get("likes_count") + 1});
- self.likes.trigger("change");
- },
- error: function(model, response) {
- app.flashMessages.handleAjaxError(response);
- }
- });
- },
-
- unlike : function() {
- var self = this;
- this.userLike().destroy({success : function() {
- self.post.set({participation: false});
- self.trigger('change');
- self.set({"likes_count" : self.get("likes_count") - 1});
- self.likes.trigger("change");
- },
- error: function(model, response) {
- app.flashMessages.handleAjaxError(response);
- }});
- },
-
comment: function(text, options) {
var self = this;
options = options || {};
@@ -109,7 +63,7 @@ app.models.Post.Interactions = Backbone.Model.extend({
});
},
- userCanReshare : function(){
+ userCanReshare: function() {
var isReshare = this.post.get("post_type") === "Reshare"
, rootExists = (isReshare ? this.post.get("root") : true)
, publicPost = this.post.get("public")
diff --git a/app/assets/javascripts/app/models/post/like_interactions.js b/app/assets/javascripts/app/models/post/like_interactions.js
new file mode 100644
index 000000000..29b102b67
--- /dev/null
+++ b/app/assets/javascripts/app/models/post/like_interactions.js
@@ -0,0 +1,57 @@
+// This class contains code extracted from interactions.js to factorize likes management between posts and comments
+
+app.models.Post.LikeInteractions = Backbone.Model.extend({
+
+ initialize: function(options) {
+ this.likes = new app.collections.Likes(this.get("likes"), options);
+ this.post = options.post;
+ },
+
+ likesCount: function() {
+ return this.get("likes_count");
+ },
+
+ userLike: function() {
+ return this.likes.select(function(like) {
+ return like.get("author") && like.get("author").guid === app.currentUser.get("guid");
+ })[0];
+ },
+
+ toggleLike: function() {
+ if (this.userLike()) {
+ this.unlike();
+ } else {
+ this.like();
+ }
+ },
+
+ like: function() {
+ var self = this;
+ this.likes.create({}, {
+ success: function() {
+ self.post.set({participation: true});
+ self.trigger("change");
+ self.set({"likes_count": self.get("likes_count") + 1});
+ self.likes.trigger("change");
+ },
+ error: function(model, response) {
+ app.flashMessages.handleAjaxError(response);
+ }
+ });
+ },
+
+ unlike: function() {
+ var self = this;
+ this.userLike().destroy({
+ success: function() {
+ // TODO: If user unlikes a post and the last like of all comments, then set participation to false
+ self.post.set({participation: false});
+ self.trigger("change");
+ self.set({"likes_count": self.get("likes_count") - 1});
+ self.likes.trigger("change");
+ },
+ error: function(model, response) {
+ app.flashMessages.handleAjaxError(response);
+ }});
+ }
+});
diff --git a/app/assets/javascripts/app/views/comment_view.js b/app/assets/javascripts/app/views/comment_view.js
index 1cd04ab62..f02258d60 100644
--- a/app/assets/javascripts/app/views/comment_view.js
+++ b/app/assets/javascripts/app/views/comment_view.js
@@ -6,7 +6,11 @@ app.views.Comment = app.views.Content.extend({
className : "comment media",
tooltipSelector: "time",
- events : function() {
+ subviews: {
+ ".likes-on-comment": "likesInfoView"
+ },
+
+ events: function() {
return _.extend({}, app.views.Content.prototype.events, {
"click .comment_delete": "destroyModel",
"click .comment_report": "report",
@@ -14,33 +18,40 @@ app.views.Comment = app.views.Content.extend({
});
},
- initialize : function(options){
+ initialize: function(options) {
this.templateName = options.templateName || this.templateName;
+ this.model.interactions.on("change", this.render, this);
this.model.on("change", this.render, this);
},
- presenter : function() {
+ presenter: function() {
return _.extend(this.defaultPresenter(), {
canRemove: this.canRemove(),
- text: app.helpers.textFormatter(this.model.get("text"), this.model.get("mentioned_people"))
+ text: app.helpers.textFormatter(this.model.get("text"), this.model.get("mentioned_people")),
+ likesCount: this.model.attributes.likesCount,
+ userLike: this.model.interactions.userLike()
});
},
- ownComment : function() {
+ ownComment: function() {
return app.currentUser.authenticated() && this.model.get("author").diaspora_id === app.currentUser.get("diaspora_id");
},
- postOwner : function() {
+ postOwner: function() {
return app.currentUser.authenticated() && this.model.get("parent").author.diaspora_id === app.currentUser.get("diaspora_id");
},
- canRemove : function() {
+ canRemove: function() {
return app.currentUser.authenticated() && (this.ownComment() || this.postOwner());
},
toggleLike: function(evt) {
if (evt) { evt.preventDefault(); }
- this.model.toggleLike();
+ this.model.interactions.toggleLike();
+ },
+
+ likesInfoView: function() {
+ return new app.views.LikesInfo({model: this.model});
}
});
diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js
index c454462ac..9843874d2 100644
--- a/app/assets/javascripts/app/views/stream_post_views.js
+++ b/app/assets/javascripts/app/views/stream_post_views.js
@@ -7,7 +7,7 @@ app.views.StreamPost = app.views.Post.extend({
subviews : {
".feedback": "feedbackView",
".comments": "commentStreamView",
- ".likes": "likesInfoView",
+ ".likes-on-post": "likesInfoView",
".reshares": "resharesInfoView",
".post-controls": "postControlsView",
".post-content": "postContentView",
diff --git a/app/assets/templates/comment_tpl.jst.hbs b/app/assets/templates/comment_tpl.jst.hbs
index dd9480548..4d58f45e4 100644
--- a/app/assets/templates/comment_tpl.jst.hbs
+++ b/app/assets/templates/comment_tpl.jst.hbs
@@ -46,5 +46,8 @@
{{~/if~}}
+
+
+
diff --git a/app/assets/templates/stream-element_tpl.jst.hbs b/app/assets/templates/stream-element_tpl.jst.hbs
index cb860b63a..27cd3aedb 100644
--- a/app/assets/templates/stream-element_tpl.jst.hbs
+++ b/app/assets/templates/stream-element_tpl.jst.hbs
@@ -37,7 +37,7 @@
{{#unless preview}}
-
+
{{/unless}}
diff --git a/app/controllers/api/v1/likes_controller.rb b/app/controllers/api/v1/likes_controller.rb
index d2d052f7f..4e0103bd3 100644
--- a/app/controllers/api/v1/likes_controller.rb
+++ b/app/controllers/api/v1/likes_controller.rb
@@ -33,7 +33,7 @@ module Api
post = post_service.find!(params.require(:post_id))
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
- like_service.create(params[:post_id])
+ like_service.create_for_post(params[:post_id])
rescue ActiveRecord::RecordInvalid => e
if e.message == "Validation failed: Target has already been taken"
return render_error 409, "Like already exists"
diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb
index ef79d0ad0..57182ac20 100644
--- a/app/controllers/likes_controller.rb
+++ b/app/controllers/likes_controller.rb
@@ -41,7 +41,12 @@ class LikesController < ApplicationController
end
def index
- render json: like_service.find_for_post(params[:post_id])
+ like = if params[:post_id]
+ like_service.find_for_post(params[:post_id])
+ else
+ like_service.find_for_comment(params[:comment_id])
+ end
+ render json: like
.includes(author: :profile)
.as_api_response(:backbone)
end
diff --git a/app/models/user/social_actions.rb b/app/models/user/social_actions.rb
index 8a6369a18..3ab60f137 100644
--- a/app/models/user/social_actions.rb
+++ b/app/models/user/social_actions.rb
@@ -17,6 +17,10 @@ module User::SocialActions
end
end
+ def like_comment!(target, opts={})
+ Like::Generator.new(self, target).create!(opts)
+ end
+
def participate_in_poll!(target, answer, opts={})
PollParticipation::Generator.new(self, target, answer).create!(opts).tap do
update_or_create_participation!(target)
diff --git a/app/presenters/comment_presenter.rb b/app/presenters/comment_presenter.rb
index 6a290337e..7556c448f 100644
--- a/app/presenters/comment_presenter.rb
+++ b/app/presenters/comment_presenter.rb
@@ -8,7 +8,8 @@ class CommentPresenter < BasePresenter
text: message.plain_text_for_json,
author: author.as_api_response(:backbone),
created_at: created_at,
- mentioned_people: mentioned_people.as_api_response(:backbone)
+ mentioned_people: mentioned_people.as_api_response(:backbone),
+ interactions: build_interactions_json
}
end
@@ -19,11 +20,25 @@ class CommentPresenter < BasePresenter
author: PersonPresenter.new(author).as_api_json,
created_at: created_at,
mentioned_people: build_mentioned_people_json,
- reported: current_user.present? && reports.where(user: current_user).exists?
+ reported: current_user.present? && reports.where(user: current_user).exists?,
+ interactions: build_interactions_json
+ }
+ end
+
+ def build_interactions_json
+ {
+ likes: as_api(likes),
+ likes_count: likes_count
}
end
def build_mentioned_people_json
mentioned_people.map {|m| PersonPresenter.new(m).as_api_json }
end
+
+ def as_api(collection)
+ collection.includes(author: :profile).map {|element|
+ element.as_api_response(:backbone)
+ }
+ end
end
diff --git a/app/services/comment_service.rb b/app/services/comment_service.rb
index 2e23033f8..adb370683 100644
--- a/app/services/comment_service.rb
+++ b/app/services/comment_service.rb
@@ -14,8 +14,8 @@ class CommentService
post_service.find!(post_id).comments.for_a_stream
end
- def find!(comment_guid)
- Comment.find_by!(guid: comment_guid)
+ def find!(id_or_guid)
+ Comment.find_by!(comment_key(id_or_guid) => id_or_guid)
end
def destroy(comment_id)
@@ -45,6 +45,11 @@ class CommentService
attr_reader :user
+ # We can assume a guid is at least 16 characters long as we have guids set to hex(8) since we started using them.
+ def comment_key(id_or_guid)
+ id_or_guid.to_s.length < 16 ? :id : :guid
+ end
+
def post_service
@post_service ||= PostService.new(user)
end
diff --git a/app/services/like_service.rb b/app/services/like_service.rb
index f3a17a6b3..2728a909a 100644
--- a/app/services/like_service.rb
+++ b/app/services/like_service.rb
@@ -12,7 +12,8 @@ class LikeService
def create_for_comment(comment_id)
comment = comment_service.find!(comment_id)
- user.like!(comment)
+ post_service.find!(comment.commentable_id) # checks implicit for visible posts
+ user.like_comment!(comment)
end
def destroy(like_id)
@@ -30,6 +31,13 @@ class LikeService
user ? likes.order(Arel.sql("author_id = #{user.person.id} DESC")) : likes
end
+ def find_for_comment(comment_id)
+ comment = comment_service.find!(comment_id)
+ post_service.find!(comment.post.id) # checks implicit for visible posts
+ likes = comment.likes
+ user ? likes.order(Arel.sql("author_id = #{user.person.id} DESC")) : likes
+ end
+
def unlike_post(post_id)
likes = post_service.find!(post_id).likes
likes = likes.order(Arel.sql("author_id = #{user.person.id} DESC"))
@@ -41,6 +49,17 @@ class LikeService
end
end
+ def unlike_comment(comment_id)
+ likes = comment_service.find!(comment_id).likes
+ likes = likes.order(Arel.sql("author_id = #{user.person.id} DESC"))
+ if !likes.empty? && user.owns?(likes[0])
+ user.retract(likes[0])
+ true
+ else
+ false
+ end
+ end
+
private
attr_reader :user
diff --git a/lib/schemas/api_v1.json b/lib/schemas/api_v1.json
index 2d807610a..d3650856b 100644
--- a/lib/schemas/api_v1.json
+++ b/lib/schemas/api_v1.json
@@ -101,9 +101,16 @@
"type": "array",
"items": { "$ref": "https://diaspora.software/api/v1/schema.json#/definitions/short_profile" }
},
- "reported": { "type": "boolean" }
+ "reported": { "type": "boolean" },
+ "interactions": {
+ "type": "object",
+ "properties" : {
+ "likes" : { "$ref": "https://diaspora.software/api/v1/schema.json#/definitions/likes"},
+ "likes_count" : { "type": "integer"}
+ }
+ }
},
- "required": ["guid", "created_at", "author", "body", "reported"],
+ "required": ["guid", "created_at", "author", "body", "reported", "interactions"],
"additionalProperties": false
}
},
diff --git a/spec/integration/api/likes_controller_spec.rb b/spec/integration/api/likes_controller_spec.rb
index 463919268..e70381494 100644
--- a/spec/integration/api/likes_controller_spec.rb
+++ b/spec/integration/api/likes_controller_spec.rb
@@ -61,9 +61,9 @@ describe Api::V1::LikesController do
end
it "succeeds in getting post with likes" do
- like_service(bob).create(@status.guid)
- like_service(auth.user).create(@status.guid)
- like_service(alice).create(@status.guid)
+ like_service(bob).create_for_post(@status.guid)
+ like_service(auth.user).create_for_post(@status.guid)
+ like_service(alice).create_for_post(@status.guid)
get(
api_v1_post_likes_path(post_id: @status.guid),
params: {access_token: access_token_minimum_scopes}
@@ -112,7 +112,7 @@ describe Api::V1::LikesController do
describe "#create" do
context "with right post id" do
- it "succeeeds in liking post" do
+ it "succeeds in liking post" do
post(
api_v1_post_likes_path(post_id: @status.guid),
params: {access_token: access_token}
@@ -181,7 +181,7 @@ describe Api::V1::LikesController do
describe "#delete" do
before do
- like_service.create(@status.guid)
+ like_service.create_for_post(@status.guid)
end
context "with right post id" do
@@ -225,7 +225,7 @@ describe Api::V1::LikesController do
context "with improper credentials" do
it "fails at unliking private post without private:read" do
- like_service(auth_public_only.user).create(@private_status.guid)
+ like_service(auth_public_only.user).create_for_post(@private_status.guid)
delete(
api_v1_post_likes_path(post_id: @private_status.guid),
params: {access_token: access_token}
@@ -234,7 +234,7 @@ describe Api::V1::LikesController do
end
it "fails in unliking post without interactions" do
- like_service(auth_minimum_scopes.user).create(@status.guid)
+ like_service(auth_minimum_scopes.user).create_for_post(@status.guid)
delete(
api_v1_post_likes_path(post_id: @status.guid),
params: {access_token: access_token_minimum_scopes}
diff --git a/spec/javascripts/jasmine_helpers/factory.js b/spec/javascripts/jasmine_helpers/factory.js
index 9b0d4ecfc..4222c4c89 100644
--- a/spec/javascripts/jasmine_helpers/factory.js
+++ b/spec/javascripts/jasmine_helpers/factory.js
@@ -43,13 +43,15 @@ var factory = {
comment : function(overrides) {
var defaultAttrs = {
- "created_at" : "2012-01-04T00:55:30Z",
- "author" : this.author(),
- "guid" : this.guid(),
- "id" : this.id.next(),
- "text" : "This is a comment!"
+ "created_at": "2012-01-04T00:55:30Z",
+ "author": this.author(),
+ "guid": this.guid(),
+ "id": this.id.next(),
+ "text": "This is a comment!"
};
+ overrides = overrides || {};
+ overrides.post = this.post();
return new app.models.Comment(_.extend(defaultAttrs, overrides));
},
diff --git a/spec/presenters/likes_presenter_spec.rb b/spec/presenters/likes_presenter_spec.rb
index 314c91d08..d3fd12635 100644
--- a/spec/presenters/likes_presenter_spec.rb
+++ b/spec/presenters/likes_presenter_spec.rb
@@ -10,7 +10,7 @@ describe LikesPresenter do
to: "all"
)
bobs_like_service = LikeService.new(bob)
- like = bobs_like_service.create(@status.guid)
+ like = bobs_like_service.create_for_post(@status.guid)
@presenter = LikesPresenter.new(like, bob)
end
diff --git a/spec/services/like_service_spec.rb b/spec/services/like_service_spec.rb
index d52e495d6..a97cd8052 100644
--- a/spec/services/like_service_spec.rb
+++ b/spec/services/like_service_spec.rb
@@ -2,67 +2,129 @@
describe LikeService do
let(:post) { alice.post(:status_message, text: "hello", to: alice.aspects.first) }
+ let(:alice_comment) { CommentService.new(alice).create(post.id, "This is a wonderful post") }
+ let(:bobs_comment) { CommentService.new(bob).create(post.id, "My post was better than yours") }
- describe "#create" do
+ describe "#create_for_post" do
it "creates a like on my own post" do
expect {
- LikeService.new(alice).create(post.id)
+ LikeService.new(alice).create_for_post(post.id)
}.not_to raise_error
end
it "creates a like on a post of a contact" do
expect {
- LikeService.new(bob).create(post.id)
+ LikeService.new(bob).create_for_post(post.id)
}.not_to raise_error
end
it "attaches the like to the post" do
- like = LikeService.new(alice).create(post.id)
+ like = LikeService.new(alice).create_for_post(post.id)
expect(post.likes.first.id).to eq(like.id)
end
it "fails if the post does not exist" do
expect {
- LikeService.new(bob).create("unknown id")
+ LikeService.new(bob).create_for_post("unknown id")
}.to raise_error ActiveRecord::RecordNotFound
end
it "fails if the user can't see the post" do
expect {
- LikeService.new(eve).create(post.id)
+ LikeService.new(eve).create_for_post(post.id)
}.to raise_error ActiveRecord::RecordNotFound
end
it "fails if the user already liked the post" do
- LikeService.new(alice).create(post.id)
+ LikeService.new(alice).create_for_post(post.id)
expect {
- LikeService.new(alice).create(post.id)
+ LikeService.new(alice).create_for_post(post.id)
+ }.to raise_error ActiveRecord::RecordInvalid
+ end
+ end
+
+ describe "#create_for_comment" do
+ it "creates a like on a posts comment" do
+ expect {
+ LikeService.new(alice).create_for_comment(alice_comment.id)
+ }.not_to raise_error
+ end
+
+ it "creates a like on someone else comment" do
+ expect {
+ LikeService.new(alice).create_for_comment(bobs_comment.id)
+ }.not_to raise_error
+ end
+
+ it "attaches the like to the comment" do
+ like = LikeService.new(alice).create_for_comment(bobs_comment.id)
+ expect(bobs_comment.likes.first.id).to eq(like.id)
+ end
+
+ it "fails if comment does not exist" do
+ expect {
+ LikeService.new(alice).create_for_comment("unknown_id")
+ }.to raise_error ActiveRecord::RecordNotFound
+ end
+
+ it "fails if user cant see post and its comments" do
+ expect {
+ LikeService.new(eve).create_for_comment(bobs_comment.id)
+ }.to raise_error ActiveRecord::RecordNotFound
+ end
+
+ it "fails if user already liked the comment" do
+ LikeService.new(alice).create_for_comment(bobs_comment.id)
+ expect {
+ LikeService.new(alice).create_for_comment(bobs_comment.id)
}.to raise_error ActiveRecord::RecordInvalid
end
end
describe "#destroy" do
- let(:like) { LikeService.new(bob).create(post.id) }
+ context "for post like" do
+ let(:like) { LikeService.new(bob).create_for_post(post.id) }
- it "lets the user destroy their own like" do
- result = LikeService.new(bob).destroy(like.id)
- expect(result).to be_truthy
+ it "lets the user destroy their own like" do
+ result = LikeService.new(bob).destroy(like.id)
+ expect(result).to be_truthy
+ end
+
+ it "doesn't let the parent author destroy others likes" do
+ result = LikeService.new(alice).destroy(like.id)
+ expect(result).to be_falsey
+ end
+
+ it "doesn't let someone destroy others likes" do
+ result = LikeService.new(eve).destroy(like.id)
+ expect(result).to be_falsey
+ end
+
+ it "fails if the like doesn't exist" do
+ expect {
+ LikeService.new(bob).destroy("unknown id")
+ }.to raise_error ActiveRecord::RecordNotFound
+ end
end
- it "doesn't let the parent author destroy others likes" do
- result = LikeService.new(alice).destroy(like.id)
- expect(result).to be_falsey
- end
+ context "for comment like" do
+ let(:like) { LikeService.new(bob).create_for_comment(alice_comment.id) }
- it "doesn't let someone destroy others likes" do
- result = LikeService.new(eve).destroy(like.id)
- expect(result).to be_falsey
- end
+ it "let the user destroy its own comment like" do
+ result = LikeService.new(bob).destroy(like.id)
+ expect(result).to be_truthy
+ end
- it "fails if the like doesn't exist" do
- expect {
- LikeService.new(bob).destroy("unknown id")
- }.to raise_error ActiveRecord::RecordNotFound
+ it "doesn't let the parent author destroy other comment likes" do
+ result = LikeService.new(alice).destroy(like.id)
+ expect(result).to be_falsey
+ end
+
+ it "fails if the like doesn't exist" do
+ expect {
+ LikeService.new(alice).destroy("unknown id")
+ }.to raise_error ActiveRecord::RecordNotFound
+ end
end
end
@@ -70,17 +132,17 @@ describe LikeService do
context "with user" do
it "returns likes for a public post" do
post = alice.post(:status_message, text: "hello", public: true)
- like = LikeService.new(alice).create(post.id)
+ like = LikeService.new(alice).create_for_post(post.id)
expect(LikeService.new(eve).find_for_post(post.id)).to include(like)
end
it "returns likes for a visible private post" do
- like = LikeService.new(alice).create(post.id)
+ like = LikeService.new(alice).create_for_post(post.id)
expect(LikeService.new(bob).find_for_post(post.id)).to include(like)
end
it "doesn't return likes for a private post the user can not see" do
- LikeService.new(alice).create(post.id)
+ LikeService.new(alice).create_for_post(post.id)
expect {
LikeService.new(eve).find_for_post(post.id)
}.to raise_error ActiveRecord::RecordNotFound
@@ -88,7 +150,7 @@ describe LikeService do
it "returns the user's like first" do
post = alice.post(:status_message, text: "hello", public: true)
- [alice, bob, eve].map {|user| LikeService.new(user).create(post.id) }
+ [alice, bob, eve].map {|user| LikeService.new(user).create_for_post(post.id) }
[alice, bob, eve].each do |user|
expect(
@@ -101,12 +163,12 @@ describe LikeService do
context "without user" do
it "returns likes for a public post" do
post = alice.post(:status_message, text: "hello", public: true)
- like = LikeService.new(alice).create(post.id)
+ like = LikeService.new(alice).create_for_post(post.id)
expect(LikeService.new.find_for_post(post.id)).to include(like)
end
it "doesn't return likes a for private post" do
- LikeService.new(alice).create(post.id)
+ LikeService.new(alice).create_for_post(post.id)
expect {
LikeService.new.find_for_post(post.id)
}.to raise_error Diaspora::NonPublic
@@ -115,15 +177,68 @@ describe LikeService do
it "returns all likes of a post" do
post = alice.post(:status_message, text: "hello", public: true)
- likes = [alice, bob, eve].map {|user| LikeService.new(user).create(post.id) }
+ likes = [alice, bob, eve].map {|user| LikeService.new(user).create_for_post(post.id) }
expect(LikeService.new.find_for_post(post.id)).to match_array(likes)
end
end
+ describe "#find_for_comment" do
+ context "with user" do
+ it "returns likes for a public post comment" do
+ post = alice.post(:status_message, text: "hello", public: true)
+ comment = CommentService.new(bob).create(post.id, "Hello comment")
+ like = LikeService.new(alice).create_for_comment(comment.id)
+ expect(LikeService.new(eve).find_for_comment(comment.id)).to include(like)
+ end
+
+ it "returns likes for visible private post comments" do
+ comment = CommentService.new(bob).create(post.id, "Hello comment")
+ like = LikeService.new(alice).create_for_comment(comment.id)
+ expect(LikeService.new(bob).find_for_comment(comment.id)).to include(like)
+ end
+
+ it "doesn't return likes for a posts comment the user can not see" do
+ expect {
+ LikeService.new(eve).find_for_comment(alice_comment.id)
+ }.to raise_error ActiveRecord::RecordNotFound
+ end
+
+ it "returns the user's like first" do
+ post = alice.post(:status_message, text: "hello", public: true)
+ comment = CommentService.new(alice).create(post.id, "I like my own post")
+
+ [alice, bob, eve].map {|user| LikeService.new(user).create_for_comment(comment.id) }
+ [alice, bob, eve].each do |user|
+ expect(
+ LikeService.new(user).find_for_comment(comment.id).first.author.id
+ ).to be user.person.id
+ end
+ end
+ end
+
+ context "without user" do
+ it "returns likes for a comment on a public post" do
+ post = alice.post(:status_message, text: "hello", public: true)
+ comment = CommentService.new(bob).create(post.id, "I like my own post")
+ like = LikeService.new(alice).create_for_comment(comment.id)
+ expect(
+ LikeService.new.find_for_comment(comment.id)
+ ).to include(like)
+ end
+
+ it "doesn't return likes for a private post comment" do
+ LikeService.new(alice).create_for_comment(alice_comment.id)
+ expect {
+ LikeService.new.find_for_comment(alice_comment.id)
+ }.to raise_error Diaspora::NonPublic
+ end
+ end
+ end
+
describe "#unlike_post" do
before do
- LikeService.new(alice).create(post.id)
+ LikeService.new(alice).create_for_post(post.id)
end
it "removes the like to the post" do
@@ -131,4 +246,16 @@ describe LikeService do
expect(post.likes.length).to eq(0)
end
end
+
+ describe "#unlike_comment" do
+ it "removes the like for a comment" do
+ comment = CommentService.new(alice).create(post.id, "I like my own post")
+ LikeService.new(alice).create_for_comment(comment.id)
+ expect(comment.likes.length).to eq(1)
+
+ LikeService.new(alice).unlike_comment(comment.id)
+ comment = CommentService.new(alice).find!(comment.id)
+ expect(comment.likes.length).to eq(0)
+ end
+ end
end