Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Candidate Detail endpoint to CandidateAPI #9614

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions app/controllers/candidate_api/candidates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class CandidatesController < ApplicationAPIController

rescue_from ActionController::ParameterMissing, with: :parameter_missing
rescue_from ParameterInvalid, with: :parameter_invalid
rescue_from ActiveRecord::RecordNotFound, with: :not_found

# Makes PG::QueryCanceled statement timeout errors appear in Skylight
# against the controller action that triggered them
Expand All @@ -19,8 +20,19 @@ class CandidatesController < ApplicationAPIController
MAX_PER_PAGE = 500

def index
serializer_index_query = serializer.index_query(updated_since: updated_since_params)

render json: {
data: serializer.serialize(paginate(serializer_index_query)),
}
end

def show
candidate_id = params[:candidate_id].gsub(/^C/, '')
candidate = serializer.find_query(candidate_id:)

render json: {
data: serializer.serialize(paginate(serializer.query)),
data: serializer.serialize([candidate]).first,
}
end

Expand All @@ -33,6 +45,10 @@ def parameter_invalid(e)
render json: { errors: [{ error: 'ParameterInvalid', message: e }] }, status: :unprocessable_entity
end

def not_found(_e)
render json: { errors: [{ error: 'NotFound', message: 'Unable to find Candidate' }] }, status: :not_found
end

def statement_timeout
render json: {
errors: [
Expand Down Expand Up @@ -83,11 +99,11 @@ def page
def serializer
@serializer ||=
if version_param == 'v1.3'
CandidateAPI::Serializers::V13.new(updated_since: updated_since_params)
CandidateAPI::Serializers::V13.new
elsif version_param == 'v1.2'
CandidateAPI::Serializers::V12.new(updated_since: updated_since_params)
CandidateAPI::Serializers::V12.new
else
CandidateAPI::Serializers::V11.new(updated_since: updated_since_params)
CandidateAPI::Serializers::V11.new
end
end

Expand Down
6 changes: 0 additions & 6 deletions app/services/candidate_api/serializers/base.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
module CandidateAPI
module Serializers
class Base
attr_reader :updated_since

def initialize(updated_since:)
@updated_since = updated_since
end

def serialize(candidates)
candidates.map do |candidate|
{
Expand Down
11 changes: 10 additions & 1 deletion app/services/candidate_api/serializers/v1_1.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module CandidateAPI
module Serializers
class V11 < Base
def query
def index_query(updated_since:)
Candidate
.left_outer_joins(:application_forms)
.where(application_forms: { recruitment_cycle_year: RecruitmentCycle.current_year })
Expand All @@ -11,6 +11,15 @@ def query
.where('candidate_api_updated_at > ?', updated_since)
.order('candidates.candidate_api_updated_at DESC')
end

def find_query(candidate_id:)
Candidate
.left_outer_joins(:application_forms)
.where(application_forms: { recruitment_cycle_year: RecruitmentCycle.current_year })
.or(Candidate.where('candidates.created_at > ? ', CycleTimetable.apply_deadline(RecruitmentCycle.previous_year)))
.includes(application_forms: :application_choices)
.find(candidate_id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SELECT "candidates".*
FROM "candidates"
LEFT OUTER JOIN "application_forms" ON "application_forms"."candidate_id" = "candidates"."id"
WHERE ("application_forms"."recruitment_cycle_year" = 2024 
    OR "candidates".created_at > '2023-09-19 17:00:00')
  AND "candidates"."id" = 2452
LIMIT 1

Just posting the query to help my future me.

end
end
end
end
12 changes: 10 additions & 2 deletions app/services/candidate_api/serializers/v1_2.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module CandidateAPI
module Serializers
class V12 < Base
class V12 < V11
def serialize(candidates)
super.map do |candidate|
candidate[:attributes][:application_forms].each do |form|
Expand All @@ -17,7 +17,7 @@ def serialize(candidates)
end
end

def query
def index_query(updated_since:)
Candidate
.left_outer_joins(application_forms: { application_choices: %i[provider course interviews], application_references: [], application_qualifications: [] })
.includes(application_forms: { application_choices: %i[provider course course_option interviews], application_qualifications: [], application_references: [] })
Expand All @@ -27,6 +27,14 @@ def query
.distinct
end

def find_query(candidate_id:)
Candidate
.left_outer_joins(application_forms: { application_choices: %i[provider course interviews], application_references: [], application_qualifications: [] })
.includes(application_forms: { application_choices: %i[provider course course_option interviews], application_qualifications: [], application_references: [] })
.where('application_forms.recruitment_cycle_year = ? OR candidates.created_at > ?', RecruitmentCycle.current_year, CycleTimetable.apply_deadline(RecruitmentCycle.previous_year))
.find(candidate_id)
end

private

def serialize_application_choices(application_form)
Expand Down
28 changes: 1 addition & 27 deletions app/services/candidate_api/serializers/v1_3.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,6 @@
module CandidateAPI
module Serializers
class V13 < Base
def serialize(candidates)
super.map do |candidate|
candidate[:attributes][:application_forms].each do |form|
application_form = ApplicationForm.find(form[:id])
form.merge!(
application_choices: serialize_application_choices(application_form),
references: serialize_references(application_form),
qualifications: serialize_qualifications(application_form),
personal_statement: serialize_personal_statement(application_form),
)
end

candidate
end
end

def query
Candidate
.left_outer_joins(application_forms: { application_choices: %i[provider course interviews], application_references: [], application_qualifications: [] })
.includes(application_forms: { application_choices: %i[provider course course_option interviews], application_qualifications: [], application_references: [] })
.where('candidates.updated_at > :updated_since OR application_forms.updated_at > :updated_since OR application_choices.updated_at > :updated_since OR "references".updated_at > :updated_since OR application_qualifications.updated_at > :updated_since', updated_since:)
.where('application_forms.recruitment_cycle_year = ? OR candidates.created_at > ?', RecruitmentCycle.current_year, CycleTimetable.apply_deadline(RecruitmentCycle.previous_year))
.order(id: :asc)
.distinct
end
Comment on lines -3 to -28
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was an exact copy of the V12 implementation


class V13 < V12
private

def serialize_application_choices(application_form)
Expand Down
53 changes: 53 additions & 0 deletions config/candidate_api/v1.1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,38 @@ paths:
"$ref": "#/components/responses/Unauthorized"
'422':
"$ref": "#/components/responses/UnprocessableEntity"
"/candidates/{candidate_id}":
get:
summary: Get a single candidate
parameters:
- in: path
name: candidate_id
schema:
type: string
example: C1234
required: true
description: The candidate’s id
responses:
'200':
description: Candidate data
content:
application/json:
schema:
"$ref": "#/components/schemas/CandidateDetail"
'401':
"$ref": "#/components/responses/Unauthorized"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/UnprocessableEntity"
components:
responses:
NotFound:
description: Record not found
content:
application/json:
schema:
"$ref": "#/components/schemas/NotFoundResponse"
Unauthorized:
description: Unauthorized
content:
Expand Down Expand Up @@ -81,6 +111,14 @@ components:
type: array
items:
"$ref": "#/components/schemas/Candidate"
CandidateDetail:
type: object
additionalProperties: false
required:
- data
properties:
data:
"$ref": "#/components/schemas/Candidate"
Candidate:
type: object
additionalProperties: false
Expand Down Expand Up @@ -186,6 +224,21 @@ components:
format: date-time
description: Time of last change
example: 2021-05-20T12:34:00Z
NotFoundResponse:
type: object
additionalProperties: false
required:
- errors
properties:
errors:
type: array
minItems: 1
description: Error objects describing the problem
items:
"$ref": "#/components/schemas/Error"
example:
- error: NotFound
message: Unable to find Candidate
UnauthorizedResponse:
type: object
additionalProperties: false
Expand Down
53 changes: 53 additions & 0 deletions config/candidate_api/v1.2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,38 @@ paths:
"$ref": "#/components/responses/Unauthorized"
'422':
"$ref": "#/components/responses/UnprocessableEntity"
"/candidates/{candidate_id}":
get:
summary: Get a single candidate
parameters:
- in: path
name: candidate_id
schema:
type: string
example: C1234
required: true
description: The candidate’s id
responses:
'200':
description: Candidate data
content:
application/json:
schema:
"$ref": "#/components/schemas/CandidateDetail"
'401':
"$ref": "#/components/responses/Unauthorized"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/UnprocessableEntity"
components:
responses:
NotFound:
description: Record not found
content:
application/json:
schema:
"$ref": "#/components/schemas/NotFoundResponse"
Unauthorized:
description: Unauthorized
content:
Expand Down Expand Up @@ -81,6 +111,14 @@ components:
type: array
items:
"$ref": "#/components/schemas/Candidate"
CandidateDetail:
type: object
additionalProperties: false
required:
- data
properties:
data:
"$ref": "#/components/schemas/Candidate"
Candidate:
type: object
additionalProperties: false
Expand Down Expand Up @@ -424,6 +462,21 @@ components:
example:
- error: Unauthorized
message: Please provide a valid authentication token
NotFoundResponse:
type: object
additionalProperties: false
required:
- errors
properties:
errors:
type: array
minItems: 1
description: Error objects describing the problem
items:
"$ref": "#/components/schemas/Error"
example:
- error: NotFound
message: Unable to find Candidate
ParameterMissingResponse:
type: object
additionalProperties: false
Expand Down
53 changes: 53 additions & 0 deletions config/candidate_api/v1.3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,38 @@ paths:
"$ref": "#/components/responses/Unauthorized"
'422':
"$ref": "#/components/responses/UnprocessableEntity"
"/candidates/{candidate_id}":
get:
summary: Get a single candidate
parameters:
- in: path
name: candidate_id
schema:
type: string
example: C1234
required: true
description: The candidate’s id
responses:
'200':
description: Candidate data
content:
application/json:
schema:
"$ref": "#/components/schemas/CandidateDetail"
'401':
"$ref": "#/components/responses/Unauthorized"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/UnprocessableEntity"
components:
responses:
NotFound:
description: Record not found
content:
application/json:
schema:
"$ref": "#/components/schemas/NotFoundResponse"
Unauthorized:
description: Unauthorized
content:
Expand Down Expand Up @@ -81,6 +111,14 @@ components:
type: array
items:
"$ref": "#/components/schemas/Candidate"
CandidateDetail:
type: object
additionalProperties: false
required:
- data
properties:
data:
"$ref": "#/components/schemas/Candidate"
Candidate:
type: object
additionalProperties: false
Expand Down Expand Up @@ -430,6 +468,21 @@ components:
example:
- error: Unauthorized
message: Please provide a valid authentication token
NotFoundResponse:
type: object
additionalProperties: false
required:
- errors
properties:
errors:
type: array
minItems: 1
description: Error objects describing the problem
items:
"$ref": "#/components/schemas/Error"
example:
- error: NotFound
message: Unable to find Candidate
ParameterMissingResponse:
type: object
additionalProperties: false
Expand Down
1 change: 1 addition & 0 deletions config/routes/api/candidate.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defaults api_version: CandidateAPISpecification::CURRENT_VERSION do
namespace :candidate_api, path: 'candidate-api(/:api_version)', api_version: /v[.0-9]+/, constraints: ValidCandidateApiRoute do
get '/candidates' => 'candidates#index'
get '/candidates/:candidate_id' => 'candidates#show'
end
end
Loading
Loading