commit
7587a9910b
37 changed files with 442 additions and 204 deletions
18
.rubocop.yml
18
.rubocop.yml
|
@ -1,15 +1,15 @@
|
|||
require:
|
||||
- rubocop/rspec/focused
|
||||
- rubocop-performance
|
||||
- rubocop-rails
|
||||
- rubocop-rspec
|
||||
- ./lib/cops/add_concurrent_index.rb
|
||||
- ./lib/cops/application_name.rb
|
||||
- ./lib/cops/unscoped.rb
|
||||
|
||||
inherit_gem:
|
||||
rubocop-rails_config:
|
||||
- config/rails.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.7
|
||||
TargetRubyVersion: 3.0
|
||||
DisabledByDefault: true
|
||||
SuggestExtensions: false
|
||||
Exclude:
|
||||
- "db/schema.rb"
|
||||
- "db/migrate/20190730153555_recreate_structure.rb"
|
||||
|
@ -644,6 +644,9 @@ Performance/RedundantMatch:
|
|||
Performance/RedundantMerge:
|
||||
Enabled: true
|
||||
|
||||
Style/HashTransformValues:
|
||||
Enabled: true
|
||||
|
||||
Style/RedundantSortBy:
|
||||
Enabled: true
|
||||
|
||||
|
@ -874,7 +877,7 @@ Rails/WhereExists:
|
|||
Rails/WhereNot:
|
||||
Enabled: true
|
||||
|
||||
RSpec/Focused:
|
||||
RSpec/Focus:
|
||||
Enabled: true
|
||||
|
||||
Security/Eval:
|
||||
|
@ -1373,4 +1376,3 @@ Style/YodaCondition:
|
|||
|
||||
Style/ZeroLengthPredicate:
|
||||
Enabled: true
|
||||
|
||||
|
|
5
Gemfile
5
Gemfile
|
@ -111,8 +111,9 @@ group :development do
|
|||
gem 'rack-mini-profiler'
|
||||
gem 'rails-erd', require: false # generates `doc/database_models.pdf`
|
||||
gem 'rubocop', require: false
|
||||
gem 'rubocop-rails_config'
|
||||
gem 'rubocop-rspec-focused', require: false
|
||||
gem 'rubocop-performance', require: false
|
||||
gem 'rubocop-rails', require: false
|
||||
gem 'rubocop-rspec', require: false
|
||||
gem 'scss_lint', require: false
|
||||
gem 'web-console'
|
||||
end
|
||||
|
|
19
Gemfile.lock
19
Gemfile.lock
|
@ -620,8 +620,6 @@ GEM
|
|||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.4.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-packaging (0.5.1)
|
||||
rubocop (>= 0.89, < 2.0)
|
||||
rubocop-performance (1.9.2)
|
||||
rubocop (>= 0.90.0, < 2.0)
|
||||
rubocop-ast (>= 0.4.0)
|
||||
|
@ -629,15 +627,9 @@ GEM
|
|||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 0.90.0, < 2.0)
|
||||
rubocop-rails_config (1.3.1)
|
||||
railties (>= 5.0)
|
||||
rubocop (>= 1.8)
|
||||
rubocop-ast (>= 1.0.1)
|
||||
rubocop-packaging (~> 0.5)
|
||||
rubocop-performance (~> 1.3)
|
||||
rubocop-rails (~> 2.0)
|
||||
rubocop-rspec-focused (1.0.0)
|
||||
rubocop (>= 0.51)
|
||||
rubocop-rspec (2.4.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-ast (>= 1.1.0)
|
||||
ruby-graphviz (1.2.5)
|
||||
rexml
|
||||
ruby-progressbar (1.11.0)
|
||||
|
@ -874,8 +866,9 @@ DEPENDENCIES
|
|||
rspec-rails
|
||||
rspec_junit_formatter
|
||||
rubocop
|
||||
rubocop-rails_config
|
||||
rubocop-rspec-focused
|
||||
rubocop-performance
|
||||
rubocop-rails
|
||||
rubocop-rspec
|
||||
ruby-saml-idp
|
||||
sanitize-url
|
||||
sassc-rails
|
||||
|
|
|
@ -295,7 +295,6 @@ $users-breakpoint: 950px;
|
|||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-top: 13px;
|
||||
color: #FFFFFF;
|
||||
|
||||
&.grey {
|
||||
color: $g700;
|
||||
|
@ -303,15 +302,19 @@ $users-breakpoint: 950px;
|
|||
}
|
||||
|
||||
.cta-panel-explanation {
|
||||
font-size: 24px;
|
||||
font-size: 22px;
|
||||
margin-bottom: 10px;
|
||||
color: #FFFFFF;
|
||||
|
||||
&.grey {
|
||||
color: $g700;
|
||||
}
|
||||
}
|
||||
|
||||
.half .cta-panel-title,
|
||||
.half .cta-panel-explanation {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.role-panel-title {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
|
@ -357,7 +360,7 @@ $cta-panel-button-border-size: 2px;
|
|||
@include vertical-padding(15px);
|
||||
display: block;
|
||||
border-radius: 100px;
|
||||
font-size: 24px;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
margin-top: 20px;
|
||||
|
|
|
@ -3,12 +3,17 @@ module Administrateurs
|
|||
before_action :retrieve_procedure
|
||||
|
||||
def edit
|
||||
@attestation_template = @procedure.attestation_template || AttestationTemplate.new(procedure: @procedure)
|
||||
@attestation_template = build_attestation
|
||||
end
|
||||
|
||||
def update
|
||||
attestation_template = @procedure.attestation_template
|
||||
attestation_template = @procedure.draft_attestation_template.revise!
|
||||
|
||||
if attestation_template.update(activated_attestation_params)
|
||||
AttestationTemplate
|
||||
.where(id: @procedure.revisions.pluck(:attestation_template_id).compact)
|
||||
.update_all(activated: attestation_template.activated?)
|
||||
|
||||
flash.notice = "L'attestation a bien été modifiée"
|
||||
else
|
||||
flash.alert = attestation_template.errors.full_messages.join('<br>')
|
||||
|
@ -18,7 +23,7 @@ module Administrateurs
|
|||
end
|
||||
|
||||
def create
|
||||
attestation_template = AttestationTemplate.new(activated_attestation_params.merge(procedure_id: @procedure.id))
|
||||
attestation_template = build_attestation(activated_attestation_params)
|
||||
|
||||
if attestation_template.save
|
||||
flash.notice = "L'attestation a bien été sauvegardée"
|
||||
|
@ -30,14 +35,19 @@ module Administrateurs
|
|||
end
|
||||
|
||||
def preview
|
||||
attestation = @procedure.attestation_template || AttestationTemplate.new
|
||||
@attestation = attestation.render_attributes_for({})
|
||||
@attestation = build_attestation.render_attributes_for({})
|
||||
|
||||
render 'administrateurs/attestation_templates/show', formats: [:pdf]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_attestation(attributes = {})
|
||||
attestation_template = @procedure.draft_attestation_template || @procedure.draft_revision.build_attestation_template
|
||||
attestation_template.attributes = attributes
|
||||
attestation_template
|
||||
end
|
||||
|
||||
def activated_attestation_params
|
||||
# cache result to avoid multiple uninterlaced computations
|
||||
if @activated_attestation_params.nil?
|
||||
|
|
38
app/lib/balancer_delivery_method.rb
Normal file
38
app/lib/balancer_delivery_method.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
# A Mail delivery method that randomly balances the actual delivery between different
|
||||
# methods.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ```ruby
|
||||
# ActionMailer::Base.add_delivery_method :balancer, BalancerDeliveryMethod
|
||||
# config.action_mailer.balancer_settings = {
|
||||
# smtp: 25,
|
||||
# sendmail: 75
|
||||
# }
|
||||
# config.action_mailer.delivery_method = :balancer
|
||||
# ```
|
||||
#
|
||||
# Be sure to restart your server when you modify this file.
|
||||
class BalancerDeliveryMethod
|
||||
# Allows configuring the random number generator used for selecting a delivery method,
|
||||
# mostly for testing purposes.
|
||||
mattr_accessor :random, default: Random.new
|
||||
|
||||
def initialize(settings)
|
||||
@delivery_methods = settings
|
||||
end
|
||||
|
||||
def deliver!(mail)
|
||||
balanced_delivery_method = delivery_method(mail)
|
||||
ApplicationMailer.wrap_delivery_behavior(mail, balanced_delivery_method)
|
||||
mail.deliver
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def delivery_method(mail)
|
||||
@delivery_methods
|
||||
.flat_map { |delivery_method, weight| [delivery_method] * weight }
|
||||
.sample(random: self.class.random)
|
||||
end
|
||||
end
|
|
@ -15,7 +15,8 @@ class AttestationTemplate < ApplicationRecord
|
|||
include ActionView::Helpers::NumberHelper
|
||||
include TagsSubstitutionConcern
|
||||
|
||||
belongs_to :procedure, optional: false
|
||||
belongs_to :procedure, optional: true
|
||||
has_many :revisions, class_name: 'ProcedureRevision', inverse_of: :attestation_template, dependent: :nullify
|
||||
|
||||
has_one_attached :logo
|
||||
has_one_attached :signature
|
||||
|
@ -103,6 +104,25 @@ class AttestationTemplate < ApplicationRecord
|
|||
}
|
||||
end
|
||||
|
||||
def revise!
|
||||
if revisions.size > 1
|
||||
attestation_template = dup
|
||||
attestation_template.save!
|
||||
revisions
|
||||
.last
|
||||
.procedure
|
||||
.draft_revision
|
||||
.update!(attestation_template: attestation_template)
|
||||
attestation_template
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
def procedure
|
||||
revisions.last&.procedure || super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def used_tags
|
||||
|
|
|
@ -720,9 +720,11 @@ class Dossier < ApplicationRecord
|
|||
{ lon: lon, lat: lat, zoom: zoom }
|
||||
end
|
||||
|
||||
def unspecified_attestation_champs
|
||||
attestation_template = procedure.attestation_template
|
||||
def attestation_template
|
||||
revision.attestation_template
|
||||
end
|
||||
|
||||
def unspecified_attestation_champs
|
||||
if attestation_template&.activated?
|
||||
attestation_template.unspecified_champs_for_dossier(self)
|
||||
else
|
||||
|
@ -731,8 +733,8 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
|
||||
def build_attestation
|
||||
if procedure.attestation_template&.activated?
|
||||
procedure.attestation_template.attestation_for(self)
|
||||
if attestation_template&.activated?
|
||||
attestation_template.attestation_for(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -77,12 +77,15 @@ class Procedure < ApplicationRecord
|
|||
has_many :published_types_de_champ_private, through: :published_revision, source: :types_de_champ_private
|
||||
has_many :draft_types_de_champ, through: :draft_revision, source: :types_de_champ
|
||||
has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private
|
||||
has_one :draft_attestation_template, through: :draft_revision, source: :attestation_template
|
||||
has_one :published_attestation_template, through: :published_revision, source: :attestation_template
|
||||
|
||||
has_many :experts_procedures, dependent: :destroy
|
||||
has_many :experts, through: :experts_procedures
|
||||
|
||||
has_one :module_api_carto, dependent: :destroy
|
||||
has_one :attestation_template, dependent: :destroy
|
||||
has_many :attestation_templates, through: :revisions, source: :attestation_template
|
||||
|
||||
belongs_to :parent_procedure, class_name: 'Procedure', optional: true
|
||||
belongs_to :canonical_procedure, class_name: 'Procedure', optional: true
|
||||
|
@ -438,7 +441,8 @@ class Procedure < ApplicationRecord
|
|||
},
|
||||
revision_types_de_champ_private: {
|
||||
type_de_champ: :types_de_champ
|
||||
}
|
||||
},
|
||||
attestation_template: []
|
||||
}
|
||||
}
|
||||
include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin
|
||||
|
@ -576,13 +580,17 @@ class Procedure < ApplicationRecord
|
|||
touch(:whitelisted_at)
|
||||
end
|
||||
|
||||
def active_attestation_template
|
||||
published_attestation_template || draft_attestation_template
|
||||
end
|
||||
|
||||
def closed_mail_template_attestation_inconsistency_state
|
||||
# As an optimization, don’t check the predefined templates (they are presumed correct)
|
||||
if closed_mail.present?
|
||||
tag_present = closed_mail.body.to_s.include?("--lien attestation--")
|
||||
if attestation_template&.activated? && !tag_present
|
||||
if active_attestation_template&.activated? && !tag_present
|
||||
:missing_tag
|
||||
elsif !attestation_template&.activated? && tag_present
|
||||
elsif !active_attestation_template&.activated? && tag_present
|
||||
:extraneous_tag
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
#
|
||||
# Table name: procedure_revisions
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# published_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# procedure_id :bigint not null
|
||||
# id :bigint not null, primary key
|
||||
# published_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# attestation_template_id :bigint
|
||||
# procedure_id :bigint not null
|
||||
#
|
||||
class ProcedureRevision < ApplicationRecord
|
||||
self.implicit_order_column = :created_at
|
||||
belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false
|
||||
belongs_to :attestation_template, inverse_of: :revisions, optional: true, dependent: :destroy
|
||||
|
||||
has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id
|
||||
|
||||
|
@ -125,6 +127,10 @@ class ProcedureRevision < ApplicationRecord
|
|||
)
|
||||
end
|
||||
|
||||
def attestation_template
|
||||
super || procedure.attestation_template
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compare_types_de_champ(from_tdc, to_tdc)
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
.procedure-grid
|
||||
|
||||
= link_to edit_admin_procedure_attestation_template_path(@procedure), class: 'card-admin' do
|
||||
- if @procedure.attestation_template.present? && @procedure.attestation_template.activated
|
||||
- if @procedure.draft_attestation_template&.activated?
|
||||
%div
|
||||
%span.icon.accept
|
||||
%p.card-admin-status-accept Activée
|
||||
|
|
|
@ -70,28 +70,33 @@ MATOMO_ENABLED="disabled"
|
|||
MATOMO_ID=""
|
||||
MATOMO_HOST="matomo.organisme.fr"
|
||||
|
||||
# SMTP Provider: Send In Blue
|
||||
# Default SMTP Provider: Mailjet
|
||||
MAILJET_API_KEY=""
|
||||
MAILJET_SECRET_KEY=""
|
||||
|
||||
# Alternate SMTP Provider: SendInBlue
|
||||
SENDINBLUE_ENABLED="disabled"
|
||||
SENDINBLUE_BALANCING=""
|
||||
SENDINBLUE_BALANCING_VALUE=""
|
||||
SENDINBLUE_CLIENT_KEY=""
|
||||
SENDINBLUE_SMTP_KEY=""
|
||||
SENDINBLUE_USER_NAME=""
|
||||
# SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc"
|
||||
|
||||
# SMTP Provider: Mailjet
|
||||
MAILJET_API_KEY=""
|
||||
MAILJET_SECRET_KEY=""
|
||||
# Ratio of emails sent using SendInBlue
|
||||
# When enabled, N % of emails will be sent using SendInBlue
|
||||
# (and the others using the default SMTP provider)
|
||||
SENDINBLUE_BALANCING="disabled"
|
||||
SENDINBLUE_BALANCING_VALUE="50"
|
||||
|
||||
# Alternate SMTP Provider: Mailtrap (mail catcher for staging environments)
|
||||
# When enabled, all emails will be sent using this provided
|
||||
MAILTRAP_ENABLED="disabled"
|
||||
MAILTRAP_USERNAME=""
|
||||
MAILTRAP_PASSWORD=""
|
||||
|
||||
# External service: live chat for admins (specific to démarches-simplifiées.fr)
|
||||
CRISP_ENABLED="disabled"
|
||||
CRISP_CLIENT_KEY=""
|
||||
|
||||
# External service: mail catcher for staging environments (specific to démarches-simplifiées.fr)
|
||||
MAILTRAP_ENABLED="disabled"
|
||||
MAILTRAP_USERNAME=""
|
||||
MAILTRAP_PASSWORD=""
|
||||
|
||||
# API Entreprise credentials
|
||||
# https://api.gouv.fr/api/api-entreprise.html
|
||||
API_ENTREPRISE_KEY=""
|
||||
|
|
|
@ -75,40 +75,13 @@ Rails.application.configure do
|
|||
config.assets.raise_runtime_errors = true
|
||||
|
||||
# Action Mailer settings
|
||||
config.action_mailer.delivery_method = :letter_opener
|
||||
|
||||
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
|
||||
# https://usehelo.com
|
||||
if ENV['HELO_ENABLED'] == 'enabled'
|
||||
config.action_mailer.delivery_method = :smtp
|
||||
config.action_mailer.smtp_settings = {
|
||||
user_name: 'demarches-simplifiees',
|
||||
password: '',
|
||||
address: '127.0.0.1',
|
||||
domain: '127.0.0.1',
|
||||
port: ENV.fetch('HELO_PORT', '2525'),
|
||||
authentication: :plain
|
||||
}
|
||||
else
|
||||
config.action_mailer.delivery_method = :letter_opener_web
|
||||
end
|
||||
|
||||
config.action_mailer.default_url_options = {
|
||||
host: 'localhost',
|
||||
port: 3000
|
||||
}
|
||||
|
||||
config.action_mailer.asset_host = "http://" + ENV['APP_HOST']
|
||||
end
|
||||
config.action_mailer.default_url_options = {
|
||||
host: 'localhost',
|
||||
port: 3000
|
||||
}
|
||||
config.action_mailer.asset_host = "http://" + ENV['APP_HOST']
|
||||
|
||||
Rails.application.routes.default_url_options = {
|
||||
host: 'localhost',
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require "active_support/core_ext/integer/time"
|
||||
require Rails.root.join("app/lib/balancer_delivery_method")
|
||||
|
||||
Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
@ -76,25 +77,19 @@ Rails.application.configure do
|
|||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
if ENV['MAILTRAP_ENABLED'] == 'enabled'
|
||||
config.action_mailer.delivery_method = :smtp
|
||||
config.action_mailer.smtp_settings = {
|
||||
user_name: Rails.application.secrets.mailtrap[:username],
|
||||
password: Rails.application.secrets.mailtrap[:password],
|
||||
address: 'smtp.mailtrap.io',
|
||||
domain: 'smtp.mailtrap.io',
|
||||
port: '2525',
|
||||
authentication: :cram_md5
|
||||
config.action_mailer.delivery_method = :mailtrap
|
||||
|
||||
elsif ENV['SENDINBLUE_ENABLED'] == 'enabled' && ENV['SENDINBLUE_BALANCING'] == 'enabled'
|
||||
ActionMailer::Base.add_delivery_method :balancer, BalancerDeliveryMethod
|
||||
config.action_mailer.balancer_settings = {
|
||||
sendinblue: ENV.fetch('SENDINBLUE_BALANCING_VALUE').to_i,
|
||||
mailjet: 100 - ENV.fetch('SENDINBLUE_BALANCING_VALUE').to_i
|
||||
}
|
||||
config.action_mailer.delivery_method = :balancer
|
||||
|
||||
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
|
||||
}
|
||||
config.action_mailer.delivery_method = :sendinblue
|
||||
|
||||
else
|
||||
config.action_mailer.delivery_method = :mailjet
|
||||
end
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
# rubocop:disable DS/ApplicationName
|
||||
# API URLs
|
||||
API_ADRESSE_URL = ENV.fetch("API_ADRESSE_URL", "https://api-adresse.data.gouv.fr")
|
||||
API_ENTREPRISE_URL = ENV.fetch("API_ENTREPRISE_URL", "https://entreprise.api.gouv.fr/v2")
|
||||
API_EDUCATION_URL = ENV.fetch("API_EDUCATION_URL", "https://data.education.gouv.fr/api/records/1.0")
|
||||
API_GEO_URL = ENV.fetch("API_GEO_URL", "https://geo.api.gouv.fr")
|
||||
API_PARTICULIER_URL = ENV.fetch("API_PARTICULIER_URL", "https://particulier.api.gouv.fr/api")
|
||||
HELPSCOUT_API_URL = ENV.fetch("HELPSCOUT_API_URL", "https://api.helpscout.net/v2")
|
||||
PIPEDRIVE_API_URL = ENV.fetch("PIPEDRIVE_API_URL", "https://api.pipedrive.com/v1")
|
||||
|
@ -11,7 +13,7 @@ UNIVERSIGN_API_URL = ENV.fetch("UNIVERSIGN_API_URL", "https://ws.universign.eu/t
|
|||
FEATURE_UPVOTE_URL = ENV.fetch("FEATURE_UPVOTE_URL", "https://demarches-simplifiees.featureupvote.com")
|
||||
|
||||
# Internal URLs
|
||||
FOG_BASE_URL = "https://static.demarches-simplifiees.fr"
|
||||
FOG_OPENSTACK_URL = ENV.fetch("FOG_OPENSTACK_URL", "https://static.demarches-simplifiees.fr")
|
||||
|
||||
# External services URLs
|
||||
WEBINAIRE_URL = "https://app.livestorm.co/demarches-simplifiees"
|
|
@ -4,30 +4,45 @@
|
|||
# For further information see the following documentation
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
||||
|
||||
# rubocop:disable DS/ApplicationName
|
||||
Rails.application.config.content_security_policy do |policy|
|
||||
# Whitelist image
|
||||
policy.img_src :self, "*.openstreetmap.org", "static.demarches-simplifiees.fr", "*.cloud.ovh.net", "stats.data.gouv.fr", "*", :data, :blob
|
||||
images_whitelist = ["*.openstreetmap.org", "*.cloud.ovh.net", "*"]
|
||||
images_whitelist << URI(FOG_OPENSTACK_URL).host if FOG_OPENSTACK_URL.present?
|
||||
images_whitelist << URI(MATOMO_IFRAME_URL).host if MATOMO_IFRAME_URL.present?
|
||||
policy.img_src(:self, :data, :blob, *images_whitelist)
|
||||
|
||||
# Whitelist JS: nous, sendinblue et matomo
|
||||
# miniprofiler et nous avons quelques boutons inline :(
|
||||
policy.script_src :self, "stats.data.gouv.fr", "*.sendinblue.com", "*.crisp.chat", "crisp.chat", "*.sibautomation.com", "sibautomation.com", 'cdn.jsdelivr.net', 'maxcdn.bootstrapcdn.com', 'code.jquery.com', :unsafe_eval, :unsafe_inline, :blob
|
||||
scripts_whitelist = ["*.sendinblue.com", "*.crisp.chat", "crisp.chat", "*.sibautomation.com", "sibautomation.com", "cdn.jsdelivr.net", "maxcdn.bootstrapcdn.com", "code.jquery.com"]
|
||||
scripts_whitelist << URI(MATOMO_IFRAME_URL).host if MATOMO_IFRAME_URL.present?
|
||||
policy.script_src(:self, :unsafe_eval, :unsafe_inline, :blob, *scripts_whitelist)
|
||||
|
||||
# Pour les CSS, on a beaucoup de style inline et quelques balises <style>
|
||||
# c'est trop compliqué pour être rectifié immédiatement (et sans valeur ajoutée:
|
||||
# c'est hardcodé dans les vues, donc pas injectable).
|
||||
policy.style_src :self, "*.crisp.chat", "crisp.chat", 'cdn.jsdelivr.net', 'maxcdn.bootstrapcdn.com', :unsafe_inline
|
||||
policy.connect_src :self, "wss://*.crisp.chat", "*.crisp.chat", "*.demarches-simplifiees.fr", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io", "geo.api.gouv.fr", "api-adresse.data.gouv.fr", "openmaptiles.geo.data.gouv.fr", "openmaptiles.github.io", "tiles.geo.api.gouv.fr", "wxs.ign.fr", "data.education.gouv.fr"
|
||||
policy.style_src(:self, "*.crisp.chat", "crisp.chat", 'cdn.jsdelivr.net', 'maxcdn.bootstrapcdn.com', :unsafe_inline)
|
||||
|
||||
connect_whitelist = ["wss://*.crisp.chat", "*.crisp.chat", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io", "openmaptiles.geo.data.gouv.fr", "openmaptiles.github.io", "tiles.geo.api.gouv.fr", "wxs.ign.fr"]
|
||||
connect_whitelist << URI(API_ADRESSE_URL).host if API_ADRESSE_URL.present?
|
||||
connect_whitelist << URI(API_EDUCATION_URL).host if API_EDUCATION_URL.present?
|
||||
connect_whitelist << URI(API_GEO_URL).host if API_GEO_URL.present?
|
||||
connect_whitelist << "*.#{ENV.fetch('APP_HOST', 'localhost:3000')}"
|
||||
policy.connect_src(:self, *connect_whitelist)
|
||||
|
||||
# Pour tout le reste, par défaut on accepte uniquement ce qui vient de chez nous
|
||||
# et dans la notification on inclue la source de l'erreur
|
||||
policy.default_src :self, :data, :blob, :report_sample, "fonts.gstatic.com", "in-automate.sendinblue.com", "player.vimeo.com", "app.franceconnect.gouv.fr", "sentry.io", "static.demarches-simplifiees.fr", "*.crisp.chat", "crisp.chat", "*.crisp.help", "*.sibautomation.com", "sibautomation.com", "data"
|
||||
default_whitelist = ["fonts.gstatic.com", "in-automate.sendinblue.com", "player.vimeo.com", "app.franceconnect.gouv.fr", "sentry.io", "*.crisp.chat", "crisp.chat", "*.crisp.help", "*.sibautomation.com", "sibautomation.com", "data"]
|
||||
default_whitelist << URI(FOG_OPENSTACK_URL).host if FOG_OPENSTACK_URL.present?
|
||||
policy.default_src(:self, :data, :blob, :report_sample, *default_whitelist)
|
||||
|
||||
if Rails.env.development?
|
||||
# Les CSP ne sont pas appliquées en dev: on notifie cependant une url quelconque de la violation
|
||||
# pour détecter les erreurs lors de l'ajout d'une nouvelle brique externe durant le développement
|
||||
policy.report_uri "http://#{ENV['APP_HOST']}/csp/"
|
||||
policy.report_uri "http://#{ENV.fetch('APP_HOST', 'localhost:3000')}/csp/"
|
||||
# En développement, quand bin/webpack-dev-server est utilisé, on autorise les requêtes faites par le live-reload
|
||||
policy.connect_src(*policy.connect_src, "ws://localhost:3035", "http://localhost:3035")
|
||||
end
|
||||
end
|
||||
# rubocop:enable DS/ApplicationName
|
||||
|
||||
# If you are using UJS then enable automatic nonce generation
|
||||
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# We want to register an interceptor, but we can't make the action idempotent
|
||||
# (because there's no way to peek at the currently registered interceptors).
|
||||
#
|
||||
# To make zeitwerk happy, instead signal that we don't want the
|
||||
# DynamicSmtpSettingsInterceptor constant to be auto-loaded, by:
|
||||
# - adding it to a non-autoloaded-path (/lib),
|
||||
# - requiring it explicitely.
|
||||
#
|
||||
# See https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoloading-when-the-application-boots
|
||||
require 'action_mailer/dynamic_smtp_settings_interceptor'
|
||||
|
||||
ActiveSupport.on_load(:action_mailer) do
|
||||
ActionMailer::Base.register_interceptor DynamicSmtpSettingsInterceptor
|
||||
end
|
17
config/initializers/helo.rb
Normal file
17
config/initializers/helo.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
if ENV['HELO_ENABLED'] == 'enabled'
|
||||
ActiveSupport.on_load(:action_mailer) do
|
||||
module Helo
|
||||
class SMTP < ::Mail::SMTP; end
|
||||
end
|
||||
|
||||
ActionMailer::Base.add_delivery_method :helo, Helo::SMTP
|
||||
ActionMailer::Base.helo_settings = {
|
||||
user_name: 'demarches-simplifiees',
|
||||
password: '',
|
||||
address: '127.0.0.1',
|
||||
domain: '127.0.0.1',
|
||||
port: ENV.fetch('HELO_PORT', '2525'),
|
||||
authentication: :plain
|
||||
}
|
||||
end
|
||||
end
|
17
config/initializers/mailtrap.rb
Normal file
17
config/initializers/mailtrap.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
if ENV.fetch('MAILTRAP_ENABLED') == 'enabled'
|
||||
ActiveSupport.on_load(:action_mailer) do
|
||||
module Mailtrap
|
||||
class SMTP < ::Mail::SMTP; end
|
||||
end
|
||||
|
||||
ActionMailer::Base.add_delivery_method :mailtrap, Mailtrap::SMTP
|
||||
ActionMailer::Base.mailtrap_settings = {
|
||||
user_name: Rails.application.secrets.mailtrap[:username],
|
||||
password: Rails.application.secrets.mailtrap[:password],
|
||||
address: 'smtp.mailtrap.io',
|
||||
domain: 'smtp.mailtrap.io',
|
||||
port: '2525',
|
||||
authentication: :cram_md5
|
||||
}
|
||||
end
|
||||
end
|
|
@ -1,5 +1,23 @@
|
|||
require 'sib-api-v3-sdk'
|
||||
if ENV.fetch('SENDINBLUE_ENABLED') == 'enabled'
|
||||
require 'sib-api-v3-sdk'
|
||||
|
||||
SibApiV3Sdk.configure do |config|
|
||||
config.api_key['api-key'] = ENV.fetch('SENDINBLUE_API_V3_KEY', '')
|
||||
ActiveSupport.on_load(:action_mailer) do
|
||||
module Sendinblue
|
||||
class SMTP < ::Mail::SMTP; end
|
||||
end
|
||||
|
||||
ActionMailer::Base.add_delivery_method :sendinblue, Sendinblue::SMTP
|
||||
ActionMailer::Base.sendinblue_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
|
||||
}
|
||||
end
|
||||
|
||||
SibApiV3Sdk.configure do |config|
|
||||
config.api_key['api-key'] = Rails.application.secrets.sendinblue[:api_v3_key]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddAttestationTemplateIdToProcedureRevisions < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_reference :procedure_revisions, :attestation_template, foreign_key: { to_table: :attestation_templates }, null: true, index: true
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_01_27_135056) do
|
||||
ActiveRecord::Schema.define(version: 2022_01_28_135056) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -593,6 +593,8 @@ ActiveRecord::Schema.define(version: 2022_01_27_135056) do
|
|||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "published_at"
|
||||
t.bigint "attestation_template_id"
|
||||
t.index ["attestation_template_id"], name: "index_procedure_revisions_on_attestation_template_id"
|
||||
t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id"
|
||||
end
|
||||
|
||||
|
@ -872,6 +874,7 @@ ActiveRecord::Schema.define(version: 2022_01_27_135056) do
|
|||
add_foreign_key "procedure_revision_types_de_champ", "procedure_revision_types_de_champ", column: "parent_id"
|
||||
add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id"
|
||||
add_foreign_key "procedure_revision_types_de_champ", "types_de_champ"
|
||||
add_foreign_key "procedure_revisions", "attestation_templates"
|
||||
add_foreign_key "procedure_revisions", "procedures"
|
||||
add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id"
|
||||
add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id"
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# Note: this class is instanciated when being added as an interceptor
|
||||
# during the app initialization.
|
||||
#
|
||||
# If you edit this file in development env, you will need to restart
|
||||
# the app to see the changes.
|
||||
|
||||
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
|
|
@ -1,20 +1,26 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: backfill_expert_id_on_avis_table'
|
||||
task backfill_experts_procedure_id_on_avis_table: :environment do
|
||||
puts "Running deploy task 'backfill_expert_id_on_avis_table'"
|
||||
puts "Running deploy task 'backfill_experts_procedure_id_on_avis_table'"
|
||||
# rubocop:disable DS/Unscoped
|
||||
# rubocop:disable Rails/PluckInWhere
|
||||
|
||||
Instructeur.includes(:user)
|
||||
.where(id: Avis.unscoped.pluck(:instructeur_id))
|
||||
.where.not(users: { instructeur_id: nil })
|
||||
.find_each do |instructeur|
|
||||
instructeurs = Instructeur.includes(:user).where.not(users: { instructeur_id: nil })
|
||||
|
||||
instructeurs =
|
||||
if Avis.column_names.include?("instructeur_id")
|
||||
instructeurs.where(id: Avis.unscoped.pluck(:instructeur_id))
|
||||
else
|
||||
instructeurs.where(id: Avis.unscoped.where(claimant_type: [nil, "Instructeur"]).pluck(:claimant_id))
|
||||
end
|
||||
|
||||
instructeurs.find_each do |instructeur|
|
||||
user = instructeur.user
|
||||
User.create_or_promote_to_expert(user.email, SecureRandom.hex)
|
||||
user.reload
|
||||
# rubocop:enable DS/Unscoped
|
||||
# rubocop:enable Rails/PluckInWhere
|
||||
instructeur.avis.each do |avis|
|
||||
Avis.where(claimant: instructeur).each do |avis|
|
||||
experts_procedure = ExpertsProcedure.find_or_create_by(expert: user.expert, procedure: avis.procedure)
|
||||
avis.update_column(:experts_procedure_id, experts_procedure.id)
|
||||
end
|
||||
|
|
|
@ -5,7 +5,8 @@ namespace :after_party do
|
|||
|
||||
BATCH_SIZE = 20000
|
||||
|
||||
with_dossiers = Avis.where(claimant_type: nil).includes(claimant: :assign_to).where.not(claimant: { assign_tos: { id: nil } })
|
||||
without_assign_to_ids = Instructeur.includes(:assign_to).where(assign_tos: { id: nil }).pluck(:id)
|
||||
with_dossiers = Avis.where(claimant_type: nil).where.not(claimant_id: without_assign_to_ids)
|
||||
|
||||
((with_dossiers.count / BATCH_SIZE).ceil + 1).times do
|
||||
with_dossiers
|
||||
|
@ -13,10 +14,9 @@ namespace :after_party do
|
|||
.update_all(claimant_type: 'Instructeur')
|
||||
end
|
||||
|
||||
without_dossiers = Avis.where(claimant_type: nil).includes(claimant: :assign_to).where(claimant: { assign_tos: { id: nil } })
|
||||
without_dossiers = Avis.where(claimant_type: nil).where(claimant_id: without_assign_to_ids)
|
||||
without_dossiers.find_each do |avis|
|
||||
claimant = avis.claimant.user
|
||||
instructeur = avis.instructeur
|
||||
instructeur = Instructeur.find(avis.claimant_id)
|
||||
|
||||
if instructeur && avis.experts_procedure_id.blank?
|
||||
User.create_or_promote_to_expert(instructeur.user.email, SecureRandom.hex)
|
||||
|
@ -33,7 +33,7 @@ namespace :after_party do
|
|||
elsif avis.experts_procedure_id.present?
|
||||
avis.update_column(:claimant_type, 'Expert')
|
||||
|
||||
elsif claimant.blank?
|
||||
elsif instructeur && instructeur.user.nil?
|
||||
avis.destroy
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,8 @@ namespace :after_party do
|
|||
task backfill_claimant_id_for_experts_on_avis_table: :environment do
|
||||
puts "Running deploy task 'backfill_claimant_id_for_experts_on_avis_table'"
|
||||
|
||||
avis_experts_claimant = Avis.where(claimant_type: 'Expert', tmp_expert_migrated: false)
|
||||
avis_experts_claimant = Avis.where(claimant_type: 'Expert')
|
||||
avis_experts_claimant = avis_experts_claimant.where(tmp_expert_migrated: false) if Avis.column_names.include?("tmp_expert_migrated")
|
||||
progress = ProgressReport.new(avis_experts_claimant.count)
|
||||
|
||||
avis_experts_claimant.find_each do |avis|
|
||||
|
@ -15,7 +16,10 @@ namespace :after_party do
|
|||
claimant_expert = claimant_instructeur.reload.user.expert
|
||||
ExpertsProcedure.find_or_create_by(procedure: avis.procedure, expert: claimant_expert)
|
||||
end
|
||||
avis.update_columns(claimant_id: claimant_expert.id, tmp_expert_migrated: true)
|
||||
|
||||
if Avis.column_names.include?("tmp_expert_migrated")
|
||||
avis.update_columns(claimant_id: claimant_expert.id, tmp_expert_migrated: true)
|
||||
end
|
||||
else
|
||||
# Avis associated to an Instructeur with no user are bad data: delete it
|
||||
avis.destroy!
|
||||
|
@ -23,6 +27,7 @@ namespace :after_party do
|
|||
progress.inc
|
||||
end
|
||||
progress.finish
|
||||
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
|
|
|
@ -3,8 +3,19 @@ namespace :after_party do
|
|||
task backfill_experts_procedure_id_on_avis_table_again: :environment do
|
||||
puts "Running deploy task 'backfill_experts_procedure_id_on_avis_table_again'"
|
||||
|
||||
without_instructeur = Avis.where(experts_procedure_id: nil, instructeur_id: nil).where.not(email: nil)
|
||||
with_instructeur = Avis.where(experts_procedure_id: nil, email: nil).where.not(instructeur_id: nil)
|
||||
if Avis.column_names.include?("instructeur_id")
|
||||
without_instructeur = Avis.where(experts_procedure_id: nil, instructeur_id: nil).where.not(email: nil)
|
||||
with_instructeur = Avis.where(experts_procedure_id: nil, email: nil).where.not(instructeur_id: nil)
|
||||
else
|
||||
without_instructeur = Avis
|
||||
.where(experts_procedure_id: nil, claimant_type: [nil, "Instructeur"])
|
||||
.where.not(email: nil)
|
||||
|
||||
with_instructeur = Avis
|
||||
.where(experts_procedure_id: nil, email: nil, claimant_type: [nil, "Instructeur"])
|
||||
.where.not(claimant_id: nil)
|
||||
end
|
||||
|
||||
progress = ProgressReport.new(without_instructeur.count)
|
||||
progress2 = ProgressReport.new(with_instructeur.count)
|
||||
|
||||
|
@ -22,7 +33,8 @@ namespace :after_party do
|
|||
progress.finish
|
||||
|
||||
with_instructeur.find_each do |avis|
|
||||
instructeur = avis.instructeur
|
||||
instructeur = avis.respond_to?(:instructeur) ? avis.instructeur : avis.claimant
|
||||
|
||||
if instructeur && instructeur.user
|
||||
user = User.create_or_promote_to_expert(instructeur.user.email, SecureRandom.hex)
|
||||
user.reload
|
||||
|
|
|
@ -3,14 +3,16 @@ namespace :after_party do
|
|||
task revise_attestation_templates: :environment do
|
||||
rake_puts "Running deploy task 'revise_attestation_templates'"
|
||||
|
||||
attestation_templates = AttestationTemplate.where.not(procedure_id: nil)
|
||||
progress = ProgressReport.new(attestation_templates.count)
|
||||
revisions = ProcedureRevision
|
||||
.joins(procedure: :attestation_template)
|
||||
.where(attestation_template_id: nil)
|
||||
|
||||
progress = ProgressReport.new(revisions.count)
|
||||
|
||||
revisions.find_each do |revision|
|
||||
attestation_template_id = revision.procedure.attestation_template.id
|
||||
revision.update_column(:attestation_template_id, attestation_template_id)
|
||||
|
||||
attestation_templates.find_each do |attestation_template|
|
||||
ProcedureRevision
|
||||
.where(procedure_id: attestation_template.procedure_id, attestation_template_id: nil)
|
||||
.update_all(attestation_template_id: attestation_template)
|
||||
attestation_template.update_column(:procedure_id, nil)
|
||||
progress.inc
|
||||
end
|
||||
progress.finish
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
include ActionDispatch::TestProcess
|
||||
|
||||
describe Administrateurs::AttestationTemplatesController, type: :controller do
|
||||
let!(:attestation_template) { create(:attestation_template) }
|
||||
let(:admin) { create(:administrateur) }
|
||||
let(:attestation_template) { build(:attestation_template) }
|
||||
let!(:procedure) { create :procedure, administrateur: admin, attestation_template: attestation_template }
|
||||
let(:logo) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
|
||||
let(:logo2) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
|
||||
|
@ -41,7 +41,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
end
|
||||
|
||||
context 'if an attestation template exists on the procedure' do
|
||||
after { procedure.attestation_template.destroy }
|
||||
after { procedure.draft_revision.attestation_template&.destroy }
|
||||
|
||||
context 'with images' do
|
||||
let!(:attestation_template) do
|
||||
|
@ -115,14 +115,14 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
procedure.reload
|
||||
end
|
||||
|
||||
it { expect(procedure.attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.attestation_template.activated).to be true }
|
||||
it { expect(procedure.attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(procedure.draft_attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.draft_attestation_template.activated).to be true }
|
||||
it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.draft_attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
|
||||
it { expect(flash.notice).to eq("L'attestation a bien été sauvegardée") }
|
||||
|
||||
after { procedure.attestation_template.destroy }
|
||||
after { procedure.draft_attestation_template.destroy }
|
||||
end
|
||||
|
||||
context 'when something wrong happens in the attestation template creation' do
|
||||
|
@ -140,7 +140,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
|
||||
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
|
||||
it { expect(flash.alert).to be_present }
|
||||
it { expect(procedure.attestation_template).to be nil }
|
||||
it { expect(procedure.draft_attestation_template).to be nil }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -158,13 +158,13 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
procedure.reload
|
||||
end
|
||||
|
||||
it { expect(procedure.attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(procedure.draft_attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.draft_attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
|
||||
it { expect(flash.notice).to eq("L'attestation a bien été modifiée") }
|
||||
|
||||
after { procedure.attestation_template.destroy }
|
||||
after { procedure.draft_attestation_template&.destroy }
|
||||
end
|
||||
|
||||
context 'when something wrong happens in the attestation template creation' do
|
||||
|
|
|
@ -4,8 +4,6 @@ FactoryBot.define do
|
|||
body { 'body' }
|
||||
footer { 'footer' }
|
||||
activated { true }
|
||||
|
||||
association :procedure
|
||||
end
|
||||
|
||||
trait :with_files do
|
||||
|
|
|
@ -18,15 +18,16 @@ FactoryBot.define do
|
|||
administrateurs { administrateur.present? ? [administrateur] : [association(:administrateur)] }
|
||||
|
||||
transient do
|
||||
administrateur { }
|
||||
administrateur {}
|
||||
instructeurs { [] }
|
||||
types_de_champ { [] }
|
||||
types_de_champ_private { [] }
|
||||
updated_at { nil }
|
||||
attestation_template { nil }
|
||||
end
|
||||
|
||||
after(:build) do |procedure, evaluator|
|
||||
initial_revision = build(:procedure_revision, procedure: procedure)
|
||||
initial_revision = build(:procedure_revision, procedure: procedure, attestation_template: evaluator.attestation_template)
|
||||
add_types_de_champs(evaluator.types_de_champ, to: initial_revision, scope: :public)
|
||||
add_types_de_champs(evaluator.types_de_champ_private, to: initial_revision, scope: :private)
|
||||
|
||||
|
|
93
spec/lib/balancer_delivery_method_spec.rb
Normal file
93
spec/lib/balancer_delivery_method_spec.rb
Normal file
|
@ -0,0 +1,93 @@
|
|||
RSpec.describe BalancerDeliveryMethod do
|
||||
class ExampleMailer < ApplicationMailer
|
||||
def greet(name)
|
||||
mail(to: "smtp_to", from: "smtp_from", body: "Hello #{name}")
|
||||
end
|
||||
end
|
||||
|
||||
class TestMail
|
||||
def self.deliveries
|
||||
@deliveries ||= []
|
||||
end
|
||||
|
||||
def self.deliveries=(val)
|
||||
@deliveries = val
|
||||
end
|
||||
|
||||
attr_accessor :settings
|
||||
|
||||
def initialize(values)
|
||||
@settings = values.dup
|
||||
end
|
||||
|
||||
def deliver!(mail)
|
||||
Mail::CheckDeliveryParams.check(mail)
|
||||
self.class.deliveries << mail
|
||||
end
|
||||
end
|
||||
|
||||
class MockSmtp < TestMail; end
|
||||
|
||||
class MockSendmail < TestMail; end
|
||||
|
||||
class FixedSequence
|
||||
def initialize(sequence)
|
||||
@enumerator = sequence.each
|
||||
end
|
||||
|
||||
def rand(_)
|
||||
@enumerator.next
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
ActionMailer::Base.add_delivery_method :mock_smtp, MockSmtp
|
||||
ActionMailer::Base.add_delivery_method :mock_sendmail, MockSendmail
|
||||
ActionMailer::Base.add_delivery_method :balancer, BalancerDeliveryMethod
|
||||
|
||||
ExampleMailer.delivery_method = :balancer
|
||||
end
|
||||
|
||||
context 'when a single delivery method is provided' do
|
||||
before do
|
||||
ActionMailer::Base.balancer_settings = { mock_smtp: 10 }
|
||||
end
|
||||
|
||||
it 'sends emails to the selected delivery method' do
|
||||
mail = ExampleMailer.greet('Joshua').deliver_now
|
||||
expect(mail).to have_been_delivered_using(MockSmtp)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multiple delivery methods are provided' do
|
||||
before do
|
||||
ActionMailer::Base.balancer_settings = { mock_smtp: 10, mock_sendmail: 5 }
|
||||
|
||||
rng_sequence = [3, 14, 1]
|
||||
BalancerDeliveryMethod.random = FixedSequence.new(rng_sequence)
|
||||
end
|
||||
|
||||
after do
|
||||
BalancerDeliveryMethod.random = Random.new
|
||||
end
|
||||
|
||||
it 'sends emails randomly, given the provided weights' do
|
||||
mail1 = ExampleMailer.greet('Lucia').deliver_now
|
||||
expect(mail1).to have_been_delivered_using(MockSmtp)
|
||||
|
||||
mail2 = ExampleMailer.greet('Damian').deliver_now
|
||||
expect(mail2).to have_been_delivered_using(MockSendmail)
|
||||
|
||||
mail3 = ExampleMailer.greet('Rahwa').deliver_now
|
||||
expect(mail3).to have_been_delivered_using(MockSmtp)
|
||||
end
|
||||
end
|
||||
|
||||
# Helpers
|
||||
|
||||
def have_been_delivered_using(delivery_class)
|
||||
satisfy("have been delivered using #{delivery_class}") do |mail|
|
||||
delivery_class.deliveries.include?(mail)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
describe '20220112184331_revise_attestation_templates' do
|
||||
let(:rake_task) { Rake::Task['after_party:revise_attestation_templates'] }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:attestation_template) { create(:attestation_template, procedure: procedure) }
|
||||
|
||||
subject(:run_task) do
|
||||
attestation_template
|
||||
rake_task.invoke
|
||||
attestation_template.reload
|
||||
end
|
||||
|
||||
after { rake_task.reenable }
|
||||
|
||||
describe 'revise_attestation_templates' do
|
||||
it 'attaches the attestation_template to the latest revision (without removing the link between attestation_template and procedure for now)' do
|
||||
expect(attestation_template.procedure.revisions.first.attestation_template_id).to be_nil
|
||||
run_task
|
||||
expect(attestation_template.procedure_id).to eq(procedure.id)
|
||||
expect(attestation_template.procedure.revisions.first.attestation_template_id).to eq(attestation_template.id)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,6 +4,10 @@ describe Universign::API do
|
|||
|
||||
let(:digest) { Digest::SHA256.hexdigest("CECI EST UN HASH") }
|
||||
|
||||
before do
|
||||
stub_const("UNIVERSIGN_API_URL", "https://ws.universign.eu/tsa/post/")
|
||||
end
|
||||
|
||||
it { is_expected.not_to be_nil }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,16 +66,12 @@ describe Procedure do
|
|||
end
|
||||
|
||||
describe '#closed_mail_template_attestation_inconsistency_state' do
|
||||
let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail) }
|
||||
let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail, attestation_template: nil) }
|
||||
let(:procedure_with_active_attestation) do
|
||||
procedure = create(:procedure, closed_mail: closed_mail)
|
||||
create(:attestation_template, procedure: procedure, activated: true)
|
||||
procedure
|
||||
create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: true))
|
||||
end
|
||||
let(:procedure_with_inactive_attestation) do
|
||||
procedure = create(:procedure, closed_mail: closed_mail)
|
||||
create(:attestation_template, procedure: procedure, activated: false)
|
||||
procedure
|
||||
create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: false))
|
||||
end
|
||||
|
||||
subject { procedure.closed_mail_template_attestation_inconsistency_state }
|
||||
|
|
|
@ -9,6 +9,7 @@ end
|
|||
|
||||
Capybara.register_driver :headless_chrome do |app|
|
||||
options = Selenium::WebDriver::Chrome::Options.new
|
||||
options.add_argument('--no-sandbox') unless ENV['SANDBOX']
|
||||
options.add_argument('--headless') unless ENV['NO_HEADLESS']
|
||||
options.add_argument('--window-size=1440,900')
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml', type: :view do
|
||||
let(:procedure) { create(:procedure, closed_mail: closed_mail) }
|
||||
let(:procedure) { create(:procedure, closed_mail: closed_mail, attestation_template: attestation_template) }
|
||||
let(:attestation_template) { nil }
|
||||
|
||||
def alert
|
||||
assign(:procedure, procedure)
|
||||
|
@ -23,7 +24,7 @@ describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml'
|
|||
|
||||
context 'when there is an active attestation but the closed mail template does not mention it' do
|
||||
let(:closed_mail) { create(:closed_mail) }
|
||||
let!(:attestation_template) { create(:attestation_template, procedure: procedure, activated: true) }
|
||||
let(:attestation_template) { build(:attestation_template) }
|
||||
|
||||
it { expect(alert).to include("Cette démarche comporte une attestation, mais l’accusé d’acceptation ne la mentionne pas") }
|
||||
it { expect(alert).to include(edit_admin_procedure_mail_template_path(procedure, Mails::ClosedMail::SLUG)) }
|
||||
|
|
Loading…
Reference in a new issue