generated from DFE-Digital/govuk-rails-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CPDLP-3080] Add NPQ participant profiles endpoint (#1403)
* [CPDLP-3080] Add NPQ participant profiles endpoint * Fix flakey test * [CPDLP-3080] Address PR comments * [CPDLP-3080] Address PR comments
- Loading branch information
1 parent
b0261af
commit 958b929
Showing
15 changed files
with
792 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,35 @@ | ||
module API | ||
module V1 | ||
class ParticipantsController < BaseController | ||
def index = head(:method_not_allowed) | ||
include Pagination | ||
include ::API::Concerns::FilterByUpdatedSince | ||
|
||
def index | ||
render json: to_json(paginate(participants_query.participants)) | ||
end | ||
|
||
def show = head(:method_not_allowed) | ||
def change_schedule = head(:method_not_allowed) | ||
def defer = head(:method_not_allowed) | ||
def withdraw = head(:method_not_allowed) | ||
def resume = head(:method_not_allowed) | ||
def outcomes = head(:method_not_allowed) | ||
|
||
private | ||
|
||
def participants_query | ||
conditions = { lead_provider: current_lead_provider, updated_since: } | ||
|
||
::Participants::Query.new(**conditions.compact) | ||
end | ||
|
||
def participant_params | ||
params.permit(filter: %i[updated_since]) | ||
end | ||
|
||
def to_json(obj) | ||
ParticipantSerializer.render(obj, view: :v1, root: "data", lead_provider: current_lead_provider) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,35 @@ | ||
module API | ||
module V2 | ||
class ParticipantsController < BaseController | ||
def index = head(:method_not_allowed) | ||
include Pagination | ||
include ::API::Concerns::FilterByUpdatedSince | ||
|
||
def index | ||
render json: to_json(paginate(participants_query.participants)) | ||
end | ||
|
||
def show = head(:method_not_allowed) | ||
def change_schedule = head(:method_not_allowed) | ||
def defer = head(:method_not_allowed) | ||
def withdraw = head(:method_not_allowed) | ||
def resume = head(:method_not_allowed) | ||
def outcomes = head(:method_not_allowed) | ||
|
||
private | ||
|
||
def participants_query | ||
conditions = { lead_provider: current_lead_provider, updated_since: } | ||
|
||
::Participants::Query.new(**conditions.compact) | ||
end | ||
|
||
def participant_params | ||
params.permit(filter: %i[updated_since]) | ||
end | ||
|
||
def to_json(obj) | ||
ParticipantSerializer.render(obj, view: :v2, root: "data", lead_provider: current_lead_provider) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,43 @@ | ||
module API | ||
module V3 | ||
class ParticipantsController < BaseController | ||
def index = head(:method_not_allowed) | ||
include Pagination | ||
include ::API::Concerns::FilterByUpdatedSince | ||
|
||
def index | ||
render json: to_json(paginate(participants_query.participants)) | ||
end | ||
|
||
def show = head(:method_not_allowed) | ||
def change_schedule = head(:method_not_allowed) | ||
def defer = head(:method_not_allowed) | ||
def withdraw = head(:method_not_allowed) | ||
def resume = head(:method_not_allowed) | ||
def outcomes = head(:method_not_allowed) | ||
|
||
private | ||
|
||
def training_status | ||
participant_params.dig(:filter, :training_status) | ||
end | ||
|
||
def from_participant_id | ||
participant_params.dig(:filter, :from_participant_id) | ||
end | ||
|
||
def participants_query | ||
conditions = { lead_provider: current_lead_provider, updated_since:, training_status:, from_participant_id: } | ||
|
||
::Participants::Query.new(**conditions.compact) | ||
end | ||
|
||
def participant_params | ||
params.permit(:sort, filter: %i[updated_since training_status from_participant_id]) | ||
end | ||
|
||
def to_json(obj) | ||
ParticipantSerializer.render(obj, view: :v3, root: "data", lead_provider: current_lead_provider) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
module API | ||
class ParticipantSerializer < Blueprinter::Base | ||
identifier :ecf_id, name: :id | ||
field(:type) { "npq-participant" } | ||
|
||
class AttributesSerializer < Blueprinter::Base | ||
exclude :id | ||
|
||
view :v1 do | ||
field(:ecf_id, name: :participant_id) | ||
field(:full_name) | ||
field(:email) | ||
|
||
field(:npq_courses) do |object, options| | ||
applications(object, options).map { |application| application.course.identifier } | ||
end | ||
|
||
field(:funded_places) do |object, options| | ||
applications(object, options).map do |application| | ||
{ | ||
npq_course: application.course.identifier, | ||
funded_place: application.funded_place, | ||
npq_application_id: application.ecf_id, | ||
} | ||
end | ||
end | ||
|
||
field(:trn, name: :teacher_reference_number) | ||
field(:updated_at) | ||
end | ||
|
||
view :v2 do | ||
field(:email) | ||
field(:full_name) | ||
field(:trn, name: :teacher_reference_number) | ||
field(:updated_at) | ||
|
||
field(:npq_enrolments) do |object, options| | ||
applications(object, options).map do |application| | ||
{ | ||
course_identifier: application.course.identifier, | ||
schedule_identifier: application&.schedule&.identifier, | ||
cohort: application.cohort&.start_year&.to_s, | ||
npq_application_id: application.ecf_id, | ||
eligible_for_funding: application.eligible_for_funding, | ||
training_status: application.training_status, | ||
school_urn: application.school&.urn, | ||
targeted_delivery_funding_eligibility: application.targeted_delivery_funding_eligibility, | ||
funded_place: application.funded_place, | ||
} | ||
end | ||
end | ||
end | ||
|
||
view :v3 do | ||
field(:full_name) | ||
field(:trn, name: :teacher_reference_number) | ||
field(:updated_at) | ||
|
||
field(:npq_enrolments) do |object, options| | ||
applications(object, options).map do |application| | ||
{ | ||
email: object.email, | ||
course_identifier: application.course.identifier, | ||
schedule_identifier: application&.schedule&.identifier, | ||
cohort: application.cohort&.start_year&.to_s, | ||
npq_application_id: application.ecf_id, | ||
eligible_for_funding: application.eligible_for_funding, | ||
training_status: application.training_status, | ||
school_urn: application.school&.urn, | ||
targeted_delivery_funding_eligibility: application.targeted_delivery_funding_eligibility, | ||
withdrawal: withdrawal(application:, lead_provider: options[:lead_provider]), | ||
deferral: deferral(application:, lead_provider: options[:lead_provider]), | ||
created_at: application.created_at.rfc3339, | ||
funded_place: application.funded_place, | ||
} | ||
end | ||
end | ||
|
||
field(:participant_id_changes) do |object, _options| | ||
(object.participant_id_changes || []).map do |participant_id_change| | ||
{ | ||
from_participant_id: participant_id_change.from_participant.ecf_id, | ||
to_participant_id: participant_id_change.to_participant.ecf_id, | ||
changed_at: participant_id_change.created_at.rfc3339, | ||
} | ||
end | ||
end | ||
end | ||
|
||
class << self | ||
def applications(object, options) | ||
return Application.none unless options[:lead_provider] | ||
|
||
object.applications.select { |application| application.lead_provider_id == options[:lead_provider].id } | ||
end | ||
|
||
def withdrawal(application:, lead_provider:) | ||
if application.withdrawn? | ||
# We are doing this in memory to avoid running those as queries on each request | ||
latest_application_state = application | ||
.application_states.sort_by(&:created_at) | ||
.reverse! | ||
.find { |as| as.state == ApplicationState.states[:withdrawn] && as.lead_provider_id == lead_provider.id } | ||
|
||
if latest_application_state.present? | ||
{ | ||
reason: latest_application_state.reason, | ||
date: latest_application_state.created_at.rfc3339, | ||
} | ||
end | ||
end | ||
end | ||
|
||
def deferral(application:, lead_provider:) | ||
if application.deferred? | ||
# We are doing this in memory to avoid running those as queries on each request | ||
latest_application_state = application | ||
.application_states.sort_by(&:created_at) | ||
.reverse! | ||
.find { |as| as.state == ApplicationState.states[:deferred] && as.lead_provider_id == lead_provider.id } | ||
|
||
if latest_application_state.present? | ||
{ | ||
reason: latest_application_state.reason, | ||
date: latest_application_state.created_at.rfc3339, | ||
} | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
association :attributes, blueprint: AttributesSerializer do |participant| | ||
participant | ||
end | ||
|
||
%i[v1 v2 v3].each do |version| | ||
view version do | ||
association :attributes, blueprint: AttributesSerializer, view: version do |participant| | ||
participant | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
module Participants | ||
class Query | ||
include API::Concerns::Orderable | ||
|
||
attr_reader :scope, :sort | ||
|
||
def initialize(lead_provider: :ignore, updated_since: :ignore, training_status: :ignore, from_participant_id: :ignore, sort: nil) | ||
@scope = all_participants | ||
@sort = sort | ||
|
||
where_lead_provider_is(lead_provider) | ||
where_updated_since(updated_since) | ||
where_training_status_is(training_status) | ||
where_from_participant_id_is(from_participant_id) | ||
end | ||
|
||
def participants | ||
scope.order(order_by) | ||
end | ||
|
||
private | ||
|
||
def where_lead_provider_is(lead_provider) | ||
return if lead_provider == :ignore | ||
|
||
scope.merge!(Application.where(lead_provider:)) | ||
end | ||
|
||
def where_updated_since(updated_since) | ||
return if updated_since == :ignore | ||
|
||
scope.merge!(User.where(updated_at: updated_since..)) | ||
end | ||
|
||
def where_training_status_is(training_status) | ||
return unless Application.training_statuses[training_status] | ||
|
||
scope.merge!(Application.where(training_status:)) | ||
end | ||
|
||
def where_from_participant_id_is(from_participant_id) | ||
return if from_participant_id == :ignore | ||
|
||
scope.merge!(scope.joins(:participant_id_changes).merge(ParticipantIdChange.where(from_participant: User.where(ecf_id: from_participant_id)))) | ||
end | ||
|
||
def order_by | ||
sort_order(sort:, model: User, default: { created_at: :asc }) | ||
end | ||
|
||
def all_participants | ||
User | ||
.joins(:applications).merge(Application.accepted) | ||
.includes( | ||
:participant_id_changes, | ||
applications: %i[ | ||
course | ||
school | ||
cohort | ||
lead_provider | ||
application_states | ||
schedule | ||
], | ||
) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.