Skip to content

Commit a03ac1b

Browse files
authored
Merge pull request #11836 from mfo/US/authen-api-referentiel
ETQ administrateur, je souhaite pouvoir utiliser le champ referentiel avancé (à configurer) avec une API qui requiert un token d'authentification (type: Authorization: Bearer XXX)
2 parents 988c7ec + a19d39e commit a03ac1b

30 files changed

+753
-501
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ gem 'i18n-tasks', require: false
5757
gem 'iban-tools'
5858
gem 'image_processing'
5959
gem 'invisible_captcha'
60+
gem 'jsonpath'
6061
gem 'json_schemer'
6162
gem 'jwt'
6263
gem 'kaminari'

Gemfile.lock

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ GEM
415415
regexp_parser (~> 2.0)
416416
simpleidn (~> 0.2)
417417
jsonapi-renderer (0.2.2)
418+
jsonpath (1.1.5)
419+
multi_json
418420
jwt (2.10.1)
419421
base64
420422
kaminari (1.2.2)
@@ -963,7 +965,6 @@ PLATFORMS
963965
arm-linux-gnu
964966
arm-linux-musl
965967
arm64-darwin
966-
ruby
967968
x86-linux-gnu
968969
x86-linux-musl
969970
x86_64-darwin
@@ -1036,6 +1037,7 @@ DEPENDENCIES
10361037
invisible_captcha
10371038
irb
10381039
json_schemer
1040+
jsonpath
10391041
jwt
10401042
kaminari
10411043
kredis

app/components/dsfr/input_errorable.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def input_group_error_class_names
2323

2424
{
2525
"#{dsfr_group_classname}--error" => errors_on_attribute?,
26-
"#{dsfr_group_classname}--valid" => !errors_on_attribute? && errors_on_another_attribute? && object.public_send(attribute).present?
26+
"#{dsfr_group_classname}--valid" => !errors_on_attribute? && errors_on_another_attribute? && object.try(attribute).present?
2727
}
2828
end
2929

app/components/referentiels/mapping_form_component.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22

33
class Referentiels::MappingFormComponent < Referentiels::MappingFormBase
44
TYPES = [:string, :decimal_number, :integer_number, :boolean, :date, :datetime, :array].index_by(&:itself).freeze
5+
attr_reader :referentiel_service
6+
delegate :test_url, :test_headers, to: :referentiel_service
7+
def initialize(**args)
8+
super
9+
@referentiel_service = ReferentielService.new(referentiel: referentiel)
10+
end
511

612
def last_request_keys
7-
JSONPath.hash_to_jsonpath(referentiel.last_response_body)
13+
JSONPathUtil.hash_to_jsonpath(referentiel.last_response_body)
814
end
915

1016
def error_title

app/components/referentiels/mapping_form_component/mapping_form_component.html.haml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
= render Dsfr::AlertComponent.new(title: error_title, state: :error, extra_class_names: 'fr-mb-3w') do |c|
66
- c.with_body do
77
%p L'API n'a pas retournée une réponse valide, veuillez vérifier les paramètres du referentiel :
8-
%pre Endpoint: #{@referentiel.url}
8+
%pre Endpoint: #{test_url}
9+
10+
- if test_headers.present?
11+
%pre Headers: #{test_headers}
12+
913
%pre Status: #{JSON.pretty_generate(@referentiel.last_response_status)}
1014
%pre Body: #{JSON.pretty_generate(@referentiel.last_response_body)}
1115

@@ -23,8 +27,11 @@
2327
%button.fr-accordion__btn{ type: :button, "aria-controls" => "last_response", "aria-expanded" => "false" } Afficher la réponse récupérée à partir de la requête configurée
2428
2529
.fr-collapse#last_response
26-
%pre= @referentiel.url
27-
%pre= JSON.pretty_generate(@referentiel.last_response_body)
30+
%pre Endpoint: #{test_url}
31+
- if test_headers.present?
32+
%pre Headers: #{test_headers}
33+
%pre Status: #{JSON.pretty_generate(@referentiel.last_response_status)}
34+
%pre Body: #{JSON.pretty_generate(@referentiel.last_response_body)}
2835
2936
%section
3037
.fr-table.fr-table--bordered

app/components/referentiels/new_form_component.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# frozen_string_literal: true
22

33
class Referentiels::NewFormComponent < Referentiels::MappingFormBase
4+
delegate :authentication_by_header_token?,
5+
:authentication_data_header,
6+
to: :referentiel
7+
48
def id
59
:new_referentiel
610
end
@@ -19,11 +23,35 @@ def form_url
1923

2024
def form_options
2125
{
22-
data: { turbo: 'true' },
26+
data: { turbo: 'true', controller: 'referentiel-new-form' },
2327
html: { novalidate: 'novalidate', id: }
2428
}
2529
end
2630

31+
def authentication_data_header_opts
32+
{
33+
opts: {
34+
name: "referentiel[authentication_data][header]",
35+
value: authentication_data_header
36+
}
37+
}
38+
end
39+
40+
def authentication_data_header_value_opts
41+
options = {
42+
opts: {
43+
name: "referentiel[authentication_data][value]",
44+
input_type: authentication_by_header_token? ? :password : :text,
45+
value: authentication_by_header_token? ? "C'est un secret" : '',
46+
data: {
47+
'referentiel-new-form-target' => 'input'
48+
}
49+
}
50+
}
51+
options[:opts][:disabled] = true if authentication_by_header_token?
52+
options
53+
end
54+
2755
def submit_options
2856
if referentiel.type.nil?
2957
{ class: 'fr-btn', disabled: true }

app/components/referentiels/new_form_component/new_form_component.html.haml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@
4848
= render Dsfr::InputComponent.new(form:, attribute: :test_data)
4949
.clearfix
5050

51+
- if @referentiel.type == 'Referentiels::APIReferentiel'
52+
%hr.fr-hr.fr-my-5w
53+
54+
%div{ data: { controller: 'hide-target'} }
55+
.fr-checkbox-group.fr-mb-3w
56+
= form.check_box :authentication_method, { checked: @referentiel.authentication_method.present?, class: 'fr-checkbox', data: { 'hide-target_target': 'source' } }
57+
= form.label :authentication_method, 'Ajouter une méthode d’authentification', class: 'fr-label'
58+
59+
%div{ data: { 'hide-target_target' => 'toHide' }, class: class_names('fr-hidden': [email protected]_method.present?) }
60+
= form.hidden_field :authentication_method, value: 'header_token'
61+
= render Dsfr::InputComponent.new(form:, attribute: "authentication_data[header]", **authentication_data_header_opts)
62+
= render Dsfr::InputComponent.new(form:, attribute: "authentication_data[value]", **authentication_data_header_value_opts)
63+
64+
%button{ type: 'button', class: 'fr-btn fr-btn--secondary', data: { action: 'click->referentiel-new-form#changeHeaderValue' } }
65+
Changer la valeur de l'en-tête
66+
5167
%ul.fr-btns-group.fr-btns-group--inline-sm.flex.justify-center.fr-mt-5w
5268
%li= link_to "Annuler", back_url, class: 'fr-btn fr-btn--secondary'
5369
%li= form.submit 'Étape suivante', submit_options

app/controllers/administrateurs/referentiels_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def referentiel_mapping_params
7070

7171
def referentiel_params
7272
params.require(:referentiel)
73-
.permit(:type, :mode, :url, :hint, :test_data)
73+
.permit(:type, :mode, :url, :hint, :test_data, :authentication_method, authentication_data: [:header, :value])
7474
rescue ActionController::ParameterMissing
7575
{}
7676
end
@@ -85,7 +85,7 @@ def retrieve_referentiel
8585

8686
def build_or_clone_by_id_params
8787
if params[:referentiel_id]
88-
Referentiel.find(params[:referentiel_id]).attributes.slice(*%w[url test_data hint mode type])
88+
Referentiel.find(params[:referentiel_id]).attributes.slice(*%w[url test_data hint mode type authentication_data authentication_method])
8989
else
9090
params = referentiel_params.to_h
9191
params = params.merge(type: Referentiels::APIReferentiel) if !Referentiels::APIReferentiel.csv_available?
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ApplicationController } from './application_controller';
2+
3+
export class ReferentielNewFormController extends ApplicationController {
4+
static targets = ['input'];
5+
6+
declare readonly inputTarget: HTMLInputElement;
7+
8+
changeHeaderValue(event: Event) {
9+
event.preventDefault();
10+
this.inputTarget.value = '';
11+
this.inputTarget.disabled = false;
12+
this.inputTarget.focus();
13+
}
14+
}

app/lib/json_path.rb renamed to app/lib/json_path_util.rb

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

3-
class JSONPath
3+
# Extension de la classe JsonPath de la gem
4+
class JSONPathUtil
45
def self.hash_to_jsonpath(hash, parent_path = '$')
56
hash.each_with_object({}) do |(key, value), result|
67
current_path = "#{parent_path}.#{key}"
@@ -24,14 +25,4 @@ def self.extract_array_name(str)
2425
def self.extract_key_after_array(str)
2526
str[/\[(.*?)\](.*)/, 2]
2627
end
27-
28-
# getters
29-
def self.value(hash, jsonpath)
30-
hash&.dig(*jsonpath.split('.')[1..])
31-
end
32-
33-
def self.get_array(hash, array_path)
34-
root_path = extract_array_name(array_path)
35-
value(hash, root_path)
36-
end
3728
end

0 commit comments

Comments
 (0)