Make the comment API match the API specs
This commit is contained in:
parent
55dbbad869
commit
bcbcf6bce3
7 changed files with 215 additions and 53 deletions
|
|
@ -6,6 +6,7 @@ module Api
|
||||||
include Api::OpenidConnect::ProtectedResourceEndpoint
|
include Api::OpenidConnect::ProtectedResourceEndpoint
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
rescue_from Exception do |e|
|
rescue_from Exception do |e|
|
||||||
logger.error e.message
|
logger.error e.message
|
||||||
logger.error e.backtrace.join("\n")
|
logger.error e.backtrace.join("\n")
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,53 @@
|
||||||
module Api
|
module Api
|
||||||
module V1
|
module V1
|
||||||
class CommentsController < Api::V1::BaseController
|
class CommentsController < Api::V1::BaseController
|
||||||
|
before_action only: %i[index report] 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[read write]
|
require_access_token %w[read write]
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordNotFound do
|
|
||||||
render json: I18n.t("comments.not_found"), status: 404
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid do
|
|
||||||
render json: I18n.t("comments.create.fail"), status: 404
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@comment = comment_service.create(params[:post_id], params[:text])
|
@comment = comment_service.create(params[:post_id], params[:body])
|
||||||
render json: CommentPresenter.new(@comment), status: 201
|
comment = comment_as_json(@comment)
|
||||||
|
render json: comment, status: 201
|
||||||
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
comments = comment_service.find_for_post(params[:post_id])
|
||||||
|
render json: comments.map {|x| comment_as_json(x) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
if comment_service.destroy(params[:id])
|
comment_service.destroy!(params[:id])
|
||||||
|
head :no_content
|
||||||
|
end
|
||||||
|
|
||||||
|
def report
|
||||||
|
comment_guid = params.require(:comment_id)
|
||||||
|
reason = params.require(:reason)
|
||||||
|
comment = comment_service.find!(comment_guid)
|
||||||
|
report = current_user.reports.new(
|
||||||
|
item_id: comment.id,
|
||||||
|
item_type: "Comment",
|
||||||
|
text: reason
|
||||||
|
)
|
||||||
|
if report.save
|
||||||
head :no_content
|
head :no_content
|
||||||
else
|
else
|
||||||
render json: I18n.t("comments.destroy.fail"), status: 403
|
render json: {error: I18n.t("report.status.failed")}, status: 500
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def comment_service
|
def comment_service
|
||||||
@comment_service ||= CommentService.new(current_user)
|
@comment_service ||= CommentService.new(current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def comment_as_json(comment)
|
||||||
|
CommentPresenter.new(comment).as_api_response
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,13 @@ class CommentPresenter < BasePresenter
|
||||||
mentioned_people: @comment.mentioned_people.as_api_response(:backbone)
|
mentioned_people: @comment.mentioned_people.as_api_response(:backbone)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def as_api_response
|
||||||
|
{
|
||||||
|
guid: @comment.guid,
|
||||||
|
body: @comment.message.plain_text_for_json,
|
||||||
|
author: @comment.author.as_api_response(:backbone),
|
||||||
|
created_at: @comment.created_at
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,14 @@ class CommentService
|
||||||
user.comment!(post, text)
|
user.comment!(post, text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_for_post(post_id)
|
||||||
|
post_service.find!(post_id).comments.for_a_stream
|
||||||
|
end
|
||||||
|
|
||||||
|
def find!(comment_guid)
|
||||||
|
Comment.find_by!(guid: comment_guid)
|
||||||
|
end
|
||||||
|
|
||||||
def destroy(comment_id)
|
def destroy(comment_id)
|
||||||
comment = Comment.find(comment_id)
|
comment = Comment.find(comment_id)
|
||||||
if user.owns?(comment) || user.owns?(comment.parent)
|
if user.owns?(comment) || user.owns?(comment.parent)
|
||||||
|
|
@ -20,8 +28,15 @@ class CommentService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_for_post(post_id)
|
def destroy!(comment_guid)
|
||||||
post_service.find!(post_id).comments.for_a_stream
|
comment = find!(comment_guid)
|
||||||
|
if user.owns?(comment)
|
||||||
|
user.retract(comment)
|
||||||
|
elsif user.owns?(comment.parent)
|
||||||
|
user.retract(comment)
|
||||||
|
else
|
||||||
|
raise ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,9 @@ Rails.application.routes.draw do
|
||||||
api_version(module: "Api::V1", path: {value: "api/v1"}) do
|
api_version(module: "Api::V1", path: {value: "api/v1"}) do
|
||||||
match "user", to: "users#show", via: %i[get post]
|
match "user", to: "users#show", via: %i[get post]
|
||||||
resources :posts, only: %i[show create destroy] do
|
resources :posts, only: %i[show create destroy] do
|
||||||
resources :comments, only: %i[create destroy]
|
resources :comments, only: %i[create index destroy] do
|
||||||
|
post "report" => "comments#report"
|
||||||
|
end
|
||||||
resource :likes, only: %i[create destroy]
|
resource :likes, only: %i[create destroy]
|
||||||
end
|
end
|
||||||
resources :conversations, only: %i[show index create destroy] do
|
resources :conversations, only: %i[show index create destroy] do
|
||||||
|
|
|
||||||
|
|
@ -18,66 +18,141 @@ describe Api::V1::CommentsController do
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
context "valid post ID" do
|
context "valid post ID" do
|
||||||
it "succeeds" do
|
it "succeeds in adding a comment" do
|
||||||
post(
|
create_comment(@status.guid, "This is a comment")
|
||||||
api_v1_post_comments_path(post_id: @status.id),
|
expect(response.status).to eq(201)
|
||||||
params: {text: "This is a comment", access_token: access_token}
|
comment = response_body(response)
|
||||||
)
|
expect(comment["body"]).to eq("This is a comment")
|
||||||
expect(JSON.parse(response.body)["text"]).to eq("This is a comment")
|
expect(comment_service.find!(comment["guid"])).to_not be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "comment too long" do
|
context "wrong post id" do
|
||||||
|
it "fails at adding a comment" do
|
||||||
|
create_comment("999_999_999", "This is a comment")
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#read" do
|
||||||
before do
|
before do
|
||||||
post(
|
create_comment(@status.guid, "This is a comment")
|
||||||
api_v1_post_comments_path(post_id: @status.id),
|
create_comment(@status.guid, "This is a comment 2")
|
||||||
params: {
|
|
||||||
text: "This is a long comment" * 99_999,
|
|
||||||
access_token: access_token
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fails with appropriate error message" do
|
context "valid post ID" do
|
||||||
expect(response.body).to eq("Comment creation has failed")
|
it "retrieves related comments" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comments_path(post_id: @status.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response_body(response).length).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "wrong post id" do
|
||||||
|
it "fails at retrieving comments" do
|
||||||
|
get(
|
||||||
|
api_v1_post_comments_path(post_id: "999_999_999"),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#delete" do
|
describe "#delete" do
|
||||||
context "valid comment ID" do
|
|
||||||
before do
|
before do
|
||||||
post(
|
create_comment(@status.guid, "This is a comment")
|
||||||
api_v1_post_comments_path(post_id: @status.id),
|
@comment_guid = response_body(response)["guid"]
|
||||||
params: {text: "This is a comment", access_token: access_token}
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "succeeds" do
|
context "valid comment ID" do
|
||||||
first_comment_id = JSON.parse(response.body)["id"]
|
it "succeeds in deleting comment" do
|
||||||
delete(
|
delete(
|
||||||
api_v1_post_comment_path(id: first_comment_id),
|
api_v1_post_comment_path(
|
||||||
|
post_id: @status.guid,
|
||||||
|
id: @comment_guid
|
||||||
|
),
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
expect(response).to be_success
|
expect(response.status).to eq(204)
|
||||||
|
expect { comment_service.find!(@comment_guid) }.to(
|
||||||
|
raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "invalid comment ID" do
|
context "invalid comment ID" do
|
||||||
|
it "fails at deleting comment" do
|
||||||
|
delete(
|
||||||
|
api_v1_post_comment_path(
|
||||||
|
post_id: @status.guid,
|
||||||
|
id: "1_234_567"
|
||||||
|
),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#report" do
|
||||||
before do
|
before do
|
||||||
|
create_comment(@status.guid, "This is a comment")
|
||||||
|
@comment_guid = response_body(response)["guid"]
|
||||||
|
end
|
||||||
|
|
||||||
|
context "valid comment ID" do
|
||||||
|
it "succeeds in reporting comment" do
|
||||||
post(
|
post(
|
||||||
api_v1_post_comments_path(post_id: @status.id),
|
api_v1_post_comment_report_path(
|
||||||
params: {text: "This is a comment", access_token: access_token}
|
post_id: @status.guid,
|
||||||
|
comment_id: @comment_guid
|
||||||
|
),
|
||||||
|
params: {
|
||||||
|
reason: "bad comment",
|
||||||
|
access_token: access_token
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
report = Report.first
|
||||||
|
expect(report.item_type).to eq("Comment")
|
||||||
|
expect(report.text).to eq("bad comment")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "invalid comment ID" do
|
||||||
|
it "fails at reporting comment" do
|
||||||
|
post(
|
||||||
|
api_v1_post_comment_report_path(
|
||||||
|
post_id: @status.guid,
|
||||||
|
comment_id: "1_234_567"
|
||||||
|
),
|
||||||
|
params: {
|
||||||
|
reason: "bad comment",
|
||||||
|
access_token: access_token
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment_service
|
||||||
|
CommentService.new(auth.user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_comment(post_guid, text)
|
||||||
|
post(
|
||||||
|
api_v1_post_comments_path(post_id: post_guid),
|
||||||
|
params: {body: text, access_token: access_token}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fails to delete" do
|
def response_body(response)
|
||||||
delete(
|
JSON.parse(response.body)
|
||||||
api_v1_post_comment_path(id: 1_234_567),
|
|
||||||
params: {access_token: access_token}
|
|
||||||
)
|
|
||||||
expect(response.body).to eq("Post or comment not found")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,21 @@ describe CommentService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#find!" do
|
||||||
|
let(:comment) { CommentService.new(bob).create(post.id, "hi") }
|
||||||
|
|
||||||
|
it "returns comment" do
|
||||||
|
result = CommentService.new(bob).find!(comment.guid)
|
||||||
|
expect(result.id).to eq(comment.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises exception the comment does not exist" do
|
||||||
|
expect {
|
||||||
|
CommentService.new(bob).find!("unknown id")
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#destroy" do
|
describe "#destroy" do
|
||||||
let(:comment) { CommentService.new(bob).create(post.id, "hi") }
|
let(:comment) { CommentService.new(bob).create(post.id, "hi") }
|
||||||
|
|
||||||
|
|
@ -58,6 +73,32 @@ describe CommentService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#destroy!" do
|
||||||
|
let(:comment) { CommentService.new(bob).create(post.id, "hi") }
|
||||||
|
|
||||||
|
it "lets the user destroy his own comment" do
|
||||||
|
result = CommentService.new(bob).destroy!(comment.guid)
|
||||||
|
expect(result).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lets the parent author destroy others comment" do
|
||||||
|
result = CommentService.new(alice).destroy!(comment.guid)
|
||||||
|
expect(result).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not let someone destroy others comment" do
|
||||||
|
expect {
|
||||||
|
CommentService.new(eve).destroy!(comment.guid)
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises exception the comment does not exist" do
|
||||||
|
expect {
|
||||||
|
CommentService.new(bob).destroy!("unknown id")
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#find_for_post" do
|
describe "#find_for_post" do
|
||||||
context "with user" do
|
context "with user" do
|
||||||
it "returns comments for a public post" do
|
it "returns comments for a public post" do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue