Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Particulier x DataPass : handle Formulaire QF modality #1579

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ Metrics/MethodLength:
RSpec/NestedGroups:
Enabled: false

RSpec/SpecFilePathFormat:
Exclude:
- "spec/**/*hubee*"

Naming/VariableNumber:
Enabled: false

Expand Down
9 changes: 7 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ gem 'ransack'
gem 'wicked'

gem 'rest-client'
gem 'faraday'
gem 'faraday-gzip'
gem 'faraday-net_http'
gem 'faraday-retry'
gem 'faraday-encoding'

group :development, :test do
gem 'awesome_print'
Expand All @@ -101,10 +106,10 @@ group :development do
# Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
gem 'rack-mini-profiler', '~> 3.3'
gem 'rubocop', require: false
gem 'rubocop-rails'
gem 'rubocop-rspec'
gem 'rubocop-capybara'
gem 'rubocop-factory_bot'
gem 'rubocop-rails'
gem 'rubocop-rspec'
gem 'rubocop-rspec_rails'

gem 'better_errors'
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,18 @@ GEM
railties (>= 5.0.0)
faraday (2.9.0)
faraday-net_http (>= 2.0, < 3.2)
faraday-encoding (0.0.6)
faraday
faraday-gzip (2.0.1)
faraday (>= 1.0)
zlib (~> 3.0)
faraday-net_http (3.1.0)
net-http
faraday-net_http_persistent (2.1.0)
faraday (~> 2.5)
net-http-persistent (~> 4.0)
faraday-retry (2.2.1)
faraday (~> 2.0)
ferrum (0.15)
addressable (~> 2.5)
concurrent-ruby (~> 1.1)
Expand Down Expand Up @@ -560,6 +567,7 @@ GEM
nokogiri (~> 1.8)
yajl-ruby (1.4.3)
zeitwerk (2.7.0)
zlib (3.1.1)

PLATFORMS
aarch64-linux
Expand All @@ -583,6 +591,11 @@ DEPENDENCIES
cuprite
draper
factory_bot_rails
faraday
faraday-encoding
faraday-gzip
faraday-net_http
faraday-retry
gaffe
good_job (~> 3.99)
guard-rspec
Expand Down
23 changes: 23 additions & 0 deletions app/clients/abstract_hubee_api_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'faraday'

class AbstractHubEEAPIClient
protected

def http_connection(&block)
Faraday.new do |conn|
conn.request :retry, max: 5
conn.response :raise_error
conn.response :json
conn.options.timeout = 2
yield(conn) if block
end
end

def consumer_key
Rails.application.credentials.hubee_consumer_key
end

def consumer_secret
Rails.application.credentials.hubee_consumer_secret
end
end
23 changes: 23 additions & 0 deletions app/clients/abstract_insee_api_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'faraday'

class AbstractINSEEAPIClient
protected

def http_connection(&block)
@http_connection ||= Faraday.new do |conn|
conn.request :retry, max: 5
conn.response :raise_error
conn.response :json
conn.options.timeout = 2
yield(conn) if block
end
end

def consumer_key
Rails.application.credentials.insee_consumer_key
end

def consumer_secret
Rails.application.credentials.insee_consumer_secret
end
end
35 changes: 35 additions & 0 deletions app/clients/formulaire_qf_api_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class FormulaireQFAPIClient
def create_collectivity(authorization_request)
organization = authorization_request.organization
editor_name = authorization_request.extra_infos.dig('service_provider', 'id')

params = {
siret: organization.siret,
code_cog: organization.code_commune_etablissement,
departement: organization.code_postal_etablissement[0..1],
name: organization.denomination,
status: 'active',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JeSuisUnCaillou on active directement ? comment on pourrait détecter si ça n'a pas fonctionné correctement côté HubEE ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je ne comprends pas ta remarque dans le cadre du client qui est complétement décorellé de HubEE.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je ne comprends pas ta remarque dans le cadre du client qui est complétement décorellé de HubEE.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Si tu parles du séquençage de l'organizer, c'est la responsabilité de l'organizer d'arrêter la séquence si il y a un souci.

editor: editor_name
}

http_connection.post("#{host}/api/collectivites", params.to_json)
end

private

def host
Rails.application.credentials.formulaire_qf.host
end

def http_connection(&block)
Faraday.new do |conn|
conn.headers['Content-Type'] = 'application/json'
conn.request :authorization, 'Bearer', -> { secret }
yield(conn) if block
end
end

def secret
Rails.application.credentials.formulaire_qf.secret
end
end
28 changes: 28 additions & 0 deletions app/clients/hubee_api_authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class HubEEAPIAuthentication < AbstractHubEEAPIClient
def access_token
http_connection.post(
auth_url,
'grant_type=client_credentials&scope=ADMIN',
{
'Authorization' => "Basic #{encoded_client_id_and_secret}"
}
).body['access_token']
skelz0r marked this conversation as resolved.
Show resolved Hide resolved
end

private

def auth_url
Rails.application.credentials.hubee_auth_url
end

def encoded_client_id_and_secret
Base64.strict_encode64("#{consumer_key}:#{consumer_secret}")
end

def http_connection(&block)
@http_connection ||= super do |conn|
conn.response :json
yield(conn) if block
end
end
end
110 changes: 110 additions & 0 deletions app/clients/hubee_api_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
class HubEEAPIClient < AbstractHubEEAPIClient
class NotFound < StandardError; end
class AlreadyExists < StandardError; end

def find_organization(organization)
http_connection.get("#{host}/referential/v1/organizations/SI-#{organization.siret}-#{organization.code_commune_etablissement}").body
rescue Faraday::ResourceNotFound
raise NotFound
end

def create_organization(organization, email)
http_connection.post(
"#{host}/referential/v1/organizations",
{
type: 'SI',
companyRegister: organization.siret,
branchCode: organization.code_commune_etablissement,
email:,
name: organization.denomination,
country: 'France',
postalCode: organization.code_postal_etablissement,
territory: organization.code_commune_etablissement,
status: 'Actif'
}.to_json,
'Content-Type' => 'application/json'
)
rescue Faraday::BadRequestError => e
raise AlreadyExists if already_exists_error?(e)

raise
end

def create_subscription(authorization_request, organization_payload, process_code) # rubocop:disable Metrics/AbcSize
http_connection.post(
"#{host}/referential/v1/subscriptions",
{
datapassId: authorization_request.external_id.to_i,
notificationFrequency: 'Aucune',
processCode: process_code,
subscriber: {
type: 'SI',
companyRegister: organization_payload['companyRegister'],
branchCode: organization_payload['branchCode']
},
email: authorization_request.demandeur.email,
status: 'Inactif',
localAdministrator: {
email: authorization_request.demandeur.email
},
validateDateTime: DateTime.now.iso8601,
updateDateTime: DateTime.now.iso8601
}.to_json,
'Content-Type' => 'application/json'
)
rescue Faraday::BadRequestError => e
raise AlreadyExists if already_exists_error?(e)

raise
end

def find_subscription(_authorization_request, organization_payload, process_code)
request = http_connection { |conn| conn.request :gzip }.get(
"#{host}/referential/v1/subscriptions",
companyRegister: organization_payload['companyRegister'],
processCode: process_code
)
request.body.first
end

def update_subscription(authorization_request, subscription_payload, editor_payload = {}) # rubocop:disable Metrics/AbcSize
subscription_id = authorization_request.extra_infos['hubee_subscription_id']
return if subscription_id.blank?

payload = subscription_payload.with_indifferent_access.merge({
status: 'Actif',
activateDateTime: DateTime.now.iso8601,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skelz0r tu parlais d'une date d'activation dans le passé, y'avait une raison particulière ? ça semble fonctionner comme ça

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

où ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ça me dit quelque chose, mais de toute manière ta ligne est une date dans le passé quasiment instantanément.

accessMode: 'API',
notificationFrequency: 'Aucune'
}.with_indifferent_access)

payload.delete('id')
payload.delete('creationDateTime')
payload.merge!(editor_payload.with_indifferent_access) if editor_payload.present?

http_connection.put(
"#{host}/referential/v1/subscriptions/#{subscription_id}",
payload.to_json,
'Content-Type' => 'application/json'
)
end

protected

def host
Rails.application.credentials.hubee_api_url
end

def already_exists_error?(faraday_error)
faraday_error.response[:body]['errors'].any? do |error|
error['message'].include?('already exists')
end
end

def http_connection(&block)
super do |conn|
conn.request :authorization, 'Bearer', -> { HubEEAPIAuthentication.new.access_token }
yield(conn) if block
end
end
end
19 changes: 19 additions & 0 deletions app/clients/insee_api_authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class INSEEAPIAuthentication < AbstractINSEEAPIClient
def access_token
http_connection.post(
'https://api.insee.fr/token',
'grant_type=client_credentials',
{
'Authorization' => "Basic #{encoded_client_id_and_secret}"
}
).body['access_token']
end

private

def encoded_client_id_and_secret
Base64.strict_encode64("#{consumer_key}:#{consumer_secret}")
end
end
15 changes: 15 additions & 0 deletions app/clients/insee_sirene_api_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class INSEESireneAPIClient < AbstractINSEEAPIClient
def etablissement(siret:)
http_connection.get(
"https://api.insee.fr/entreprises/sirene/V3.11/siret/#{siret}"
).body
end

protected

def http_connection
super do |conn|
conn.request :authorization, 'Bearer', -> { INSEEAPIAuthentication.new.access_token }
end
end
end
4 changes: 3 additions & 1 deletion app/interactors/datapass_webhook/adapt_v2_to_v1.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class DatapassWebhook::AdaptV2ToV1 < ApplicationInteractor
def call
context.event = context.event.sub('authorization_request', 'enrollment')
context.authorization_request_data = generic_data.dup
context.data = build_data
end

Expand All @@ -21,7 +22,8 @@ def build_data
'previous_enrollment_id' => nil,
'scopes' => generic_data['scopes'].index_with { |_scope| true },
'team_members' => build_team_members,
'events' => []
'events' => [],
'service_provider' => context.data['service_provider']
}
}
end
Expand Down
5 changes: 5 additions & 0 deletions app/interactors/datapass_webhook/create_or_prolong_token.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
class DatapassWebhook::CreateOrProlongToken < ApplicationInteractor
before do
context.modalities ||= %w[params]
end

def call
return if %w[approve validate].exclude?(context.event)
return if context.modalities.exclude?('params')

token = create_or_prolong_token

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,17 @@ def authorization_request_attributes
).merge(authorization_request_attributes_for_current_event).merge(
'last_update' => fired_at_as_datetime,
'previous_external_id' => context.data['pass']['copied_from_enrollment_id'],
'api' => context.api
'api' => context.api,
'extra_infos' => extra_infos_with_service_provider
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dans 100% des cas il s'agit d'un éditeur, autant mettre editor ici imo

)
end

def extra_infos_with_service_provider
context.authorization_request.extra_infos.merge({
'service_provider' => Hash(context.data.dig('pass', 'service_provider'))
})
end

def authorization_request_attributes_for_current_event
authorization_request_attributes_for_current_event = {}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class DatapassWebhook::ScheduleCreateFormulaireQFHubEESubscriptionJob < ApplicationInteractor
def call
return unless context.event == 'approve'
return unless context.modalities.include?('formulaire_qf')

CreateFormulaireQFHubEESubscriptionJob.perform_later(context.authorization_request.id)
CreateFormulaireQFCollectivityJob.perform_later(context.authorization_request.id)
end
end
Loading
Loading