commit
dc39df1edc
25 changed files with 206 additions and 84 deletions
42
Gemfile.lock
42
Gemfile.lock
|
@ -102,7 +102,7 @@ GEM
|
|||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.1)
|
||||
attr_required (1.0.1)
|
||||
autoprefixer-rails (10.0.0.1)
|
||||
autoprefixer-rails (10.0.0.2)
|
||||
execjs
|
||||
axe-matchers (2.6.1)
|
||||
dumb_delegator (~> 0.8)
|
||||
|
@ -138,7 +138,7 @@ GEM
|
|||
rack-test (>= 0.6.3)
|
||||
regexp_parser (~> 1.5)
|
||||
xpath (~> 3.2)
|
||||
capybara-email (3.0.1)
|
||||
capybara-email (3.0.2)
|
||||
capybara (>= 2.4, < 4.0)
|
||||
mail
|
||||
capybara-screenshot (1.0.24)
|
||||
|
@ -159,7 +159,7 @@ GEM
|
|||
choice (0.2.0)
|
||||
chunky_png (1.3.11)
|
||||
clamav-client (3.2.0)
|
||||
coderay (1.1.2)
|
||||
coderay (1.1.3)
|
||||
coercible (1.0.0)
|
||||
descendants_tracker (~> 0.0.1)
|
||||
coffee-rails (5.0.0)
|
||||
|
@ -171,8 +171,7 @@ GEM
|
|||
coffee-script-source (1.12.2)
|
||||
concurrent-ruby (1.1.7)
|
||||
connection_pool (2.2.3)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
crack (0.4.4)
|
||||
crass (1.0.6)
|
||||
css_parser (1.7.1)
|
||||
addressable
|
||||
|
@ -289,7 +288,7 @@ GEM
|
|||
thor (>= 0.19, < 2.0)
|
||||
graphql_playground-rails (2.1.0)
|
||||
rails (>= 5.1.0)
|
||||
groupdate (5.0.0)
|
||||
groupdate (5.2.1)
|
||||
activesupport (>= 5)
|
||||
guard (2.16.2)
|
||||
formatador (>= 0.2.4)
|
||||
|
@ -467,7 +466,7 @@ GEM
|
|||
prawn (>= 0.11.1, < 3)
|
||||
prawn-table (0.2.2)
|
||||
prawn (>= 1.3.0, < 3.0.0)
|
||||
premailer (1.11.1)
|
||||
premailer (1.13.1)
|
||||
addressable
|
||||
css_parser (>= 1.6.0)
|
||||
htmlentities (>= 4.0.0)
|
||||
|
@ -488,9 +487,9 @@ GEM
|
|||
activesupport (>= 3.0.0)
|
||||
raabro (1.1.6)
|
||||
rack (2.2.3)
|
||||
rack-attack (6.2.2)
|
||||
rack-attack (6.3.1)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-mini-profiler (2.0.1)
|
||||
rack-mini-profiler (2.1.0)
|
||||
rack (>= 1.2.0)
|
||||
rack-oauth2 (1.15.0)
|
||||
activesupport
|
||||
|
@ -624,10 +623,9 @@ GEM
|
|||
rexml
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby2_keywords (0.0.2)
|
||||
ruby_parser (3.14.2)
|
||||
ruby_parser (3.15.0)
|
||||
sexp_processor (~> 4.9)
|
||||
rubyzip (2.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sanitize-url (0.1.4)
|
||||
sass (3.7.4)
|
||||
sass-listen (~> 4.0.0)
|
||||
|
@ -649,11 +647,11 @@ GEM
|
|||
childprocess (>= 0.5, < 4.0)
|
||||
rubyzip (>= 1.2.2)
|
||||
semantic_range (2.3.0)
|
||||
sentry-raven (3.0.0)
|
||||
sentry-raven (3.1.0)
|
||||
faraday (>= 1.0)
|
||||
sexp_processor (4.14.1)
|
||||
sexp_processor (4.15.1)
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (4.3.0)
|
||||
shoulda-matchers (4.4.1)
|
||||
activesupport (>= 4.2.0)
|
||||
simple_xlsx_reader (1.0.4)
|
||||
nokogiri
|
||||
|
@ -676,7 +674,7 @@ GEM
|
|||
axlsx_styler (>= 1.0.0, < 2)
|
||||
caxlsx (>= 2.0.2, < 4)
|
||||
rodf (>= 1.0.0, < 2)
|
||||
spring (2.1.0)
|
||||
spring (2.1.1)
|
||||
spring-commands-rspec (1.0.4)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (3.7.2)
|
||||
|
@ -697,7 +695,7 @@ GEM
|
|||
tilt (2.0.10)
|
||||
timecop (0.9.1)
|
||||
ttfunk (1.6.2.1)
|
||||
typhoeus (1.3.1)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.7)
|
||||
thread_safe (~> 0.1)
|
||||
|
@ -708,10 +706,10 @@ GEM
|
|||
validate_email (0.1.6)
|
||||
activemodel (>= 3.0)
|
||||
mail (>= 2.2.5)
|
||||
validate_url (1.0.8)
|
||||
validate_url (1.0.11)
|
||||
activemodel (>= 3.0.0)
|
||||
public_suffix
|
||||
vcr (5.1.0)
|
||||
vcr (6.0.0)
|
||||
virtus (1.0.5)
|
||||
axiom-types (~> 0.1)
|
||||
coercible (~> 1.0)
|
||||
|
@ -719,19 +717,19 @@ GEM
|
|||
equalizer (~> 0.0, >= 0.0.9)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
web-console (4.0.1)
|
||||
web-console (4.0.4)
|
||||
actionview (>= 6.0.0)
|
||||
activemodel (>= 6.0.0)
|
||||
bindex (>= 0.4.0)
|
||||
railties (>= 6.0.0)
|
||||
webdrivers (4.2.0)
|
||||
webdrivers (4.4.1)
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (>= 1.3.0)
|
||||
selenium-webdriver (>= 3.0, < 4.0)
|
||||
webfinger (1.1.0)
|
||||
activesupport
|
||||
httpclient (>= 2.4)
|
||||
webmock (3.8.3)
|
||||
webmock (3.9.1)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
@ -752,7 +750,7 @@ GEM
|
|||
zipline (1.1.1)
|
||||
rails (>= 3.2.1, < 6.1)
|
||||
zip_tricks (>= 4.2.1, <= 5.0.0)
|
||||
zxcvbn-ruby (1.0.0)
|
||||
zxcvbn-ruby (1.1.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
|
|
@ -1291,6 +1291,11 @@ enum TypeDeChamp {
|
|||
"""
|
||||
textarea
|
||||
|
||||
"""
|
||||
Titre identité
|
||||
"""
|
||||
titre_identite
|
||||
|
||||
"""
|
||||
Oui/Non
|
||||
"""
|
||||
|
|
|
@ -26,6 +26,7 @@ const TypeDeChamp = sortableElement(
|
|||
const isCarte = typeDeChamp.type_champ === 'carte';
|
||||
const isExplication = typeDeChamp.type_champ === 'explication';
|
||||
const isHeaderSection = typeDeChamp.type_champ === 'header_section';
|
||||
const isTitreIdentite = typeDeChamp.type_champ === 'titre_identite';
|
||||
const isRepetition = typeDeChamp.type_champ === 'repetition';
|
||||
const canBeMandatory =
|
||||
!isHeaderSection && !isExplication && !state.isAnnotation;
|
||||
|
@ -118,7 +119,7 @@ const TypeDeChamp = sortableElement(
|
|||
</div>
|
||||
<div className="flex justify-start">
|
||||
<DescriptionInput
|
||||
isVisible={!isHeaderSection}
|
||||
isVisible={!isHeaderSection && !isTitreIdentite}
|
||||
handler={updateHandlers.description}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
class AdministrationMailer < ApplicationMailer
|
||||
layout 'mailers/layout'
|
||||
|
||||
def invite_admin(admin, reset_password_token, administration_id)
|
||||
def invite_admin(user, reset_password_token, administration_id)
|
||||
@reset_password_token = reset_password_token
|
||||
@admin = admin
|
||||
@user = user
|
||||
@author_name = BizDev.full_name(administration_id)
|
||||
subject = "Activez votre compte administrateur"
|
||||
|
||||
mail(to: admin.email,
|
||||
mail(to: user.email,
|
||||
subject: subject,
|
||||
reply_to: CONTACT_EMAIL)
|
||||
end
|
||||
|
|
|
@ -31,14 +31,6 @@ class Administrateur < ApplicationRecord
|
|||
user&.email
|
||||
end
|
||||
|
||||
# validate :password_complexity, if: Proc.new { |a| Devise.password_length.include?(a.password.try(:size)) }
|
||||
|
||||
def password_complexity
|
||||
if password.present? && ZxcvbnService.new(password).score < PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
errors.add(:password, :not_strong)
|
||||
end
|
||||
end
|
||||
|
||||
def self.find_inactive_by_token(reset_password_token)
|
||||
self.inactive.with_reset_password_token(reset_password_token)
|
||||
end
|
||||
|
|
57
app/models/champs/titre_identite_champ.rb
Normal file
57
app/models/champs/titre_identite_champ.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: champs
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# private :boolean default(FALSE), not null
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
# etablissement_id :integer
|
||||
# parent_id :bigint
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::TitreIdentiteChamp < Champ
|
||||
MAX_SIZE = 20.megabytes
|
||||
|
||||
ACCEPTED_FORMATS = [
|
||||
"image/png",
|
||||
"image/jpeg"
|
||||
]
|
||||
|
||||
# TODO: once we're running on Rails 6, re-enable this validation.
|
||||
# See https://github.com/betagouv/demarches-simplifiees.fr/issues/4926
|
||||
#
|
||||
validates :piece_justificative_file,
|
||||
content_type: ACCEPTED_FORMATS,
|
||||
size: { less_than: MAX_SIZE }
|
||||
|
||||
def main_value_name
|
||||
:piece_justificative_file
|
||||
end
|
||||
|
||||
def search_terms
|
||||
# We don’t know how to search inside documents yet
|
||||
end
|
||||
|
||||
def mandatory_and_blank?
|
||||
mandatory? && !piece_justificative_file.attached?
|
||||
end
|
||||
|
||||
def for_export
|
||||
piece_justificative_file.filename.to_s if piece_justificative_file.attached?
|
||||
end
|
||||
|
||||
def for_api
|
||||
if piece_justificative_file.attached? && (piece_justificative_file.virus_scanner.safe? || piece_justificative_file.virus_scanner.pending?)
|
||||
piece_justificative_file.service_url
|
||||
end
|
||||
end
|
||||
|
||||
def update_skip_pj_validation
|
||||
type_de_champ.update(skip_pj_validation: true)
|
||||
end
|
||||
end
|
|
@ -47,7 +47,8 @@ class TypeDeChamp < ApplicationRecord
|
|||
piece_justificative: 'piece_justificative',
|
||||
siret: 'siret',
|
||||
carte: 'carte',
|
||||
repetition: 'repetition'
|
||||
repetition: 'repetition',
|
||||
titre_identite: 'titre_identite'
|
||||
}
|
||||
|
||||
belongs_to :revision, class_name: 'ProcedureRevision', optional: true
|
||||
|
@ -189,7 +190,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
end
|
||||
|
||||
def piece_justificative?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative)
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) || type_champ == TypeDeChamp.type_champs.fetch(:titre_identite)
|
||||
end
|
||||
|
||||
def legacy_number?
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
class TypesDeChamp::TitreIdentiteTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
|
@ -54,6 +54,14 @@ class User < ApplicationRecord
|
|||
|
||||
before_validation -> { sanitize_email(:email) }
|
||||
|
||||
validate :password_complexity, if: -> (u) { u.administrateur.present? && Devise.password_length.include?(u.password.try(:size)) }
|
||||
|
||||
def password_complexity
|
||||
if password.present? && ZxcvbnService.new(password).score < PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
errors.add(:password, :not_strong)
|
||||
end
|
||||
end
|
||||
|
||||
# Override of Devise::Models::Confirmable#send_confirmation_instructions
|
||||
def send_confirmation_instructions
|
||||
unless @raw_confirmation_token
|
||||
|
@ -90,13 +98,7 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def invite_administrateur!(administration_id)
|
||||
reset_password_token = nil
|
||||
|
||||
if !active?
|
||||
reset_password_token = set_reset_password_token
|
||||
end
|
||||
|
||||
AdministrationMailer.invite_admin(self, reset_password_token, administration_id).deliver_later
|
||||
AdministrationMailer.invite_admin(self, set_reset_password_token, administration_id).deliver_later
|
||||
end
|
||||
|
||||
def remind_invitation!
|
||||
|
|
|
@ -7,17 +7,18 @@
|
|||
Je vous remercie de l’intérêt que vous portez à notre outil de dématérialisation de démarches.
|
||||
|
||||
%p
|
||||
Votre compte administrateur a été créé pour l'adresse email #{@admin.email}.
|
||||
Votre compte administrateur a été créé pour l'adresse email #{@user.email}.
|
||||
|
||||
- if @reset_password_token.present?
|
||||
- if !@user.active?
|
||||
%p
|
||||
%b
|
||||
Pour l’activer, cliquez sur le lien suivant :
|
||||
= link_to(admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token))
|
||||
- else
|
||||
%p
|
||||
%b
|
||||
Pour vous connecter, cliquez sur le lien suivant :
|
||||
= link_to(new_user_session_url, new_user_session_url)
|
||||
= link_to edit_user_password_url(@user, reset_password_token: @reset_password_token), edit_user_password_url(@user, reset_password_token: @reset_password_token)
|
||||
|
||||
%p
|
||||
= render partial: "layouts/mailers/bizdev_signature", locals: { author_name: @author_name }
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
= render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:piece_justificative)
|
||||
= render partial: "shared/champs/piece_justificative/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:titre_identite)
|
||||
= render partial: "shared/champs/piece_justificative/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:siret)
|
||||
= render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile }
|
||||
- when TypeDeChamp.type_champs.fetch(:textarea)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
- elsif has_label?(champ)
|
||||
= render partial: 'shared/dossiers/editable_champs/champ_label', locals: { form: form, champ: champ, seen_at: defined?(seen_at) ? seen_at : nil }
|
||||
- if champ.type_champ == "titre_identite"
|
||||
%p.notice Carte d'identité (uniquement le recto), passeport ou titre de séjour. Formats acceptés : jpg / png.
|
||||
|
||||
= render partial: "shared/dossiers/editable_champs/#{champ.type_champ}",
|
||||
locals: { champ: champ, form: form }
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
= render 'shared/attachment/edit',
|
||||
{ form: form,
|
||||
attached_file: champ.piece_justificative_file,
|
||||
template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true }
|
|
@ -82,6 +82,7 @@ fr:
|
|||
taken: déjà utilisé
|
||||
password:
|
||||
too_short: 'est trop court'
|
||||
not_strong: 'n’est pas assez complexe'
|
||||
password_confirmation:
|
||||
confirmation: ': Les deux mots de passe ne correspondent pas'
|
||||
invite:
|
||||
|
|
|
@ -33,3 +33,4 @@ fr:
|
|||
siret: 'SIRET'
|
||||
carte: 'Carte'
|
||||
repetition: 'Bloc répétable'
|
||||
titre_identite: 'Titre identité'
|
||||
|
|
|
@ -25,7 +25,7 @@ describe WebhookController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when there is a matching user' do
|
||||
let(:user) { create(:user) }
|
||||
let(:user) { create(:user, :with_strong_password) }
|
||||
let(:customer_email) { user.email }
|
||||
|
||||
it 'returns a 200 response' do
|
||||
|
|
|
@ -3,7 +3,7 @@ FactoryBot.define do
|
|||
factory :administrateur do
|
||||
transient do
|
||||
email { generate(:administrateur_email) }
|
||||
password { 'mon chien aime les bananes' }
|
||||
password { 'Mon [hien 4im3 {es banane$' }
|
||||
end
|
||||
|
||||
initialize_with do
|
||||
|
|
|
@ -143,6 +143,14 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
factory :champ_titre_identite, class: 'Champs::TitreIdentiteChamp' do
|
||||
type_de_champ { association :type_de_champ_titre_identite, procedure: dossier.procedure }
|
||||
|
||||
after(:build) do |champ, _evaluator|
|
||||
champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png")
|
||||
end
|
||||
end
|
||||
|
||||
factory :champ_carte, class: 'Champs::CarteChamp' do
|
||||
type_de_champ { association :type_de_champ_carte, procedure: dossier.procedure }
|
||||
end
|
||||
|
|
|
@ -133,6 +133,9 @@ FactoryBot.define do
|
|||
type_de_champ.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
|
||||
end
|
||||
end
|
||||
factory :type_de_champ_titre_identite do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:titre_identite) }
|
||||
end
|
||||
factory :type_de_champ_siret do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:siret) }
|
||||
end
|
||||
|
|
|
@ -8,5 +8,9 @@ FactoryBot.define do
|
|||
trait :unconfirmed do
|
||||
confirmed_at { nil }
|
||||
end
|
||||
|
||||
trait :with_strong_password do
|
||||
password { '{my-%s3cure[]-p4$$w0rd' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,24 @@
|
|||
RSpec.describe AdministrationMailer, type: :mailer do
|
||||
describe '#invite_admin' do
|
||||
let(:admin) { create(:administrateur) }
|
||||
let(:token) { "Toc toc toc" }
|
||||
let(:admin_user) { create(:user, last_sign_in_at: last_sign_in_at) }
|
||||
let(:token) { "some_token" }
|
||||
let(:administration_id) { BizDev::PIPEDRIVE_ID }
|
||||
let(:last_sign_in_at) { nil }
|
||||
|
||||
subject { described_class.invite_admin(admin, token, administration_id) }
|
||||
subject { described_class.invite_admin(admin_user, token, administration_id) }
|
||||
|
||||
it { expect(subject.subject).not_to be_empty }
|
||||
|
||||
describe "when the user has not been activated" do
|
||||
it { expect(subject.body).to include(admin_activate_path(token: token)) }
|
||||
it { expect(subject.body).not_to include(edit_user_password_url(admin_user, reset_password_token: token)) }
|
||||
end
|
||||
|
||||
describe "when the user is already active" do
|
||||
let(:last_sign_in_at) { Time.zone.now }
|
||||
it { expect(subject.body).not_to include(admin_activate_path(token: token)) }
|
||||
it { expect(subject.body).to include(edit_user_password_url(admin_user, reset_password_token: token)) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#refuse_admin' do
|
||||
|
|
|
@ -75,34 +75,4 @@ describe Administrateur, type: :model do
|
|||
expect(Administrateur.find_by(id: administrateur.id)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
# describe '#password_complexity' do
|
||||
# let(:email) { 'mail@beta.gouv.fr' }
|
||||
# let(:passwords) { ['pass', '12pass23', 'démarches ', 'démarches-simple', 'my-s3cure-p4ssword'] }
|
||||
# let(:administrateur) { build(:administrateur, email: email, password: password) }
|
||||
# let(:min_complexity) { PASSWORD_COMPLEXITY_FOR_ADMIN }
|
||||
|
||||
# subject do
|
||||
# administrateur.save
|
||||
# administrateur.errors.full_messages
|
||||
# end
|
||||
|
||||
# context 'when password is too short' do
|
||||
# let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
# it { expect(subject).to eq(["Le mot de passe est trop court"]) }
|
||||
# end
|
||||
|
||||
# context 'when password is too simple' do
|
||||
# let(:password) { passwords[min_complexity - 1] }
|
||||
|
||||
# it { expect(subject).to eq(["Le mot de passe n'est pas assez complexe"]) }
|
||||
# end
|
||||
|
||||
# context 'when password is acceptable' do
|
||||
# let(:password) { passwords[min_complexity] }
|
||||
|
||||
# it { expect(subject).to eq([]) }
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
|
|
@ -186,7 +186,9 @@ describe User, type: :model do
|
|||
subject
|
||||
end
|
||||
|
||||
it { expect(AdministrationMailer).to have_received(:invite_admin).with(user, nil, administration.id) }
|
||||
it 'receives an invitation to update its password' do
|
||||
expect(AdministrationMailer).to have_received(:invite_admin).with(user, kind_of(String), administration.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -293,4 +295,55 @@ describe User, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#password_complexity' do
|
||||
# This password list is sorted by password complexity, according to zxcvbn (used for complexity evaluation)
|
||||
# 0 - too guessable: risky password. (guesses < 10^3)
|
||||
# 1 - very guessable: protection from throttled online attacks. (guesses < 10^6)
|
||||
# 2 - somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
|
||||
# 3 - safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
|
||||
# 4 - very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
|
||||
passwords = ['pass', '12pass23', 'démarches ', 'démarches-simple', '{My-$3cure-p4ssWord}']
|
||||
min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
|
||||
context 'administrateurs' do
|
||||
let(:email) { 'mail@beta.gouv.fr' }
|
||||
let(:administrateur) { build(:user, email: email, password: password, administrateur: build(:administrateur)) }
|
||||
|
||||
subject do
|
||||
administrateur.save
|
||||
administrateur.errors.full_messages
|
||||
end
|
||||
|
||||
context 'when password is too short' do
|
||||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it { expect(subject).to eq(["Le mot de passe est trop court"]) }
|
||||
end
|
||||
|
||||
context 'when password is too simple' do
|
||||
passwords[0..(min_complexity - 1)].each do |password|
|
||||
let(:password) { password }
|
||||
|
||||
it { expect(subject).to eq(["Le mot de passe n’est pas assez complexe"]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when password is acceptable' do
|
||||
let(:password) { passwords[min_complexity] }
|
||||
|
||||
it { expect(subject).to eq([]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'simple users' do
|
||||
passwords.each do |password|
|
||||
let(:user) { build(:user, email: 'some@email.fr', password: password) }
|
||||
it 'has no complexity validation' do
|
||||
user.save
|
||||
expect(user.errors.full_messages).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,7 +36,7 @@ describe AdministrateurUsageStatisticsService do
|
|||
context 'for an administrateur that has plenty of things' do
|
||||
let(:administrateur) do
|
||||
create(:administrateur,
|
||||
user: create(:user, sign_in_count: 17, current_sign_in_at: Time.zone.local(2019, 3, 7), last_sign_in_at: Time.zone.local(2019, 2, 27)),
|
||||
user: create(:user, :with_strong_password, sign_in_count: 17, current_sign_in_at: Time.zone.local(2019, 3, 7), last_sign_in_at: Time.zone.local(2019, 2, 27)),
|
||||
services: [create(:service)],
|
||||
instructeurs: [create(:instructeur)])
|
||||
end
|
||||
|
|
|
@ -73,6 +73,7 @@ describe ProcedureExportService do
|
|||
"piece_justificative",
|
||||
"siret",
|
||||
"carte",
|
||||
"titre_identite",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
@ -156,6 +157,7 @@ describe ProcedureExportService do
|
|||
"piece_justificative",
|
||||
"siret",
|
||||
"carte",
|
||||
"titre_identite",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
@ -235,6 +237,7 @@ describe ProcedureExportService do
|
|||
"piece_justificative",
|
||||
"siret",
|
||||
"carte",
|
||||
"titre_identite",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue