Skip to content

Commit

Permalink
Merge branch 'staging' into rdv-solidarites-oauth
Browse files Browse the repository at this point in the history
  • Loading branch information
Michaelvilleneuve authored Jan 29, 2025
2 parents 3df115c + 7d9b1af commit 6d4496f
Show file tree
Hide file tree
Showing 59 changed files with 1,593 additions and 485 deletions.
11 changes: 10 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,17 @@ CARNET_DE_BORD_URL=https://demo.carnetdebord.inclusion.beta.gouv.fr
CARNET_DE_BORD_API_SECRET=secret_api_token

DEPARTMENTS_WHERE_PARCOURS_DISABLED=44

# France Travail Recette
FRANCE_TRAVAIL_AUTH_URL=https://proxyproconnect-r.ft-qvr.net/connexion/oauth2/access_token
FRANCE_TRAVAIL_API_URL=https://api-r.ft-qvr.io
FRANCE_TRAVAIL_CLIENT_ID=client_id
FRANCE_TRAVAIL_CLIENT_SECRET=client_secret

ORGANISATION_IDS_WHERE_STATS_DISABLED=

# Ces valeurs correspondent au seed de RDV Solidarités
RDV_SOLIDARITES_OAUTH_APP_ID=zC24y16rYftyrBgTj8h08g1NZKkwStXWe3E_lLMGoHc
RDV_SOLIDARITES_OAUTH_APP_SECRET=development-EdtuETfEK5Lr_--kx6S_QlItIJov-iThILw6M8IyTus # secret de test uniquement
RDV_SOLIDARITES_OAUTH_APP_SECRET=development-EdtuETfEK5Lr_--kx6S_QlItIJov-iThILw6M8IyTus
CRISP_WEBSITE_ID=change_me
ENABLE_CRISP=false
5 changes: 4 additions & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ AGENT_CONNECT_CLIENT_SECRET=client_secret

# France Travail
FRANCE_TRAVAIL_AUTH_URL=https://somefakeauthurl.fr
FRANCE_TRAVAIL_RDV_API_URL=https://francetravailfakerdvurl.fr
FRANCE_TRAVAIL_API_URL=https://francetravailfakerdvurl.fr
FRANCE_TRAVAIL_CLIENT_ID=client_id
FRANCE_TRAVAIL_CLIENT_SECRET=client_secret
FRANCE_TRAVAIL_WEBHOOKS_DEPARTMENTS=83

AGENT_SIGNATURE_KEY=bc995863-5c80-43a3-a31d-0da216e814a4
HOST=http://www.rdv-insertion-test.fake
33 changes: 33 additions & 0 deletions app/clients/france_travail_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class FranceTravailClient
def self.create_participation(payload:, headers:)
Faraday.post(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rendez-vous-partenaire/v1/rendez-vous",
payload.to_json,
headers
)
end

def self.update_participation(payload:, headers:)
Faraday.put(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rendez-vous-partenaire/v1/rendez-vous",
payload.to_json,
headers
)
end

def self.delete_participation(france_travail_id:, headers:)
Faraday.delete(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rendez-vous-partenaire/v1/rendez-vous/#{france_travail_id}",
{},
headers
)
end

def self.retrieve_user_token(payload:, headers:)
Faraday.post(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rechercher-usager/v2/usagers/par-datenaissance-et-nir",
payload.to_json,
headers
)
end
end
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ApplicationController < ActionController::Base
include EnvironmentsHelper
include TurboStreamConcern
include ModalAgreementsConcern
include CrispConcern

protect_from_forgery with: :exception
before_action :set_sentry_context
Expand Down
18 changes: 18 additions & 0 deletions app/controllers/concerns/crisp_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module CrispConcern
extend ActiveSupport::Concern

included do
before_action :should_display_crisp_chatbox, if: -> { request.get? }
end

private

def should_display_crisp_chatbox
if current_agent.nil? || agent_impersonated? || ENV["ENABLE_CRISP"] != "true"
@should_display_crisp_chatbox = false
return
end

@should_display_crisp_chatbox = true
end
end
4 changes: 2 additions & 2 deletions app/controllers/users/orientations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Users
class OrientationsController < ApplicationController
before_action :set_user, :set_organisations, :set_agents, only: [:new, :edit, :create, :update]
before_action :set_orientations, only: [:create]
before_action :set_orientations, only: [:create, :update]
before_action :set_orientation, only: [:edit, :update, :destroy]
before_action :set_agent_ids_by_organisation_id, :set_orientation_types, only: [:new, :edit]

Expand Down Expand Up @@ -83,7 +83,7 @@ def reloaded_user_orientations
def save_orientation_and_redirect
@should_notify_organisation = new_organisation?
if save_orientation.success?
render :create
render :after_save
elsif save_orientation.shrinkeable_orientation.present?
turbo_stream_confirm_update_anterior_ends_at_modal
else
Expand Down
71 changes: 71 additions & 0 deletions app/javascript/controllers/crisp_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static values = {
displayCrisp: Boolean,
userEmail: String,
userNickname: String,
userCrispToken: String,
};

connect() {
if (!this.displayCrispValue) {
// If the user is logged out from the app but crisp is still loaded, we loggout the user from crisp
if (window.$crisp) { this.logout(); };
return;
}

if (window.CRISP_TOKEN_ID === this.userCrispTokenValue) {
// If the user is already logged in, we don't need to do anything
return;
}

const user = {
email: this.userEmailValue,
nickname: this.userNicknameValue,
crispToken: this.userCrispTokenValue,
};

this.initCrisp(user);
this.handleFirstVisit();
}

initCrisp(user) {
window.$crisp = [];
window.CRISP_WEBSITE_ID = process.env.CRISP_WEBSITE_ID;

if (user) {
window.CRISP_TOKEN_ID = user.crispToken;
window.$crisp.push(["set", "user:email", [user.email]]);
window.$crisp.push(["set", "user:nickname", [user.nickname]]);
}

if (!document.querySelector("script[src='https://client.crisp.chat/l.js']")) {
const crispScriptTag = document.createElement("script");
crispScriptTag.async = true;
crispScriptTag.src = "https://client.crisp.chat/l.js";

const firstScriptTag = document.getElementsByTagName("head")[0];
firstScriptTag.appendChild(crispScriptTag);
}
}

handleFirstVisit() {
const firstVisit = localStorage.getItem("crispFirstVisit");
if (!firstVisit) {
window.$crisp.push(["on", "session:loaded", () => {
window.$crisp.push(["do", "chat:open"]);
localStorage.setItem("crispFirstVisit", "true");
}]);
}
}

logout() {
if (window.$crisp) {
window.CRISP_TOKEN_ID = null;
window.$crisp.push(["do", "session:reset"]);
window.$crisp.push(["do", "session:destroy"]);
window.$crisp.push(["do", "chat:hide"]);
}
}
}
17 changes: 17 additions & 0 deletions app/jobs/outgoing_webhooks/france_travail/base_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module OutgoingWebhooks
module FranceTravail
class BaseJob < ApplicationJob
include LockedAndOrderedJobs

discard_on FranceTravailApi::RetrieveUserToken::UserNotFound

def self.lock_key(participation_id:, **)
"#{base_lock_key}:#{participation_id}"
end

def self.job_timestamp(timestamp:, **)
timestamp
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module OutgoingWebhooks
module FranceTravail
class CreateParticipationJob < BaseJob
def perform(participation_id:, timestamp:)
call_service!(FranceTravailApi::CreateParticipation, participation_id: participation_id, timestamp: timestamp)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module OutgoingWebhooks
module FranceTravail
class DeleteParticipationJob < BaseJob
def perform(participation_id:, france_travail_id:, user_id:, timestamp:)
call_service!(FranceTravailApi::DeleteParticipation,
participation_id: participation_id,
france_travail_id: france_travail_id,
user_id: user_id, timestamp: timestamp)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module OutgoingWebhooks
module FranceTravail
class UpdateParticipationJob < BaseJob
def perform(participation_id:, timestamp:)
call_service!(FranceTravailApi::UpdateParticipation, participation_id: participation_id, timestamp: timestamp)
end
end
end
end
10 changes: 0 additions & 10 deletions app/jobs/outgoing_webhooks/send_france_travail_webhook_job.rb

This file was deleted.

6 changes: 6 additions & 0 deletions app/models/agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class Agent < ApplicationRecord
scope :super_admins, -> { where(super_admin: true) }
scope :with_last_name, -> { where.not(last_name: nil) }

before_create :generate_crisp_token

def delete_organisation(organisation)
organisations.delete(organisation)
save!
Expand Down Expand Up @@ -59,6 +61,10 @@ def with_rdv_solidarites_session(&)

private

def generate_crisp_token
self.crisp_token ||= SecureRandom.uuid
end

# This is to make sure an agent can't be set as super_admin through an agent creation or update in the app.
# To set an agent as superadmin a developer should use agent#update_column.
def cannot_save_as_super_admin
Expand Down
92 changes: 92 additions & 0 deletions app/models/concerns/participation/france_travail_payload.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
module Participation::FranceTravailPayload
extend ActiveSupport::Concern

# rubocop:disable Metrics/AbcSize
def to_ft_payload
{
id: france_travail_id,
adresse: address,
date: starts_at.to_datetime,
duree: duration_in_min,
information: motif.instruction_for_rdv,
initiateur: france_travail_initiateur,
libelleAdresse: organisation.name,
modaliteContact: france_travail_modalite,
motif: france_travail_motif,
organisme: {
code: france_travail_organisme_code,
emailContact: organisation.email,
idStructure: organisation.safir_code,
libelleStructure: organisation.name,
telephoneContact: organisation.phone_number
},
statut: france_travail_statut,
telephoneContactUsager: user.phone_number,
theme: motif.name,
typeReception: france_travail_type_reception,
interlocuteur: {
email: agents.first.email,
nom: agents.first.last_name,
prenom: agents.first.first_name
}
}
end
# rubocop:enable Metrics/AbcSize

private

# Liste des modalités FT (on ne prend en compte que le physique et le telephone): PHYSIQUE, TELEPHONE, VISIO
def france_travail_modalite
by_phone? ? "TELEPHONE" : "PHYSIQUE"
end

# Liste des initiateurs FT : USAGER, PARTENAIRE
def france_travail_initiateur
created_by_user? ? "USAGER" : "PARTENAIRE"
end

# Liste des motifs FT : AUT, ACC, ORI
def france_travail_motif
case motif.motif_category&.motif_category_type
when "rsa_orientation"
"ORI"
when "rsa_accompagnement"
"ACC"
else
"AUT"
end
end

# Liste des codes organismes FT : IND, FT, CD, DCD, ML, CE
def france_travail_organisme_code
case organisation.organisation_type
when "conseil_departemental"
"CD"
when "france_travail"
"FT"
when "delegataire_rsa"
"DCD"
else
"IND"
end
end

# Liste des types de réception FT : COL, IND
def france_travail_type_reception
collectif? ? "COL" : "IND"
end

# Liste des statuts FT : PRIS, EFFECTUE, MODIFIE, ABSENT, ANNULE
def france_travail_statut
case status
when "seen"
"EFFECTUE"
when "excused", "revoked"
"ANNULE"
when "noshow"
"ABSENT"
else
"PRIS"
end
end
end
Loading

0 comments on commit 6d4496f

Please sign in to comment.