[deploy] Introduce /api/profile_images/:username endpoint (#10547)
* Documents the new /profile-images/:username API endpoint * Introduces the /api/profile_images/:username endpoint This endpoint receives either an user or organization username as input via the URL path and returns the profile image information for that user/orgnization. * Updates the /api/profile_images/:username response Adapts the response according to the review comments: 1. Removes the cache directives 1. Tweaks how the user query is being done 1. Adds a `image_of` property to the response * Bump API version Co-authored-by: rhymes <rhymes@hey.com> Co-authored-by: Molly Struve <mollylbs@gmail.com>
This commit is contained in:
parent
9ff7f82664
commit
2b72a35d3d
6 changed files with 166 additions and 1 deletions
27
app/controllers/api/v0/profile_images_controller.rb
Normal file
27
app/controllers/api/v0/profile_images_controller.rb
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
module Api
|
||||
module V0
|
||||
class ProfileImagesController < ApiController
|
||||
def show
|
||||
not_found unless profile_image_owner
|
||||
|
||||
@profile_image_owner = profile_image_owner
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def profile_image_owner
|
||||
user || organization
|
||||
end
|
||||
|
||||
def user
|
||||
@user ||= User.registered.select(:id, :profile_image)
|
||||
.find_by(username: params[:username])
|
||||
end
|
||||
|
||||
def organization
|
||||
@organization ||= Organization.select(:id, :profile_image)
|
||||
.find_by(username: params[:username])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
5
app/views/api/v0/profile_images/show.json.jbuilder
Normal file
5
app/views/api/v0/profile_images/show.json.jbuilder
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
json.type_of "profile_image"
|
||||
|
||||
json.image_of @profile_image_owner.class.name.downcase
|
||||
json.profile_image Images::Profile.call(@profile_image_owner.profile_image_url, length: 640)
|
||||
json.profile_image_90 Images::Profile.call(@profile_image_owner.profile_image_url, length: 90)
|
||||
|
|
@ -194,6 +194,8 @@ Rails.application.routes.draw do
|
|||
get :cache
|
||||
end
|
||||
end
|
||||
|
||||
resources :profile_images, only: %i[show], param: :username
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -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.0"
|
||||
version: "0.9.1"
|
||||
termsOfService: https://dev.to/terms
|
||||
contact:
|
||||
name: DEV Team
|
||||
|
|
@ -1086,6 +1086,24 @@ components:
|
|||
user:
|
||||
$ref: "#/components/schemas/SharedUser"
|
||||
|
||||
ProfileImage:
|
||||
description: Profile image
|
||||
type: object
|
||||
properties:
|
||||
type_of:
|
||||
type: string
|
||||
enum: [profile_image]
|
||||
image_of:
|
||||
description: "Discriminates what is the type of the profile image owner (user or organization)"
|
||||
type: string
|
||||
enum: [user, organization]
|
||||
profile_image:
|
||||
type: string
|
||||
description: Profile image (640x640)
|
||||
profile_image_90:
|
||||
type: string
|
||||
description: Profile image (90x90)
|
||||
|
||||
examples:
|
||||
ErrorBadRequest:
|
||||
value:
|
||||
|
|
@ -1642,6 +1660,13 @@ components:
|
|||
profile_image: "..."
|
||||
profile_image_90: "..."
|
||||
|
||||
ProfileImage:
|
||||
value:
|
||||
type_of: profile_image
|
||||
image_of: user
|
||||
profile_image: https://res.cloudinary.com/...jpeg
|
||||
profile_image_90: https://res.cloudinary.com/...jpeg
|
||||
|
||||
tags:
|
||||
- name: articles
|
||||
description: Articles are all the posts users create on DEV
|
||||
|
|
@ -1665,6 +1690,8 @@ tags:
|
|||
description: Video articles
|
||||
- name: webhooks
|
||||
description: Webhooks are HTTP endpoints registered to receive events
|
||||
- name: profile images
|
||||
description: User or organization profile images
|
||||
|
||||
paths:
|
||||
/articles:
|
||||
|
|
@ -3080,6 +3107,48 @@ paths:
|
|||
source: |
|
||||
curl -H "api-key: API_KEY" https://dev.to/api/users/me
|
||||
|
||||
/profile_images/{username}:
|
||||
get:
|
||||
operationId: getProfileImage
|
||||
summary: User or organization profile picture
|
||||
description: |
|
||||
This endpoint allows the client to retrieve a user or organization
|
||||
profile image information by its corresponding username
|
||||
tags:
|
||||
- profile images
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
required: true
|
||||
description: Username of the user or organization
|
||||
schema:
|
||||
type: string
|
||||
example: "diogoosorio"
|
||||
responses:
|
||||
"200":
|
||||
description: The profile image
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProfileImage"
|
||||
examples:
|
||||
profile-image-success:
|
||||
$ref: "#/components/examples/ProfileImage"
|
||||
"404":
|
||||
description: Resource not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/APIError"
|
||||
examples:
|
||||
profile-image-not-found:
|
||||
$ref: "#/components/examples/ErrorNotFound"
|
||||
x-code-samples:
|
||||
- lang: Shell
|
||||
label: curl
|
||||
source: |
|
||||
curl https://dev.to/api/profile_images/diogoosorio
|
||||
|
||||
/videos:
|
||||
get:
|
||||
operationId: getArticlesWithVideo
|
||||
|
|
|
|||
|
|
@ -83,6 +83,13 @@ FactoryBot.define do
|
|||
after(:build) { |user| user.add_role(:banned) }
|
||||
end
|
||||
|
||||
trait :invited do
|
||||
after(:build) do |user|
|
||||
user.registered = false
|
||||
user.registered_at = nil
|
||||
end
|
||||
end
|
||||
|
||||
trait :ignore_mailchimp_subscribe_callback do
|
||||
after(:build) do |user|
|
||||
user.define_singleton_method(:subscribe_to_mailchimp_newsletter) {}
|
||||
|
|
|
|||
55
spec/requests/api/v0/profile_images_spec.rb
Normal file
55
spec/requests/api/v0/profile_images_spec.rb
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "Api::V0::ProfileImages", type: :request do
|
||||
describe "GET /api/profile_images/:username" do
|
||||
it "returns 404 if the username is not taken" do
|
||||
get api_profile_image_path("invalid-username")
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
|
||||
context "when the username relates to an user" do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it "returns the user profile image information" do
|
||||
get api_profile_image_path(user.username)
|
||||
|
||||
expect(response.parsed_body).to eq(
|
||||
"type_of" => "profile_image",
|
||||
"image_of" => "user",
|
||||
"profile_image" => profile_image(user.profile_image_url, 640),
|
||||
"profile_image_90" => profile_image(user.profile_image_url, 90),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the username relates to an invited user" do
|
||||
let(:user) { create(:user, :invited) }
|
||||
|
||||
it "returns a 404" do
|
||||
get api_profile_image_path(user.username)
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the username relates to an organization" do
|
||||
let(:organization) { create(:organization) }
|
||||
|
||||
it "returns the organization's profile image information" do
|
||||
get api_profile_image_path(organization.username)
|
||||
|
||||
expect(response.parsed_body).to eq(
|
||||
"type_of" => "profile_image",
|
||||
"image_of" => "organization",
|
||||
"profile_image" => profile_image(organization.profile_image_url, 640),
|
||||
"profile_image_90" => profile_image(organization.profile_image_url, 90),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def profile_image(url, length)
|
||||
Images::Profile.call(url, length: length)
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue