Merge pull request #8439 from jhass/feature/comment_likes_api
add API routes for comment likes
This commit is contained in:
commit
7ec2a68256
5 changed files with 342 additions and 12 deletions
|
|
@ -81,7 +81,7 @@ We recommend setting up new pods using Ruby 3.3, and updating existing pods to t
|
||||||
* Tell users that there is no help in mobile version, allow to switch to desktop [#8407](https://github.com/diaspora/diaspora/pull/8407)
|
* Tell users that there is no help in mobile version, allow to switch to desktop [#8407](https://github.com/diaspora/diaspora/pull/8407)
|
||||||
* Add Smart App Banner on iOS devices [#8409](https://github.com/diaspora/diaspora/pull/8409)
|
* Add Smart App Banner on iOS devices [#8409](https://github.com/diaspora/diaspora/pull/8409)
|
||||||
* Add a more detailed modal when reporting a post or a comment [#8035](https://github.com/diaspora/diaspora/pull/8035)
|
* Add a more detailed modal when reporting a post or a comment [#8035](https://github.com/diaspora/diaspora/pull/8035)
|
||||||
* Re-introduce likes on comments [#8203](https://github.com/diaspora/diaspora/pull/8203) [#8442](https://github.com/diaspora/diaspora/pull/8442)
|
* Re-introduce likes on comments [#8203](https://github.com/diaspora/diaspora/pull/8203) [#8439](https://github.com/diaspora/diaspora/pull/8439) [#8442](https://github.com/diaspora/diaspora/pull/8442)
|
||||||
* New redesigned registration page [#8285](https://github.com/diaspora/diaspora/pull/8285)
|
* New redesigned registration page [#8285](https://github.com/diaspora/diaspora/pull/8285)
|
||||||
* Allow comments to be fetched [#8441](https://github.com/diaspora/diaspora/pull/8441)
|
* Allow comments to be fetched [#8441](https://github.com/diaspora/diaspora/pull/8441)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,10 @@ module Api
|
||||||
post = post_service.find!(params.require(:post_id))
|
post = post_service.find!(params.require(:post_id))
|
||||||
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
|
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
|
||||||
|
|
||||||
likes_query = like_service.find_for_post(params[:post_id])
|
likes_query = find_likes
|
||||||
|
|
||||||
|
return unless likes_query
|
||||||
|
|
||||||
likes_page = index_pager(likes_query).response
|
likes_page = index_pager(likes_query).response
|
||||||
likes_page[:data] = likes_page[:data].map {|x| like_json(x) }
|
likes_page[:data] = likes_page[:data].map {|x| like_json(x) }
|
||||||
render_paged_api_response likes_page
|
render_paged_api_response likes_page
|
||||||
|
|
@ -33,31 +36,42 @@ module Api
|
||||||
post = post_service.find!(params.require(:post_id))
|
post = post_service.find!(params.require(:post_id))
|
||||||
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
|
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
|
||||||
|
|
||||||
like_service.create_for_post(params[:post_id])
|
if params[:comment_id].present?
|
||||||
|
create_for_comment
|
||||||
|
else
|
||||||
|
create_for_post
|
||||||
|
end
|
||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
if e.message == "Validation failed: Target has already been taken"
|
if e.message == "Validation failed: Target has already been taken"
|
||||||
return render_error 409, "Like already exists"
|
return render_error 409, "Like already exists"
|
||||||
end
|
end
|
||||||
|
|
||||||
raise
|
raise
|
||||||
else
|
|
||||||
head :no_content
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
post = post_service.find!(params.require(:post_id))
|
post = post_service.find!(params.require(:post_id))
|
||||||
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
|
raise ActiveRecord::RecordInvalid unless post.public? || private_read?
|
||||||
|
|
||||||
success = like_service.unlike_post(params[:post_id])
|
if params[:comment_id].present?
|
||||||
if success
|
destroy_for_comment
|
||||||
head :no_content
|
|
||||||
else
|
else
|
||||||
render_error 410, "Like doesn’t exist"
|
destroy_for_post
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def find_likes
|
||||||
|
if params[:comment_id].present?
|
||||||
|
return unless comment_and_post_validate(params[:post_id], params[:comment_id])
|
||||||
|
|
||||||
|
like_service.find_for_comment(params[:comment_id])
|
||||||
|
else
|
||||||
|
like_service.find_for_post(params[:post_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def like_service
|
def like_service
|
||||||
@like_service ||= LikeService.new(current_user)
|
@like_service ||= LikeService.new(current_user)
|
||||||
end
|
end
|
||||||
|
|
@ -66,9 +80,59 @@ module Api
|
||||||
@post_service ||= PostService.new(current_user)
|
@post_service ||= PostService.new(current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def comment_service
|
||||||
|
@comment_service ||= CommentService.new(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
def like_json(like)
|
def like_json(like)
|
||||||
LikesPresenter.new(like).as_api_json
|
LikesPresenter.new(like).as_api_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_for_post
|
||||||
|
like_service.create_for_post(params[:post_id])
|
||||||
|
|
||||||
|
head :no_content
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_for_comment
|
||||||
|
return unless comment_and_post_validate(params[:post_id], params[:comment_id])
|
||||||
|
|
||||||
|
like_service.create_for_comment(params[:comment_id])
|
||||||
|
|
||||||
|
head :no_content
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_for_post
|
||||||
|
if like_service.unlike_post(params[:post_id])
|
||||||
|
head :no_content
|
||||||
|
else
|
||||||
|
render_error 410, "Like doesn’t exist"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_for_comment
|
||||||
|
return unless comment_and_post_validate(params[:post_id], params[:comment_id])
|
||||||
|
|
||||||
|
if like_service.unlike_comment(params[:comment_id])
|
||||||
|
head :no_content
|
||||||
|
else
|
||||||
|
render_error 410, "Like doesn’t exist"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment_and_post_validate(post_guid, comment_guid)
|
||||||
|
if comment_is_for_post(post_guid, comment_guid)
|
||||||
|
true
|
||||||
|
else
|
||||||
|
render_error 404, "Comment not found for the given post"
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment_is_for_post(post_guid, comment_guid)
|
||||||
|
comments = comment_service.find_for_post(post_guid)
|
||||||
|
comments.exists?(guid: comment_guid)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,8 @@ Rails.application.routes.draw do
|
||||||
resources :photos, only: %i[show index create destroy]
|
resources :photos, only: %i[show index create destroy]
|
||||||
resources :posts, only: %i[show create destroy] do
|
resources :posts, only: %i[show create destroy] do
|
||||||
resources :comments, only: %i[create index destroy] do
|
resources :comments, only: %i[create index destroy] do
|
||||||
post "report" => "comments#report"
|
resource :likes, only: %i[show create destroy]
|
||||||
|
post :report
|
||||||
end
|
end
|
||||||
resource :reshares, only: %i[show create]
|
resource :reshares, only: %i[show create]
|
||||||
resource :likes, only: %i[show create destroy]
|
resource :likes, only: %i[show create destroy]
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ describe Api::V1::CommentsController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#read" do
|
describe "#index" do
|
||||||
before do
|
before do
|
||||||
@comment_text1 = "This is a comment"
|
@comment_text1 = "This is a comment"
|
||||||
@comment_text2 = "This is a comment 2"
|
@comment_text2 = "This is a comment 2"
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,88 @@ describe Api::V1::LikesController do
|
||||||
expect(response.status).to eq(401)
|
expect(response.status).to eq(401)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "for comments" do
|
||||||
|
before do
|
||||||
|
comment = comment_service.create(@status.guid, "This is a comment")
|
||||||
|
@comment_guid = comment.guid
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with right post and comment id" do
|
||||||
|
it "succeeds in getting empty likes" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token_minimum_scopes}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
likes = response_body(response)
|
||||||
|
expect(likes.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "succeeds in getting comment likes" do
|
||||||
|
like_service(bob).create_for_comment(@comment_guid)
|
||||||
|
like_service(auth.user).create_for_comment(@comment_guid)
|
||||||
|
like_service(alice).create_for_comment(@comment_guid)
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token_minimum_scopes}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
likes = response_body(response)
|
||||||
|
expect(likes.length).to eq(3)
|
||||||
|
confirm_like_format(likes, alice)
|
||||||
|
confirm_like_format(likes, bob)
|
||||||
|
confirm_like_format(likes, auth.user)
|
||||||
|
|
||||||
|
expect_to_match_json_schema(likes.to_json, "#/definitions/likes")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong post id" do
|
||||||
|
it "fails at getting likes" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: "badguid", comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Post with provided guid could not be found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong comment id" do
|
||||||
|
it "fails at getting likes" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: "badguid"),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Comment not found for the given post")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with improper credentials" do
|
||||||
|
before do
|
||||||
|
comment = comment_service(auth_public_only.user).create(@private_status.guid, "This is a comment")
|
||||||
|
@comment_guid = comment.guid
|
||||||
|
end
|
||||||
|
|
||||||
|
context "without private:read scope in token" do
|
||||||
|
it "fails at getting likes" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token_public_only}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 422, "User is not allowed to like")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails without valid token" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: invalid_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
|
|
@ -177,9 +259,98 @@ describe Api::V1::LikesController do
|
||||||
expect(response.status).to eq(401)
|
expect(response.status).to eq(401)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "for comments" do
|
||||||
|
before do
|
||||||
|
comment = comment_service.create(@status.guid, "This is a comment")
|
||||||
|
@comment_guid = comment.guid
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with right post and comment id" do
|
||||||
|
it "succeeds in liking comment" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
likes = like_service.find_for_comment(@comment_guid)
|
||||||
|
expect(likes.length).to eq(1)
|
||||||
|
expect(likes[0].author.id).to eq(auth.user.person.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails in liking already liked comment" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 409, "Like already exists")
|
||||||
|
|
||||||
|
likes = like_service.find_for_comment(@comment_guid)
|
||||||
|
expect(likes.length).to eq(1)
|
||||||
|
expect(likes[0].author.id).to eq(auth.user.person.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong post id" do
|
||||||
|
it "fails at liking comment" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: 99_999_999, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Post with provided guid could not be found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong comment id" do
|
||||||
|
it "fails at liking comment" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: 99_999_999),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Comment not found for the given post")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with improper credentials" do
|
||||||
|
before do
|
||||||
|
comment = comment_service(auth_public_only.user).create(@private_status.guid, "This is a comment")
|
||||||
|
@comment_guid = comment.guid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails in liking private comment without private:read" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token_public_only}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(422)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails in liking post without interactions" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token_minimum_scopes}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails without valid token" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: invalid_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#delete" do
|
describe "#destroy" do
|
||||||
before do
|
before do
|
||||||
like_service.create_for_post(@status.guid)
|
like_service.create_for_post(@status.guid)
|
||||||
end
|
end
|
||||||
|
|
@ -250,6 +421,96 @@ describe Api::V1::LikesController do
|
||||||
expect(response.status).to eq(401)
|
expect(response.status).to eq(401)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "for comments" do
|
||||||
|
before do
|
||||||
|
comment = comment_service.create(@status.guid, "This is a comment")
|
||||||
|
@comment_guid = comment.guid
|
||||||
|
like_service.create_for_comment(@comment_guid)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with right post and comment id" do
|
||||||
|
it "succeeds at unliking comment" do
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
likes = like_service.find_for_comment(@comment_guid)
|
||||||
|
expect(likes.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails at unliking comment user didn't like" do
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 410, "Like doesn’t exist")
|
||||||
|
|
||||||
|
likes = like_service.find_for_comment(@comment_guid)
|
||||||
|
expect(likes.length).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong post id" do
|
||||||
|
it "fails at unliking comment" do
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: 99_999_999, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Post with provided guid could not be found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong comment id" do
|
||||||
|
it "fails at unliking comment" do
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @status.guid, comment_id: 99_999_999),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Comment not found for the given post")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with improper credentials" do
|
||||||
|
before do
|
||||||
|
comment = comment_service(auth_public_only.user).create(@private_status.guid, "This is a comment")
|
||||||
|
@comment_guid = comment.guid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails at unliking private post without private:read" do
|
||||||
|
like_service(auth_public_only.user).create_for_post(@private_status.guid)
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "Post with provided guid could not be found")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails in unliking post without interactions" do
|
||||||
|
like_service(auth_minimum_scopes.user).create_for_post(@status.guid)
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: access_token_minimum_scopes}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails without valid token" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comment_likes_path(post_id: @private_status.guid, comment_id: @comment_guid),
|
||||||
|
params: {access_token: invalid_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -268,6 +529,10 @@ describe Api::V1::LikesController do
|
||||||
LikeService.new(user)
|
LikeService.new(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def comment_service(user=auth.user)
|
||||||
|
CommentService.new(user)
|
||||||
|
end
|
||||||
|
|
||||||
def response_body(response)
|
def response_body(response)
|
||||||
JSON.parse(response.body)
|
JSON.parse(response.body)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue