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