Likes API endpoint complete
This commit is contained in:
parent
2c94994f32
commit
d6915ff5d0
7 changed files with 182 additions and 9 deletions
|
|
@ -5,6 +5,8 @@ module Api
|
||||||
class BaseController < ApplicationController
|
class BaseController < ApplicationController
|
||||||
include Api::OpenidConnect::ProtectedResourceEndpoint
|
include Api::OpenidConnect::ProtectedResourceEndpoint
|
||||||
|
|
||||||
|
protect_from_forgery unless: -> { request.format.json? }
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
rescue_from Exception do |e|
|
rescue_from Exception do |e|
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,55 @@
|
||||||
module Api
|
module Api
|
||||||
module V1
|
module V1
|
||||||
class LikesController < Api::V1::BaseController
|
class LikesController < Api::V1::BaseController
|
||||||
|
before_action only: %i[show] do
|
||||||
|
require_access_token %w[read]
|
||||||
|
end
|
||||||
|
|
||||||
before_action only: %i[create destroy] do
|
before_action only: %i[create destroy] do
|
||||||
require_access_token %w[write]
|
require_access_token %w[write]
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordNotFound do
|
rescue_from ActiveRecord::RecordNotFound do
|
||||||
render json: I18n.t("likes.not_found"), status: :not_found
|
render json: I18n.t("api.endpoint_errors.posts.post_not_found"), status: :not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid do
|
rescue_from ActiveRecord::RecordInvalid do
|
||||||
render json: I18n.t("likes.create.fail"), status: :not_found
|
render json: I18n.t("api.endpoint_errors.likes.user_not_allowed_to_like"), status: :not_found
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
likes = like_service.find_for_post(params[:post_id])
|
||||||
|
render json: likes.map {|x| like_json(x) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
like_service.create(params[:post_id])
|
like_service.create(params[:post_id])
|
||||||
head :no_content, status: 204
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
return render json: I18n.t("api.endpoint_errors.likes.like_exists"), status: :unprocessable_entity if
|
||||||
|
e.message == "Validation failed: Target has already been taken"
|
||||||
|
raise
|
||||||
|
else
|
||||||
|
head :no_content
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
like_service.unlike_post(params[:post_id])
|
success = like_service.unlike_post(params[:post_id])
|
||||||
head :no_content, status: 204
|
if success
|
||||||
|
head :no_content
|
||||||
|
else
|
||||||
|
render json: I18n.t("api.endpoint_errors.likes.no_like"), status: :not_found
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def like_service
|
def like_service
|
||||||
@like_service ||= LikeService.new(current_user)
|
@like_service ||= LikeService.new(current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def like_json(like)
|
||||||
|
LikesPresenter.new(like).as_api_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
10
app/presenters/likes_presenter.rb
Normal file
10
app/presenters/likes_presenter.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class LikesPresenter < BasePresenter
|
||||||
|
def as_api_json
|
||||||
|
{
|
||||||
|
guid: @presentable.guid,
|
||||||
|
author: PersonPresenter.new(@presentable.author).as_api_json
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -950,6 +950,13 @@ en:
|
||||||
contact_developer: "You should contact the developer of the application and include the following detailed error message:"
|
contact_developer: "You should contact the developer of the application and include the following detailed error message:"
|
||||||
login_required: "You must first login before you can authorize this application"
|
login_required: "You must first login before you can authorize this application"
|
||||||
could_not_authorize: "The application could not be authorized"
|
could_not_authorize: "The application could not be authorized"
|
||||||
|
endpoint_errors:
|
||||||
|
likes:
|
||||||
|
user_not_allowed_to_like: "User is not allowed to like"
|
||||||
|
like_exists: "Like already exists"
|
||||||
|
no_like: "Like doesn’t exist"
|
||||||
|
posts:
|
||||||
|
post_not_found: "Post with provided guid could not be found"
|
||||||
|
|
||||||
error:
|
error:
|
||||||
not_found: "No record found for given id."
|
not_found: "No record found for given id."
|
||||||
|
|
@ -1360,3 +1367,5 @@ en:
|
||||||
disabled: "Not available"
|
disabled: "Not available"
|
||||||
open: "Open"
|
open: "Open"
|
||||||
closed: "Closed"
|
closed: "Closed"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ Rails.application.routes.draw do
|
||||||
resources :comments, only: %i[create index destroy] do
|
resources :comments, only: %i[create index destroy] do
|
||||||
post "report" => "comments#report"
|
post "report" => "comments#report"
|
||||||
end
|
end
|
||||||
resource :likes, only: %i[create destroy]
|
resource :likes, only: %i[show create destroy]
|
||||||
end
|
end
|
||||||
resources :conversations, only: %i[show index create destroy] do
|
resources :conversations, only: %i[show index create destroy] do
|
||||||
resources :messages, only: %i[index create]
|
resources :messages, only: %i[index create]
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,47 @@ describe Api::V1::LikesController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#show" do
|
||||||
|
context "with right post id" do
|
||||||
|
it "succeeds in getting empty likes" do
|
||||||
|
get(
|
||||||
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
likes = response_body(response)
|
||||||
|
expect(likes.length).to eq(0)
|
||||||
|
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)
|
||||||
|
get(
|
||||||
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with wrong post id" do
|
||||||
|
it "fails at getting likes" do
|
||||||
|
get(
|
||||||
|
api_v1_post_likes_path(post_id: "badguid"),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
context "with right post id" do
|
context "with right post id" do
|
||||||
it "succeeeds in liking post" do
|
it "succeeeds in liking post" do
|
||||||
|
|
@ -27,6 +68,25 @@ describe Api::V1::LikesController do
|
||||||
expect(likes.length).to eq(1)
|
expect(likes.length).to eq(1)
|
||||||
expect(likes[0].author.id).to eq(auth.user.person.id)
|
expect(likes[0].author.id).to eq(auth.user.person.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "fails in liking already liked post" do
|
||||||
|
post(
|
||||||
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
|
||||||
|
post(
|
||||||
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(422)
|
||||||
|
expect(response.body).to eq(I18n.t("api.endpoint_errors.likes.like_exists"))
|
||||||
|
|
||||||
|
likes = like_service.find_for_post(@status.guid)
|
||||||
|
expect(likes.length).to eq(1)
|
||||||
|
expect(likes[0].author.id).to eq(auth.user.person.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with wrong post id" do
|
context "with wrong post id" do
|
||||||
|
|
@ -36,11 +96,12 @@ describe Api::V1::LikesController do
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#create" do
|
describe "#delete" do
|
||||||
before do
|
before do
|
||||||
post(
|
post(
|
||||||
api_v1_post_likes_path(post_id: @status.guid),
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
|
@ -58,6 +119,24 @@ describe Api::V1::LikesController do
|
||||||
likes = like_service.find_for_post(@status.guid)
|
likes = like_service.find_for_post(@status.guid)
|
||||||
expect(likes.length).to eq(0)
|
expect(likes.length).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "fails at unliking post user didn't like" do
|
||||||
|
delete(
|
||||||
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
|
||||||
|
delete(
|
||||||
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
expect(response.body).to eq(I18n.t("api.endpoint_errors.likes.no_like"))
|
||||||
|
|
||||||
|
likes = like_service.find_for_post(@status.guid)
|
||||||
|
expect(likes.length).to eq(0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with wrong post id" do
|
context "with wrong post id" do
|
||||||
|
|
@ -67,11 +146,28 @@ describe Api::V1::LikesController do
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
|
expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def like_service
|
private
|
||||||
LikeService.new(auth.user)
|
|
||||||
|
# rubocop:disable Metrics/AbcSize
|
||||||
|
def confirm_like_format(likes, user)
|
||||||
|
like = likes.find {|like_element| like_element["author"]["guid"] == user.guid }
|
||||||
|
author = like["author"]
|
||||||
|
expect(author["diaspora_id"]).to eq(user.diaspora_handle)
|
||||||
|
expect(author["name"]).to eq(user.name)
|
||||||
|
expect(author["avatar"]).to eq(user.profile.image_url)
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/AbcSize
|
||||||
|
|
||||||
|
def like_service(user=auth.user)
|
||||||
|
LikeService.new(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def response_body(response)
|
||||||
|
JSON.parse(response.body)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
32
spec/presenters/likes_presenter_spec.rb
Normal file
32
spec/presenters/likes_presenter_spec.rb
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe LikesPresenter do
|
||||||
|
before do
|
||||||
|
@status = alice.post(
|
||||||
|
:status_message,
|
||||||
|
text: "This is a status message from alice",
|
||||||
|
public: true,
|
||||||
|
to: "all"
|
||||||
|
)
|
||||||
|
bobs_like_service = LikeService.new(bob)
|
||||||
|
like = bobs_like_service.create(@status.guid)
|
||||||
|
@presenter = LikesPresenter.new(like, bob)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#as_api_json" do
|
||||||
|
it "works" do
|
||||||
|
expect(@presenter.as_api_json).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
it "confirm API V1 compliance" do
|
||||||
|
like = @presenter.as_api_json
|
||||||
|
expect(like.has_key?(:guid)).to be_truthy
|
||||||
|
author = like[:author]
|
||||||
|
expect(author).not_to be_nil
|
||||||
|
expect(author).to include(guid: bob.guid)
|
||||||
|
expect(author).to include(diaspora_id: bob.diaspora_handle)
|
||||||
|
expect(author).to include(name: bob.name)
|
||||||
|
expect(author).to include(avatar: bob.profile.image_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue