discourse/spec/requests/api/posts_spec.rb
Daniel Waterworth 6e161d3e75
DEV: Allow fab! without block (#24314)
The most common thing that we do with fab! is:

    fab!(:thing) { Fabricate(:thing) }

This commit adds a shorthand for this which is just simply:

    fab!(:thing)

i.e. If you omit the block, then, by default, you'll get a `Fabricate`d object using the fabricator of the same name.
2023-11-09 16:47:59 -06:00

595 lines
19 KiB
Ruby

# frozen_string_literal: true
require "swagger_helper"
RSpec.describe "posts" do
let(:"Api-Key") { Fabricate(:api_key).key }
let(:"Api-Username") { "system" }
let(:admin) { Fabricate(:admin) }
before do
Jobs.run_immediately!
sign_in(admin)
end
path "/posts.json" do
get "List latest posts across topics" do
tags "Posts"
operationId "listPosts"
parameter name: "Api-Key", in: :header, type: :string, required: true
parameter name: "Api-Username", in: :header, type: :string, required: true
parameter name: "before",
in: :query,
type: :string,
description: "Load posts with an id lower than this value. Useful for pagination.",
required: false
produces "application/json"
response "200", "latest posts" do
schema type: :object,
properties: {
latest_posts: {
type: :array,
items: {
type: :object,
properties: {
id: {
type: :integer,
},
name: {
type: :string,
},
username: {
type: :string,
},
avatar_template: {
type: :string,
},
created_at: {
type: :string,
},
cooked: {
type: :string,
},
post_number: {
type: :integer,
},
post_type: {
type: :integer,
},
updated_at: {
type: :string,
},
reply_count: {
type: :integer,
},
reply_to_post_number: {
type: %i[string null],
},
quote_count: {
type: :integer,
},
incoming_link_count: {
type: :integer,
},
reads: {
type: :integer,
},
readers_count: {
type: :integer,
},
score: {
type: :number,
},
yours: {
type: :boolean,
},
topic_id: {
type: :integer,
},
topic_slug: {
type: :string,
},
topic_title: {
type: :string,
},
topic_html_title: {
type: :string,
},
category_id: {
type: :integer,
},
display_username: {
type: :string,
},
primary_group_name: {
type: %i[string null],
},
flair_name: {
type: %i[string null],
},
flair_url: {
type: %i[string null],
},
flair_bg_color: {
type: %i[string null],
},
flair_color: {
type: %i[string null],
},
flair_group_id: {
type: %i[string null],
},
version: {
type: :integer,
},
can_edit: {
type: :boolean,
},
can_delete: {
type: :boolean,
},
can_recover: {
type: :boolean,
},
can_see_hidden_post: {
type: :boolean,
},
can_wiki: {
type: :boolean,
},
user_title: {
type: %i[string null],
},
raw: {
type: :string,
},
actions_summary: {
type: :array,
items: {
type: :object,
properties: {
id: {
type: :integer,
},
can_act: {
type: :boolean,
},
},
},
},
moderator: {
type: :boolean,
},
admin: {
type: :boolean,
},
staff: {
type: :boolean,
},
user_id: {
type: :integer,
},
hidden: {
type: :boolean,
},
trust_level: {
type: :integer,
},
deleted_at: {
type: %i[string null],
},
user_deleted: {
type: :boolean,
},
edit_reason: {
type: %i[string null],
},
can_view_edit_history: {
type: :boolean,
},
wiki: {
type: :boolean,
},
reviewable_id: {
type: %i[string null],
},
reviewable_score_count: {
type: :integer,
},
reviewable_score_pending_count: {
type: :integer,
},
},
},
},
}
let!(:post) { Fabricate(:post) }
run_test!
end
end
post "Creates a new topic, a new post, or a private message" do
tags "Posts", "Topics", "Private Messages"
operationId "createTopicPostPM"
consumes "application/json"
expected_request_schema = load_spec_schema("topic_create_request")
parameter name: :params, in: :body, schema: expected_request_schema
produces "application/json"
response "200", "post created" do
expected_response_schema = load_spec_schema("topic_create_response")
schema expected_response_schema
let(:params) { Fabricate(:post) }
it_behaves_like "a JSON endpoint", 200 do
let(:expected_response_schema) { expected_response_schema }
let(:expected_request_schema) { expected_request_schema }
end
end
end
end
path "/posts/{id}.json" do
get "Retrieve a single post" do
tags "Posts"
operationId "getPost"
consumes "application/json"
description <<~TEXT
This endpoint can be used to get the number of likes on a post using the
`actions_summary` property in the response. `actions_summary` responses
with the id of `2` signify a `like`. If there are no `actions_summary`
items with the id of `2`, that means there are 0 likes. Other ids likely
refer to various different flag types.
TEXT
expected_request_schema = nil
parameter name: :id, in: :path, schema: { type: :string }
produces "application/json"
response "200", "single post" do
expected_response_schema = load_spec_schema("post_show_response")
schema expected_response_schema
let(:id) { Fabricate(:post).id }
run_test!
it_behaves_like "a JSON endpoint", 200 do
let(:expected_response_schema) { expected_response_schema }
let(:expected_request_schema) { expected_request_schema }
end
end
end
put "Update a single post" do
tags "Posts"
operationId "updatePost"
consumes "application/json"
expected_request_schema = load_spec_schema("post_update_request")
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :params, in: :body, schema: expected_request_schema
produces "application/json"
response "200", "post updated" do
expected_response_schema = load_spec_schema("post_update_response")
schema expected_response_schema
let(:params) do
{ "post" => { "raw" => "Updated content!", "edit_reason" => "fixed typo" } }
end
let(:id) { Fabricate(:post).id }
run_test! do |response|
data = JSON.parse(response.body)
expect(data["post"]["cooked"]).to eq("<p>Updated content!</p>")
expect(data["post"]["edit_reason"]).to eq("fixed typo")
end
it_behaves_like "a JSON endpoint", 200 do
let(:expected_response_schema) { expected_response_schema }
let(:expected_request_schema) { expected_request_schema }
end
end
end
delete "delete a single post" do
tags "Posts"
operationId "deletePost"
consumes "application/json"
expected_request_schema = load_spec_schema("post_delete_request")
parameter name: :id, in: :path, schema: { type: :integer }
parameter name: :params, in: :body, schema: expected_request_schema
produces "application/json"
response "200", "success response" do
expected_response_schema = nil
schema expected_response_schema
let(:topic) { Fabricate(:topic) }
let(:post) { Fabricate(:post, topic_id: topic.id, post_number: 3) }
let(:id) { post.id }
let(:params) { { "force_destroy" => false } }
it_behaves_like "a JSON endpoint", 200 do
let(:expected_response_schema) { expected_response_schema }
let(:expected_request_schema) { expected_request_schema }
end
end
end
end
path "/posts/{id}/replies.json" do
get "List replies to a post" do
tags "Posts"
operationId "postReplies"
consumes "application/json"
expected_request_schema = nil
parameter name: :id, in: :path, schema: { type: :string }
produces "application/json"
response "200", "post replies" do
expected_response_schema = load_spec_schema("post_replies_response")
schema expected_response_schema
fab!(:user)
fab!(:topic)
fab!(:post) { Fabricate(:post, topic: topic, user: user) }
let!(:reply) do
PostCreator.new(
user,
raw: "this is some text for my post",
topic_id: topic.id,
reply_to_post_number: post.post_number,
).create
end
let!(:id) { post.id }
it_behaves_like "a JSON endpoint", 200 do
let(:expected_response_schema) { expected_response_schema }
let(:expected_request_schema) { expected_request_schema }
end
end
end
end
path "/posts/{id}/locked.json" do
put "Lock a post from being edited" do
tags "Posts"
operationId "lockPost"
consumes "application/json"
parameter name: "Api-Key", in: :header, type: :string, required: true
parameter name: "Api-Username", in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :post_body,
in: :body,
schema: {
type: :object,
properties: {
locked: {
type: :string,
},
},
required: ["locked"],
}
produces "application/json"
response "200", "post updated" do
schema type: :object, properties: { locked: { type: :boolean } }
let(:post_body) { { locked: "true" } }
let(:id) { Fabricate(:post).id }
run_test! do |response|
data = JSON.parse(response.body)
expect(data["locked"]).to eq(true)
end
end
end
end
path "/post_actions.json" do
post "Like a post and other actions" do
tags "Posts"
operationId "performPostAction"
consumes "application/json"
parameter name: "Api-Key", in: :header, type: :string, required: true
parameter name: "Api-Username", in: :header, type: :string, required: true
parameter name: :post_body,
in: :body,
schema: {
type: :object,
properties: {
id: {
type: :integer,
},
post_action_type_id: {
type: :integer,
},
flag_topic: {
type: :boolean,
},
},
required: %w[id post_action_type_id],
}
produces "application/json"
response "200", "post updated" do
schema type: :object,
properties: {
id: {
type: :integer,
},
name: {
type: :string,
},
username: {
type: :string,
},
avatar_template: {
type: :string,
},
created_at: {
type: :string,
},
cooked: {
type: :string,
},
post_number: {
type: :integer,
},
post_type: {
type: :integer,
},
updated_at: {
type: :string,
},
reply_count: {
type: :integer,
},
reply_to_post_number: {
type: %i[string null],
},
quote_count: {
type: :integer,
},
incoming_link_count: {
type: :integer,
},
reads: {
type: :integer,
},
readers_count: {
type: :integer,
},
score: {
type: :number,
},
yours: {
type: :boolean,
},
topic_id: {
type: :integer,
},
topic_slug: {
type: :string,
},
display_username: {
type: :string,
},
primary_group_name: {
type: %i[string null],
},
flair_name: {
type: %i[string null],
},
flair_url: {
type: %i[string null],
},
flair_bg_color: {
type: %i[string null],
},
flair_color: {
type: %i[string null],
},
version: {
type: :integer,
},
can_edit: {
type: :boolean,
},
can_delete: {
type: :boolean,
},
can_recover: {
type: :boolean,
},
can_wiki: {
type: :boolean,
},
user_title: {
type: %i[string null],
},
actions_summary: {
type: :array,
items: {
type: :object,
properties: {
id: {
type: :integer,
},
count: {
type: :integer,
},
acted: {
type: :boolean,
},
can_undo: {
type: :boolean,
},
},
},
},
moderator: {
type: :boolean,
},
admin: {
type: :boolean,
},
staff: {
type: :boolean,
},
user_id: {
type: :integer,
},
hidden: {
type: :boolean,
},
trust_level: {
type: :integer,
},
deleted_at: {
type: %i[string null],
},
user_deleted: {
type: :boolean,
},
edit_reason: {
type: %i[string null],
},
can_view_edit_history: {
type: :boolean,
},
wiki: {
type: :boolean,
},
notice: {
type: :object,
},
reviewable_id: {
type: %i[string null],
},
reviewable_score_count: {
type: :integer,
},
reviewable_score_pending_count: {
type: :integer,
},
}
let(:id) { Fabricate(:post).id }
let(:post_body) { { id: id, post_action_type_id: 2 } }
run_test! do |response|
data = JSON.parse(response.body)
expect(data["actions_summary"][0]["id"]).to eq(2)
expect(data["actions_summary"][0]["count"]).to eq(1)
end
end
end
end
end