Merge pull request #6464 from betagouv/show_avalaible_sources

montre les sources disponibles pour un jeton api particulier
This commit is contained in:
LeSim 2021-09-17 14:08:23 +02:00 committed by GitHub
commit 47e3c0067c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 231 additions and 2 deletions

View file

@ -0,0 +1,26 @@
@import "constants";
#sources-particulier-form {
h2 {
margin-bottom: 0;
}
h3 {
margin-top: 2 * $default-padding;
}
.explication {
padding: $default-padding;
ul {
list-style-type: circle;
list-style-position: inside;
padding-left: $default-padding;
margin-bottom: $default-padding;
}
}
.form input[type="checkbox"] {
margin-bottom: 0;
}
}

View file

@ -21,7 +21,7 @@ module NewAdministrateur
@procedure.api_particulier_scopes = scopes
@procedure.save!
redirect_to admin_procedure_api_particulier_jeton_path(procedure_id: @procedure.id),
redirect_to admin_procedure_api_particulier_sources_path(procedure_id: @procedure.id),
notice: t('.token_ok')
end

View file

@ -0,0 +1,13 @@
module NewAdministrateur
class SourcesParticulierController < AdministrateurController
before_action :retrieve_procedure
def show
sources_service = APIParticulier::Services::SourcesService.new(@procedure)
@available_sources = sources_service.available_sources
end
def update
end
end
end

View file

@ -0,0 +1,42 @@
module APIParticulier
module Services
class SourcesService
def initialize(procedure)
@procedure = procedure
end
def available_sources
@procedure.api_particulier_scopes
.map { |provider_and_scope| raw_scopes[provider_and_scope] }
.map { |provider, scope| extract_sources(provider, scope) }
.reduce({}) { |acc, el| acc.deep_merge(el) }
end
private
def extract_sources(provider, scope)
{ provider => { scope => providers[provider][scope] } }
end
def raw_scopes
{
'cnaf_allocataires' => ['cnaf', 'allocataires'],
'cnaf_enfants' => ['cnaf', 'enfants'],
'cnaf_adresse' => ['cnaf', 'adresse'],
'cnaf_quotient_familial' => ['cnaf', 'quotient_familial']
}
end
def providers
{
'cnaf' => {
'allocataires' => ['noms_prenoms', 'date_de_naissance', 'sexe'],
'enfants' => ['noms_prenoms', 'date_de_naissance', 'sexe'],
'adresse' => ['identite', 'complement_d_identite', 'complement_d_identite_geo', 'numero_et_rue', 'lieu_dit', 'code_postal_et_ville', 'pays'],
'quotient_familial' => ['quotient_familial', 'annee', 'mois']
}
}
end
end
end
end

View file

@ -7,6 +7,7 @@
# allow_expert_review :boolean default(TRUE), not null
# api_entreprise_token :string
# api_particulier_scopes :text default([]), is an Array
# api_particulier_sources :jsonb
# ask_birthday :boolean default(FALSE), not null
# auto_archive_on :date
# cadre_juridique :string

View file

@ -18,3 +18,17 @@
%p.card-admin-title
= Procedure.human_attribute_name(:jeton_api_particulier)
%p.button= t('views.shared.actions.edit')
- if @procedure.api_particulier_scopes.present?
= link_to admin_procedure_api_particulier_sources_path, class: 'card-admin' do
- if @procedure.api_particulier_token.blank?
%div
%span.icon.clock
%p.card-admin-status-todo= t('.needs_configuration')
- else
%div
%span.icon.accept
%p.card-admin-status-accept= t('.already_configured')
%div
%p.card-admin-title= t('new_administrateur.sources_particulier.show.data_sources')
%p.button= t('views.shared.actions.edit')

View file

@ -0,0 +1,28 @@
= render partial: 'new_administrateur/breadcrumbs',
locals: { steps: [link_to('Démarches', admin_procedures_path),
link_to(@procedure.libelle, admin_procedure_path(@procedure)),
link_to(Procedure.human_attribute_name(:jeton_api_particulier), admin_procedure_api_particulier_path(@procedure)),
t('.data_sources')] }
.container
%h1.page-title= t('.title')
.container#sources-particulier-form.mb-2
= form_with model: @procedure, url: admin_procedure_api_particulier_sources_path, local: true, html: { class: 'form' } do |f|
.explication= t('.explication_html')
- @available_sources.each do |provider_key, scopes|
%h2.header-section= t("api_particulier.providers.#{provider_key}.libelle")
- scopes.each do |scope_key, sources|
%h3.explication-libelle= t("api_particulier.providers.#{provider_key}.scopes.#{scope_key}.libelle")
%ul.procedure-admin-api-particulier-sources
- sources.each do |source_key, enabled_hash|
- enabled = (@procedure.api_particulier_sources.dig(provider_key, scope_key)&.include?(source_key)).present?
%li
%label
= check_box_tag "api_particulier_sources[#{provider_key}][#{scope_key}][]", "#{source_key}", enabled
#{t("api_particulier.providers.#{provider_key}.scopes.#{scope_key}.#{source_key}")}
.text-right
= f.button t('views.shared.actions.save'), class: 'button primary send'

View file

@ -0,0 +1,30 @@
fr:
api_particulier:
providers:
cnaf:
libelle: Caisse dallocations familiales (CAF)
scopes:
personne: &personne
noms_prenoms: noms et prénoms
date_de_naissance: date de naissance
sexe: genre
allocataires:
libelle: allocataires
<<: *personne
enfants:
libelle: enfants
<<: *personne
adresse:
libelle: adresse
identite: identité
complement_d_identite: complément didentité
complement_d_identite_geo: complément didentité géographique
numero_et_rue: numéro et rue
lieu_dit: lieu-dit
code_postal_et_ville: code postal et ville
pays: pays
quotient_familial:
libelle: quotient familial
quotient_familial: quotient familial
mois: mois
annee: année

View file

@ -395,3 +395,13 @@ fr:
api_particulier:
already_configured: "Déjà rempli"
needs_configuration: "À remplir"
sources_particulier:
show:
title: "Définir les sources de données"
data_sources: "Sources de données"
explication_html: "<p>API Particulier facilite laccès des administrations aux données familiales (CAF) pour simplifier les démarches administratives mises en œuvre par les collectivités et les administrations.<br> Cela permet aux administrations daccéder à des informations certifiées à la source et ainsi : </p> <ul> <li>de saffranchir des pièces justificatives lors des démarches en ligne,</li> <li>de réduire le nombre derreurs de saisie,</li> <li>décarter le risque de fraude documentaire.</li> </ul> <p> <strong>Important&nbsp;:</strong> les disposition de l'article <a href='https://www.legifrance.gouv.fr/affichCodeArticle.do?cidTexte=LEGITEXT000031366350&amp;idArticle=LEGIARTI000031367412&amp;dateTexte=&amp;categorieLien=cid'>L144-8</a> nautorisent que léchange des informations strictement nécessaires pour traiter une démarche.<br /><br />En conséquence, ne sélectionnez ici que les données auxquelles vous aurez accès dun point de vue légal.</p>"
procedures:
show:
ready: "Validé"
needs_configuration: "À configurer"
configure_api_particulier_token: "Configurer le jeton API particulier"

View file

@ -401,6 +401,7 @@ Rails.application.routes.draw do
resource 'api_particulier', only: [] do
resource 'jeton', only: [:show, :update], controller: 'jeton_particulier'
resource 'sources', only: [:show, :update], controller: 'sources_particulier'
end
put 'clone'

View file

@ -0,0 +1,6 @@
class AddAPIParticulierSourcesToProcedure < ActiveRecord::Migration[6.0]
def change
add_column :procedures, :api_particulier_sources, :jsonb, :default => {}
add_index :procedures, :api_particulier_sources, using: :gin
end
end

View file

@ -10,7 +10,8 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_09_08_162000) do
ActiveRecord::Schema.define(version: 2021_09_08_170019) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
enable_extension "unaccent"
@ -619,6 +620,8 @@ ActiveRecord::Schema.define(version: 2021_09_08_162000) do
t.boolean "experts_require_administrateur_invitation", default: false
t.string "encrypted_api_particulier_token"
t.text "api_particulier_scopes", default: [], array: true
t.jsonb "api_particulier_sources", default: {}
t.index ["api_particulier_sources"], name: "index_procedures_on_api_particulier_sources", using: :gin
t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state"
t.index ["draft_revision_id"], name: "index_procedures_on_draft_revision_id"
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"

View file

@ -0,0 +1,21 @@
describe NewAdministrateur::SourcesParticulierController, type: :controller do
let(:admin) { create(:administrateur) }
before { sign_in(admin.user) }
describe "#show" do
let(:procedure) { create(:procedure, administrateur: admin, api_particulier_scopes: ['cnaf_enfants'], api_particulier_sources: { cnaf: { enfants: ['noms_prenoms'] } }) }
render_views
subject { get :show, params: { procedure_id: procedure.id } }
it 'renders the sources form' do
expect(subject.body).to include(I18n.t('api_particulier.providers.cnaf.scopes.enfants.date_de_naissance'))
expect(subject.body).to have_selector("input#api_particulier_sources_cnaf_enfants_[value=noms_prenoms][checked=checked]")
expect(subject.body).to have_selector("input#api_particulier_sources_cnaf_enfants_[value=date_de_naissance]")
expect(subject.body).not_to have_selector("input#api_particulier_sources_cnaf_enfants_[value=date_de_naissance][checked=checked]")
end
end
end

View file

@ -0,0 +1,34 @@
describe APIParticulier::Services::SourcesService do
describe "#sources" do
let(:service) { described_class.new(procedure) }
let(:procedure) { create(:procedure) }
let(:api_particulier_scopes) { [] }
let(:api_particulier_sources) { {} }
before do
procedure.update(api_particulier_scopes: api_particulier_scopes)
procedure.update(api_particulier_sources: api_particulier_sources)
end
subject { service.available_sources }
context 'when the procedure doesnt have any available scopes' do
it { is_expected.to eq({}) }
end
context 'when a procedure has a cnaf_allocataires and a cnaf_adresse scopes' do
let(:api_particulier_scopes) { ['cnaf_allocataires', 'cnaf_enfants'] }
let(:cnaf_allocataires_and_enfants) do
{
'cnaf' => {
'allocataires' => ['noms_prenoms', 'date_de_naissance', 'sexe'],
'enfants' => ['noms_prenoms', 'date_de_naissance', 'sexe']
}
}
end
it { is_expected.to match(cnaf_allocataires_and_enfants) }
end
end
end