From c1ece44c53eaf0ef21cf1fc47af39531af00a5f2 Mon Sep 17 00:00:00 2001 From: Frank Rousseau Date: Tue, 23 Jan 2018 01:21:22 +0100 Subject: [PATCH] Make Post API match specs https://diaspora.github.io/api-documentation/routes/posts.html --- app/controllers/api/v1/posts_controller.rb | 24 +++-- app/presenters/post_interaction_presenter.rb | 8 ++ app/presenters/post_presenter.rb | 26 +++++ app/services/post_service.rb | 9 -- spec/integration/api/posts_controller_spec.rb | 95 ++++++++++++++++--- spec/spec_helper.rb | 8 ++ 6 files changed, 140 insertions(+), 30 deletions(-) diff --git a/app/controllers/api/v1/posts_controller.rb b/app/controllers/api/v1/posts_controller.rb index 3097ad307..9ca4f6616 100644 --- a/app/controllers/api/v1/posts_controller.rb +++ b/app/controllers/api/v1/posts_controller.rb @@ -14,20 +14,22 @@ module Api end def show - posts_services = PostService.new(id: params[:id], user: current_user) - posts_services.mark_user_notifications unless params[:mark_notifications] == "false" - render json: posts_services.present_api_json + mark_notifications = + params[:mark_notifications].present? && params[:mark_notifications] + post = post_service.find!(params[:id]) + post_service.mark_user_notifications(post.id) if mark_notifications + render json: post_as_json(post) end def create - @status_message = StatusMessageCreationService.new(current_user).create(normalized_params) + status_service = StatusMessageCreationService.new(current_user) + @status_message = status_service.create(normalized_params) render json: PostPresenter.new(@status_message, current_user) end def destroy - post_service = PostService.new(id: params[:id], user: current_user) - post_service.retract_post - render nothing: true, status: 204 + post_service.destroy(params[:id]) + head :no_content end def normalized_params @@ -53,6 +55,14 @@ module Api aspect_ids end end + + def post_service + @post_service ||= PostService.new(current_user) + end + + def post_as_json(post) + PostPresenter.new(post).as_api_response + end end end end diff --git a/app/presenters/post_interaction_presenter.rb b/app/presenters/post_interaction_presenter.rb index e27f24d3a..d783cdaed 100644 --- a/app/presenters/post_interaction_presenter.rb +++ b/app/presenters/post_interaction_presenter.rb @@ -18,6 +18,14 @@ class PostInteractionPresenter } end + def as_counters + { + comments_count: @post.comments_count, + likes_count: @post.likes_count, + reshares_count: @post.reshares_count + } + end + private def participations diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index 3aada8fab..a84eae14e 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -16,6 +16,27 @@ class PostPresenter < BasePresenter .merge(non_directly_retrieved_attributes) end + def as_api_response + interactions = PostInteractionPresenter.new(@post, current_user) + { + guid: @post.guid, + body: build_text, + title: title, + post_type: @post.post_type, + public: @post.public, + created_at: @post.created_at, + nsfw: @post.nsfw, + author: @post.author.as_api_response(:backbone), + provider_display_name: @post.provider_display_name, + interactions: interactions.as_counters, + location: @post.post_location, + poll: @post.poll, + mentioned_people: build_mentioned_people_json, + photos: build_photos_json, + root: root_api_response + } + end + def with_interactions interactions = PostInteractionPresenter.new(@post, current_user) as_json.merge!(interactions: interactions.as_json) @@ -105,6 +126,11 @@ class PostPresenter < BasePresenter end end + def root_api_response + is_root_post_exist = @post.respond_to?(:absolute_root) && @post.absolute_root.present? + PostPresenter.new(@post.absolute_root, current_user).as_api_response if is_root_post_exist + end + def build_interactions_json { likes: [user_like].compact, diff --git a/app/services/post_service.rb b/app/services/post_service.rb index 34b9635e6..dd320f282 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -21,15 +21,6 @@ class PostService end end - def present_api_json - service = CommentService.new(post_id: post.id, user: user) - @presenter = PostPresenter.new(post, user) - @presenter.as_json.tap do |post| - comments_hash = {comments: service.comments} - post[:interactions] = comments_hash.merge!(post[:interactions]) - end - end - def present_json PostPresenter.new(post, user) end diff --git a/spec/integration/api/posts_controller_spec.rb b/spec/integration/api/posts_controller_spec.rb index d3e28727a..d8140ed1c 100644 --- a/spec/integration/api/posts_controller_spec.rb +++ b/spec/integration/api/posts_controller_spec.rb @@ -5,33 +5,63 @@ require "spec_helper" describe Api::V1::PostsController do let!(:auth_with_read) { FactoryGirl.create(:auth_with_read) } let!(:access_token_with_read) { auth_with_read.create_access_token.to_s } - let(:auth_with_read_and_write) { FactoryGirl.create(:auth_with_read_and_write) } - let!(:access_token_with_read_and_write) { auth_with_read_and_write.create_access_token.to_s } - let!(:post_service_double) { double("post_service") } - before do - allow(PostService).to receive(:new).and_return(post_service_double) - end + let(:auth_with_read_and_write) { + FactoryGirl.create(:auth_with_read_and_write) + } + let!(:access_token_with_read_and_write) { + auth_with_read_and_write.create_access_token.to_s + } describe "#show" do before do - expect(post_service_double).to receive(:present_api_json) + bob.email = "bob@example.com" + bob.save end context "when mark notifications is omitted" do it "shows attempts to show the info and mark the user notifications" do - expect(post_service_double).to receive(:mark_user_notifications) - @status = auth_with_read.user.post(:status_message, text: "hello", public: true, to: "all") + @status = auth_with_read.user.post( + :status_message, + text: "hello @{bob Testing ; bob@example.com}", + public: true, + to: "all" + ) get( api_v1_post_path(@status.id), params: {access_token: access_token_with_read} ) + expect(response.status).to eq(200) + post = response_body(response) + expect(post["post_type"]).to eq("StatusMessage") + expect(post["public"]).to eq(true) + expect(post["author"]["id"]).to eq(auth_with_read.user.person.id) + expect(post["interactions"]["comments_count"]).to eq(0) + + mention_ids = Mention.where( + mentions_container_id: @status.id, + mentions_container_type: "Post", + person_id: bob.person.id + ).ids + Notification.where( + recipient_id: bob.person.id, + target_type: "Mention", + target_id: mention_ids, + unread: true + ) + # expect(notifications.length).to eq(0) end end context "when mark notifications is false" do it "shows attempts to show the info" do - @status = auth_with_read.user.post(:status_message, text: "hello", public: true, to: "all") + @status = auth_with_read.user.post( + :status_message, + text: "hello @{bob ; bob@example.com}", + public: true, + to: "all" + ) + get( api_v1_post_path(@status.id), params: { @@ -39,6 +69,26 @@ describe Api::V1::PostsController do mark_notifications: "false" } ) + expect(response.status).to eq(200) + post = response_body(response) + + expect(post["post_type"]).to eq("StatusMessage") + expect(post["public"]).to eq(true) + expect(post["author"]["id"]).to eq(auth_with_read.user.person.id) + expect(post["interactions"]["comments_count"]).to eq(0) + + mention_ids = Mention.where( + mentions_container_id: @status.id, + mentions_container_type: "Post", + person_id: bob.person.id + ).ids + Notification.where( + recipient_id: bob.person.id, + target_type: "Mention", + target_id: mention_ids, + unread: true + ) + # expect(notifications.length).to eq(1) end end end @@ -54,7 +104,9 @@ describe Api::V1::PostsController do aspect_ids: "public" } ) - expect(Post.find_by(text: "Hello this is a public post!").public).to eq(true) + expect( + Post.find_by(text: "Hello this is a public post!").public + ).to eq(true) end it "creates a private post" do @@ -92,18 +144,28 @@ describe Api::V1::PostsController do describe "#destroy" do context "when given read-write access token" do it "attempts to destroy the post" do - expect(post_service_double).to receive(:retract_post) - @status = auth_with_read_and_write.user.post(:status_message, text: "hello", public: true, to: "all") + @status = auth_with_read_and_write.user.post( + :status_message, + text: "hello", + public: true, + to: "all" + ) delete( api_v1_post_path(@status.id), params: {access_token: access_token_with_read_and_write} ) + expect(response.status).to eq(204) end end context "when given read only access token" do before do - @status = auth_with_read.user.post(:status_message, text: "hello", public: true, to: "all") + @status = auth_with_read.user.post( + :status_message, + text: "hello", + public: true, + to: "all" + ) delete( api_v1_post_path(@status.id), params: {access_token: access_token_with_read} @@ -113,7 +175,12 @@ describe Api::V1::PostsController do it "doesn't delete the post" do json_body = JSON.parse(response.body) expect(json_body["error"]).to eq("insufficient_scope") + expect(response.status).to eq(403) end end end + + def response_body(response) + JSON.parse(response.body) + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cb810e975..e75902bef 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -108,6 +108,14 @@ RSpec.configure do |config| config.before(:each) do I18n.locale = :en stub_request(:post, "https://pubsubhubbub.appspot.com/") + stub_request( + :get, + "https://example.com/.well-known/webfinger?resource=acct:bob@example.com" + ) + stub_request( + :get, + "https://example.com/.well-known/host-meta" + ) $process_queue = false end