demarches-normaliennes/app/controllers/application_controller.rb

441 lines
12 KiB
Ruby
Raw Normal View History

2015-08-10 11:05:06 +02:00
class ApplicationController < ActionController::Base
2019-02-01 17:17:10 +01:00
include TrustedDeviceConcern
include Pundit::Authorization
include Devise::StoreLocationExtension
include ApplicationController::LongLivedAuthenticityToken
include ApplicationController::ErrorHandling
2019-02-01 17:17:10 +01:00
2018-04-26 10:52:41 +02:00
MAINTENANCE_MESSAGE = 'Le site est actuellement en maintenance. Il sera à nouveau disponible dans un court instant.'
2021-01-28 14:49:22 +01:00
before_action :set_sentry_user
2019-02-01 17:17:10 +01:00
before_action :redirect_if_untrusted
before_action :reject, if: -> { ENV.fetch("MAINTENANCE_MODE", 'false') == 'true' }
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :staging_authenticate
2018-04-26 14:36:27 +02:00
before_action :set_active_storage_host
2019-11-19 14:40:28 +01:00
before_action :setup_javascript_settings
before_action :setup_tracking
before_action :set_customizable_view_path
2021-05-12 16:30:35 +02:00
around_action :switch_locale
2021-02-09 10:24:13 +01:00
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur, :current_expert, :expert_signed_in?,
2023-08-25 22:53:30 +02:00
:administrateur_signed_in?, :current_administrateur, :current_account, :localization_enabled?, :set_locale, :current_expert_not_instructeur?,
:gestionnaire_signed_in?, :current_gestionnaire
before_action do
Current.request_id = request.uuid
2023-06-21 16:42:41 +02:00
Current.user = current_user
Current.browser = browser
# TODO: remove this block when migration to new domain is done
# headers['Host'] instead of request.host to keep the port (ex: localhost:3000)
Current.host = request.headers['Host']
2024-03-19 21:41:45 +01:00
if Current.host.include?("gouv.fr")
Current.application_name = "demarches.gouv.fr"
2024-03-19 22:13:40 +01:00
Current.contact_email = "contact@demarches.gouv.fr"
2024-03-19 22:31:27 +01:00
Current.application_base_url = "https://demarches.gouv.fr"
2024-03-19 21:41:45 +01:00
else
Current.application_name = APPLICATION_NAME
2024-03-19 22:13:40 +01:00
Current.contact_email = CONTACT_EMAIL
2024-03-21 14:01:52 +01:00
Current.application_base_url = APPLICATION_BASE_URL
2024-03-19 21:41:45 +01:00
end
end
def staging_authenticate
if StagingAuthService.enabled? && !authenticate_with_http_basic { |username, password| StagingAuthService.authenticate(username, password) }
request_http_basic_authentication
end
end
def multiple_devise_profile_connect?
user_signed_in? && instructeur_signed_in? ||
instructeur_signed_in? && administrateur_signed_in? ||
instructeur_signed_in? && gestionnaire_signed_in? ||
2021-02-09 10:24:13 +01:00
instructeur_signed_in? && expert_signed_in? ||
user_signed_in? && administrateur_signed_in? ||
user_signed_in? && gestionnaire_signed_in? ||
2023-08-25 22:53:30 +02:00
user_signed_in? && expert_signed_in? ||
administrateur_signed_in? && gestionnaire_signed_in?
end
def current_instructeur
current_user&.instructeur
end
def instructeur_signed_in?
user_signed_in? && current_user&.instructeur.present?
end
def current_administrateur
current_user&.administrateur
end
def administrateur_signed_in?
current_administrateur.present?
end
def current_gestionnaire
current_user&.gestionnaire
2023-08-25 22:53:30 +02:00
end
def gestionnaire_signed_in?
current_gestionnaire.present?
2023-08-25 22:53:30 +02:00
end
2021-02-09 10:24:13 +01:00
def current_expert
current_user&.expert
end
def current_expert_not_instructeur?
current_user&.expert? && !current_user&.instructeur?
end
2021-02-09 10:24:13 +01:00
def expert_signed_in?
current_expert.present?
end
def current_account
{
gestionnaire: current_gestionnaire,
administrateur: current_administrateur,
instructeur: current_instructeur,
expert: current_expert,
user: current_user
}.compact
end
alias_method :pundit_user, :current_account
def localization_enabled?
ENV.fetch('LOCALIZATION_ENABLED', 'false') == 'true' || cookies[:locale].present? || !browser_prefers_french?
end
def browser_prefers_french?
http_accept_language.compatible_language_from(I18n.available_locales) == 'fr'
end
def set_locale(locale)
if locale && locale.to_sym.in?(I18n.available_locales)
cookies[:locale] = locale
2021-09-01 18:50:38 +02:00
if user_signed_in?
current_user.update(locale: locale)
end
locale
end
end
def ajax_redirect(path)
"window.location.href='#{path}'"
end
def message_verifier
@message_verifier ||= ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base)
end
2017-01-03 11:32:21 +01:00
protected
2019-07-04 12:36:17 +02:00
def feature_enabled?(feature_name)
Flipper.enabled?(feature_name, current_user)
end
def authenticate_logged_user!
if instructeur_signed_in?
authenticate_instructeur!
2021-02-09 10:24:13 +01:00
elsif expert_signed_in?
authenticate_expert!
elsif administrateur_signed_in?
authenticate_administrateur!
elsif gestionnaire_signed_in?
authenticate_gestionnaire!
else
authenticate_user!
end
end
def authenticate_instructeur!
if !instructeur_signed_in?
2017-01-03 11:32:21 +01:00
redirect_to new_user_session_path
end
end
2021-02-09 10:24:13 +01:00
def authenticate_expert!
if !expert_signed_in?
redirect_to new_user_session_path
end
end
def authenticate_instructeur_or_expert!
if !instructeur_signed_in? && !expert_signed_in?
redirect_to new_user_session_path
end
end
2017-01-03 11:32:21 +01:00
def authenticate_administrateur!
if !administrateur_signed_in?
2017-01-03 11:32:21 +01:00
redirect_to new_user_session_path
end
end
def authenticate_gestionnaire!
if !gestionnaire_signed_in?
2023-08-25 22:53:30 +02:00
redirect_to new_user_session_path
end
end
def after_sign_out_path_for(_resource_or_scope)
stored_location_for(:user) || super
end
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_in, keys: [:otp_attempt])
end
private
2018-04-26 14:36:27 +02:00
def set_active_storage_host
ActiveStorage::Current.url_options ||= {}
ActiveStorage::Current.url_options[:host] = request.base_url
2018-04-26 14:36:27 +02:00
end
2019-11-19 14:40:28 +01:00
def setup_javascript_settings
gon.autosave = Rails.application.config.ds_autosave
gon.autocomplete = Rails.application.secrets.autocomplete
2019-11-19 14:40:28 +01:00
end
def setup_tracking
gon.matomo = matomo_config
gon.sentry = sentry_config
if administrateur_signed_in?
gon.crisp = crisp_config
end
end
def current_user_roles
@current_user_roles ||= begin
roles = [
current_user,
current_instructeur,
current_expert,
current_administrateur,
current_gestionnaire,
current_super_admin
].compact.map { |role| role.class.name }
2018-08-07 16:13:40 +02:00
roles.any? ? roles.join(', ') : 'Guest'
end
2018-01-17 14:40:31 +01:00
end
2021-01-28 14:49:22 +01:00
def set_sentry_user
Sentry.set_user(sentry_user)
end
2018-01-17 14:40:31 +01:00
def set_sentry_dossier(dossier)
Sentry.configure_scope do |scope|
scope.set_tags(procedure: dossier.procedure.id)
scope.set_tags(dossier: dossier.id)
end
end
# private method called by rails fwk
# see https://github.com/roidrage/lograge
2018-08-12 10:31:28 +02:00
def append_info_to_payload(payload)
super
2018-08-07 16:13:40 +02:00
payload[:to_log] = {}
request_logs(payload[:to_log])
end
def request_logs(logs)
logs.merge!({
2018-01-17 14:40:31 +01:00
user_agent: request.user_agent,
user_id: current_user&.id,
2023-02-01 17:57:27 +01:00
user_roles: current_user_roles,
client_ip: request.headers['X-Forwarded-For'],
request_id: request.headers['X-Request-ID']
})
2018-01-17 14:40:31 +01:00
if browser.known?
logs.merge!({
2018-01-17 14:40:31 +01:00
browser: browser.name,
browser_version: browser.version.to_s,
platform: browser.platform.name
2018-01-17 14:40:31 +01:00
})
end
end
2018-04-26 10:52:41 +02:00
def reject
authorized_request =
request.path_info == '/' ||
request.path_info.start_with?('/manager') ||
request.path_info.start_with?('/super_admins')
2018-04-26 10:52:41 +02:00
api_request = request.path_info.start_with?('/api/')
if super_admin_signed_in? || authorized_request
2018-04-26 10:52:41 +02:00
flash.now.alert = MAINTENANCE_MESSAGE
elsif api_request
render json: { error: MAINTENANCE_MESSAGE }.to_json, status: :service_unavailable
else
[:user, :instructeur, :administrateur].each { |role| sign_out(role) }
2018-04-26 10:52:41 +02:00
flash[:alert] = MAINTENANCE_MESSAGE
redirect_to root_path
end
end
2019-02-01 17:17:10 +01:00
def redirect_if_untrusted
if instructeur_signed_in? &&
2019-02-01 17:17:10 +01:00
sensitive_path &&
!current_instructeur.bypass_email_login_token &&
!IPService.ip_trusted?(request.headers['X-Forwarded-For']) &&
2019-02-01 17:17:10 +01:00
!trusted_device?
# return at this location
# after the device is trusted
2020-03-20 10:26:21 +01:00
if get_stored_location_for(:user).blank?
store_location_for(:user, request.fullpath)
end
send_login_token_or_bufferize(current_instructeur)
signed_email = message_verifier.generate(current_instructeur.email, purpose: :reset_link, expires_in: 1.hour)
redirect_to link_sent_path(email: signed_email)
2019-02-01 17:17:10 +01:00
end
end
def sensitive_path
path = request.path_info
if path == '/' ||
path == '/users/sign_out' ||
path == '/contact' ||
path == '/contact-admin' ||
2019-02-01 17:17:10 +01:00
path.start_with?('/connexion-par-jeton') ||
path.start_with?('/api/') ||
path.start_with?('/lien-envoye')
false
else
true
end
end
def sentry_user
if user_signed_in?
{ id: "User##{current_user.id}" }
elsif administrateur_signed_in?
{ id: "Administrateur##{current_administrateur.id}" }
else
{ id: 'Guest' }
end
end
def sentry_config
sentry = Rails.application.secrets.sentry
{
key: sentry[:js_client_key],
enabled: sentry[:enabled],
environment: sentry[:environment],
browser: { modern: BrowserSupport.supported?(browser) },
user: sentry_user,
release: SentryRelease.current
}
end
def matomo_config
matomo = Rails.application.secrets.matomo
{
cookieDomain: matomo[:cookie_domain],
domain: matomo[:domain],
enabled: matomo[:enabled],
host: matomo[:host],
key: matomo[:client_key]
}
end
def crisp_config
crisp = Rails.application.secrets.crisp
2019-09-25 17:51:28 +02:00
nb_demarches_by_state = if current_administrateur.present?
current_administrateur.procedures.group(:aasm_state).count
else
{}
end
{
key: crisp[:client_key],
enabled: crisp[:enabled],
administrateur: {
email: current_user&.email,
DS_SIGN_IN_COUNT: current_user&.sign_in_count,
DS_CREATED_AT: current_administrateur&.created_at,
DS_ID: current_administrateur&.id,
DS_NB_DEMARCHES_BROUILLONS: nb_demarches_by_state['brouillon'] || 0,
DS_NB_DEMARCHES_ACTIVES: nb_demarches_by_state['publiee'] || 0,
DS_NB_DEMARCHES_ARCHIVES: nb_demarches_by_state['close'] || 0
}
}
end
def current_email
current_user&.email
end
2021-05-12 16:30:35 +02:00
def switch_locale(&action)
locale = extract_locale_from_query_params ||
extract_locale_from_cookie ||
2021-09-01 18:50:38 +02:00
extract_locale_from_user ||
extract_locale_from_accept_language_header ||
I18n.default_locale
gon.locale = locale
2021-05-12 16:30:35 +02:00
I18n.with_locale(locale, &action)
end
def extract_locale_from_query_params
set_locale(request.query_parameters[:locale])
end
2021-09-01 18:50:38 +02:00
def extract_locale_from_user
current_user&.locale
end
def extract_locale_from_cookie
cookies[:locale]
end
def extract_locale_from_accept_language_header
if localization_enabled?
http_accept_language.compatible_language_from(I18n.available_locales)
end
end
def set_customizable_view_path
prepend_view_path "app/custom_views"
end
# Extract a value from params based on the "path"
#
# params: { dossiers: { champs_public_attributes: { 1234 => { value: "hello" } } } }
#
# Usage: read_param_value("dossiers[champs_public_attributes][1234]", "value")
def read_param_value(path, name)
parts = path.split(/\[|\]\[|\]/) + [name]
parts.reduce(params) do |value, part|
if part.to_i != 0
value[part.to_i] || value[part]
else
value[part]
end
end
end
def cast_bool(value)
ActiveRecord::Type::Boolean.new.deserialize(value)
end
2015-08-10 11:05:06 +02:00
end