diff --git a/app/controllers/api/v1/dossiers_controller.rb b/app/controllers/api/v1/dossiers_controller.rb index 980ba7e81..9a990734d 100644 --- a/app/controllers/api/v1/dossiers_controller.rb +++ b/app/controllers/api/v1/dossiers_controller.rb @@ -2,6 +2,7 @@ class API::V1::DossiersController < APIController before_action :fetch_procedure_and_check_token DEFAULT_PAGE_SIZE = 100 + MAX_PAGE_SIZE = 1000 ORDER_DIRECTIONS = { 'asc' => :asc, 'desc' => :desc } def index @@ -33,7 +34,12 @@ class API::V1::DossiersController < APIController end def per_page # inherited value from will_paginate - [params[:resultats_par_page]&.to_i || DEFAULT_PAGE_SIZE, 1000].min + resultats_par_page = params[:resultats_par_page]&.to_i + if resultats_par_page && resultats_par_page > 0 + [resultats_par_page, MAX_PAGE_SIZE].min + else + DEFAULT_PAGE_SIZE + end end def fetch_procedure_and_check_token diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 23cb10410..8c0ccad0f 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -48,8 +48,11 @@ module Users end def attestation - if dossier.attestation.pdf.attached? + if dossier.attestation&.pdf&.attached? redirect_to url_for(dossier.attestation.pdf) + else + flash.notice = "L'attestation n'est plus disponible sur ce dossier." + redirect_to dossier_path(dossier) end end diff --git a/app/models/dynamic_smtp_settings_interceptor.rb b/app/models/dynamic_smtp_settings_interceptor.rb new file mode 100644 index 000000000..885c4b8e9 --- /dev/null +++ b/app/models/dynamic_smtp_settings_interceptor.rb @@ -0,0 +1,16 @@ +class DynamicSmtpSettingsInterceptor + def self.delivering_email(message) + if ENV['SENDINBLUE_BALANCING'] == 'enabled' + if rand(0..99) < ENV['SENDINBLUE_BALANCING_VALUE'].to_i + message.delivery_method.settings = { + user_name: ENV['SENDINBLUE_USER_NAME'], + password: ENV['SENDINBLUE_SMTP_KEY'], + address: 'smtp-relay.sendinblue.com', + domain: 'smtp-relay.sendinblue.com', + port: '587', + authentication: :cram_md5 + } + end + end + end +end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 6a6d3ecd6..96a427dbb 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -595,14 +595,18 @@ class Procedure < ApplicationRecord def move_type_de_champ_attributes(types_de_champ, type_de_champ, new_index) old_index = types_de_champ.index(type_de_champ) - types_de_champ.insert(new_index, types_de_champ.delete_at(old_index)) - .map.with_index do |type_de_champ, index| - { - id: type_de_champ.id, - libelle: type_de_champ.libelle, - order_place: index - } - end + if types_de_champ.delete_at(old_index) + types_de_champ.insert(new_index, type_de_champ) + .map.with_index do |type_de_champ, index| + { + id: type_de_champ.id, + libelle: type_de_champ.libelle, + order_place: index + } + end + else + [] + end end def before_publish diff --git a/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb b/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb index 71f0784b1..24410c6f6 100644 --- a/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb +++ b/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb @@ -53,7 +53,7 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas def check_presence_of_primary_options if !PRIMARY_PATTERN.match?(drop_down_list.options.second) - errors.add(libelle, "doit commencer par une entrée de menu primaire de la forme --texte--") + errors.add(libelle.presence || "La liste", "doit commencer par une entrée de menu primaire de la forme --texte--") end end diff --git a/app/views/champs/repetition/_show.html.haml b/app/views/champs/repetition/_show.html.haml index 508593712..8b3240829 100644 --- a/app/views/champs/repetition/_show.html.haml +++ b/app/views/champs/repetition/_show.html.haml @@ -1,10 +1,11 @@ - champs = champ.rows.last -- index = (champ.rows.size - 1) * champs.size -%div{ class: "row row-#{champs.first.row}" } - - champs.each.with_index(index) do |champ, index| - = fields_for "#{attribute}[#{index}]", champ do |form| - = render partial: "shared/dossiers/editable_champs/editable_champ", locals: { champ: champ, form: form } - = form.hidden_field :id - = form.hidden_field :_destroy, disabled: true - %button.button.danger.remove-row - Supprimer +- if champs.present? + - index = (champ.rows.size - 1) * champs.size + %div{ class: "row row-#{champs.first.row}" } + - champs.each.with_index(index) do |champ, index| + = fields_for "#{attribute}[#{index}]", champ do |form| + = render partial: "shared/dossiers/editable_champs/editable_champ", locals: { champ: champ, form: form } + = form.hidden_field :id + = form.hidden_field :_destroy, disabled: true + %button.button.danger.remove-row + Supprimer diff --git a/config/env.example b/config/env.example index 4f704adab..c3c40d089 100644 --- a/config/env.example +++ b/config/env.example @@ -46,8 +46,14 @@ SENTRY_DSN_JS="" MATOMO_ENABLED="disabled" MATOMO_ID="73" -SENDINBLUE_ENABLED="disabled" +SENDINBLUE_BALANCING="" +SENDINBLUE_BALANCING_VALUE="" +SENDINBLUE_ENABLED="" SENDINBLUE_CLIENT_KEY="" +SENDINBLUE_SMTP_KEY="" +SENDINBLUE_USER_NAME="" + + CRISP_ENABLED="disabled" CRISP_CLIENT_KEY="" diff --git a/config/environments/development.rb b/config/environments/development.rb index 385185b36..718db3436 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -45,14 +45,26 @@ Rails.application.configure do config.assets.raise_runtime_errors = true # Action Mailer settings - config.action_mailer.delivery_method = :letter_opener_web - # Configure default root URL for generating URLs to routes - config.action_mailer.default_url_options = { - host: 'localhost', - port: 3000 - } - # Configure default root URL for email assets - config.action_mailer.asset_host = "http://" + ENV['APP_HOST'] + + if ENV['SENDINBLUE_ENABLED'] == 'enabled' + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { + user_name: Rails.application.secrets.sendinblue[:username], + password: Rails.application.secrets.sendinblue[:smtp_key], + address: 'smtp-relay.sendinblue.com', + domain: 'smtp-relay.sendinblue.com', + port: '587', + authentication: :cram_md5 + } + else + config.action_mailer.delivery_method = :letter_opener_web + config.action_mailer.default_url_options = { + host: 'localhost', + port: 3000 + } + + config.action_mailer.asset_host = "http://" + ENV['APP_HOST'] + end Rails.application.routes.default_url_options = { host: 'localhost', diff --git a/config/environments/production.rb b/config/environments/production.rb index 8837fb88b..262c15c4b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -77,6 +77,16 @@ Rails.application.configure do port: '2525', authentication: :cram_md5 } + elsif ENV['SENDINBLUE_ENABLED'] == 'enabled' + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { + user_name: Rails.application.secrets.sendinblue[:username], + password: Rails.application.secrets.sendinblue[:smtp_key], + address: 'smtp-relay.sendinblue.com', + domain: 'smtp-relay.sendinblue.com', + port: '587', + authentication: :cram_md5 + } else config.action_mailer.delivery_method = :mailjet end diff --git a/config/initializers/dynamic_smtp_settings_interceptor.rb b/config/initializers/dynamic_smtp_settings_interceptor.rb new file mode 100644 index 000000000..a3f8e2d13 --- /dev/null +++ b/config/initializers/dynamic_smtp_settings_interceptor.rb @@ -0,0 +1 @@ +ActionMailer::Base.register_interceptor "DynamicSmtpSettingsInterceptor" diff --git a/config/secrets.yml b/config/secrets.yml index 7ad675ffe..2ac8aa244 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -54,7 +54,9 @@ defaults: &defaults webhook_secret: <%= ENV['HELPSCOUT_WEBHOOK_SECRET'] %> sendinblue: enabled: <%= ENV['SENDINBLUE_ENABLED'] == 'enabled' %> + username: <%= ENV['SENDINBLUE_USER_NAME'] %> client_key: <%= ENV['SENDINBLUE_CLIENT_KEY'] %> + smtp_key: <%= ENV['SENDINBLUE_SMTP_KEY'] %> api_v3_key: <%= ENV['SENDINBLUE_API_V3_KEY'] %> matomo: enabled: <%= ENV['MATOMO_ENABLED'] == 'enabled' %> diff --git a/spec/models/type_de_champ_shared_example.rb b/spec/models/type_de_champ_shared_example.rb index d0b6e4ecf..a710b4ef0 100644 --- a/spec/models/type_de_champ_shared_example.rb +++ b/spec/models/type_de_champ_shared_example.rb @@ -148,4 +148,22 @@ shared_examples 'type_de_champ_spec' do expect(cloned_procedure.types_de_champ.first.types_de_champ).not_to be_empty end end + + describe "linked_drop_down_list" do + let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list) } + + it 'should validate without label' do + type_de_champ.drop_down_list_value = 'toto' + expect(type_de_champ.validate).to be_falsey + messages = type_de_champ.errors.full_messages + expect(messages.size).to eq(1) + expect(messages.first.starts_with?("#{type_de_champ.libelle} doit commencer par")).to be_truthy + + type_de_champ.libelle = '' + expect(type_de_champ.validate).to be_falsey + messages = type_de_champ.errors.full_messages + expect(messages.size).to eq(2) + expect(messages.last.starts_with?("La liste doit commencer par")).to be_truthy + end + end end