API: Add pagination to articles (#4483)

* Add pagination to articles

* Refactoring

* Update specs
This commit is contained in:
Nadiya Karachevska 2019-10-22 19:41:00 +03:00 committed by Ben Halpern
parent f9f7e1813b
commit 4dad407289
2 changed files with 130 additions and 68 deletions

View file

@ -1,5 +1,8 @@
class ArticleApiIndexService
attr_accessor :tag, :username, :page, :state, :top, :collection_id
attr_accessor :tag, :username, :page, :state, :top, :collection_id, :per_page
DEFAULT_PER_PAGE = 30
MAX_PER_PAGE = 1000
def initialize(params)
@page = params[:page]
@ -8,6 +11,7 @@ class ArticleApiIndexService
@state = params[:state]
@top = params[:top]
@collection_id = params[:collection_id]
@per_page = params[:per_page]
end
def get
@ -32,9 +36,9 @@ class ArticleApiIndexService
def username_articles
num = if @state == "all"
1000
MAX_PER_PAGE
else
30
DEFAULT_PER_PAGE
end
if (user = User.find_by(username: username))
@ -42,13 +46,13 @@ class ArticleApiIndexService
includes(:organization).
order("published_at DESC").
page(page).
per(num)
per(per_page || num)
elsif (organization = Organization.find_by(slug: username))
organization.articles.published.
includes(:user).
order("published_at DESC").
page(page).
per(num)
per(per_page || num)
else
Article.none
end
@ -66,12 +70,12 @@ class ArticleApiIndexService
articles.order("hotness_score DESC")
end
articles.page(page).per(30)
articles.page(page).per(per_page || DEFAULT_PER_PAGE)
end
def top_articles
Article.published.order("positive_reactions_count DESC").where("published_at > ?", top.to_i.days.ago).
page(page).per(30)
page(page).per(per_page || DEFAULT_PER_PAGE)
end
def state_articles(state)
@ -90,7 +94,7 @@ class ArticleApiIndexService
includes(:user, :organization).
order("published_at").
page(page).
per(30)
per(per_page || DEFAULT_PER_PAGE)
end
def base_articles
@ -99,6 +103,6 @@ class ArticleApiIndexService
includes(:user, :organization).
order("hotness_score DESC").
page(page).
per(30)
per(per_page || DEFAULT_PER_PAGE)
end
end

View file

@ -9,74 +9,132 @@ RSpec.describe "Api::V0::Articles", type: :request do
end
describe "GET /api/articles" do
it "returns json response" do
get api_articles_path
expect(response.content_type).to eq("application/json")
context "without params" do
it "returns json response" do
get api_articles_path
expect(response.content_type).to eq("application/json")
end
it "returns featured articles if no param is given" do
article.update_column(:featured, true)
get api_articles_path
expect(json_response.size).to eq(1)
end
it "supports pagination" do
create_list(:article, 2, featured: true)
get api_articles_path, params: { page: 1, per_page: 2 }
expect(json_response.length).to eq(2)
get api_articles_path, params: { page: 2, per_page: 2 }
expect(json_response.length).to eq(1)
end
it "returns flare tag in the response" do
get api_articles_path
response_article = JSON.parse(response.body)[0]
expect(response_article["flare_tag"]).to be_present
expect(response_article["flare_tag"].keys).to eq(%w[name bg_color_hex text_color_hex])
expect(response_article["flare_tag"]["name"]).to eq("discuss")
end
end
it "returns featured articles if no param is given" do
article.update_column(:featured, true)
get api_articles_path
expect(json_response.size).to eq(1)
context "with username param" do
it "returns user's articles for the given username" do
create(:article, user: article.user)
get api_articles_path(username: article.user.username)
expect(json_response.size).to eq(2)
end
it "returns nothing if given user is not found" do
get api_articles_path(username: "foobar")
expect(json_response.size).to eq(0)
end
it "returns org's articles if org's slug is given" do
create(:article, user: article.user, organization: organization)
get api_articles_path(username: organization.slug)
expect(json_response.size).to eq(1)
end
it "supports pagination" do
create_list(:article, 2, user: article.user)
get api_articles_path(username: article.user.username), params: { page: 1, per_page: 2 }
expect(json_response.length).to eq(2)
get api_articles_path(username: article.user.username), params: { page: 2, per_page: 2 }
expect(json_response.length).to eq(1)
end
end
it "returns user's articles for the given username" do
create(:article, user: article.user)
get api_articles_path(username: article.user.username)
expect(json_response.size).to eq(2)
context "with tag param" do
it "returns tag's articles" do
get api_articles_path(tag: article.tag_list.first)
expect(json_response.size).to eq(1)
end
it "returns top tag articles if tag and top param is present" do
get api_articles_path(tag: article.tag_list.first, top: "7")
expect(json_response.size).to eq(1)
end
it "returns not tag articles if article and tag are not approved" do
article.update_column(:approved, false)
tag = Tag.find_by(name: article.tag_list.first)
tag.update(requires_approval: true)
get api_articles_path(tag: tag.name)
expect(JSON.parse(response.body).size).to eq(0)
end
it "supports pagination" do
create_list(:article, 2, tags: "discuss")
get api_articles_path(tag: article.tag_list.first), params: { page: 1, per_page: 2 }
expect(json_response.length).to eq(2)
get api_articles_path(tag: article.tag_list.first), params: { page: 2, per_page: 2 }
expect(json_response.length).to eq(1)
end
end
it "returns nothing if given user is not found" do
get api_articles_path(username: "foobar")
expect(json_response.size).to eq(0)
context "with top param" do
it "only returns fresh top articles if top param is present" do
# TODO: slight duplication, test should be removed
old_article = create(:article)
old_article.update_column(:published_at, 10.days.ago)
get api_articles_path(top: "7")
expect(json_response.size).to eq(1)
end
it "supports pagination" do
old_articles = create_list(:article, 2, featured: true)
old_articles.each do |old_article|
old_article.update_column(:published_at, 10.days.ago)
end
get api_articles_path(top: "11"), params: { page: 1, per_page: 2 }
expect(json_response.length).to eq(2)
get api_articles_path(top: "11"), params: { page: 2, per_page: 2 }
expect(json_response.length).to eq(1)
end
end
it "returns org's articles if org's slug is given" do
create(:article, user: article.user, organization: organization)
get api_articles_path(username: organization.slug)
expect(json_response.size).to eq(1)
end
context "with collection_id param" do
it "returns a collection id" do
collection = create(:collection, user: article.user)
article.update_columns(collection_id: collection.id)
get api_articles_path(collection_id: collection.id)
expect(json_response[0]["collection_id"]).to eq collection.id
end
it "returns tag's articles" do
get api_articles_path(tag: article.tag_list.first)
expect(json_response.size).to eq(1)
end
it "returns top tag articles if tag and top param is present" do
get api_articles_path(tag: article.tag_list.first, top: "7")
expect(json_response.size).to eq(1)
end
it "only returns fresh top articles if top param is present" do
# TODO: slight duplication, test should be removed
old_article = create(:article)
old_article.update_column(:published_at, 10.days.ago)
get api_articles_path(top: "7")
expect(json_response.size).to eq(1)
end
it "returns not tag articles if article and tag are not approved" do
article.update_column(:approved, false)
tag = Tag.find_by(name: article.tag_list.first)
tag.update(requires_approval: true)
get api_articles_path(tag: tag.name)
expect(JSON.parse(response.body).size).to eq(0)
end
it "returns flare tag in the response" do
get api_articles_path
response_article = JSON.parse(response.body)[0]
expect(response_article["flare_tag"]).to be_present
expect(response_article["flare_tag"].keys).to eq(%w[name bg_color_hex text_color_hex])
expect(response_article["flare_tag"]["name"]).to eq("discuss")
end
it "returns a collection id" do
collection = create(:collection, user: article.user)
article.update_columns(collection_id: collection.id)
get api_articles_path(collection_id: collection.id)
expect(json_response[0]["collection_id"]).to eq collection.id
it "supports pagination" do
collection = create(:collection, user: article.user)
article.update_columns(collection_id: collection.id)
collection_articles = create_list(:article, 2, featured: true)
collection_articles.each do |collection_article|
collection_article.update_columns(collection_id: collection.id)
end
get api_articles_path(collection_id: collection.id), params: { page: 1, per_page: 2 }
expect(json_response.length).to eq(2)
get api_articles_path(collection_id: collection.id), params: { page: 2, per_page: 2 }
expect(json_response.length).to eq(1)
end
end
end