commit
1d113ecf52
45 changed files with 454 additions and 549 deletions
1
Gemfile
1
Gemfile
|
@ -48,6 +48,7 @@ gem 'prawn_rails'
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
gem 'puma' # Use Puma as the app server
|
gem 'puma' # Use Puma as the app server
|
||||||
gem 'pundit'
|
gem 'pundit'
|
||||||
|
gem 'rack-attack'
|
||||||
gem 'rack-mini-profiler'
|
gem 'rack-mini-profiler'
|
||||||
gem 'rails'
|
gem 'rails'
|
||||||
gem 'rails-i18n' # Locales par défaut
|
gem 'rails-i18n' # Locales par défaut
|
||||||
|
|
|
@ -434,6 +434,8 @@ GEM
|
||||||
pundit (2.0.1)
|
pundit (2.0.1)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
rack (2.0.6)
|
rack (2.0.6)
|
||||||
|
rack-attack (6.0.0)
|
||||||
|
rack (>= 1.0, < 3)
|
||||||
rack-mini-profiler (1.0.1)
|
rack-mini-profiler (1.0.1)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
rack-oauth2 (1.9.3)
|
rack-oauth2 (1.9.3)
|
||||||
|
@ -752,6 +754,7 @@ DEPENDENCIES
|
||||||
pry-byebug
|
pry-byebug
|
||||||
puma
|
puma
|
||||||
pundit
|
pundit
|
||||||
|
rack-attack
|
||||||
rack-mini-profiler
|
rack-mini-profiler
|
||||||
rails
|
rails
|
||||||
rails-controller-testing
|
rails-controller-testing
|
||||||
|
|
|
@ -37,21 +37,15 @@ class Admin::InstructeursController < AdminController
|
||||||
private
|
private
|
||||||
|
|
||||||
def invite_instructeur(email)
|
def invite_instructeur(email)
|
||||||
user = User.find_by(email: email)
|
user = User.create_or_promote_to_instructeur(
|
||||||
|
email,
|
||||||
if user.nil?
|
SecureRandom.hex,
|
||||||
user = User.create(
|
administrateurs: [current_administrateur]
|
||||||
email: email,
|
)
|
||||||
password: SecureRandom.hex,
|
|
||||||
confirmed_at: Time.zone.now
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.errors.empty?
|
|
||||||
@instructeur = Instructeur.create(email: email, administrateurs: [current_administrateur])
|
|
||||||
user.update!(instructeur: @instructeur)
|
|
||||||
|
|
||||||
|
if user.valid?
|
||||||
user.invite!
|
user.invite!
|
||||||
|
|
||||||
flash.notice = 'Instructeur ajouté'
|
flash.notice = 'Instructeur ajouté'
|
||||||
else
|
else
|
||||||
flash.alert = user.errors.full_messages
|
flash.alert = user.errors.full_messages
|
||||||
|
|
|
@ -47,7 +47,6 @@ class Administrateurs::ActivateController < ApplicationController
|
||||||
|
|
||||||
if resource&.valid_password?(password)
|
if resource&.valid_password?(password)
|
||||||
sign_in resource
|
sign_in resource
|
||||||
resource.force_sync_credentials
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,23 +83,13 @@ module Instructeurs
|
||||||
email = params[:email]
|
email = params[:email]
|
||||||
password = params['instructeur']['password']
|
password = params['instructeur']['password']
|
||||||
|
|
||||||
user = User.find_by(email: email)
|
# Not perfect because the password will not be changed if the user already exists
|
||||||
|
user = User.create_or_promote_to_instructeur(email, password)
|
||||||
if user.nil?
|
|
||||||
user = User.create(
|
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
confirmed_at: Time.zone.now
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.errors.empty?
|
|
||||||
instructeur = Instructeur.create(email: email)
|
|
||||||
user.update!(instructeur: instructeur)
|
|
||||||
|
|
||||||
|
if user.valid?
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
|
||||||
Avis.link_avis_to_instructeur(instructeur)
|
Avis.link_avis_to_instructeur(user.instructeur)
|
||||||
redirect_to url_for(instructeur_avis_index_path)
|
redirect_to url_for(instructeur_avis_index_path)
|
||||||
else
|
else
|
||||||
flash[:alert] = user.errors.full_messages
|
flash[:alert] = user.errors.full_messages
|
||||||
|
|
|
@ -42,7 +42,7 @@ module Manager
|
||||||
administrateur.dossiers.each(&:delete_and_keep_track)
|
administrateur.dossiers.each(&:delete_and_keep_track)
|
||||||
administrateur.destroy
|
administrateur.destroy
|
||||||
|
|
||||||
logger.info("L'administrateur #{administrateur.id} est supprimé par #{current_user.id}")
|
logger.info("L'administrateur #{administrateur.id} est supprimé par #{current_administration.id}")
|
||||||
flash[:notice] = "L'administrateur #{administrateur.id} est supprimé"
|
flash[:notice] = "L'administrateur #{administrateur.id} est supprimé"
|
||||||
|
|
||||||
redirect_to manager_administrateurs_path
|
redirect_to manager_administrateurs_path
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
class Sessions::SessionsController < Devise::SessionsController
|
|
||||||
before_action :before_sign_in, only: [:create]
|
|
||||||
|
|
||||||
layout 'new_application'
|
|
||||||
|
|
||||||
def before_sign_in
|
|
||||||
if user_signed_in?
|
|
||||||
sign_out :user
|
|
||||||
end
|
|
||||||
|
|
||||||
if instructeur_signed_in?
|
|
||||||
sign_out :instructeur
|
|
||||||
end
|
|
||||||
|
|
||||||
if administrateur_signed_in?
|
|
||||||
sign_out :administrateur
|
|
||||||
end
|
|
||||||
|
|
||||||
if administration_signed_in?
|
|
||||||
sign_out :administration
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -14,36 +14,25 @@ class Users::ActivateController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
password = create_user_params[:password]
|
|
||||||
user = User.reset_password_by_token({
|
user = User.reset_password_by_token({
|
||||||
password: password,
|
password: user_params[:password],
|
||||||
password_confirmation: password,
|
reset_password_token: user_params[:reset_password_token]
|
||||||
reset_password_token: create_user_params[:reset_password_token]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if user && user.errors.empty?
|
if user.valid?
|
||||||
sign_in(user, scope: :user)
|
sign_in(user, scope: :user)
|
||||||
|
|
||||||
flash.notice = "Mot de passe enregistré"
|
flash.notice = "Mot de passe enregistré"
|
||||||
redirect_to instructeur_procedures_path
|
redirect_to instructeur_procedures_path
|
||||||
else
|
else
|
||||||
flash.alert = user.errors.full_messages
|
flash.alert = user.errors.full_messages
|
||||||
redirect_to users_activate_path(token: create_user_params[:reset_password_token])
|
redirect_to users_activate_path(token: user_params[:reset_password_token])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_user_params
|
def user_params
|
||||||
params.require(:user).permit(:reset_password_token, :password)
|
params.require(:user).permit(:reset_password_token, :password)
|
||||||
end
|
end
|
||||||
|
|
||||||
def try_to_authenticate(klass, email, password)
|
|
||||||
resource = klass.find_for_database_authentication(email: email)
|
|
||||||
|
|
||||||
if resource&.valid_password?(password)
|
|
||||||
sign_in resource
|
|
||||||
resource.force_sync_credentials
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,7 +42,6 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
|
||||||
if sign_in_after_confirmation?(resource)
|
if sign_in_after_confirmation?(resource)
|
||||||
resource.remember_me = true
|
resource.remember_me = true
|
||||||
sign_in(resource)
|
sign_in(resource)
|
||||||
resource.force_sync_credentials
|
|
||||||
after_sign_in_path_for(resource_name)
|
after_sign_in_path_for(resource_name)
|
||||||
else
|
else
|
||||||
super(resource_name, resource)
|
super(resource_name, resource)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
class Users::SessionsController < Sessions::SessionsController
|
class Users::SessionsController < Devise::SessionsController
|
||||||
include ProcedureContextConcern
|
include ProcedureContextConcern
|
||||||
include TrustedDeviceConcern
|
include TrustedDeviceConcern
|
||||||
include ActionView::Helpers::DateHelper
|
include ActionView::Helpers::DateHelper
|
||||||
|
@ -7,33 +7,15 @@ class Users::SessionsController < Sessions::SessionsController
|
||||||
|
|
||||||
before_action :restore_procedure_context, only: [:new, :create]
|
before_action :restore_procedure_context, only: [:new, :create]
|
||||||
|
|
||||||
# GET /resource/sign_in
|
|
||||||
def new
|
|
||||||
@user = User.new
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST /resource/sign_in
|
# POST /resource/sign_in
|
||||||
def create
|
def create
|
||||||
remember_me = params[:user][:remember_me] == '1'
|
user = User.find_by(email: params[:user][:email])
|
||||||
|
|
||||||
if resource_locked?(try_to_authenticate(User, remember_me))
|
if user&.valid_password?(params[:user][:password])
|
||||||
flash.alert = 'Votre compte est verrouillé.'
|
user.update(loged_in_with_france_connect: nil)
|
||||||
new
|
|
||||||
return render :new, status: 401
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if user_signed_in?
|
super
|
||||||
current_user.update(loged_in_with_france_connect: nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
if instructeur_signed_in? || user_signed_in?
|
|
||||||
set_flash_message :notice, :signed_in
|
|
||||||
redirect_to after_sign_in_path_for(:user)
|
|
||||||
else
|
|
||||||
flash.alert = 'Mauvais couple login / mot de passe'
|
|
||||||
new
|
|
||||||
render :new, status: 401
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_sent
|
def link_sent
|
||||||
|
@ -91,23 +73,4 @@ class Users::SessionsController < Sessions::SessionsController
|
||||||
redirect_to link_sent_path(email: instructeur.email)
|
redirect_to link_sent_path(email: instructeur.email)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def try_to_authenticate(klass, remember_me = false)
|
|
||||||
resource = klass.find_for_database_authentication(email: params[:user][:email])
|
|
||||||
|
|
||||||
if resource.present?
|
|
||||||
if resource.valid_password?(params[:user][:password])
|
|
||||||
resource.remember_me = remember_me
|
|
||||||
sign_in resource
|
|
||||||
resource.force_sync_credentials
|
|
||||||
end
|
|
||||||
end
|
|
||||||
resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def resource_locked?(resource)
|
|
||||||
resource.present? && resource.access_locked?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
class Administrateur < ApplicationRecord
|
class Administrateur < ApplicationRecord
|
||||||
include CredentialsSyncableConcern
|
|
||||||
include EmailSanitizableConcern
|
include EmailSanitizableConcern
|
||||||
include ActiveRecord::SecureToken
|
include ActiveRecord::SecureToken
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ class Administrateur < ApplicationRecord
|
||||||
has_many :services
|
has_many :services
|
||||||
has_many :dossiers, -> { state_not_brouillon }, through: :procedures
|
has_many :dossiers, -> { state_not_brouillon }, through: :procedures
|
||||||
|
|
||||||
has_one :user
|
has_one :user, dependent: :nullify
|
||||||
|
|
||||||
before_validation -> { sanitize_email(:email) }
|
before_validation -> { sanitize_email(:email) }
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ class Administrateur < ApplicationRecord
|
||||||
def registration_state
|
def registration_state
|
||||||
if active?
|
if active?
|
||||||
'Actif'
|
'Actif'
|
||||||
elsif reset_password_period_valid?
|
elsif user.reset_password_period_valid?
|
||||||
'En attente'
|
'En attente'
|
||||||
else
|
else
|
||||||
'Expiré'
|
'Expiré'
|
||||||
|
@ -56,7 +55,7 @@ class Administrateur < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def invitation_expired?
|
def invitation_expired?
|
||||||
!active && !reset_password_period_valid?
|
!active && !user.reset_password_period_valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.reset_password(reset_password_token, password)
|
def self.reset_password(reset_password_token, password)
|
||||||
|
|
|
@ -8,32 +8,11 @@ class Administration < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_admin(email)
|
def invite_admin(email)
|
||||||
password = SecureRandom.hex
|
user = User.create_or_promote_to_administrateur(email, SecureRandom.hex)
|
||||||
|
|
||||||
user = User.find_by(email: email)
|
if user.valid?
|
||||||
|
AdministrationMailer.new_admin_email(user.administrateur, self).deliver_later
|
||||||
if user.nil?
|
user.invite_administrateur!(id)
|
||||||
# set confirmed_at otherwise admin confirmation doesnt work
|
|
||||||
# we somehow mess up using reset_password logic instead of
|
|
||||||
# confirmation_logic
|
|
||||||
# FIXME
|
|
||||||
user = User.create(
|
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
confirmed_at: Time.zone.now
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.errors.empty?
|
|
||||||
if user.instructeur.nil?
|
|
||||||
Instructeur.create!(email: email, user: user)
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.administrateur.nil?
|
|
||||||
administrateur = Administrateur.create!(email: email, active: false, user: user)
|
|
||||||
AdministrationMailer.new_admin_email(administrateur, self).deliver_later
|
|
||||||
user.invite_administrateur!(id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
user
|
user
|
||||||
|
|
|
@ -4,7 +4,6 @@ class Commentaire < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :instructeur
|
belongs_to :instructeur
|
||||||
|
|
||||||
mount_uploader :file, CommentaireFileUploader
|
|
||||||
validate :messagerie_available?, on: :create
|
validate :messagerie_available?, on: :create
|
||||||
|
|
||||||
has_one_attached :piece_jointe
|
has_one_attached :piece_jointe
|
||||||
|
@ -48,15 +47,8 @@ class Commentaire < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def file_url
|
def file_url
|
||||||
if piece_jointe.attached?
|
if piece_jointe.attached? && piece_jointe.virus_scanner.safe?
|
||||||
if piece_jointe.virus_scanner.safe?
|
Rails.application.routes.url_helpers.url_for(piece_jointe)
|
||||||
Rails.application.routes.url_helpers.url_for(piece_jointe)
|
|
||||||
end
|
|
||||||
elsif Rails.application.secrets.fog[:enabled]
|
|
||||||
RemoteDownloader.new(file.path).url
|
|
||||||
elsif file&.url
|
|
||||||
# FIXME: this is horrible but used only in dev and will be removed after migration
|
|
||||||
File.join(LOCAL_DOWNLOAD_URL, file.url)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
module CredentialsSyncableConcern
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
after_update :sync_credentials
|
|
||||||
end
|
|
||||||
|
|
||||||
def sync_credentials
|
|
||||||
if saved_change_to_email? || saved_change_to_encrypted_password?
|
|
||||||
return force_sync_credentials
|
|
||||||
end
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def force_sync_credentials
|
|
||||||
SyncCredentialsService.new(self.class, email_before_last_save, email, encrypted_password).change_credentials!
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +1,4 @@
|
||||||
class Instructeur < ApplicationRecord
|
class Instructeur < ApplicationRecord
|
||||||
include CredentialsSyncableConcern
|
|
||||||
include EmailSanitizableConcern
|
include EmailSanitizableConcern
|
||||||
|
|
||||||
has_and_belongs_to_many :administrateurs
|
has_and_belongs_to_many :administrateurs
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
include CredentialsSyncableConcern
|
|
||||||
include EmailSanitizableConcern
|
include EmailSanitizableConcern
|
||||||
|
|
||||||
enum loged_in_with_france_connect: {
|
enum loged_in_with_france_connect: {
|
||||||
|
@ -62,6 +61,32 @@ class User < ApplicationRecord
|
||||||
AdministrateurMailer.activate_before_expiration(self, reset_password_token).deliver_later
|
AdministrateurMailer.activate_before_expiration(self, reset_password_token).deliver_later
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.create_or_promote_to_instructeur(email, password, administrateurs: [])
|
||||||
|
user = User
|
||||||
|
.create_with(password: password, confirmed_at: Time.zone.now)
|
||||||
|
.find_or_create_by(email: email)
|
||||||
|
|
||||||
|
if user.valid?
|
||||||
|
if user.instructeur_id.nil?
|
||||||
|
user.create_instructeur!(email: email)
|
||||||
|
end
|
||||||
|
|
||||||
|
user.instructeur.administrateurs << administrateurs
|
||||||
|
end
|
||||||
|
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_or_promote_to_administrateur(email, password)
|
||||||
|
user = User.create_or_promote_to_instructeur(email, password)
|
||||||
|
|
||||||
|
if user.valid? && user.administrateur_id.nil?
|
||||||
|
user.create_administrateur!(email: email)
|
||||||
|
end
|
||||||
|
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def link_invites!
|
def link_invites!
|
||||||
|
|
|
@ -3,13 +3,7 @@ class IPService
|
||||||
def ip_trusted?(ip)
|
def ip_trusted?(ip)
|
||||||
ip_address = parse_address(ip)
|
ip_address = parse_address(ip)
|
||||||
|
|
||||||
if ip_address.nil?
|
trusted_networks.any? { |network| network.include?(ip_address) }
|
||||||
false
|
|
||||||
elsif trusted_networks.present?
|
|
||||||
trusted_networks.any? { |network| network.include?(ip_address) }
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
class SyncCredentialsService
|
|
||||||
def initialize(klass, email_before_last_save, email, encrypted_password)
|
|
||||||
@klass = klass
|
|
||||||
@email_before_last_save = email_before_last_save
|
|
||||||
@email = email
|
|
||||||
@encrypted_password = encrypted_password
|
|
||||||
end
|
|
||||||
|
|
||||||
def change_credentials!
|
|
||||||
if @klass != User
|
|
||||||
user = User.find_by(email: @email_before_last_save)
|
|
||||||
if user && !user.update_columns(email: @email, encrypted_password: @encrypted_password)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if @klass != Instructeur
|
|
||||||
instructeur = Instructeur.find_by(email: @email_before_last_save)
|
|
||||||
if instructeur && !instructeur.update_columns(email: @email, encrypted_password: @encrypted_password)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if @klass != Administrateur
|
|
||||||
administrateur = Administrateur.find_by(email: @email_before_last_save)
|
|
||||||
if administrateur && !administrateur.update_columns(email: @email, encrypted_password: @encrypted_password)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
class CommentaireFileUploader < BaseUploader
|
|
||||||
def root
|
|
||||||
Rails.root.join("public")
|
|
||||||
end
|
|
||||||
|
|
||||||
if Rails.application.secrets.fog[:enabled]
|
|
||||||
storage :fog
|
|
||||||
else
|
|
||||||
storage :file
|
|
||||||
end
|
|
||||||
|
|
||||||
def store_dir
|
|
||||||
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def extension_whitelist
|
|
||||||
['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp', 'jpg', 'jpeg', 'png', 'zip', 'txt']
|
|
||||||
end
|
|
||||||
|
|
||||||
def accept_extension_list
|
|
||||||
extension_whitelist.map { |e| ".#{e}" }.join(",")
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,26 +0,0 @@
|
||||||
#form-login
|
|
||||||
%h2#login_admin
|
|
||||||
= t('dynamics.admin.connexion_title')
|
|
||||||
|
|
||||||
%br
|
|
||||||
%br
|
|
||||||
#new-user
|
|
||||||
= form_for @administrateur, url: { controller: 'administrateurs/sessions', action: :create } do |f|
|
|
||||||
%h4
|
|
||||||
= f.label :email
|
|
||||||
.input-group
|
|
||||||
.input-group-addon
|
|
||||||
%span.fa.fa-user
|
|
||||||
= f.email_field :email, class: 'form-control'
|
|
||||||
%br
|
|
||||||
%h4
|
|
||||||
= f.label 'Mot de passe'
|
|
||||||
.input-group
|
|
||||||
.input-group-addon
|
|
||||||
%span.fa.fa-asterisk
|
|
||||||
= f.password_field :password, class: 'form-control', value: @administrateur.password
|
|
||||||
%br
|
|
||||||
%br
|
|
||||||
.actions
|
|
||||||
= f.submit "Se connecter", class: 'btn btn-primary'
|
|
||||||
%br
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
- if @avis.instructeur.present?
|
- if @avis.instructeur.present?
|
||||||
%p
|
%p
|
||||||
= link_to "Connectez-vous pour donner votre avis", avis_link
|
= link_to "Cliquez ici pour donner votre avis", avis_link
|
||||||
- else
|
- else
|
||||||
%p
|
%p
|
||||||
= link_to "Inscrivez-vous pour donner votre avis", avis_link
|
= link_to "Inscrivez-vous pour donner votre avis", avis_link
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#form-login
|
|
||||||
%h2#instructeur_login Instructeur
|
|
||||||
|
|
||||||
%br
|
|
||||||
%br
|
|
||||||
#new-user
|
|
||||||
= form_for @instructeur, url: instructeur_session_path, method: :post do |f|
|
|
||||||
%h4
|
|
||||||
= f.label :email
|
|
||||||
.input-group
|
|
||||||
.input-group-addon
|
|
||||||
%span.fa.fa-user
|
|
||||||
= f.email_field :email, class: 'form-control'
|
|
||||||
%br
|
|
||||||
%h4
|
|
||||||
= f.label :password
|
|
||||||
.input-group
|
|
||||||
.input-group-addon
|
|
||||||
%span.fa.fa-asterisk
|
|
||||||
= f.password_field :password, autocomplete: "off", class: 'form-control', value: @instructeur.password
|
|
||||||
%br
|
|
||||||
%br
|
|
||||||
.actions
|
|
||||||
= f.submit "Se connecter", class: 'btn btn-primary'
|
|
||||||
%br
|
|
||||||
= render "instructeurs/shared/links"
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
.stat-card.stat-card-half.pull-left
|
.stat-card.stat-card-half.pull-left
|
||||||
%span.stat-card-title
|
%span.stat-card-title
|
||||||
Pourcentage de contact usagers
|
Pourcentage de contact usager
|
||||||
|
|
||||||
.chart-container
|
.chart-container
|
||||||
.chart
|
.chart
|
||||||
|
|
|
@ -1,32 +1,29 @@
|
||||||
= content_for(:page_id, 'auth')
|
= content_for(:page_id, 'auth')
|
||||||
|
|
||||||
.auth-form.sign-in-form
|
.auth-form.sign-in-form
|
||||||
- if resource_name == :user
|
%p.register
|
||||||
%p.register
|
%span
|
||||||
%span
|
Nouveau sur demarches‑simplifiees.fr ?
|
||||||
Nouveau sur demarches‑simplifiees.fr ?
|
= link_to "Créer un compte", new_user_registration_path, class: "button primary auth-signup-button"
|
||||||
= link_to "Créer un compte", new_registration_path(resource_name), class: "button primary auth-signup-button"
|
|
||||||
|
|
||||||
%hr
|
%hr
|
||||||
|
|
||||||
= form_for @user, url: user_session_path, html: { class: "form" } do |f|
|
= form_for User.new, url: user_session_path, html: { class: "form" } do |f|
|
||||||
%h1 Connectez-vous
|
%h1 Connectez-vous
|
||||||
|
|
||||||
= f.label :email, "Email"
|
= f.label :email, "Email"
|
||||||
= f.text_field :email, autofocus: true
|
= f.text_field :email, autofocus: true
|
||||||
|
|
||||||
= f.label :password, "Mot de passe"
|
= f.label :password, "Mot de passe"
|
||||||
= f.password_field :password, value: @user.password, placeholder: "8 caractères minimum"
|
= f.password_field :password, placeholder: "8 caractères minimum"
|
||||||
|
|
||||||
.auth-options
|
.auth-options
|
||||||
- if devise_mapping.rememberable?
|
%div
|
||||||
%div
|
= f.check_box :remember_me, as: :boolean
|
||||||
= f.check_box :remember_me, as: :boolean
|
= f.label :remember_me, "Se souvenir de moi", class: 'remember-me'
|
||||||
= f.label :remember_me, "Se souvenir de moi", class: 'remember-me'
|
|
||||||
|
|
||||||
- if [:user, :instructeur].include?(resource_name)
|
.text-right
|
||||||
.text-right
|
= link_to "Mot de passe oublié ?", new_user_password_path, class: "link"
|
||||||
= link_to "Mot de passe oublié ?", new_password_path(resource_name), class: "link"
|
|
||||||
|
|
||||||
= f.submit "Se connecter", class: "button large primary expand"
|
= f.submit "Se connecter", class: "button large primary expand"
|
||||||
|
|
||||||
|
|
|
@ -41,5 +41,6 @@ module TPS
|
||||||
end
|
end
|
||||||
|
|
||||||
config.ds_weekly_overview = ENV['APP_NAME'] == 'tps'
|
config.ds_weekly_overview = ENV['APP_NAME'] == 'tps'
|
||||||
|
config.middleware.use Rack::Attack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
27
config/initializers/rack_attack.rb
Normal file
27
config/initializers/rack_attack.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
class Rack::Attack
|
||||||
|
throttle('/users/sign_in/ip', limit: 5, period: 20.seconds) do |req|
|
||||||
|
if req.path == '/users/sign_in' && req.post? && rack_attack_enabled?
|
||||||
|
req.remote_ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
throttle('stats/ip', limit: 5, period: 20.seconds) do |req|
|
||||||
|
if req.path == '/stats' && rack_attack_enabled?
|
||||||
|
req.remote_ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
throttle('contact/ip', limit: 5, period: 20.seconds) do |req|
|
||||||
|
if req.path == '/contact' && req.post? && rack_attack_enabled?
|
||||||
|
req.remote_ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rack::Attack.safelist('allow from localhost') do |req|
|
||||||
|
IPService.ip_trusted?(req.remote_ip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.rack_attack_enabled?
|
||||||
|
ENV['RACK_ATTACK_ENABLE'] == 'true'
|
||||||
|
end
|
||||||
|
end
|
7
config/initializers/rack_attack_request.rb
Normal file
7
config/initializers/rack_attack_request.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class Rack::Attack
|
||||||
|
class Request < ::Rack::Request
|
||||||
|
def remote_ip
|
||||||
|
@remote_ip ||= (env['action_dispatch.remote_ip'] || ip).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,18 +0,0 @@
|
||||||
namespace :after_party do
|
|
||||||
desc 'Deployment task: add_procedure_administrateur_to_administrateurs'
|
|
||||||
task add_procedure_administrateur_to_administrateurs: :environment do
|
|
||||||
rake_puts "Running deploy task: 'add_procedure_administrateur_to_administrateurs'"
|
|
||||||
procedures = Procedure.includes(:administrateurs)
|
|
||||||
progress = ProgressReport.new(procedures.count)
|
|
||||||
|
|
||||||
procedures.find_each do |procedure|
|
|
||||||
if !procedure.administrateurs.include?(procedure.administrateur)
|
|
||||||
procedure.administrateurs << procedure.administrateur
|
|
||||||
end
|
|
||||||
progress.inc
|
|
||||||
end
|
|
||||||
|
|
||||||
progress.finish
|
|
||||||
AfterParty::TaskRecord.create version: '20190226101524'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
namespace :after_party do
|
|
||||||
desc 'Deployment task: migrate_virus_scans'
|
|
||||||
task migrate_virus_scans: :environment do
|
|
||||||
puts "Running deploy task 'migrate_virus_scans'"
|
|
||||||
|
|
||||||
virus_scans = VirusScan.all
|
|
||||||
progress = ProgressReport.new(virus_scans.count)
|
|
||||||
virus_scans.find_each do |virus_scan|
|
|
||||||
blob = ActiveStorage::Blob.find_by(key: virus_scan.blob_key)
|
|
||||||
if blob
|
|
||||||
metadata = { virus_scan_result: virus_scan.status, scanned_at: virus_scan.scanned_at }
|
|
||||||
blob.update_column(:metadata, blob.metadata.merge(metadata))
|
|
||||||
end
|
|
||||||
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.create version: '20190425102459'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
namespace :after_party do
|
|
||||||
desc 'Deployment task: add_procedure_administrateur_to_administrateurs_for_hidden_procedures'
|
|
||||||
task add_procedure_administrateur_to_administrateurs_for_hidden_procedures: :environment do
|
|
||||||
rake_puts "Running deploy task: 'add_procedure_administrateur_to_administrateurs_for_hidden_procedures'"
|
|
||||||
hidden_procedures = Procedure.unscoped.hidden.includes(:administrateurs)
|
|
||||||
progress = ProgressReport.new(hidden_procedures.count)
|
|
||||||
|
|
||||||
hidden_procedures.find_each do |procedure|
|
|
||||||
deprecated_administrateur = Administrateur.find_by(id: procedure.administrateur_id)
|
|
||||||
if deprecated_administrateur && !procedure.administrateurs.include?(deprecated_administrateur)
|
|
||||||
procedure.administrateurs << deprecated_administrateur
|
|
||||||
end
|
|
||||||
progress.inc
|
|
||||||
end
|
|
||||||
|
|
||||||
progress.finish
|
|
||||||
AfterParty::TaskRecord.create version: '20190429103024'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace :after_party do
|
|
||||||
desc 'Deployment task: enable_secured_login_for_all'
|
|
||||||
task enable_secured_login_for_all: :environment do
|
|
||||||
Gestionnaire.update_all(features: { "enable_email_login_token": true })
|
|
||||||
|
|
||||||
AfterParty::TaskRecord.create version: '20190627142239'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
namespace :after_party do
|
|
||||||
desc 'Deployment task: purge_unattached_piece_justificative'
|
|
||||||
task purge_unattached_piece_justificative: :environment do
|
|
||||||
puts "Running deploy task 'purge_unattached_piece_justificative'"
|
|
||||||
|
|
||||||
piece_justificatives = PieceJustificative.where(type_de_piece_justificative_id: nil)
|
|
||||||
progress = ProgressReport.new(piece_justificatives.count)
|
|
||||||
piece_justificatives.find_each do |pj|
|
|
||||||
# detach from dossier to ensure we do not trigger touch
|
|
||||||
pj.update_column(:dossier_id, nil)
|
|
||||||
pj.remove_content!
|
|
||||||
pj.destroy
|
|
||||||
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.create version: '20190701131030'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: clean_procedure_presentation_from_followers_gestionnaires'
|
||||||
|
task clean_procedure_presentation_from_followers_gestionnaires: :environment do
|
||||||
|
ProcedurePresentation.find_each do |pp|
|
||||||
|
if pp.sort["table"] == "followers_gestionnaires"
|
||||||
|
pp.sort["table"] = "followers_instructeurs"
|
||||||
|
end
|
||||||
|
|
||||||
|
pp.displayed_fields.each do |df|
|
||||||
|
if df["table"] == "followers_gestionnaires"
|
||||||
|
df["table"] = "followers_instructeurs"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pp.filters.each do |(_name, values)|
|
||||||
|
values.each do |value|
|
||||||
|
if value["table"] == "followers_gestionnaires"
|
||||||
|
value["table"] = "followers_instructeurs"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
pp.save!
|
||||||
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
AfterParty::TaskRecord.create version: '20190819100424'
|
||||||
|
end
|
||||||
|
end
|
|
@ -31,4 +31,18 @@ describe Manager::AdministrateursController, type: :controller do
|
||||||
it { expect { subject }.to change(Administrateur, :count).by(0) }
|
it { expect { subject }.to change(Administrateur, :count).by(0) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#delete' do
|
||||||
|
let!(:admin) { create(:administrateur) }
|
||||||
|
|
||||||
|
before { sign_in administration }
|
||||||
|
|
||||||
|
subject { delete :delete, params: { id: admin.id } }
|
||||||
|
|
||||||
|
it 'deletes the admin' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(Administrateur.find_by(id: admin.id)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe Sessions::SessionsController, type: :controller do
|
|
||||||
controller Sessions::SessionsController do
|
|
||||||
def create
|
|
||||||
render json: ''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:user) { create(:user) }
|
|
||||||
|
|
||||||
describe '#create' do
|
|
||||||
before do
|
|
||||||
@request.env["devise.mapping"] = Devise.mappings[:user]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'calls before_sign_in' do
|
|
||||||
expect_any_instance_of(Sessions::SessionsController).to receive(:before_sign_in)
|
|
||||||
post :create
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#create with user connected' do
|
|
||||||
before do
|
|
||||||
@request.env["devise.mapping"] = Devise.mappings[:user]
|
|
||||||
|
|
||||||
allow_any_instance_of(described_class).to receive(:user_signed_in?).and_return(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'calls sign out for user' do
|
|
||||||
expect_any_instance_of(described_class).to receive(:sign_out).with(:user)
|
|
||||||
post :create
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -17,4 +17,24 @@ describe Users::ActivateController, type: :controller do
|
||||||
it { expect(controller).not_to have_received(:trust_device) }
|
it { expect(controller).not_to have_received(:trust_device) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#create' do
|
||||||
|
let!(:user) { create(:user) }
|
||||||
|
let(:token) { user.send(:set_reset_password_token) }
|
||||||
|
let(:password) { 'another-password-ok?' }
|
||||||
|
|
||||||
|
before { post :create, params: { user: { reset_password_token: token, password: password } } }
|
||||||
|
|
||||||
|
context 'when the token is ok' do
|
||||||
|
it { expect(user.reload.valid_password?(password)).to be true }
|
||||||
|
it { expect(response).to redirect_to(instructeur_procedures_path) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the token is bad' do
|
||||||
|
let(:token) { 'bad' }
|
||||||
|
|
||||||
|
it { expect(user.reload.valid_password?(password)).to be false }
|
||||||
|
it { expect(response).to redirect_to(users_activate_path(token: token)) }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,71 +9,74 @@ describe Users::SessionsController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#create' do
|
describe '#create' do
|
||||||
context "when the user is also a instructeur and an administrateur" do
|
let(:user) { create(:user, email: email, password: password, loged_in_with_france_connect: 'particulier') }
|
||||||
let!(:administrateur) { create(:administrateur, email: email, password: password) }
|
let(:send_password) { password }
|
||||||
let(:instructeur) { administrateur.instructeur }
|
let(:remember_me) { '0' }
|
||||||
let(:user) { instructeur.user }
|
|
||||||
let(:trusted_device) { true }
|
|
||||||
let(:send_password) { password }
|
|
||||||
|
|
||||||
before do
|
subject do
|
||||||
allow(controller).to receive(:trusted_device?).and_return(trusted_device)
|
post :create, params: {
|
||||||
allow(InstructeurMailer).to receive(:send_login_token).and_return(double(deliver_later: true))
|
user: {
|
||||||
|
email: email,
|
||||||
|
password: send_password,
|
||||||
|
remember_me: remember_me
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the credentials are right' do
|
||||||
|
it 'signs in' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
expect(controller.current_user).to eq(user)
|
||||||
|
expect(user.reload.loged_in_with_france_connect).to be(nil)
|
||||||
|
expect(user.reload.remember_created_at).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
subject do
|
context 'when remember_me is specified' do
|
||||||
post :create, params: { user: { email: email, password: send_password } }
|
let(:remember_me) { '1' }
|
||||||
user.reload
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the device is not trusted' do
|
it 'remembers' do
|
||||||
before do
|
|
||||||
Flipflop::FeatureSet.current.test!.switch!(:bypass_email_login_token, false)
|
|
||||||
end
|
|
||||||
let(:trusted_device) { false }
|
|
||||||
|
|
||||||
it 'redirects to the send_linked_path' do
|
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(controller).to redirect_to(link_sent_path(email: user.email))
|
expect(user.reload.remember_created_at).to be_present
|
||||||
|
|
||||||
expect(controller.current_user).to eq(user)
|
|
||||||
expect(controller.current_instructeur).to eq(instructeur)
|
|
||||||
# WTF?
|
|
||||||
# expect(controller.current_administrateur).to eq(administrateur)
|
|
||||||
expect(user.loged_in_with_france_connect).to eq(nil)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the device is trusted' do
|
context 'when a previous path was registered' do
|
||||||
it 'signs in as user, instructeur and adminstrateur' do
|
let(:stored_path) { 'a_path' }
|
||||||
|
|
||||||
|
before { controller.store_location_for(:user, stored_path) }
|
||||||
|
|
||||||
|
it 'redirects to that previous path' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(response.redirect?).to be(true)
|
expect(response).to redirect_to(stored_path)
|
||||||
expect(controller).not_to redirect_to link_sent_path(email: email)
|
|
||||||
# TODO when signing in as non-administrateur, and not starting a demarche, log in to instructeur path
|
|
||||||
# expect(controller).to redirect_to instructeur_procedures_path
|
|
||||||
|
|
||||||
expect(controller.current_user).to eq(user)
|
|
||||||
expect(controller.current_instructeur).to eq(instructeur)
|
|
||||||
expect(controller.current_administrateur).to eq(administrateur)
|
|
||||||
expect(user.loged_in_with_france_connect).to be(nil)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the credentials are wrong' do
|
context 'when the user is locked' do
|
||||||
let(:send_password) { 'wrong_password' }
|
before { user.lock_access! }
|
||||||
|
|
||||||
it 'fails to sign in with bad credentials' do
|
it 'redirects to new_path' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(response.unauthorized?).to be(true)
|
expect(response).to render_template(:new)
|
||||||
expect(controller.current_user).to be(nil)
|
expect(flash.alert).to eq(I18n.t('devise.failure.invalid'))
|
||||||
expect(controller.current_instructeur).to be(nil)
|
|
||||||
expect(controller.current_administrateur).to be(nil)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the credentials are wrong' do
|
||||||
|
let(:send_password) { 'wrong_password' }
|
||||||
|
|
||||||
|
it 'fails to sign in with bad credentials' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to render_template(:new)
|
||||||
|
expect(controller.current_user).to be(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#destroy' do
|
describe '#destroy' do
|
||||||
|
|
|
@ -4,18 +4,11 @@ FactoryBot.define do
|
||||||
email { generate(:administrateur_email) }
|
email { generate(:administrateur_email) }
|
||||||
|
|
||||||
transient do
|
transient do
|
||||||
user { nil }
|
|
||||||
password { 'mon chien aime les bananes' }
|
password { 'mon chien aime les bananes' }
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:create) do |administrateur, evaluator|
|
initialize_with do
|
||||||
if evaluator.user.present?
|
User.create_or_promote_to_administrateur(email, password).administrateur
|
||||||
user = evaluator.user
|
|
||||||
else
|
|
||||||
user = create(:user, email: administrateur.email, password: evaluator.password, administrateur: administrateur)
|
|
||||||
end
|
|
||||||
|
|
||||||
create(:instructeur, email: administrateur.email, user: user)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,8 @@ FactoryBot.define do
|
||||||
password { 'somethingverycomplated!' }
|
password { 'somethingverycomplated!' }
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:create) do |instructeur, evaluator|
|
initialize_with do
|
||||||
if evaluator.user.present?
|
User.create_or_promote_to_instructeur(email, password).instructeur
|
||||||
user = evaluator.user
|
|
||||||
else
|
|
||||||
user = create(:user, email: instructeur.email, password: evaluator.password)
|
|
||||||
end
|
|
||||||
|
|
||||||
instructeur.update!(user: user)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,17 @@ feature 'Signin in:' do
|
||||||
expect(page).to have_current_path dossiers_path
|
expect(page).to have_current_path dossiers_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'an existing user can lock its account' do
|
||||||
|
visit root_path
|
||||||
|
click_on 'Connexion'
|
||||||
|
|
||||||
|
5.times { sign_in_with user.email, 'bad password' }
|
||||||
|
expect(user.reload.access_locked?).to be false
|
||||||
|
|
||||||
|
sign_in_with user.email, 'bad password'
|
||||||
|
expect(user.reload.access_locked?).to be true
|
||||||
|
end
|
||||||
|
|
||||||
context 'when visiting a procedure' do
|
context 'when visiting a procedure' do
|
||||||
let(:procedure) { create :simple_procedure, :with_service }
|
let(:procedure) { create :simple_procedure, :with_service }
|
||||||
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
describe '2019_05_29_migrate_commentaire_pj.rake' do
|
|
||||||
let(:rake_task) { Rake::Task['2019_05_29_migrate_commentaire_pj:run'] }
|
|
||||||
|
|
||||||
let(:commentaires) do
|
|
||||||
[
|
|
||||||
create(:commentaire),
|
|
||||||
create(:commentaire, :with_file),
|
|
||||||
create(:commentaire, :with_file)
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
commentaires.each do |commentaire|
|
|
||||||
if commentaire.file.present?
|
|
||||||
stub_request(:get, commentaire.file_url)
|
|
||||||
.to_return(status: 200, body: File.read(commentaire.file.path))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
after do
|
|
||||||
ENV['LIMIT'] = nil
|
|
||||||
rake_task.reenable
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should migrate pj' do
|
|
||||||
comment_updated_at = Commentaire.last.updated_at
|
|
||||||
dossier_updated_at = Commentaire.last.dossier.updated_at
|
|
||||||
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, false, false])
|
|
||||||
rake_task.invoke
|
|
||||||
expect(Commentaire.where(file: nil).count).to eq(1)
|
|
||||||
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, true, true])
|
|
||||||
expect(Commentaire.last.updated_at).to eq(comment_updated_at)
|
|
||||||
expect(Commentaire.last.dossier.updated_at).to eq(dossier_updated_at)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should migrate pj within limit' do
|
|
||||||
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, false, false])
|
|
||||||
ENV['LIMIT'] = '1'
|
|
||||||
rake_task.invoke
|
|
||||||
expect(Commentaire.where(file: nil).count).to eq(1)
|
|
||||||
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, true, false])
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when a commentaire’s dossier is hidden' do
|
|
||||||
let(:hidden_dossier) { create(:dossier, :en_construction, :hidden) }
|
|
||||||
let(:commentaire) { create(:commentaire, :with_file, dossier: hidden_dossier) }
|
|
||||||
let(:commentaires) { [commentaire] }
|
|
||||||
|
|
||||||
it 'should migrate the pj' do
|
|
||||||
comment_updated_at = commentaire.reload.updated_at
|
|
||||||
dossier_updated_at = hidden_dossier.reload.updated_at
|
|
||||||
|
|
||||||
rake_task.invoke
|
|
||||||
commentaires.each(&:reload)
|
|
||||||
|
|
||||||
expect(commentaire.piece_jointe.attached?).to be true
|
|
||||||
expect(commentaire.updated_at).to eq(comment_updated_at)
|
|
||||||
expect(hidden_dossier.updated_at).to eq(dossier_updated_at)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
describe '20190819100424_clean_procedure_presentation_from_followers_gestionnaires.rake' do
|
||||||
|
let(:rake_task) { Rake::Task['after_party:clean_procedure_presentation_from_followers_gestionnaires'] }
|
||||||
|
|
||||||
|
let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private) }
|
||||||
|
let(:assign_to) { create(:assign_to, procedure: procedure) }
|
||||||
|
|
||||||
|
let!(:procedure_presentation) do
|
||||||
|
pp = ProcedurePresentation.new(
|
||||||
|
assign_to: assign_to,
|
||||||
|
sort: {
|
||||||
|
"order" => "asc",
|
||||||
|
"table" => "followers_gestionnaires",
|
||||||
|
"column" => "email"
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
"tous" => [],
|
||||||
|
"suivis" => [],
|
||||||
|
"traites" => [{
|
||||||
|
"label" => "Email instructeur",
|
||||||
|
"table" => "followers_gestionnaires",
|
||||||
|
"value" => "mail@simon.lehericey.net",
|
||||||
|
"column" => "email"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"a-suivre" => [],
|
||||||
|
"archives" => []
|
||||||
|
},
|
||||||
|
displayed_fields: [
|
||||||
|
{
|
||||||
|
"column" => "email",
|
||||||
|
"label" => "Demandeur",
|
||||||
|
"table" => "user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column" => "email",
|
||||||
|
"label" => "Email instructeur",
|
||||||
|
"table" => "followers_gestionnaires"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
pp.save(validate: false)
|
||||||
|
pp
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
rake_task.invoke
|
||||||
|
procedure_presentation.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
after { rake_task.reenable }
|
||||||
|
|
||||||
|
it do
|
||||||
|
expect(procedure_presentation.displayed_fields[1]["table"]).to eq("followers_instructeurs")
|
||||||
|
expect(procedure_presentation.sort["table"]).to eq("followers_instructeurs")
|
||||||
|
expect(procedure_presentation.filters["traites"][0]["table"]).to eq("followers_instructeurs")
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an invalid procedure_presentation' do
|
||||||
|
let!(:procedure_presentation) do
|
||||||
|
pp = ProcedurePresentation.new(
|
||||||
|
assign_to: assign_to,
|
||||||
|
filters: {
|
||||||
|
"tous" => [],
|
||||||
|
"suivis" => [],
|
||||||
|
"traites" => [{
|
||||||
|
"label" => "Email instructeur",
|
||||||
|
"table" => "invalid table",
|
||||||
|
"value" => "mail@simon.lehericey.net",
|
||||||
|
"column" => "email"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"a-suivre" => [],
|
||||||
|
"archives" => []
|
||||||
|
},
|
||||||
|
displayed_fields: []
|
||||||
|
)
|
||||||
|
pp.save(validate: false)
|
||||||
|
pp
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not stop the script' do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
56
spec/middlewares/rack_attack_spec.rb
Normal file
56
spec/middlewares/rack_attack_spec.rb
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe Rack::Attack, type: :request do
|
||||||
|
let(:limit) { 5 }
|
||||||
|
let(:period) { 20 }
|
||||||
|
let(:ip) { "1.2.3.4" }
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
ENV['RACK_ATTACK_ENABLE'] = 'true'
|
||||||
|
setup_rack_attack_cache_store
|
||||||
|
avoid_test_overlaps_in_cache
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
ENV['RACK_ATTACK_ENABLE'] = 'false'
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_rack_attack_cache_store
|
||||||
|
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def avoid_test_overlaps_in_cache
|
||||||
|
Rails.cache.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
context '/users/sign_in' do
|
||||||
|
before do
|
||||||
|
limit.times do
|
||||||
|
Rack::Attack.cache.count("/users/sign_in/ip:#{ip}", period)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subject do
|
||||||
|
post "/users/sign_in", headers: { 'X-Forwarded-For': ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "throttle excessive requests by IP address" do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:too_many_requests)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the ip is whitelisted' do
|
||||||
|
before do
|
||||||
|
allow(IPService).to receive(:ip_trusted?).and_return(true)
|
||||||
|
allow_any_instance_of(Users::SessionsController).to receive(:create).and_return(:ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "respects the whitelist" do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).not_to have_http_status(:too_many_requests)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -100,4 +100,68 @@ describe User, type: :model do
|
||||||
it { is_expected.to be_falsey }
|
it { is_expected.to be_falsey }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.create_or_promote_to_instructeur' do
|
||||||
|
let(:email) { 'inst1@gmail.com' }
|
||||||
|
let(:password) { 'un super password !' }
|
||||||
|
let(:admins) { [] }
|
||||||
|
|
||||||
|
subject { User.create_or_promote_to_instructeur(email, password, administrateurs: admins) }
|
||||||
|
|
||||||
|
context 'without an existing user' do
|
||||||
|
it do
|
||||||
|
user = subject
|
||||||
|
expect(user.valid_password?(password)).to be true
|
||||||
|
expect(user.confirmed_at).to be_present
|
||||||
|
expect(user.instructeur).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an administrateur' do
|
||||||
|
let(:admins) { [create(:administrateur)] }
|
||||||
|
|
||||||
|
it do
|
||||||
|
user = subject
|
||||||
|
expect(user.instructeur.administrateurs).to eq(admins)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an existing user' do
|
||||||
|
before { create(:user, email: email, password: 'démarches-simplifiées-pwd') }
|
||||||
|
|
||||||
|
it 'keeps the previous password' do
|
||||||
|
user = subject
|
||||||
|
expect(user.valid_password?('démarches-simplifiées-pwd')).to be true
|
||||||
|
expect(user.instructeur).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an existing instructeur' do
|
||||||
|
let(:old_admins) { [create(:administrateur)] }
|
||||||
|
let(:admins) { [create(:administrateur)] }
|
||||||
|
let!(:instructeur) { Instructeur.create(email: 'i@mail.com', administrateurs: old_admins) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
User
|
||||||
|
.find_by(email: email)
|
||||||
|
.update!(instructeur: instructeur)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'keeps the existing instructeurs and adds administrateur' do
|
||||||
|
user = subject
|
||||||
|
expect(user.instructeur).to eq(instructeur)
|
||||||
|
expect(user.instructeur.administrateurs).to eq(old_admins + admins)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an invalid email' do
|
||||||
|
let(:email) { 'invalid' }
|
||||||
|
|
||||||
|
it 'does not build an instructeur' do
|
||||||
|
user = subject
|
||||||
|
expect(user.valid?).to be false
|
||||||
|
expect(user.instructeur).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,6 +28,18 @@ describe IPService do
|
||||||
|
|
||||||
it { is_expected.to be(false) }
|
it { is_expected.to be(false) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the trusted network is not defined' do
|
||||||
|
it { is_expected.to be(false) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the trusted network is malformed' do
|
||||||
|
before do
|
||||||
|
ENV['TRUSTED_NETWORKS'] = 'bad network'
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to be(false) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a trusted network is defined' do
|
context 'when a trusted network is defined' do
|
||||||
|
|
Loading…
Reference in a new issue