API: Endpoint to get an organization's users (#11514)

* add tests

* add route

* add users action to organizations controller

* add jbuilder file

* update api docs

* add recource routes

* make updates to organizations controller

* remove org_users from api docs

* update spec

* add users show jbuilder

* bug fix for user show
This commit is contained in:
Spencer 2020-11-25 03:50:57 -08:00 committed by GitHub
parent d5546d6d6b
commit de3d62bc40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 151 additions and 25 deletions

View file

@ -1,15 +1,37 @@
module Api
module V0
class OrganizationsController < ApiController
before_action :find_organization, only: %i[users]
SHOW_ATTRIBUTES_FOR_SERIALIZATION = %i[
username name summary twitter_username github_username url
location created_at profile_image tech_stack tag_line story
].freeze
private_constant :SHOW_ATTRIBUTES_FOR_SERIALIZATION
USERS_FOR_SERIALIZATION = %i[
id username name twitter_username github_username
profile_image website_url location summary created_at
].freeze
private_constant :USERS_FOR_SERIALIZATION
def show
@organization = Organization.select(SHOW_ATTRIBUTES_FOR_SERIALIZATION)
.find_by!(username: params[:org_username])
.find_by!(username: params[:username])
end
def users
per_page = (params[:per_page] || 30).to_i
num = [per_page, 1000].min
page = params[:page] || 1
@users = @organization.users.select(USERS_FOR_SERIALIZATION).page(page).per(num)
end
private
def find_organization
@organization = Organization.find_by!(username: params[:organization_username])
end
end
end

View file

@ -0,0 +1,3 @@
json.array! @users do |user|
json.partial! "api/v0/shared/user_show", user: user
end

View file

@ -0,0 +1,16 @@
json.type_of "user"
json.extract!(
user,
:id,
:username,
:name,
:summary,
:twitter_username,
:github_username,
:website_url,
:location,
)
json.joined_at user.created_at.strftime("%b %e, %Y")
json.profile_image Images::Profile.call(user.profile_image_url, length: 320)

View file

@ -1,16 +1 @@
json.type_of "user"
json.extract!(
@user,
:id,
:username,
:name,
:summary,
:twitter_username,
:github_username,
:website_url,
:location,
)
json.joined_at @user.created_at.strftime("%b %e, %Y")
json.profile_image Images::Profile.call(@user.profile_image_url, length: 320)
json.partial! "api/v0/shared/user_show", user: @user

View file

@ -203,10 +203,8 @@ Rails.application.routes.draw do
end
resources :profile_images, only: %i[show], param: :username
resources :organizations, only: [] do
collection do
get "/:org_username", to: "organizations#show"
end
resources :organizations, only: [:show], param: :username do
resources :users, only: [:index], to: "organizations#users"
end
end
end

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.2"
version: "0.9.3"
termsOfService: https://dev.to/terms
contact:
name: DEV Team
@ -1683,6 +1683,20 @@ components:
joined_at: Jan 1, 2017
profile_image: https://res.cloudinary.com/...jpeg
Users:
value:
- type_of: user
id: 1234
username: bob
name: bob
summary: Hello, world
twitter_username: bob
github_username: bob
website_url:
location: New York
joined_at: Jan 1, 2017
profile_image: https://res.cloudinary.com/...jpeg
WebhookCreate:
value:
webhook_endpoint:
@ -2986,7 +3000,7 @@ paths:
source: |
curl -H "api-key: API_KEY" https://dev.to/api/readinglist
/organizations/{org_username}:
/organizations/{username}:
get:
operationId: getOrganization
summary: An organization
@ -2995,7 +3009,7 @@ paths:
tags:
- organizations
parameters:
- name: org_username
- name: username
in: path
required: true
description: |
@ -3028,6 +3042,54 @@ paths:
source: |
curl https://dev.to/api/organizations/ecorp
/organizations/{username}/users:
get:
operationId: getOrgUsers
summary: Organization's users
description: |
This endpoint allows the client to retrieve a list of users belonging to the organization
It supports pagination, each page will contain `30` users 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/User"
examples:
user-success:
$ref: "#/components/examples/Users"
"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/users
/podcast_episodes:
get:
operationId: getPodcastEpisodes

View file

@ -10,7 +10,7 @@ RSpec.describe "Api::V0::Organizations", type: :request do
end
it "returns the correct json representation of the organization", :aggregate_failures do
get "/api/organizations/#{organization.username}"
get api_organization_path(organization.username)
response_organization = response.parsed_body
@ -25,4 +25,44 @@ RSpec.describe "Api::V0::Organizations", type: :request do
expect(response_organization["joined_at"]).to eq(organization.created_at.utc.iso8601)
end
end
describe "GET /api/organizations/:username/users" do
let!(:org_user) { create(:user, :org_member) }
let(:organization) { org_user.organizations.first }
it "returns 404 if the organizations username is not found" do
get "/api/organizations/invalid-username/users"
expect(response).to have_http_status(:not_found)
end
it "supports pagination" do
create(:organization_membership, user: create(:user), organization: organization)
get api_organization_users_path(organization.username), params: { page: 1, per_page: 1 }
expect(response.parsed_body.length).to eq(1)
get api_organization_users_path(organization.username), params: { page: 2, per_page: 1 }
expect(response.parsed_body.length).to eq(1)
get api_organization_users_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 users", :aggregate_failures do
get api_organization_users_path(organization.username)
response_org_users = response.parsed_body.first
expect(response_org_users["type_of"]).to eq("user")
%w[
id username name summary twitter_username github_username website_url location
].each do |attr|
expect(response_org_users[attr]).to eq(org_user.public_send(attr))
end
expect(response_org_users["joined_at"]).to eq(org_user.created_at.strftime("%b %e, %Y"))
expect(response_org_users["profile_image"]).to eq(Images::Profile.call(org_user.profile_image_url, length: 320))
end
end
end