feat(api particulier): add MESRI adapter
This commit is contained in:
parent
5097e78b45
commit
3d81d4b541
7 changed files with 386 additions and 0 deletions
|
@ -5,6 +5,7 @@ class APIParticulier::API
|
||||||
COMPOSITION_FAMILIALE_RESOURCE_NAME = "v2/composition-familiale"
|
COMPOSITION_FAMILIALE_RESOURCE_NAME = "v2/composition-familiale"
|
||||||
AVIS_IMPOSITION_RESOURCE_NAME = "v2/avis-imposition"
|
AVIS_IMPOSITION_RESOURCE_NAME = "v2/avis-imposition"
|
||||||
SITUATION_POLE_EMPLOI = "v2/situations-pole-emploi"
|
SITUATION_POLE_EMPLOI = "v2/situations-pole-emploi"
|
||||||
|
ETUDIANTS_RESOURCE_NAME = "v2/etudiants"
|
||||||
|
|
||||||
TIMEOUT = 20
|
TIMEOUT = 20
|
||||||
|
|
||||||
|
@ -34,6 +35,16 @@ class APIParticulier::API
|
||||||
get(SITUATION_POLE_EMPLOI, identifiant: identifiant)
|
get(SITUATION_POLE_EMPLOI, identifiant: identifiant)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def etudiants(ine)
|
||||||
|
# NOTE: Paramètres d'appel mutuellement exclusifs,
|
||||||
|
# l'appel par INE est réservé aux acteurs de la sphère de l'enseignement
|
||||||
|
# - INE, l'Identifiant National Étudiant
|
||||||
|
# - état civil, constitué du nom, prénom, date de naissance, sexe et lieu de naissance
|
||||||
|
|
||||||
|
# TODO: ajouter le support de l'état civil
|
||||||
|
get(ETUDIANTS_RESOURCE_NAME, ine: ine)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def get(resource_name, params = {})
|
def get(resource_name, params = {})
|
||||||
|
|
48
app/lib/api_particulier/mesri_adapter.rb
Normal file
48
app/lib/api_particulier/mesri_adapter.rb
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
class APIParticulier::MesriAdapter
|
||||||
|
class InvalidSchemaError < ::StandardError
|
||||||
|
def initialize(errors)
|
||||||
|
super(errors.map(&:to_json).join("\n"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(api_particulier_token, ine, requested_sources)
|
||||||
|
@api = APIParticulier::API.new(api_particulier_token)
|
||||||
|
@ine = ine
|
||||||
|
@requested_sources = requested_sources
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_params
|
||||||
|
@api.etudiants(@ine)
|
||||||
|
.tap { |d| ensure_valid_schema!(d) }
|
||||||
|
.then { |d| extract_requested_sources(d) }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensure_valid_schema!(data)
|
||||||
|
if !schemer.valid?(data)
|
||||||
|
errors = schemer.validate(data).to_a
|
||||||
|
raise InvalidSchemaError.new(errors)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def schemer
|
||||||
|
@schemer ||= JSONSchemer.schema(Rails.root.join('app/schemas/etudiants.json'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_requested_sources(data)
|
||||||
|
@requested_sources['mesri']&.map do |(scope, sources)|
|
||||||
|
case scope
|
||||||
|
when 'inscriptions'
|
||||||
|
{ scope => data[scope].filter_map { |d| d.slice(*sources) if d.key?('dateDebutInscription') } }
|
||||||
|
when 'admissions'
|
||||||
|
{ scope => data['inscriptions'].filter_map { |d| d.slice(*sources) if d.key?('dateDebutAdmission') } }
|
||||||
|
when 'etablissements'
|
||||||
|
{ scope => data['inscriptions'].map { |d| d['etablissement'].slice(*sources) }.uniq }
|
||||||
|
else
|
||||||
|
{ scope => data.slice(*sources) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
&.flatten&.reduce(&:deep_merge) || {}
|
||||||
|
end
|
||||||
|
end
|
57
app/schemas/etudiants.json
Normal file
57
app/schemas/etudiants.json
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "http://demarches-simplifiees.fr/etudiants.schema.json",
|
||||||
|
"title": "statut étudiant",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ine": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nom": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"prenom": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dateNaissance": {
|
||||||
|
"format": "date",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"inscriptions": {
|
||||||
|
"type": "array",
|
||||||
|
"items" : {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"dateDebutInscription": {
|
||||||
|
"format": "date",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dateFinInscription": {
|
||||||
|
"format": "date",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"statut": {
|
||||||
|
"enum": ["admis", "inscrit"]
|
||||||
|
},
|
||||||
|
"regime": {
|
||||||
|
"enum": ["formation initiale", "formation continue"]
|
||||||
|
},
|
||||||
|
"codeCommune": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"etablissement": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"uai": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nom": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
spec/fixtures/cassettes/api_particulier/success/etudiants.yml
vendored
Normal file
83
spec/fixtures/cassettes/api_particulier/success/etudiants.yml
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
---
|
||||||
|
http_interactions:
|
||||||
|
- request:
|
||||||
|
method: get
|
||||||
|
uri: https://particulier.api.gouv.fr/api/v2/etudiants?ine=090601811AB
|
||||||
|
body:
|
||||||
|
encoding: US-ASCII
|
||||||
|
string: ''
|
||||||
|
headers:
|
||||||
|
User-Agent:
|
||||||
|
- demarches-simplifiees.fr
|
||||||
|
Accept:
|
||||||
|
- application/json
|
||||||
|
X-Api-Key:
|
||||||
|
- c6d23f3900b8fb4b3586c4804c051af79062f54b
|
||||||
|
Expect:
|
||||||
|
- ''
|
||||||
|
response:
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
headers:
|
||||||
|
Date:
|
||||||
|
- Tue, 16 Mar 2021 17:01:19 GMT
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
Content-Length:
|
||||||
|
- '805'
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Keep-Alive:
|
||||||
|
- timeout=5
|
||||||
|
Access-Control-Allow-Credentials:
|
||||||
|
- 'true'
|
||||||
|
Access-Control-Expose-Headers:
|
||||||
|
- Range,Content-Range,X-Content-Range,X-API-Key
|
||||||
|
Etag:
|
||||||
|
- W/"2eb-A0NiRd+gbJKIAT0y4tR4j9tjXb0"
|
||||||
|
Server:
|
||||||
|
- nginx
|
||||||
|
Strict-Transport-Security:
|
||||||
|
- max-age=15552000
|
||||||
|
- max-age=15552000
|
||||||
|
Vary:
|
||||||
|
- Origin, Accept
|
||||||
|
X-Gravitee-Request-Id:
|
||||||
|
- 7bfb7f99-ac2d-4443-bb7f-99ac2d0443c5
|
||||||
|
X-Gravitee-Transaction-Id:
|
||||||
|
- f5dca8b3-2ab7-4c9a-9ca8-b32ab70c9a2b
|
||||||
|
body:
|
||||||
|
encoding: ASCII-8BIT
|
||||||
|
string: '{
|
||||||
|
"ine": "090601811AB",
|
||||||
|
"nom": "DUBOIS",
|
||||||
|
"prenom": "Angela Claire Louise",
|
||||||
|
"dateNaissance": "1962-08-24",
|
||||||
|
"inscriptions": [
|
||||||
|
{
|
||||||
|
"statut": "admis",
|
||||||
|
"regime": "formation continue",
|
||||||
|
"dateDebutAdmission": "2021-09-01T00:00:00.000Z",
|
||||||
|
"dateFinAdmission": "2022-08-31T00:00:00.000Z",
|
||||||
|
"etablissement": {
|
||||||
|
"uai": "0751722P",
|
||||||
|
"nom": "Université Pierre et Marie Curie - UPCM (Paris 6)"
|
||||||
|
},
|
||||||
|
"codeCommune": "75106"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"statut": "inscrit",
|
||||||
|
"regime": "formation continue",
|
||||||
|
"dateDebutInscription": "2022-09-01",
|
||||||
|
"dateFinInscription": "2023-08-31",
|
||||||
|
"etablissement": {
|
||||||
|
"uai": "0751722P",
|
||||||
|
"nom": "Université Pierre et Marie Curie - UPCM (Paris 6)"
|
||||||
|
},
|
||||||
|
"codeCommune": "75106"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
recorded_at: Tue, 16 Mar 2021 17:01:18 GMT
|
||||||
|
recorded_with: VCR 6.0.0
|
83
spec/fixtures/cassettes/api_particulier/success/etudiants_invalid.yml
vendored
Normal file
83
spec/fixtures/cassettes/api_particulier/success/etudiants_invalid.yml
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
---
|
||||||
|
http_interactions:
|
||||||
|
- request:
|
||||||
|
method: get
|
||||||
|
uri: https://particulier.api.gouv.fr/api/v2/etudiants?ine=090601811AB
|
||||||
|
body:
|
||||||
|
encoding: US-ASCII
|
||||||
|
string: ''
|
||||||
|
headers:
|
||||||
|
User-Agent:
|
||||||
|
- demarches-simplifiees.fr
|
||||||
|
Accept:
|
||||||
|
- application/json
|
||||||
|
X-Api-Key:
|
||||||
|
- c6d23f3900b8fb4b3586c4804c051af79062f54b
|
||||||
|
Expect:
|
||||||
|
- ''
|
||||||
|
response:
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
headers:
|
||||||
|
Date:
|
||||||
|
- Tue, 16 Mar 2021 17:01:19 GMT
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
Content-Length:
|
||||||
|
- '806'
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Keep-Alive:
|
||||||
|
- timeout=5
|
||||||
|
Access-Control-Allow-Credentials:
|
||||||
|
- 'true'
|
||||||
|
Access-Control-Expose-Headers:
|
||||||
|
- Range,Content-Range,X-Content-Range,X-API-Key
|
||||||
|
Etag:
|
||||||
|
- W/"2eb-A0NiRd+gbJKIAT0y4tR4j9tjXb0"
|
||||||
|
Server:
|
||||||
|
- nginx
|
||||||
|
Strict-Transport-Security:
|
||||||
|
- max-age=15552000
|
||||||
|
- max-age=15552000
|
||||||
|
Vary:
|
||||||
|
- Origin, Accept
|
||||||
|
X-Gravitee-Request-Id:
|
||||||
|
- 7bfb7f99-ac2d-4443-bb7f-99ac2d0443c5
|
||||||
|
X-Gravitee-Transaction-Id:
|
||||||
|
- f5dca8b3-2ab7-4c9a-9ca8-b32ab70c9a2b
|
||||||
|
body:
|
||||||
|
encoding: ASCII-8BIT
|
||||||
|
string: '{
|
||||||
|
"ine": "090601811AB",
|
||||||
|
"nom": "DUBOIS",
|
||||||
|
"prenom": "Angela Claire Louise",
|
||||||
|
"dateNaissance": "1962-08-24",
|
||||||
|
"inscriptions": [
|
||||||
|
{
|
||||||
|
"statut": "absent",
|
||||||
|
"regime": "formation continue",
|
||||||
|
"dateDebutAdmission": "2021-09-01T00:00:00.000Z",
|
||||||
|
"dateFinAdmission": "2022-08-31T00:00:00.000Z",
|
||||||
|
"etablissement": {
|
||||||
|
"uai": "0751722P",
|
||||||
|
"nom": "Université Pierre et Marie Curie - UPCM (Paris 6)"
|
||||||
|
},
|
||||||
|
"codeCommune": "75106"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"statut": "inscrit",
|
||||||
|
"regime": "formation continue",
|
||||||
|
"dateDebutInscription": "2022-09-01",
|
||||||
|
"dateFinInscription": "2023-08-31",
|
||||||
|
"etablissement": {
|
||||||
|
"uai": "0751722P",
|
||||||
|
"nom": "Université Pierre et Marie Curie - UPCM (Paris 6)"
|
||||||
|
},
|
||||||
|
"codeCommune": "75106"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
recorded_at: Tue, 16 Mar 2021 17:01:18 GMT
|
||||||
|
recorded_with: VCR 6.0.0
|
34
spec/fixtures/files/api_particulier/etudiants.json
vendored
Normal file
34
spec/fixtures/files/api_particulier/etudiants.json
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"identifiant": {
|
||||||
|
"ine": "090601811AB"
|
||||||
|
},
|
||||||
|
"identite": {
|
||||||
|
"nom": "DUBOIS",
|
||||||
|
"prenom": "Angela Claire Louise",
|
||||||
|
"dateNaissance": "1962-08-24"
|
||||||
|
},
|
||||||
|
"admissions": [
|
||||||
|
{
|
||||||
|
"statut": "admis",
|
||||||
|
"regime": "formation continue",
|
||||||
|
"dateDebutAdmission": "2021-09-01T00:00:00.000Z",
|
||||||
|
"dateFinAdmission": "2022-08-31T00:00:00.000Z",
|
||||||
|
"codeCommune": "75106"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inscriptions": [
|
||||||
|
{
|
||||||
|
"statut": "inscrit",
|
||||||
|
"regime": "formation continue",
|
||||||
|
"dateDebutInscription": "2022-09-01",
|
||||||
|
"dateFinInscription": "2023-08-31",
|
||||||
|
"codeCommune": "75106"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"etablissements": [
|
||||||
|
{
|
||||||
|
"uai": "0751722P",
|
||||||
|
"nom": "Université Pierre et Marie Curie - UPCM (Paris 6)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
70
spec/lib/api_particulier/mesri_adapter_spec.rb
Normal file
70
spec/lib/api_particulier/mesri_adapter_spec.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
describe APIParticulier::MesriAdapter do
|
||||||
|
let(:adapter) { described_class.new(api_particulier_token, ine, requested_sources) }
|
||||||
|
|
||||||
|
before { stub_const('API_PARTICULIER_URL', 'https://particulier.api.gouv.fr/api') }
|
||||||
|
|
||||||
|
describe '#to_params' do
|
||||||
|
let(:api_particulier_token) { 'c6d23f3900b8fb4b3586c4804c051af79062f54b' }
|
||||||
|
let(:ine) { '090601811AB' }
|
||||||
|
|
||||||
|
subject { VCR.use_cassette(cassette) { adapter.to_params } }
|
||||||
|
|
||||||
|
context 'when the api answer is valid' do
|
||||||
|
let(:cassette) { 'api_particulier/success/etudiants' }
|
||||||
|
|
||||||
|
context 'when the token has all the MESRI scopes' do
|
||||||
|
context 'and all the sources are requested' do
|
||||||
|
let(:requested_sources) do
|
||||||
|
{
|
||||||
|
'mesri' => {
|
||||||
|
'identifiant' => ['ine'],
|
||||||
|
'identite' => ['nom', 'prenom', 'dateNaissance'],
|
||||||
|
'inscriptions' => ['statut', 'regime', 'dateDebutInscription', 'dateFinInscription', 'codeCommune'],
|
||||||
|
'admissions' => ['statut', 'regime', 'dateDebutAdmission', 'dateFinAdmission', 'codeCommune'],
|
||||||
|
'etablissements' => ['uai', 'nom']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:result) { JSON.parse(File.read('spec/fixtures/files/api_particulier/etudiants.json')) }
|
||||||
|
|
||||||
|
it { is_expected.to eq(result) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no sources is requested' do
|
||||||
|
let(:requested_sources) { {} }
|
||||||
|
|
||||||
|
it { is_expected.to eq({}) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when an admission statut is requested' do
|
||||||
|
let(:requested_sources) { { 'mesri' => { 'admissions' => ['statut'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to eq('admissions' => [{ 'statut' => 'admis' }]) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when an inscription statut is requested' do
|
||||||
|
let(:requested_sources) { { 'mesri' => { 'inscriptions' => ['statut'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to eq('inscriptions' => [{ 'statut' => 'inscrit' }]) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a first name is requested' do
|
||||||
|
let(:requested_sources) { { 'mesri' => { 'identite' => ['prenom'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to eq('identite' => { 'prenom' => 'Angela Claire Louise' }) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the api answer is invalid' do
|
||||||
|
let(:cassette) { 'api_particulier/success/etudiants_invalid' }
|
||||||
|
|
||||||
|
context 'when no sources is requested' do
|
||||||
|
let(:requested_sources) { {} }
|
||||||
|
|
||||||
|
it { expect { subject }.to raise_error(APIParticulier::MesriAdapter::InvalidSchemaError) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue