API: Endpoint to get an organization's articles (#12237)

* update route

* add controller action

* add article jbuilder/update shared files

* add tests

* update api docs

* add published to query

* render articles index/delete articles jbuilder

* call articles index attributes const

* put back article/flare partials

* bug fix for readinglist index

* bug fix for render partial in jbuilder
This commit is contained in:
Spencer 2021-01-13 04:09:58 -08:00 committed by GitHub
parent 4329ea94a0
commit 27648a938b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 4 deletions

View file

@ -1,7 +1,7 @@
module Api
module V0
class OrganizationsController < ApiController
before_action :find_organization, only: %i[users listings]
before_action :find_organization, only: %i[users listings articles]
SHOW_ATTRIBUTES_FOR_SERIALIZATION = %i[
id username name summary twitter_username github_username url
@ -21,6 +21,8 @@ module Api
].freeze
private_constant :LISTINGS_FOR_SERIALIZATION
ARTICLES_FOR_SERIALIZATION = Api::V0::ArticlesController::INDEX_ATTRIBUTES_FOR_SERIALIZATION
def show
@organization = Organization.select(SHOW_ATTRIBUTES_FOR_SERIALIZATION)
.find_by!(username: params[:username])
@ -47,6 +49,22 @@ module Api
@listings = @listings.in_category(params[:category]) if params[:category].present?
end
def articles
per_page = (params[:per_page] || 30).to_i
num = [per_page, 1000].min
page = params[:page] || 1
@articles = @organization.articles.published
.select(ARTICLES_FOR_SERIALIZATION)
.includes(:user)
.order(published_at: :desc)
.page(page)
.per(num)
.decorate
render "api/v0/articles/index.json.jbuilder"
end
private
def find_organization

View file

@ -1,5 +1,5 @@
json.array! @articles do |article|
json.partial! "article", article: article
json.partial! "api/v0/articles/article", article: article
# /api/articles and /api/articles/:id have opposite representations
# of `tag_list` and `tags and we can't align them without breaking the API,
@ -16,6 +16,6 @@ json.array! @articles do |article|
flare_tag = FlareTag.new(article).tag
if flare_tag
json.partial! "flare_tag", flare_tag: flare_tag
json.partial! "api/v0/articles/flare_tag", flare_tag: flare_tag
end
end

View file

@ -204,6 +204,7 @@ Rails.application.routes.draw do
resources :organizations, only: [:show], param: :username do
resources :users, only: [:index], to: "organizations#users"
resources :listings, only: [:index], to: "organizations#listings"
resources :articles, only: [:index], to: "organizations#articles"
end
namespace :admin do

View file

@ -17,7 +17,7 @@ info:
Dates and date times, unless otherwise specified, must be in
the [RFC 3339](https://tools.ietf.org/html/rfc3339) format.
version: "0.9.4"
version: "0.9.5"
termsOfService: https://dev.to/terms
contact:
name: DEV Team
@ -3274,6 +3274,53 @@ paths:
source: |
curl https://dev.to/api/organizations/ecorp/listings
/organizations/{username}/articles:
get:
operationId: getOrgArticles
summary: Organization's Articles
description: |
This endpoint allows the client to retrieve a list of Articles belonging to the organization
It supports pagination, each page will contain `30` listing by default.
tags:
- organizations
parameters:
- name: username
in: path
required: true
description: |
Username of the organization
schema:
type: string
example: "ecorp"
- $ref: '#/components/parameters/pageParam'
- $ref: '#/components/parameters/perPageParam30to1000'
responses:
"200":
description: A list of users belonging to the organization
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ArticleIndex"
examples:
article-success:
$ref: "#/components/examples/ArticlesIndex"
"404":
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/APIError"
examples:
user-not-found:
$ref: "#/components/examples/ErrorNotFound"
x-code-samples:
- lang: Shell
label: curl
source: |
curl https://dev.to/api/organizations/ecorp/listings
/podcast_episodes:
get:

View file

@ -113,4 +113,49 @@ RSpec.describe "Api::V0::Organizations", type: :request do
end
end
end
describe "GET /api/organizations/:username/articles" do
let(:org_user) { create(:user, :org_member) }
let(:organization) { org_user.organizations.first }
let!(:article) { create(:article, user: org_user, organization: organization) }
it "returns 404 if the organizations articles is not found" do
get "/api/organizations/invalid-username/articles"
expect(response).to have_http_status(:not_found)
end
it "supports pagination" do
create(:article, organization: organization)
get api_organization_articles_path(organization.username), params: { page: 1, per_page: 1 }
expect(response.parsed_body.length).to eq(1)
get api_organization_articles_path(organization.username), params: { page: 2, per_page: 1 }
expect(response.parsed_body.length).to eq(1)
get api_organization_articles_path(organization.username), params: { page: 3, per_page: 1 }
expect(response.parsed_body.length).to eq(0)
end
it "returns the correct json representation of the organizations articles", :aggregate_failures do
get api_organization_articles_path(organization.username)
response_article = response.parsed_body.first
expect(response_article["type_of"]).to eq("article")
%w[id title slug description path public_reactions_count
positive_reactions_count comments_count published_timestamp].each do |attr|
expect(response_article[attr]).to eq(article.public_send(attr))
end
expect(response_article["tag_list"]).to match_array(article.tag_list)
%w[name username twitter_username github_username website_url].each do |attr|
expect(response_article["user"][attr]).to eq(org_user.public_send(attr))
end
%w[name username slug].each do |attr|
expect(response_article["organization"][attr]).to eq(organization.public_send(attr))
end
end
end
end