Skip to content

Commit

Permalink
Handle missing info details
Browse files Browse the repository at this point in the history
The omniauth hash from DfE sign in is not populating the first name and
last name fields. We require these fields when displaying who verified a
task. This commit adds a fallback to request this information from the
DSI api, if it's not present in the oauth payload.
  • Loading branch information
rjlynch committed Oct 11, 2024
1 parent abf9404 commit cf3b1ab
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module Journeys
module FurtherEducationPayments
module Provider
class OmniauthCallbackForm
include DfeSignIn::Utils

def initialize(journey_session:, auth:)
@journey_session = journey_session
@auth = auth
Expand Down Expand Up @@ -65,17 +67,46 @@ def dfe_sign_in_role_codes
end

def dfe_sign_in_first_name
auth.dig("info", "first_name")
auth.dig("info", "first_name") || dfe_sign_in_api_user&.first_name
end

def dfe_sign_in_last_name
auth.dig("info", "last_name")
auth.dig("info", "last_name") || dfe_sign_in_api_user&.last_name
end

def dfe_sign_in_email
auth.dig("info", "email")
end

class ApiUser < Struct.new(:first_name, :last_name, keyword_init: true); end

def dfe_sign_in_api_user
return @dfe_sign_in_api_user if @dfe_sign_in_api_user

ukprn = journey_session.answers.claim.school.ukprn

uri = URI(DfeSignIn.configuration.base_url)
uri.path = "/organisations/#{ukprn}/users"
uri.query = {email: dfe_sign_in_email}.to_query

response = dfe_sign_in_request(uri)

return unless response.code == "200"

data = JSON.parse(response.body)
users = data.fetch("users")
user = users.detect { |user| user["email"] == dfe_sign_in_email }

return unless user.present?

@dfe_sign_in_api_user = ApiUser.new(
first_name: user.fetch("firstName"),
last_name: user.fetch("lastName")
)
rescue JSON::ParserError, KeyError => e
raise e if Rails.env.development?
end

class StubApiUser
def initialize(params)
@params = params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
RSpec.feature "Provider verifying claims" do
before do
create(:journey_configuration, :further_education_payments_provider)
# Stub fetching name from DSI, not required for these tests
stub_request(
:get,
%r{https://example.com/organisations/.*}
).to_return(
status: 404,
body: nil
)
end

scenario "provider visits a claim without service access" do
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
require "rails_helper"

RSpec.describe Journeys::FurtherEducationPayments::Provider::OmniauthCallbackForm do
let(:school) { create(:school, ukprn: "123456") }

let(:claim) do
create(
:claim,
policy: Policies::FurtherEducationPayments,
eligibility_attributes: {
school: school
}
)
end

let(:journey_session) do
create(:further_education_payments_provider_session)
create(
:further_education_payments_provider_session,
answers: {
claim_id: claim.id
}
)
end

let(:form) do
Expand Down Expand Up @@ -30,8 +47,8 @@
"uid" => "11111",
"info" => {
"email" => "[email protected]",
"first_name" => "Seymoure",
"last_name" => "Skinner"
"first_name" => info_first_name,
"last_name" => info_last_name
},
"extra" => {
"raw_info" => {
Expand All @@ -48,47 +65,223 @@
context "with access to the service" do
let(:service_access) { true }

it "updates the session with the auth details from dfe signin" do
expect { form.save! }.to(
change(journey_session.answers, :dfe_sign_in_uid).from(nil).to("11111").and(
change(journey_session.answers, :dfe_sign_in_organisation_ukprn)
.from(nil)
.to("12345678")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_id)
.from(nil)
.to("22222")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_name)
.from(nil)
.to("Springfield Elementary")
).and(
change(journey_session.answers, :dfe_sign_in_service_access?)
.from(false)
.to(true)
).and(
change(journey_session.answers, :dfe_sign_in_role_codes)
.from([])
.to(["teacher_payments_claim_verifier"])
).and(
change(journey_session.answers, :dfe_sign_in_first_name)
.from(nil)
.to("Seymoure")
).and(
change(journey_session.answers, :dfe_sign_in_last_name)
.from(nil)
.to("Skinner")
).and(
change(journey_session.answers, :dfe_sign_in_email)
.from(nil)
.to("[email protected]")
context "when the info payload contains the user's name" do
let(:info_first_name) { "Seymoure" }
let(:info_last_name) { "Skinner" }

it "updates the session with the auth details from dfe signin" do
expect { form.save! }.to(
change(journey_session.answers, :dfe_sign_in_uid).from(nil).to("11111").and(
change(journey_session.answers, :dfe_sign_in_organisation_ukprn)
.from(nil)
.to("12345678")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_id)
.from(nil)
.to("22222")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_name)
.from(nil)
.to("Springfield Elementary")
).and(
change(journey_session.answers, :dfe_sign_in_service_access?)
.from(false)
.to(true)
).and(
change(journey_session.answers, :dfe_sign_in_role_codes)
.from([])
.to(["teacher_payments_claim_verifier"])
).and(
change(journey_session.answers, :dfe_sign_in_first_name)
.from(nil)
.to("Seymoure")
).and(
change(journey_session.answers, :dfe_sign_in_last_name)
.from(nil)
.to("Skinner")
).and(
change(journey_session.answers, :dfe_sign_in_email)
.from(nil)
.to("[email protected]")
)
)
)
end
end

context "when the info payload does not contain the user's name" do
let(:info_first_name) { nil }
let(:info_last_name) { nil }

before do
stub_request(
:get,
"https://example.com/organisations/123456/users?email=seymore.skinner%40springfield-elementary.edu"
).to_return(
status: status,
body: body.to_json
)
end

context "when the dfe api request isn't successful" do
let(:status) { 404 }
let(:body) do
{}
end

it "updates the session with the auth details from dfe signin" do
expect { form.save! }.to(
change(journey_session.answers, :dfe_sign_in_uid).from(nil).to("11111").and(
change(journey_session.answers, :dfe_sign_in_organisation_ukprn)
.from(nil)
.to("12345678")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_id)
.from(nil)
.to("22222")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_name)
.from(nil)
.to("Springfield Elementary")
).and(
change(journey_session.answers, :dfe_sign_in_service_access?)
.from(false)
.to(true)
).and(
change(journey_session.answers, :dfe_sign_in_role_codes)
.from([])
.to(["teacher_payments_claim_verifier"])
).and(
not_change(journey_session.answers, :dfe_sign_in_first_name)
.from(nil)
).and(
not_change(journey_session.answers, :dfe_sign_in_last_name)
.from(nil)
).and(
change(journey_session.answers, :dfe_sign_in_email)
.from(nil)
.to("[email protected]")
)
)
end
end

# Edge case: I don't think this can happen IRL as the user has just signed into that org!
context "when the dfe api request doesn't include the user" do
let(:status) { 200 }
let(:body) do
{
"ukprn" => "12345678",
"users" => [
{
"email" => "[email protected]",
"firstName" => "Seymoure",
"lastName" => "Skinner",
"userStatus" => 1,
"roles" => ["teacher_payments_claim_verifier"]
}
]
}
end

it "updates the session with the auth details from dfe signin" do
expect { form.save! }.to(
change(journey_session.answers, :dfe_sign_in_uid).from(nil).to("11111").and(
change(journey_session.answers, :dfe_sign_in_organisation_ukprn)
.from(nil)
.to("12345678")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_id)
.from(nil)
.to("22222")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_name)
.from(nil)
.to("Springfield Elementary")
).and(
change(journey_session.answers, :dfe_sign_in_service_access?)
.from(false)
.to(true)
).and(
change(journey_session.answers, :dfe_sign_in_role_codes)
.from([])
.to(["teacher_payments_claim_verifier"])
).and(
not_change(journey_session.answers, :dfe_sign_in_first_name)
.from(nil)
).and(
not_change(journey_session.answers, :dfe_sign_in_last_name)
.from(nil)
).and(
change(journey_session.answers, :dfe_sign_in_email)
.from(nil)
.to("[email protected]")
)
)
end
end

context "when the dfe api request is successful" do
let(:status) { 200 }
let(:body) do
{
"ukprn" => "12345678",
"users" => [
{
"email" => "[email protected]",
"firstName" => "Seymoure",
"lastName" => "Skinner",
"userStatus" => 1,
"roles" => ["teacher_payments_claim_verifier"]
}
]
}
end

it "updates the session with the auth details from dfe signin" do
expect { form.save! }.to(
change(journey_session.answers, :dfe_sign_in_uid).from(nil).to("11111").and(
change(journey_session.answers, :dfe_sign_in_organisation_ukprn)
.from(nil)
.to("12345678")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_id)
.from(nil)
.to("22222")
).and(
change(journey_session.answers, :dfe_sign_in_organisation_name)
.from(nil)
.to("Springfield Elementary")
).and(
change(journey_session.answers, :dfe_sign_in_service_access?)
.from(false)
.to(true)
).and(
change(journey_session.answers, :dfe_sign_in_role_codes)
.from([])
.to(["teacher_payments_claim_verifier"])
).and(
change(journey_session.answers, :dfe_sign_in_first_name)
.from(nil)
.to("Seymoure")
).and(
change(journey_session.answers, :dfe_sign_in_last_name)
.from(nil)
.to("Skinner")
).and(
change(journey_session.answers, :dfe_sign_in_email)
.from(nil)
.to("[email protected]")
)
)
end
end
end
end

context "without access to the service" do
let(:service_access) { false }
let(:info_first_name) { "Seymoure" }
let(:info_last_name) { "Skinner" }

it "sets the service access flag to false" do
expect { form.save! }.to(
Expand Down

0 comments on commit cf3b1ab

Please sign in to comment.