commit
42ddaf05f8
56 changed files with 430 additions and 315 deletions
4
Gemfile
4
Gemfile
|
@ -23,6 +23,7 @@ gem 'delayed_job_web'
|
|||
gem 'devise' # Gestion des comptes utilisateurs
|
||||
gem 'devise-async'
|
||||
gem 'devise-i18n'
|
||||
gem 'devise-two-factor', github: 'bryanfagan/devise-two-factor'
|
||||
gem 'discard'
|
||||
gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails
|
||||
gem 'ffi-geos', require: false
|
||||
|
@ -49,8 +50,6 @@ gem 'kaminari', '1.2.1' # Pagination
|
|||
gem 'lograge'
|
||||
gem 'logstash-event'
|
||||
gem 'mailjet'
|
||||
gem 'omniauth-github'
|
||||
gem 'omniauth-rails_csrf_protection', '~> 0.1'
|
||||
gem 'openid_connect'
|
||||
gem 'pg'
|
||||
gem 'phonelib'
|
||||
|
@ -65,6 +64,7 @@ gem 'rails-i18n' # Locales par défaut
|
|||
gem 'rake-progressbar', require: false
|
||||
gem 'react-rails'
|
||||
gem 'rgeo-geojson'
|
||||
gem 'rqrcode'
|
||||
gem 'sanitize-url'
|
||||
gem 'sassc-rails' # Use SCSS for stylesheets
|
||||
gem 'sentry-raven'
|
||||
|
|
43
Gemfile.lock
43
Gemfile.lock
|
@ -1,3 +1,14 @@
|
|||
GIT
|
||||
remote: https://github.com/bryanfagan/devise-two-factor.git
|
||||
revision: 60038a699b1847266f6ce0a3457fdc2cd24715be
|
||||
specs:
|
||||
devise-two-factor (3.1.1)
|
||||
activesupport (< 6.1)
|
||||
attr_encrypted (>= 1.3, < 4, != 2)
|
||||
devise (~> 4.0)
|
||||
railties (< 6.1)
|
||||
rotp (~> 4.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/mina-deploy/mina.git
|
||||
revision: 84fa84c7f7f94f9518ef9b7099396ab6676b5881
|
||||
|
@ -101,6 +112,8 @@ GEM
|
|||
activerecord (>= 3.2, < 7.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.1)
|
||||
attr_encrypted (3.1.0)
|
||||
encryptor (~> 3.0.0)
|
||||
attr_required (1.0.1)
|
||||
autoprefixer-rails (10.0.1.0)
|
||||
execjs
|
||||
|
@ -220,6 +233,7 @@ GEM
|
|||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
encryptor (3.0.0)
|
||||
equalizer (0.0.11)
|
||||
erubi (1.9.0)
|
||||
erubis (2.7.0)
|
||||
|
@ -407,7 +421,6 @@ GEM
|
|||
momentjs-rails (2.20.1)
|
||||
railties (>= 3.1)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
|
@ -419,24 +432,6 @@ GEM
|
|||
notiffany (0.1.3)
|
||||
nenv (~> 0.1)
|
||||
shellany (~> 0.0)
|
||||
oauth2 (1.4.4)
|
||||
faraday (>= 0.8, < 2.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-github (1.4.0)
|
||||
omniauth (~> 1.5)
|
||||
omniauth-oauth2 (>= 1.4.0, < 2.0)
|
||||
omniauth-oauth2 (1.6.0)
|
||||
oauth2 (~> 1.1)
|
||||
omniauth (~> 1.9)
|
||||
omniauth-rails_csrf_protection (0.1.2)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (>= 1.3.1)
|
||||
open4 (1.3.4)
|
||||
openid_connect (1.1.8)
|
||||
activemodel
|
||||
|
@ -573,7 +568,13 @@ GEM
|
|||
builder (>= 3.0)
|
||||
dry-inflector (~> 0.1)
|
||||
rubyzip (>= 1.0)
|
||||
rotp (4.1.0)
|
||||
addressable (~> 2.5)
|
||||
rouge (3.17.0)
|
||||
rqrcode (1.1.2)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
rqrcode_core (0.1.2)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
|
@ -798,6 +799,7 @@ DEPENDENCIES
|
|||
devise
|
||||
devise-async
|
||||
devise-i18n
|
||||
devise-two-factor!
|
||||
discard
|
||||
dotenv-rails
|
||||
factory_bot
|
||||
|
@ -833,8 +835,6 @@ DEPENDENCIES
|
|||
logstash-event
|
||||
mailjet
|
||||
mina!
|
||||
omniauth-github
|
||||
omniauth-rails_csrf_protection (~> 0.1)
|
||||
openid_connect
|
||||
pg
|
||||
phonelib
|
||||
|
@ -853,6 +853,7 @@ DEPENDENCIES
|
|||
rake-progressbar
|
||||
react-rails
|
||||
rgeo-geojson
|
||||
rqrcode
|
||||
rspec-rails
|
||||
rspec_junit_formatter
|
||||
rubocop
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
class Administrations::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
def github
|
||||
administration = Administration.from_omniauth(request.env["omniauth.auth"])
|
||||
if administration.present?
|
||||
sign_in administration
|
||||
redirect_to manager_administrateurs_path
|
||||
else
|
||||
flash[:alert] = "Compte GitHub non autorisé"
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
def failure
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
class Administrations::SessionsController < ApplicationController
|
||||
def new
|
||||
end
|
||||
|
||||
def destroy
|
||||
if administration_signed_in?
|
||||
sign_out :administration
|
||||
end
|
||||
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
|
@ -13,6 +13,7 @@ class ApplicationController < ActionController::Base
|
|||
before_action :set_raven_context
|
||||
before_action :redirect_if_untrusted
|
||||
before_action :reject, if: -> { feature_enabled?(:maintenance_mode) }
|
||||
before_action :configure_permitted_parameters, if: :devise_controller?
|
||||
|
||||
before_action :staging_authenticate
|
||||
before_action :set_active_storage_host
|
||||
|
@ -105,6 +106,10 @@ class ApplicationController < ActionController::Base
|
|||
stored_location_for(:user) || super
|
||||
end
|
||||
|
||||
def configure_permitted_parameters
|
||||
devise_parameter_sanitizer.permit(:sign_in, keys: [:otp_attempt])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_current_roles
|
||||
|
@ -137,7 +142,7 @@ class ApplicationController < ActionController::Base
|
|||
current_user,
|
||||
current_instructeur,
|
||||
current_administrateur,
|
||||
current_administration
|
||||
current_super_admin
|
||||
].compact.map { |role| role.class.name }
|
||||
|
||||
roles.any? ? roles.join(', ') : 'Guest'
|
||||
|
@ -175,11 +180,11 @@ class ApplicationController < ActionController::Base
|
|||
authorized_request =
|
||||
request.path_info == '/' ||
|
||||
request.path_info.start_with?('/manager') ||
|
||||
request.path_info.start_with?('/administrations')
|
||||
request.path_info.start_with?('/super_admins')
|
||||
|
||||
api_request = request.path_info.start_with?('/api/')
|
||||
|
||||
if administration_signed_in? || authorized_request
|
||||
if super_admin_signed_in? || authorized_request
|
||||
flash.now.alert = MAINTENANCE_MESSAGE
|
||||
elsif api_request
|
||||
render json: { error: MAINTENANCE_MESSAGE }.to_json, status: :service_unavailable
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Manager
|
||||
class AdministrateursController < Manager::ApplicationController
|
||||
def create
|
||||
administrateur = current_administration.invite_admin(create_administrateur_params[:email])
|
||||
administrateur = current_super_admin.invite_admin(create_administrateur_params[:email])
|
||||
|
||||
if administrateur.errors.empty?
|
||||
flash.notice = "Administrateur créé"
|
||||
|
@ -14,7 +14,7 @@ module Manager
|
|||
end
|
||||
|
||||
def reinvite
|
||||
Administrateur.find_inactive_by_id(params[:id]).user.invite_administrateur!(current_administration.id)
|
||||
Administrateur.find_inactive_by_id(params[:id]).user.invite_administrateur!(current_super_admin.id)
|
||||
flash.notice = "Invitation renvoyée"
|
||||
redirect_to manager_administrateur_path(params[:id])
|
||||
end
|
||||
|
@ -24,7 +24,7 @@ module Manager
|
|||
|
||||
administrateur.delete_and_transfer_services
|
||||
|
||||
logger.info("L'administrateur #{administrateur.id} est supprimé par #{current_administration.id}")
|
||||
logger.info("L'administrateur #{administrateur.id} est supprimé par #{current_super_admin.id}")
|
||||
flash[:notice] = "L'administrateur #{administrateur.id} est supprimé"
|
||||
|
||||
redirect_to manager_administrateurs_path
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module Manager
|
||||
class ApplicationController < Administrate::ApplicationController
|
||||
before_action :authenticate_administration!
|
||||
before_action :authenticate_super_admin!
|
||||
before_action :default_params
|
||||
|
||||
def default_params
|
||||
|
@ -12,11 +12,13 @@ module Manager
|
|||
|
||||
protected
|
||||
|
||||
def authenticate_administration!
|
||||
if administration_signed_in?
|
||||
def authenticate_super_admin!
|
||||
if super_admin_signed_in? && current_super_admin.otp_required_for_login?
|
||||
super
|
||||
elsif super_admin_signed_in?
|
||||
redirect_to edit_super_admin_otp_path
|
||||
else
|
||||
redirect_to manager_sign_in_path
|
||||
redirect_to new_super_admin_session_path
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ module Manager
|
|||
end
|
||||
|
||||
def create_administrateur
|
||||
administrateur = current_administration.invite_admin(create_administrateur_params[:email])
|
||||
administrateur = current_super_admin.invite_admin(create_administrateur_params[:email])
|
||||
|
||||
if administrateur.errors.empty?
|
||||
PipedriveAcceptsDealsJob.perform_later(
|
||||
create_administrateur_params[:person_id],
|
||||
current_administration.id,
|
||||
current_super_admin.id,
|
||||
create_administrateur_params[:stage_id]
|
||||
)
|
||||
|
||||
|
@ -26,7 +26,7 @@ module Manager
|
|||
def refuse_administrateur
|
||||
PipedriveRefusesDealsJob.perform_later(
|
||||
refuse_administrateur_params[:person_id],
|
||||
current_administration.id
|
||||
current_super_admin.id
|
||||
)
|
||||
|
||||
AdministrationMailer
|
||||
|
|
|
@ -22,9 +22,9 @@ module Manager
|
|||
|
||||
def discard
|
||||
dossier = Dossier.find(params[:id])
|
||||
dossier.discard_and_keep_track!(current_administration, :manager_request)
|
||||
dossier.discard_and_keep_track!(current_super_admin, :manager_request)
|
||||
|
||||
logger.info("Le dossier #{dossier.id} est supprimé par #{current_administration.email}")
|
||||
logger.info("Le dossier #{dossier.id} est supprimé par #{current_super_admin.email}")
|
||||
flash[:notice] = "Le dossier #{dossier.id} a été supprimé."
|
||||
|
||||
redirect_to manager_dossier_path(dossier)
|
||||
|
@ -32,7 +32,7 @@ module Manager
|
|||
|
||||
def restore
|
||||
dossier = Dossier.with_discarded.find(params[:id])
|
||||
dossier.restore(current_administration)
|
||||
dossier.restore(current_super_admin)
|
||||
|
||||
flash[:notice] = "Le dossier #{dossier.id} a été restauré."
|
||||
|
||||
|
@ -41,9 +41,9 @@ module Manager
|
|||
|
||||
def repasser_en_instruction
|
||||
dossier = Dossier.find(params[:id])
|
||||
dossier.repasser_en_instruction(current_administration)
|
||||
dossier.repasser_en_instruction(current_super_admin)
|
||||
|
||||
logger.info("Le dossier #{dossier.id} est repassé en instruction par #{current_administration.email}")
|
||||
logger.info("Le dossier #{dossier.id} est repassé en instruction par #{current_super_admin.email}")
|
||||
flash[:notice] = "Le dossier #{dossier.id} est repassé en instruction."
|
||||
|
||||
redirect_to manager_dossier_path(dossier)
|
||||
|
|
|
@ -15,7 +15,7 @@ module Manager
|
|||
end
|
||||
instructeur.destroy!
|
||||
|
||||
logger.info("L'instructeur #{instructeur.id} est supprimé par #{current_administration.id}")
|
||||
logger.info("L'instructeur #{instructeur.id} est supprimé par #{current_super_admin.id}")
|
||||
flash[:notice] = "L'instructeur #{instructeur.id} est supprimé"
|
||||
|
||||
redirect_to manager_instructeurs_path
|
||||
|
|
|
@ -23,16 +23,16 @@ module Manager
|
|||
end
|
||||
|
||||
def discard
|
||||
procedure.discard_and_keep_track!(current_administration)
|
||||
procedure.discard_and_keep_track!(current_super_admin)
|
||||
|
||||
logger.info("La démarche #{procedure.id} est supprimée par #{current_administration.email}")
|
||||
logger.info("La démarche #{procedure.id} est supprimée par #{current_super_admin.email}")
|
||||
flash[:notice] = "La démarche #{procedure.id} a été supprimée."
|
||||
|
||||
redirect_to manager_procedure_path(procedure)
|
||||
end
|
||||
|
||||
def restore
|
||||
procedure.restore(current_administration)
|
||||
procedure.restore(current_super_admin)
|
||||
|
||||
flash[:notice] = "La démarche #{procedure.id} a été restauré."
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ module Manager
|
|||
if !user.can_be_deleted?
|
||||
fail "Impossible de supprimer cet utilisateur. Il a des dossiers en instruction ou il est administrateur."
|
||||
end
|
||||
user.delete_and_keep_track_dossiers(current_administration)
|
||||
user.delete_and_keep_track_dossiers(current_super_admin)
|
||||
|
||||
logger.info("L'utilisateur #{user.id} est supprimé par #{current_administration.id}")
|
||||
logger.info("L'utilisateur #{user.id} est supprimé par #{current_super_admin.id}")
|
||||
flash[:notice] = "L'utilisateur #{user.id} est supprimé"
|
||||
|
||||
redirect_to manager_users_path
|
||||
|
|
|
@ -8,7 +8,7 @@ class RootController < ApplicationController
|
|||
return redirect_to instructeur_procedures_path
|
||||
elsif user_signed_in?
|
||||
return redirect_to dossiers_path
|
||||
elsif administration_signed_in?
|
||||
elsif super_admin_signed_in?
|
||||
return redirect_to manager_root_path
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class StatsController < ApplicationController
|
||||
before_action :authenticate_administration!, only: [:download]
|
||||
before_action :authenticate_super_admin!, only: [:download]
|
||||
|
||||
MEAN_NUMBER_OF_CHAMPS_IN_A_FORM = 24.0
|
||||
|
||||
|
@ -34,7 +34,7 @@ class StatsController < ApplicationController
|
|||
@dossiers_cumulative = stat.dossiers_cumulative
|
||||
@dossiers_in_the_last_4_months = stat.dossiers_in_the_last_4_months
|
||||
|
||||
if administration_signed_in?
|
||||
if super_admin_signed_in?
|
||||
@dossier_instruction_mean_time = Rails.cache.fetch("dossier_instruction_mean_time", expires_in: 1.day) do
|
||||
dossier_instruction_mean_time(dossiers)
|
||||
end
|
||||
|
@ -201,7 +201,7 @@ class StatsController < ApplicationController
|
|||
end
|
||||
|
||||
def max_date
|
||||
if administration_signed_in?
|
||||
if super_admin_signed_in?
|
||||
Time.zone.now
|
||||
else
|
||||
Time.zone.now.beginning_of_month - 1.second
|
||||
|
|
6
app/controllers/super_admins/passwords_controller.rb
Normal file
6
app/controllers/super_admins/passwords_controller.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class Administrations::PasswordsController < Devise::PasswordsController
|
||||
def update
|
||||
super
|
||||
self.resource.disable_otp!
|
||||
end
|
||||
end
|
2
app/controllers/super_admins/sessions_controller.rb
Normal file
2
app/controllers/super_admins/sessions_controller.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class Administrations::SessionsController < Devise::SessionsController
|
||||
end
|
28
app/controllers/super_admins_controller.rb
Normal file
28
app/controllers/super_admins_controller.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
class SuperAdminsController < ApplicationController
|
||||
before_action :authenticate_super_admin!
|
||||
|
||||
def edit_otp
|
||||
end
|
||||
|
||||
def enable_otp
|
||||
current_super_admin.enable_otp!
|
||||
@qrcode = generate_qr_code
|
||||
sign_out :super_admin
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def authenticate_super_admin!
|
||||
if !super_admin_signed_in?
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_qr_code
|
||||
issuer = 'DSManager'
|
||||
label = "#{issuer}:#{current_super_admin.email}"
|
||||
RQRCode::QRCode.new(current_super_admin.otp_provisioning_uri(label, issuer: issuer))
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: administrations
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# current_sign_in_at :datetime
|
||||
# current_sign_in_ip :string
|
||||
# email :string default(""), not null
|
||||
# encrypted_password :string default(""), not null
|
||||
# failed_attempts :integer default(0), not null
|
||||
# last_sign_in_at :datetime
|
||||
# last_sign_in_ip :string
|
||||
# locked_at :datetime
|
||||
# remember_created_at :datetime
|
||||
# reset_password_sent_at :datetime
|
||||
# reset_password_token :string
|
||||
# sign_in_count :integer default(0), not null
|
||||
# unlock_token :string
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
class Administration < ApplicationRecord
|
||||
# Include default devise modules. Others available are:
|
||||
# :confirmable, :lockable, :timeoutable and :omniauthable
|
||||
devise :database_authenticatable, :rememberable, :trackable, :validatable, :omniauthable, :lockable, :async, omniauth_providers: [:github]
|
||||
|
||||
def self.from_omniauth(params)
|
||||
find_by(email: params["info"]["email"])
|
||||
end
|
||||
|
||||
def invite_admin(email)
|
||||
user = User.create_or_promote_to_administrateur(email, SecureRandom.hex)
|
||||
|
||||
if user.valid?
|
||||
user.invite_administrateur!(id)
|
||||
end
|
||||
|
||||
user
|
||||
end
|
||||
end
|
59
app/models/super_admin.rb
Normal file
59
app/models/super_admin.rb
Normal file
|
@ -0,0 +1,59 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: super_admins
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# consumed_timestep :integer
|
||||
# current_sign_in_at :datetime
|
||||
# current_sign_in_ip :string
|
||||
# email :string default(""), not null
|
||||
# encrypted_otp_secret :string
|
||||
# encrypted_otp_secret_iv :string
|
||||
# encrypted_otp_secret_salt :string
|
||||
# encrypted_password :string default(""), not null
|
||||
# failed_attempts :integer default(0), not null
|
||||
# last_sign_in_at :datetime
|
||||
# last_sign_in_ip :string
|
||||
# locked_at :datetime
|
||||
# otp_required_for_login :boolean
|
||||
# remember_created_at :datetime
|
||||
# reset_password_sent_at :datetime
|
||||
# reset_password_token :string
|
||||
# sign_in_count :integer default(0), not null
|
||||
# unlock_token :string
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
class SuperAdmin < ApplicationRecord
|
||||
devise :rememberable, :trackable, :validatable, :lockable, :async, :recoverable,
|
||||
:two_factor_authenticatable, :otp_secret_encryption_key => Rails.application.secrets.otp_secret_key
|
||||
|
||||
def enable_otp!
|
||||
self.otp_secret = SuperAdmin.generate_otp_secret
|
||||
self.otp_required_for_login = true
|
||||
save!
|
||||
end
|
||||
|
||||
def disable_otp!
|
||||
self.assign_attributes(
|
||||
{
|
||||
encrypted_otp_secret: nil,
|
||||
encrypted_otp_secret_iv: nil,
|
||||
encrypted_otp_secret_salt: nil,
|
||||
consumed_timestep: nil,
|
||||
otp_required_for_login: false
|
||||
}
|
||||
)
|
||||
save!
|
||||
end
|
||||
|
||||
def invite_admin(email)
|
||||
user = User.create_or_promote_to_administrateur(email, SecureRandom.hex)
|
||||
|
||||
if user.valid?
|
||||
user.invite_administrateur!(id)
|
||||
end
|
||||
|
||||
user
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ class OperationAuthorSerializer < ActiveModel::Serializer
|
|||
"Instructeur##{object.id}"
|
||||
when Administrateur
|
||||
"Administrateur##{object.id}"
|
||||
when Administration
|
||||
when SuperAdmin
|
||||
"Manager##{object.id}"
|
||||
else
|
||||
nil
|
||||
|
|
6
app/views/administrations/edit_otp.html.haml
Normal file
6
app/views/administrations/edit_otp.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
.super-admin.flex.justify-center
|
||||
%div
|
||||
%h2.huge-title Espace Manager
|
||||
%p Munissez-vous de votre téléphone sur lequel vous avez installé une application cliente 2FA (Google Authenticator, Authy, AndOTP, ...)
|
||||
%br
|
||||
%p= link_to "Activer l'authentification double-facteur", enable_administration_otp_path, method: :put, class: 'button primary'
|
12
app/views/administrations/enable_otp.html.haml
Normal file
12
app/views/administrations/enable_otp.html.haml
Normal file
|
@ -0,0 +1,12 @@
|
|||
.container
|
||||
%p
|
||||
%strong Si vous n'effectuez pas cette étape maintenant, vous ne pourrez plus vous connecter au manager !
|
||||
%p Depuis votre téléphone, lancez votre application cliente 2FA et scannez ce QRCode afin d'ajouter votre compte DSManager. Votre application vous fournira ensuite à chaque connexion au manager le code otp à saisir.
|
||||
%br
|
||||
= raw @qrcode.as_svg(module_size: 6)
|
||||
|
||||
%br
|
||||
|
||||
%p
|
||||
Après avoir scanné le QRCode ci-dessus, nous vous invitons à
|
||||
= link_to 'accéder au Manager' , manager_root_path
|
22
app/views/administrations/passwords/edit.html.haml
Normal file
22
app/views/administrations/passwords/edit.html.haml
Normal file
|
@ -0,0 +1,22 @@
|
|||
- content_for(:title, 'Changement de mot de passe')
|
||||
|
||||
- content_for :footer do
|
||||
= render partial: 'root/footer'
|
||||
|
||||
.container.devise-container
|
||||
.one-column-centered
|
||||
= devise_error_messages!
|
||||
|
||||
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :patch, class: 'form' }) do |f|
|
||||
|
||||
%h1 Changement de mot de passe
|
||||
|
||||
= f.hidden_field :reset_password_token
|
||||
|
||||
= f.label 'Nouveau mot de passe'
|
||||
= f.password_field :password, autofocus: true, autocomplete: 'off'
|
||||
|
||||
= f.label 'Confirmez le nouveau mot de passe'
|
||||
= f.password_field :password_confirmation, autocomplete: 'off'
|
||||
|
||||
= f.submit 'Changer le mot de passe', class: 'button primary'
|
17
app/views/administrations/passwords/new.html.haml
Normal file
17
app/views/administrations/passwords/new.html.haml
Normal file
|
@ -0,0 +1,17 @@
|
|||
- content_for(:title, 'Mot de passe oublié')
|
||||
|
||||
- content_for :footer do
|
||||
= render partial: 'root/footer'
|
||||
|
||||
.container.devise-container
|
||||
.one-column-centered
|
||||
= devise_error_messages!
|
||||
|
||||
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { class: 'form' }) do |f|
|
||||
|
||||
%h1 Mot de passe oublié
|
||||
|
||||
= f.label :email, 'Email'
|
||||
= f.email_field :email, autofocus: true
|
||||
|
||||
= f.submit 'Réinitialiser', class: 'button primary'
|
|
@ -1,6 +1,21 @@
|
|||
.super-admin.flex.justify-center
|
||||
%div
|
||||
%h2 Espace Admin
|
||||
= link_to administration_github_omniauth_authorize_path, method: :post, class: "button large" do
|
||||
%span.icon.lock
|
||||
Connexion avec GitHub
|
||||
%h2.huge-title Espace Manager
|
||||
.auth-form.sign-in-form
|
||||
|
||||
= form_for Administration.new, url: administration_session_path, html: { class: "form" } do |f|
|
||||
%h1 Connectez-vous
|
||||
|
||||
= f.label :email, "Email (nom@site.com)"
|
||||
= f.text_field :email, type: :email, autocomplete: 'username', autofocus: true
|
||||
|
||||
= f.label :password, "Mot de passe (#{PASSWORD_MIN_LENGTH} caractères minimum)"
|
||||
= f.password_field :password, autocomplete: 'current-password'
|
||||
|
||||
= f.label :otp_attempt, 'Code OTP (uniquement si vous avez déjà activé 2FA)'
|
||||
= f.text_field :otp_attempt
|
||||
|
||||
.auth-options
|
||||
.text-right
|
||||
= link_to "Mot de passe oublié ou réinitialisation 2FA ?", new_administration_password_path, class: "link"
|
||||
= f.submit "Se connecter", class: "button large primary expand"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
%li
|
||||
.menu-item{ title: current_email }
|
||||
= current_email
|
||||
- if administration_signed_in?
|
||||
- if super_admin_signed_in?
|
||||
%li
|
||||
= link_to manager_root_path, class: "menu-item menu-link" do
|
||||
= image_tag "icons/super-admin.svg", alt: ''
|
||||
|
|
|
@ -8,7 +8,7 @@ as defined by the routes in the `admin/` namespace
|
|||
%>
|
||||
|
||||
<nav class="navigation" role="navigation">
|
||||
<%= link_to "Se déconnecter", manager_sign_out_path, method: :delete, class: "navigation__link" %>
|
||||
<%= link_to "Se déconnecter", destroy_super_admin_session_path, method: :delete, class: "navigation__link" %>
|
||||
|
||||
<hr />
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
.chart.cumulative-dossiers-chart.hidden
|
||||
= area_chart @dossiers_cumulative
|
||||
|
||||
- if administration_signed_in?
|
||||
- if super_admin_signed_in?
|
||||
.stat-card.stat-card-half.pull-left
|
||||
%span.stat-card-title Temps de traitement moyen d'un dossier
|
||||
|
||||
|
@ -107,7 +107,7 @@
|
|||
|
||||
.clearfix
|
||||
|
||||
- if administration_signed_in?
|
||||
- if super_admin_signed_in?
|
||||
%h2.new-h2 Téléchargement
|
||||
|
||||
= link_to "Télécharger les statistiques (CSV)", stats_download_path(format: :csv), class: 'button secondary'
|
||||
|
|
|
@ -17,6 +17,9 @@ SOURCE="tps_local"
|
|||
SECRET_KEY_BASE="05a2d479d8e412198dabd08ef0eee9d6e180f5cbb48661a35fd1cae287f0a93d40b5f1da08f06780d698bbd458a0ea97f730f83ee780de5d4e31f649a0130cf0"
|
||||
SIGNING_KEY="aef3153a9829fa4ba10acb02927ac855df6b92795b1ad265d654443c4b14a017"
|
||||
|
||||
# Clé de chiffrement OTP, pour 2FA
|
||||
OTP_SECRET_KEY=""
|
||||
|
||||
# Database
|
||||
DB_DATABASE="tps_development"
|
||||
DB_HOST="localhost"
|
||||
|
@ -42,10 +45,6 @@ FC_PARTICULIER_ID=""
|
|||
FC_PARTICULIER_SECRET=""
|
||||
FC_PARTICULIER_BASE_URL=""
|
||||
|
||||
# Service externe: Authentification pour manager (auth Github obligatoire), permet d'accéder à /manager
|
||||
GITHUB_CLIENT_ID=""
|
||||
GITHUB_CLIENT_SECRET=""
|
||||
|
||||
# Service externe: Support Utilisateur HelpScout | Spécifique démarches-simplifiées.fr
|
||||
HELPSCOUT_MAILBOX_ID=""
|
||||
HELPSCOUT_CLIENT_ID=""
|
||||
|
|
|
@ -232,21 +232,12 @@ Devise.setup do |config|
|
|||
# The default HTTP method used to sign out a resource. Default is :delete.
|
||||
config.sign_out_via = :delete
|
||||
|
||||
# ==> OmniAuth
|
||||
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
||||
# up on your models and hooks.
|
||||
if !Rails.env.test?
|
||||
config.omniauth :github, Rails.application.secrets.github[:client_id], Rails.application.secrets.github[:client_secret], scope: 'user:email'
|
||||
end
|
||||
|
||||
# ==> Warden configuration
|
||||
# If you want to use other strategies, that are not supported by Devise, or
|
||||
# change the failure app, you can configure them inside the config.warden block.
|
||||
#
|
||||
config.warden do |manager|
|
||||
# manager.intercept_401 = false
|
||||
# manager.default_strategies(scope: :user).unshift :some_external_strategy
|
||||
# manager.failure_app = User::CustomFailure
|
||||
manager.default_strategies(:scope => :administration).unshift :two_factor_authenticatable
|
||||
end
|
||||
|
||||
# ==> Mountable engine configurations
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
# OmniAuth GET requests may be vulnerable to CSRF.
|
||||
# Ensure that OmniAuth only uses POST requests.
|
||||
# See https://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284
|
||||
OmniAuth.config.allowed_request_methods = [:post]
|
|
@ -3,8 +3,6 @@ Rails.application.routes.draw do
|
|||
# Manager
|
||||
#
|
||||
|
||||
get 'manager/sign_in' => 'administrations/sessions#new'
|
||||
delete 'manager/sign_out' => 'administrations/sessions#destroy'
|
||||
namespace :manager do
|
||||
resources :procedures, only: [:index, :show] do
|
||||
post 'whitelist', on: :member
|
||||
|
@ -77,11 +75,13 @@ Rails.application.routes.draw do
|
|||
# Authentication
|
||||
#
|
||||
|
||||
devise_for :administrations,
|
||||
skip: [:password, :registrations, :sessions],
|
||||
controllers: {
|
||||
omniauth_callbacks: 'administrations/omniauth_callbacks'
|
||||
}
|
||||
devise_for :super_admins, skip: [:registrations], controllers: {
|
||||
sessions: 'super_admins/sessions',
|
||||
passwords: 'super_admins/passwords'
|
||||
}
|
||||
|
||||
get 'super_admins/edit_otp', to: 'super_admins#edit_otp', as: 'edit_super_admin_otp'
|
||||
put 'super_admins/enable_otp', to: 'super_admins#enable_otp', as: 'enable_super_admin_otp'
|
||||
|
||||
devise_for :users, controllers: {
|
||||
sessions: 'users/sessions',
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
defaults: &defaults
|
||||
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
||||
signing_key: <%= ENV["SIGNING_KEY"] %>
|
||||
otp_secret_key: <%= ENV["OTP_SECRET_KEY"] %>
|
||||
basic_auth:
|
||||
username: <%= ENV['BASIC_AUTH_USERNAME'] %>
|
||||
password: <%= ENV['BASIC_AUTH_PASSWORD'] %>
|
||||
|
@ -23,9 +24,6 @@ defaults: &defaults
|
|||
token_endpoint: <%= ENV['FC_PARTICULIER_BASE_URL'] %>/api/v1/token
|
||||
userinfo_endpoint: <%= ENV['FC_PARTICULIER_BASE_URL'] %>/api/v1/userinfo
|
||||
logout_endpoint: <%= ENV['FC_PARTICULIER_BASE_URL'] %>/api/v1/logout
|
||||
github:
|
||||
client_id: <%= ENV['GITHUB_CLIENT_ID'] %>
|
||||
client_secret: <%= ENV['GITHUB_CLIENT_SECRET'] %>
|
||||
mailjet:
|
||||
api_key: <%= ENV['MAILJET_API_KEY'] %>
|
||||
secret_key: <%= ENV['MAILJET_SECRET_KEY'] %>
|
||||
|
@ -76,6 +74,7 @@ test:
|
|||
<<: *defaults
|
||||
secret_key_base: aa52abc3f3a629d04a61e9899a24c12f52b24c679cbf45f8ec0cdcc64ab9526d673adca84212882dff3911ac98e0c32ec4729ca7b3429ba18ef4dfd1bd18bc7a
|
||||
signing_key: aef3153a9829fa4ba10acb02927ac855df6b92795b1ad265d654443c4b14a017
|
||||
otp_secret_key: 78ddda3679dc0ba2c99f50bcff04f49d862358dbeb7ead50368fdd6de14392be884ee10a204a0375b4b382e1a842fafe40d7858b7ab4796ec3a67c518d31112b
|
||||
api_entreprise:
|
||||
key: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik9oIHllYWgiLCJpYXQiOjE1MTYyMzkwMjJ9.f06sBo3q2Yxnw_TYPFUEs0CozBmcV-XniH_DeKNWzKE"
|
||||
pipedrive:
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class AddDeviseTwoFactorToAdministrations < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :administrations, :encrypted_otp_secret, :string
|
||||
add_column :administrations, :encrypted_otp_secret_iv, :string
|
||||
add_column :administrations, :encrypted_otp_secret_salt, :string
|
||||
add_column :administrations, :consumed_timestep, :integer
|
||||
add_column :administrations, :otp_required_for_login, :boolean
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class RenameAdministrationsToSuperAdmins < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
rename_table :administrations, :super_admins
|
||||
end
|
||||
end
|
49
db/schema.rb
49
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_10_02_124154) do
|
||||
ActiveRecord::Schema.define(version: 2020_11_05_131443) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -74,27 +74,6 @@ ActiveRecord::Schema.define(version: 2020_10_02_124154) do
|
|||
t.index ["procedure_id"], name: "index_administrateurs_procedures_on_procedure_id"
|
||||
end
|
||||
|
||||
create_table "administrations", id: :serial, force: :cascade do |t|
|
||||
t.string "email", default: "", null: false
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
t.string "reset_password_token"
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
t.string "current_sign_in_ip"
|
||||
t.string "last_sign_in_ip"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "failed_attempts", default: 0, null: false
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.index ["email"], name: "index_administrations_on_email", unique: true
|
||||
t.index ["reset_password_token"], name: "index_administrations_on_reset_password_token", unique: true
|
||||
t.index ["unlock_token"], name: "index_administrations_on_unlock_token", unique: true
|
||||
end
|
||||
|
||||
create_table "assign_tos", id: :serial, force: :cascade do |t|
|
||||
t.integer "instructeur_id"
|
||||
t.integer "procedure_id"
|
||||
|
@ -601,6 +580,32 @@ ActiveRecord::Schema.define(version: 2020_10_02_124154) do
|
|||
t.datetime "updated_at", precision: 6, null: false
|
||||
end
|
||||
|
||||
create_table "super_admins", id: :serial, force: :cascade do |t|
|
||||
t.string "email", default: "", null: false
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
t.string "reset_password_token"
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
t.string "current_sign_in_ip"
|
||||
t.string "last_sign_in_ip"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "failed_attempts", default: 0, null: false
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.string "encrypted_otp_secret"
|
||||
t.string "encrypted_otp_secret_iv"
|
||||
t.string "encrypted_otp_secret_salt"
|
||||
t.integer "consumed_timestep"
|
||||
t.boolean "otp_required_for_login"
|
||||
t.index ["email"], name: "index_super_admins_on_email", unique: true
|
||||
t.index ["reset_password_token"], name: "index_super_admins_on_reset_password_token", unique: true
|
||||
t.index ["unlock_token"], name: "index_super_admins_on_unlock_token", unique: true
|
||||
end
|
||||
|
||||
create_table "task_records", id: false, force: :cascade do |t|
|
||||
t.string "version", null: false
|
||||
end
|
||||
|
|
|
@ -18,10 +18,12 @@ namespace :superadmin do
|
|||
email = args[:email]
|
||||
|
||||
rake_puts "Creating Administration for #{email}"
|
||||
a = Administration.new(email: email, password: Devise.friendly_token[0, 20])
|
||||
a = Administration.new(email: email, password: Devise.friendly_token)
|
||||
|
||||
if a.save
|
||||
rake_puts "#{a.email} created"
|
||||
a.send_reset_password_instructions
|
||||
rake_puts "Password reset instructions sent to #{a.email}"
|
||||
else
|
||||
rake_puts "An error occured: #{a.errors.full_messages}"
|
||||
end
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
describe Administrations::OmniauthCallbacksController, type: :controller do
|
||||
before(:each) do
|
||||
@request.env["devise.mapping"] = Devise.mappings[:administration]
|
||||
end
|
||||
|
||||
describe 'POST #github' do
|
||||
let(:params) { { "info" => { "email" => email } } }
|
||||
before do
|
||||
allow(controller).to receive(:sign_in).and_return true
|
||||
@request.env["omniauth.auth"] = params
|
||||
end
|
||||
subject { post :github }
|
||||
|
||||
context 'with an authorized email' do
|
||||
let(:email) { "ivan@tps.fr" }
|
||||
let(:administration) { create(:administration, email: email) }
|
||||
before { administration }
|
||||
|
||||
it { is_expected.to redirect_to(manager_administrateurs_path) }
|
||||
it do
|
||||
expect(controller).to receive(:sign_in).with(administration)
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an unauthorized email' do
|
||||
let(:email) { "michel@tps.fr" }
|
||||
|
||||
it { is_expected.to redirect_to(root_path) }
|
||||
it do
|
||||
expect(controller).to_not receive(:sign_in)
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,7 +15,7 @@ describe ApplicationController, type: :controller do
|
|||
let(:current_user) { nil }
|
||||
let(:current_instructeur) { nil }
|
||||
let(:current_administrateur) { nil }
|
||||
let(:current_administration) { nil }
|
||||
let(:current_super_admin) { nil }
|
||||
let(:payload) { {} }
|
||||
|
||||
before do
|
||||
|
@ -23,7 +23,7 @@ describe ApplicationController, type: :controller do
|
|||
allow(@controller).to receive(:current_user).and_return(current_user)
|
||||
expect(@controller).to receive(:current_instructeur).and_return(current_instructeur)
|
||||
expect(@controller).to receive(:current_administrateur).and_return(current_administrateur)
|
||||
expect(@controller).to receive(:current_administration).and_return(current_administration)
|
||||
expect(@controller).to receive(:current_super_admin).and_return(current_super_admin)
|
||||
allow(Raven).to receive(:user_context)
|
||||
|
||||
@controller.send(:set_raven_context)
|
||||
|
@ -72,11 +72,11 @@ describe ApplicationController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when someone is logged as a user, instructeur, administrateur and administration' do
|
||||
context 'when someone is logged as a user, instructeur, administrateur and super_admin' do
|
||||
let(:current_user) { create(:user) }
|
||||
let(:current_instructeur) { create(:instructeur) }
|
||||
let(:current_administrateur) { create(:administrateur) }
|
||||
let(:current_administration) { create(:administration) }
|
||||
let(:current_super_admin) { create(:super_admin) }
|
||||
|
||||
it do
|
||||
expect(Raven).to have_received(:user_context)
|
||||
|
@ -93,7 +93,7 @@ describe ApplicationController, type: :controller do
|
|||
user_agent: 'Rails Testing',
|
||||
user_id: current_user.id,
|
||||
user_email: current_user.email,
|
||||
user_roles: 'User, Instructeur, Administrateur, Administration'
|
||||
user_roles: 'User, Instructeur, Administrateur, SuperAdmin'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
@ -109,7 +109,7 @@ describe ApplicationController, type: :controller do
|
|||
@request.path_info = path_info
|
||||
end
|
||||
|
||||
context 'when no administration is logged in' do
|
||||
context 'when no super_admin is logged in' do
|
||||
before { @controller.send(:reject) }
|
||||
|
||||
it { expect(@controller).to have_received(:sign_out).with(:user) }
|
||||
|
@ -119,7 +119,7 @@ describe ApplicationController, type: :controller do
|
|||
it { expect(@controller).to have_received(:redirect_to).with(root_path) }
|
||||
|
||||
context 'when the path is safe' do
|
||||
['/', '/manager', '/administrations'].each do |path|
|
||||
['/', '/manager', '/super_admins'].each do |path|
|
||||
let(:path_info) { path }
|
||||
|
||||
it { expect(@controller).not_to have_received(:sign_out) }
|
||||
|
@ -138,11 +138,11 @@ describe ApplicationController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when a administration is logged in' do
|
||||
let(:current_administration) { create(:administration) }
|
||||
context 'when a super_admin is logged in' do
|
||||
let(:current_super_admin) { create(:super_admin) }
|
||||
|
||||
before do
|
||||
sign_in(current_administration)
|
||||
sign_in(current_super_admin)
|
||||
@controller.send(:reject)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
describe Manager::AdministrateursController, type: :controller do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
|
||||
before do
|
||||
sign_in administration
|
||||
sign_in super_admin
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
render_views
|
||||
let(:subject) { get :show, params: { id: administrateur.id } }
|
||||
|
||||
before do
|
||||
get :show, params: { id: administrateur.id }
|
||||
context 'with 2FA not enabled' do
|
||||
let(:super_admin) { create(:super_admin, otp_required_for_login: false) }
|
||||
it { expect(subject).to redirect_to(edit_super_admin_otp_path) }
|
||||
end
|
||||
|
||||
it { expect(response.body).to include(administrateur.email) }
|
||||
context 'with 2FA enabled' do
|
||||
render_views
|
||||
let(:super_admin) { create(:super_admin, otp_required_for_login: true) }
|
||||
|
||||
before do
|
||||
subject
|
||||
end
|
||||
|
||||
it { expect(response.body).to include(administrateur.email) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #new' do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
describe Manager::ApplicationController, type: :controller do
|
||||
describe 'append_info_to_payload' do
|
||||
let(:current_user) { create(:administration) }
|
||||
let(:current_user) { create(:super_admin) }
|
||||
let(:payload) { {} }
|
||||
|
||||
before do
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
describe Manager::DemandesController, type: :controller do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
|
||||
describe 'GET #index' do
|
||||
before do
|
||||
sign_in administration
|
||||
sign_in super_admin
|
||||
end
|
||||
|
||||
it "display pending demandes" do
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
describe Manager::DossiersController, type: :controller do
|
||||
let(:administration) { create :administration }
|
||||
let(:super_admin) { create :super_admin }
|
||||
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier) }
|
||||
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
||||
|
||||
before { sign_in administration }
|
||||
before { sign_in super_admin }
|
||||
|
||||
describe '#discard' do
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
|
@ -23,7 +23,7 @@ describe Manager::DossiersController, type: :controller do
|
|||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
|
||||
before do
|
||||
dossier.discard_and_keep_track!(administration, :manager_request)
|
||||
dossier.discard_and_keep_track!(super_admin, :manager_request)
|
||||
|
||||
post :restore, params: { id: dossier.id }
|
||||
dossier.reload
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
describe Manager::InstructeursController, type: :controller do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
|
||||
describe '#show' do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in(administration)
|
||||
sign_in(super_admin)
|
||||
get :show, params: { id: instructeur.id }
|
||||
end
|
||||
|
||||
|
@ -14,7 +14,7 @@ describe Manager::InstructeursController, type: :controller do
|
|||
end
|
||||
|
||||
describe '#delete' do
|
||||
before { sign_in administration }
|
||||
before { sign_in super_admin }
|
||||
|
||||
subject { delete :delete, params: { id: instructeur.id } }
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
describe Manager::ProceduresController, type: :controller do
|
||||
let(:administration) { create :administration }
|
||||
let(:super_admin) { create :super_admin }
|
||||
|
||||
before { sign_in administration }
|
||||
before { sign_in super_admin }
|
||||
|
||||
describe '#whitelist' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
@ -52,7 +52,7 @@ describe Manager::ProceduresController, type: :controller do
|
|||
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
||||
|
||||
before do
|
||||
procedure.discard_and_keep_track!(administration)
|
||||
procedure.discard_and_keep_track!(super_admin)
|
||||
|
||||
post :restore, params: { id: procedure.id }
|
||||
procedure.reload
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
describe Manager::UsersController, type: :controller do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
|
||||
describe '#show' do
|
||||
render_views
|
||||
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
sign_in(administration)
|
||||
sign_in(super_admin)
|
||||
get :show, params: { id: user.id }
|
||||
end
|
||||
|
||||
|
@ -19,7 +19,7 @@ describe Manager::UsersController, type: :controller do
|
|||
let!(:user) { create(:user, email: 'ancien.email@domaine.fr') }
|
||||
|
||||
before {
|
||||
sign_in administration
|
||||
sign_in super_admin
|
||||
}
|
||||
subject { patch :update, params: { id: user.id, user: { email: nouvel_email } } }
|
||||
|
||||
|
@ -48,7 +48,7 @@ describe Manager::UsersController, type: :controller do
|
|||
describe '#delete' do
|
||||
let!(:user) { create(:user) }
|
||||
|
||||
before { sign_in administration }
|
||||
before { sign_in super_admin }
|
||||
|
||||
subject { delete :delete, params: { id: user.id } }
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ describe RootController, type: :controller do
|
|||
|
||||
context 'when Administration is connected' do
|
||||
before do
|
||||
sign_in create(:administration)
|
||||
sign_in create(:super_admin)
|
||||
end
|
||||
|
||||
it { expect(subject).to redirect_to(manager_root_path) }
|
||||
|
|
|
@ -9,7 +9,7 @@ describe StatsController, type: :controller do
|
|||
create(:procedure, created_at: 2.months.ago, updated_at: Time.zone.now)
|
||||
@controller = StatsController.new
|
||||
|
||||
allow(@controller).to receive(:administration_signed_in?).and_return(false)
|
||||
allow(@controller).to receive(:super_admin_signed_in?).and_return(false)
|
||||
end
|
||||
|
||||
let(:association) { Procedure.all }
|
||||
|
@ -33,7 +33,7 @@ describe StatsController, type: :controller do
|
|||
|
||||
@controller = StatsController.new
|
||||
|
||||
allow(@controller).to receive(:administration_signed_in?).and_return(true)
|
||||
allow(@controller).to receive(:super_admin_signed_in?).and_return(true)
|
||||
end
|
||||
|
||||
let (:association) { Procedure.all }
|
||||
|
@ -64,7 +64,7 @@ describe StatsController, type: :controller do
|
|||
let (:association) { Procedure.all }
|
||||
|
||||
context "while a super admin is logged in" do
|
||||
before { allow(@controller).to receive(:administration_signed_in?).and_return(true) }
|
||||
before { allow(@controller).to receive(:super_admin_signed_in?).and_return(true) }
|
||||
|
||||
subject { @controller.send(:cumulative_hash, association, :updated_at) }
|
||||
|
||||
|
@ -78,7 +78,7 @@ describe StatsController, type: :controller do
|
|||
end
|
||||
|
||||
context "while a super admin is not logged in" do
|
||||
before { allow(@controller).to receive(:administration_signed_in?).and_return(false) }
|
||||
before { allow(@controller).to receive(:super_admin_signed_in?).and_return(false) }
|
||||
|
||||
subject { @controller.send(:cumulative_hash, association, :updated_at) }
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
FactoryBot.define do
|
||||
sequence(:administration_email) { |n| "plop#{n}@plop.com" }
|
||||
factory :administration do
|
||||
email { generate(:administration_email) }
|
||||
password { 'my-s3cure-p4ssword' }
|
||||
end
|
||||
end
|
8
spec/factories/super_admin.rb
Normal file
8
spec/factories/super_admin.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
FactoryBot.define do
|
||||
sequence(:super_admin_email) { |n| "plop#{n}@plop.com" }
|
||||
factory :super_admin do
|
||||
email { generate(:super_admin_email) }
|
||||
password { 'my-s3cure-p4ssword' }
|
||||
otp_required_for_login { true }
|
||||
end
|
||||
end
|
|
@ -1,11 +1,11 @@
|
|||
feature 'As an administrateur', js: true do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:admin_email) { 'new_admin@gouv.fr' }
|
||||
let(:new_admin) { Administrateur.by_email(admin_email) }
|
||||
|
||||
before do
|
||||
perform_enqueued_jobs do
|
||||
administration.invite_admin(admin_email)
|
||||
super_admin.invite_admin(admin_email)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
describe Administration, type: :model do
|
||||
describe '#invite_admin' do
|
||||
let(:administration) { create :administration }
|
||||
let(:valid_email) { 'paul@tps.fr' }
|
||||
|
||||
subject { administration.invite_admin(valid_email) }
|
||||
|
||||
it {
|
||||
user = subject
|
||||
expect(user.errors).to be_empty
|
||||
expect(user).to be_persisted
|
||||
}
|
||||
|
||||
it { expect(administration.invite_admin(nil).errors).not_to be_empty }
|
||||
it { expect(administration.invite_admin('toto').errors).not_to be_empty }
|
||||
|
||||
it 'creates a corresponding user account for the email' do
|
||||
subject
|
||||
user = User.find_by(email: valid_email)
|
||||
expect(user).to be_present
|
||||
end
|
||||
|
||||
it 'creates a corresponding instructeur account for the email' do
|
||||
subject
|
||||
instructeur = Instructeur.by_email(valid_email)
|
||||
expect(instructeur).to be_present
|
||||
end
|
||||
|
||||
context 'when there already is a user account with the same email' do
|
||||
before { create(:user, email: valid_email) }
|
||||
it 'still creates an admin account' do
|
||||
expect(subject.errors).to be_empty
|
||||
expect(subject).to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1247,7 +1247,7 @@ describe Dossier do
|
|||
end
|
||||
|
||||
describe 'discarded_brouillon_expired and discarded_en_construction_expired' do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
|
||||
before do
|
||||
create(:dossier)
|
||||
|
@ -1259,8 +1259,8 @@ describe Dossier do
|
|||
create(:dossier).discard!
|
||||
create(:dossier, :en_construction).discard!
|
||||
|
||||
create(:dossier).procedure.discard_and_keep_track!(administration)
|
||||
create(:dossier, :en_construction).procedure.discard_and_keep_track!(administration)
|
||||
create(:dossier).procedure.discard_and_keep_track!(super_admin)
|
||||
create(:dossier, :en_construction).procedure.discard_and_keep_track!(super_admin)
|
||||
end
|
||||
Timecop.travel(1.week.ago) do
|
||||
create(:dossier).discard!
|
||||
|
|
|
@ -845,7 +845,7 @@ describe Procedure do
|
|||
end
|
||||
|
||||
describe "#discard_and_keep_track!" do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let!(:dossier) { create(:dossier, procedure: procedure) }
|
||||
let!(:dossier2) { create(:dossier, procedure: procedure) }
|
||||
|
@ -857,7 +857,7 @@ describe Procedure do
|
|||
context "when discarding procedure" do
|
||||
before do
|
||||
instructeur.followed_dossiers << dossier
|
||||
procedure.discard_and_keep_track!(administration)
|
||||
procedure.discard_and_keep_track!(super_admin)
|
||||
instructeur.reload
|
||||
end
|
||||
|
||||
|
|
64
spec/models/super_admin_spec.rb
Normal file
64
spec/models/super_admin_spec.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
describe SuperAdmin, type: :model do
|
||||
describe '#invite_admin' do
|
||||
let(:super_admin) { create :super_admin }
|
||||
let(:valid_email) { 'paul@tps.fr' }
|
||||
|
||||
subject { super_admin.invite_admin(valid_email) }
|
||||
|
||||
it {
|
||||
user = subject
|
||||
expect(user.errors).to be_empty
|
||||
expect(user).to be_persisted
|
||||
}
|
||||
|
||||
it { expect(super_admin.invite_admin(nil).errors).not_to be_empty }
|
||||
it { expect(super_admin.invite_admin('toto').errors).not_to be_empty }
|
||||
|
||||
it 'creates a corresponding user account for the email' do
|
||||
subject
|
||||
user = User.find_by(email: valid_email)
|
||||
expect(user).to be_present
|
||||
end
|
||||
|
||||
it 'creates a corresponding instructeur account for the email' do
|
||||
subject
|
||||
instructeur = Instructeur.by_email(valid_email)
|
||||
expect(instructeur).to be_present
|
||||
end
|
||||
|
||||
context 'when there already is a user account with the same email' do
|
||||
before { create(:user, email: valid_email) }
|
||||
it 'still creates an admin account' do
|
||||
expect(subject.errors).to be_empty
|
||||
expect(subject).to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'enable_otp!' do
|
||||
let(:super_admin) { create(:super_admin, otp_required_for_login: false) }
|
||||
let(:subject) { super_admin.enable_otp! }
|
||||
|
||||
it 'updates otp_required_for_login' do
|
||||
expect { subject }.to change { super_admin.otp_required_for_login? }.from(false).to(true)
|
||||
end
|
||||
|
||||
it 'updates otp_secret' do
|
||||
expect { subject }.to change { super_admin.otp_secret }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'disable_otp!' do
|
||||
let(:super_admin) { create(:super_admin, otp_required_for_login: true) }
|
||||
let(:subject) { super_admin.disable_otp! }
|
||||
|
||||
it 'updates otp_required_for_login' do
|
||||
expect { subject }.to change { super_admin.otp_required_for_login? }.from(true).to(false)
|
||||
end
|
||||
|
||||
it 'nullifies otp_secret' do
|
||||
super_admin.enable_otp!
|
||||
expect { subject }.to change { super_admin.reload.otp_secret }.to(nil)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -164,7 +164,7 @@ describe User, type: :model do
|
|||
end
|
||||
|
||||
describe 'invite_administrateur!' do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
let(:user) { administrateur.user }
|
||||
|
||||
|
@ -172,12 +172,12 @@ describe User, type: :model do
|
|||
|
||||
before { allow(AdministrationMailer).to receive(:invite_admin).and_return(mailer_double) }
|
||||
|
||||
subject { user.invite_administrateur!(administration.id) }
|
||||
subject { user.invite_administrateur!(super_admin.id) }
|
||||
|
||||
context 'when the user is inactif' do
|
||||
before { subject }
|
||||
|
||||
it { expect(AdministrationMailer).to have_received(:invite_admin).with(user, kind_of(String), administration.id) }
|
||||
it { expect(AdministrationMailer).to have_received(:invite_admin).with(user, kind_of(String), super_admin.id) }
|
||||
end
|
||||
|
||||
context 'when the user is actif' do
|
||||
|
@ -187,7 +187,7 @@ describe User, type: :model do
|
|||
end
|
||||
|
||||
it 'receives an invitation to update its password' do
|
||||
expect(AdministrationMailer).to have_received(:invite_admin).with(user, kind_of(String), administration.id)
|
||||
expect(AdministrationMailer).to have_received(:invite_admin).with(user, kind_of(String), super_admin.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -245,13 +245,13 @@ describe User, type: :model do
|
|||
end
|
||||
|
||||
describe '#delete_and_keep_track_dossiers' do
|
||||
let(:administration) { create(:administration) }
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context 'with a dossier in instruction' do
|
||||
let!(:dossier_en_instruction) { create(:dossier, :en_instruction, user: user) }
|
||||
it 'raises' do
|
||||
expect { user.delete_and_keep_track_dossiers(administration) }.to raise_error(RuntimeError)
|
||||
expect { user.delete_and_keep_track_dossiers(super_admin) }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -261,7 +261,7 @@ describe User, type: :model do
|
|||
|
||||
context 'without a discarded dossier' do
|
||||
it "keep track of dossiers and delete user" do
|
||||
user.delete_and_keep_track_dossiers(administration)
|
||||
user.delete_and_keep_track_dossiers(super_admin)
|
||||
|
||||
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
||||
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_nil
|
||||
|
@ -278,8 +278,8 @@ describe User, type: :model do
|
|||
end
|
||||
|
||||
it "keep track of dossiers and delete user" do
|
||||
dossier_cache.discard_and_keep_track!(administration, :user_request)
|
||||
user.delete_and_keep_track_dossiers(administration)
|
||||
dossier_cache.discard_and_keep_track!(super_admin, :user_request)
|
||||
user.delete_and_keep_track_dossiers(super_admin)
|
||||
|
||||
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
||||
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_nil
|
||||
|
@ -287,8 +287,8 @@ describe User, type: :model do
|
|||
end
|
||||
|
||||
it "doesn't destroy dossiers of another user" do
|
||||
dossier_cache.discard_and_keep_track!(administration, :user_request)
|
||||
user.delete_and_keep_track_dossiers(administration)
|
||||
dossier_cache.discard_and_keep_track!(super_admin, :user_request)
|
||||
user.delete_and_keep_track_dossiers(super_admin)
|
||||
|
||||
expect(Dossier.find_by(id: dossier_from_another_user.id)).to be_present
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue