Merge branch 'dev'
This commit is contained in:
commit
4494d0ab58
25 changed files with 275 additions and 58 deletions
|
@ -203,7 +203,7 @@ GEM
|
|||
ffi (1.9.23)
|
||||
fission (0.5.0)
|
||||
CFPropertyList (~> 2.2)
|
||||
flipflop (2.3.1)
|
||||
flipflop (2.4.0)
|
||||
activesupport (>= 4.0)
|
||||
fog (1.42.0)
|
||||
fog-aliyun (>= 0.1.0)
|
||||
|
|
|
@ -23,7 +23,7 @@ class Admin::GestionnairesController < AdminController
|
|||
procedure_id = params[:procedure_id]
|
||||
|
||||
if @gestionnaire.nil?
|
||||
new_gestionnaire!
|
||||
invite_gestionnaire(params[:gestionnaire][:email])
|
||||
else
|
||||
assign_gestionnaire!
|
||||
end
|
||||
|
@ -42,22 +42,23 @@ class Admin::GestionnairesController < AdminController
|
|||
|
||||
private
|
||||
|
||||
def new_gestionnaire!
|
||||
attributes = params.require(:gestionnaire).permit(:email)
|
||||
.merge(password: SecureRandom.hex(5))
|
||||
def invite_gestionnaire(email)
|
||||
password = SecureRandom.hex
|
||||
|
||||
@gestionnaire = Gestionnaire.create(
|
||||
attributes.merge(
|
||||
administrateurs: [current_administrateur]
|
||||
)
|
||||
email: email,
|
||||
password: password,
|
||||
password_confirmation: password,
|
||||
administrateurs: [current_administrateur]
|
||||
)
|
||||
|
||||
if @gestionnaire.errors.messages.empty?
|
||||
@gestionnaire.invite!
|
||||
|
||||
if User.exists?(email: @gestionnaire.email)
|
||||
GestionnaireMailer.user_to_gestionnaire(@gestionnaire.email).deliver_now!
|
||||
else
|
||||
User.create(attributes)
|
||||
GestionnaireMailer.new_gestionnaire(@gestionnaire.email, @gestionnaire.password).deliver_now!
|
||||
User.create(email: email, password: password)
|
||||
end
|
||||
flash.notice = 'Accompagnateur ajouté'
|
||||
else
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
MAINTENANCE_MESSAGE = 'Le site est actuellement en maintenance. Il sera à nouveau disponible dans un court instant.'
|
||||
|
||||
# Prevent CSRF attacks by raising an exception.
|
||||
# For APIs, you may want to use :null_session instead.
|
||||
protect_from_forgery with: :exception
|
||||
before_action :load_navbar_left_pannel_partial_url
|
||||
before_action :set_raven_context
|
||||
before_action :authorize_request_for_profiler
|
||||
before_action :reject, if: -> { Flipflop.maintenance_mode? }
|
||||
|
||||
before_action :staging_authenticate
|
||||
|
||||
|
@ -135,4 +138,23 @@ class ApplicationController < ActionController::Base
|
|||
)
|
||||
# END OF FIXME
|
||||
end
|
||||
|
||||
def reject
|
||||
authorized_request =
|
||||
request.path_info == '/' ||
|
||||
request.path_info.start_with?('/manager') ||
|
||||
request.path_info.start_with?('/administrations')
|
||||
|
||||
api_request = request.path_info.start_with?('/api/')
|
||||
|
||||
if administration_signed_in? || authorized_request
|
||||
flash.now.alert = MAINTENANCE_MESSAGE
|
||||
elsif api_request
|
||||
render json: { error: MAINTENANCE_MESSAGE }.to_json, status: :service_unavailable
|
||||
else
|
||||
%i(user gestionnaire administrateur).each { |role| sign_out(role) }
|
||||
flash[:alert] = MAINTENANCE_MESSAGE
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
47
app/controllers/gestionnaires/activate_controller.rb
Normal file
47
app/controllers/gestionnaires/activate_controller.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
class Gestionnaires::ActivateController < ApplicationController
|
||||
layout "new_application"
|
||||
|
||||
def new
|
||||
@gestionnaire = Gestionnaire.with_reset_password_token(params[:token])
|
||||
|
||||
if !@gestionnaire
|
||||
flash.alert = "Le lien de validation du compte accompagnateur a expiré, contactez-nous à contact@demarches-simplifiees.fr pour obtenir un nouveau lien."
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
password = create_gestionnaire_params[:password]
|
||||
gestionnaire = Gestionnaire.reset_password_by_token({
|
||||
password: password,
|
||||
password_confirmation: password,
|
||||
reset_password_token: create_gestionnaire_params[:reset_password_token]
|
||||
})
|
||||
|
||||
if gestionnaire && gestionnaire.errors.empty?
|
||||
sign_in(gestionnaire, scope: :gestionnaire)
|
||||
try_to_authenticate(User, gestionnaire.email, password)
|
||||
try_to_authenticate(Administrateur, gestionnaire.email, password)
|
||||
flash.notice = "Mot de passe enregistré"
|
||||
redirect_to gestionnaire_procedures_path
|
||||
else
|
||||
flash.alert = gestionnaire.errors.full_messages
|
||||
redirect_to gestionnaire_activate_path(token: create_gestionnaire_params[:reset_password_token])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_gestionnaire_params
|
||||
params.require(:gestionnaire).permit(:reset_password_token, :password)
|
||||
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
|
|
@ -19,6 +19,20 @@ module Manager
|
|||
redirect_to manager_administrateur_path(params[:id])
|
||||
end
|
||||
|
||||
def enable_feature
|
||||
administrateur = Administrateur.find(params[:id])
|
||||
|
||||
params[:features].each do |key, enable|
|
||||
if enable
|
||||
administrateur.enable_feature(key.to_sym)
|
||||
else
|
||||
administrateur.disable_feature(key.to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_administrateur_params
|
||||
|
|
|
@ -237,9 +237,10 @@ module NewGestionnaire
|
|||
|
||||
when 'user', 'etablissement', 'entreprise'
|
||||
if filter['column'] == 'date_creation'
|
||||
date = filter['value'].to_date rescue nil
|
||||
dossiers
|
||||
.includes(filter['table'])
|
||||
.where("#{filter['table'].pluralize}.#{filter['column']} = ?", filter['value'].to_date)
|
||||
.where("#{filter['table'].pluralize}.#{filter['column']} = ?", date)
|
||||
else
|
||||
dossiers
|
||||
.includes(filter['table'])
|
||||
|
|
|
@ -15,6 +15,7 @@ class AdministrateurDashboard < Administrate::BaseDashboard
|
|||
procedures: Field::HasMany.with_options(limit: 20),
|
||||
registration_state: Field::String.with_options(searchable: false),
|
||||
current_sign_in_at: Field::DateTime,
|
||||
features: FeaturesField
|
||||
}.freeze
|
||||
|
||||
# COLLECTION_ATTRIBUTES
|
||||
|
@ -38,6 +39,7 @@ class AdministrateurDashboard < Administrate::BaseDashboard
|
|||
:updated_at,
|
||||
:registration_state,
|
||||
:current_sign_in_at,
|
||||
:features,
|
||||
:procedures,
|
||||
].freeze
|
||||
|
||||
|
|
4
app/fields/features_field.rb
Normal file
4
app/fields/features_field.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
require "administrate/field/base"
|
||||
|
||||
class FeaturesField < Administrate::Field::Base
|
||||
end
|
|
@ -11,29 +11,12 @@ module Flipflop::Strategies
|
|||
def enabled?(feature)
|
||||
# Can only check features if we have the user's session.
|
||||
if request?
|
||||
legacy_enabled?(feature) || find_current_administrateur&.feature_enabled?(feature)
|
||||
find_current_administrateur&.feature_enabled?(feature)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def legacy_enabled?(feature)
|
||||
if self.class.legacy_features_map.present?
|
||||
ids = self.class.legacy_features_map["#{feature}_allowed_for_admin_ids"]
|
||||
ids.present? && find_current_administrateur&.id&.in?(ids)
|
||||
end
|
||||
end
|
||||
|
||||
LEGACY_CONFIG_FILE = Rails.root.join("config", "initializers", "features.yml")
|
||||
|
||||
def self.legacy_features_map
|
||||
@@legacy_features_map = begin
|
||||
if File.exist?(LEGACY_CONFIG_FILE)
|
||||
YAML.load_file(LEGACY_CONFIG_FILE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_current_administrateur
|
||||
if request.session["warden.user.administrateur.key"]
|
||||
administrateur_id = request.session["warden.user.administrateur.key"][0][0]
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
class GestionnaireMailer < ApplicationMailer
|
||||
layout 'mailers/layout'
|
||||
|
||||
def new_gestionnaire(email, password)
|
||||
send_mail(email, password, "Vous avez été nommé accompagnateur sur demarches-simplifiees.fr")
|
||||
def invite_gestionnaire(gestionnaire, reset_password_token)
|
||||
@reset_password_token = reset_password_token
|
||||
@gestionnaire = gestionnaire
|
||||
mail(to: gestionnaire.email,
|
||||
subject: "demarches-simplifiees.fr - Activez votre compte accompagnateur",
|
||||
reply_to: "contact@demarches-simplifiees.fr")
|
||||
end
|
||||
|
||||
def user_to_gestionnaire(email)
|
||||
|
|
|
@ -144,6 +144,12 @@ class Gestionnaire < ApplicationRecord
|
|||
Follow.where(gestionnaire: self, dossier: dossier).update_all(attributes)
|
||||
end
|
||||
|
||||
def invite!
|
||||
reset_password_token = set_reset_password_token
|
||||
|
||||
GestionnaireMailer.invite_gestionnaire(self, reset_password_token).deliver_now!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_couple_table_attr?(table, column)
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
class ChampSerializer < ActiveModel::Serializer
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
attributes :value
|
||||
|
||||
has_one :type_de_champ
|
||||
|
||||
def value
|
||||
if object.piece_justificative_file.attached?
|
||||
url_for(object.piece_justificative_file)
|
||||
else
|
||||
object.value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
%span{ "aria-hidden" => "true" } ×
|
||||
|
||||
%h4#myModalLabel.modal-title
|
||||
Transférer la procédure à un autre administrateur
|
||||
Envoyer une copie de cette procédure à un autre administrateur
|
||||
|
||||
.modal-body
|
||||
%p
|
||||
Cette fonctionnalité vous permet de transmettre un clone de votre procédure à un autre administrateur.
|
||||
Cette fonctionnalité vous permet de d'envoyer une copie de votre procédure à un autre administrateur.
|
||||
|
||||
%div{ style:'margin-top:20px' }
|
||||
= text_field_tag :email_admin, '', { class: 'form-control',
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
%a#transfer.btn.btn-small.btn-default{ "data-target" => "#transferModal", "data-toggle" => "modal", :type => "button", style: 'float: right; margin-top: 10px; margin-right: 10px;' }
|
||||
%i.fa.fa-exchange
|
||||
Transférer
|
||||
Envoyer une copie
|
||||
|
||||
= render partial: '/admin/procedures/modal_transfer'
|
||||
|
||||
|
|
26
app/views/fields/features_field/_show.html.haml
Normal file
26
app/views/fields/features_field/_show.html.haml
Normal file
|
@ -0,0 +1,26 @@
|
|||
%table#features
|
||||
- Flipflop.feature_set.features.each do |feature|
|
||||
- if !feature.group || feature.group.key != :production
|
||||
%tr
|
||||
%td= feature.title
|
||||
%td
|
||||
= check_box_tag "enable-feature", "enable", field.data[feature.name], data: { url: enable_feature_manager_administrateur_path(field.resource.id), key: feature.key }
|
||||
|
||||
:javascript
|
||||
window.onload = function() {
|
||||
$('#features input[type=checkbox]').on('change', function(evt) {
|
||||
let url = $(evt.target).data('url');
|
||||
let key = $(evt.target).data('key');
|
||||
let features = {};
|
||||
features[key] = $(evt.target).prop('checked');
|
||||
$.ajax(url, {
|
||||
method: 'put',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({
|
||||
features: features
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
|
19
app/views/gestionnaire_mailer/invite_gestionnaire.html.haml
Normal file
19
app/views/gestionnaire_mailer/invite_gestionnaire.html.haml
Normal file
|
@ -0,0 +1,19 @@
|
|||
- content_for(:title, 'Activation de votre compte accompagnateur')
|
||||
|
||||
Bonjour,
|
||||
%br
|
||||
%br
|
||||
Vous venez d'être nommé accompagnateur sur demarches-simplifiees.fr.
|
||||
%br
|
||||
Votre compte a été créé pour l'adresse email #{@gestionnaire.email}. Pour l’activer, je vous invite à cliquer sur le lien suivant :
|
||||
= link_to(gestionnaire_activate_url(token: @reset_password_token), gestionnaire_activate_url(token: @reset_password_token))
|
||||
%br
|
||||
%br
|
||||
Par ailleurs, notre site de documentation qui regroupe l'ensemble des informations relatives à demarches-simplifiees.fr ainsi que des tutoriels d’utilisation est à votre disposition :
|
||||
= link_to('https://demarches-simplifiees.gitbook.io/demarches-simplifiees/', 'https://demarches-simplifiees.gitbook.io/demarches-simplifiees/')
|
||||
%br
|
||||
%br
|
||||
Bonne journée,
|
||||
%br
|
||||
%br
|
||||
L'équipe demarches-simplifiees.fr
|
|
@ -1,11 +0,0 @@
|
|||
Bienvenue sur demarches-simplifiees.fr,
|
||||
|
||||
Vous venez d'être nommé accompagnateur sur demarches-simplifiees.fr. Pour mémoire, voici quelques informations utiles :
|
||||
|
||||
URL : <%= new_gestionnaire_session_url %>
|
||||
Login : <%= @email %>
|
||||
Mot de passe : <%= @args %>
|
||||
|
||||
Bonne journée,
|
||||
|
||||
L'équipe demarches-simplifiees.fr
|
7
app/views/gestionnaires/activate/new.html.haml
Normal file
7
app/views/gestionnaires/activate/new.html.haml
Normal file
|
@ -0,0 +1,7 @@
|
|||
.container
|
||||
= form_for @gestionnaire, url: { controller: 'gestionnaires/activate', action: :create }, html: { class: "form" } do |f|
|
||||
%br
|
||||
%h1= @gestionnaire.email
|
||||
= f.password_field :password, placeholder: 'Mot de passe'
|
||||
= f.hidden_field :reset_password_token, value: params[:token]
|
||||
= f.submit 'Définir le mot de passe', class: 'button large primary expand'
|
|
@ -31,6 +31,8 @@ Rails.application.configure do
|
|||
# ActionMailer::Base.deliveries array.
|
||||
config.action_mailer.delivery_method = :test
|
||||
|
||||
config.active_storage.service = :local
|
||||
|
||||
# Randomize the order test cases are executed.
|
||||
config.active_support.test_order = :random
|
||||
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
Flipflop.configure do
|
||||
strategy :cookie
|
||||
strategy :cookie,
|
||||
secure: Rails.env.production?,
|
||||
httponly: true
|
||||
strategy :active_record
|
||||
strategy :user_preference
|
||||
strategy :default
|
||||
|
||||
group :champs do
|
||||
feature :champ_pj
|
||||
feature :champ_siret
|
||||
feature :champ_pj,
|
||||
title: "Champ pièce justificative"
|
||||
feature :champ_siret,
|
||||
title: "Champ SIRET"
|
||||
end
|
||||
|
||||
feature :web_hook
|
||||
|
||||
group :production do
|
||||
feature :remote_storage,
|
||||
default: Rails.env.production? || Rails.env.staging?
|
||||
feature :weekly_overview,
|
||||
default: Rails.env.production?
|
||||
end
|
||||
|
||||
feature :maintenance_mode
|
||||
end
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
remote_storage: false
|
||||
weekly_overview: false
|
||||
champ_pj_allowed_for_admin_ids:
|
||||
- 0
|
||||
champ_siret_allowed_for_admin_ids:
|
||||
- 0
|
||||
web_hook_allowed_for_admin_ids:
|
||||
- 0
|
|
@ -8,6 +8,7 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :administrateurs, only: [:index, :show, :new, :create] do
|
||||
post 'reinvite', on: :member
|
||||
put 'enable_feature', on: :member
|
||||
end
|
||||
|
||||
resources :demandes, only: [:index]
|
||||
|
@ -114,6 +115,11 @@ Rails.application.routes.draw do
|
|||
resource :dossiers
|
||||
end
|
||||
|
||||
namespace :gestionnaire do
|
||||
get 'activate' => '/gestionnaires/activate#new'
|
||||
patch 'activate' => '/gestionnaires/activate#create'
|
||||
end
|
||||
|
||||
namespace :admin do
|
||||
get 'activate' => '/administrateurs/activate#new'
|
||||
patch 'activate' => '/administrateurs/activate#create'
|
||||
|
|
|
@ -149,8 +149,7 @@ describe Admin::GestionnairesController, type: :controller do
|
|||
|
||||
context 'Email notification' do
|
||||
it 'Notification email is sent when accompagnateur is create' do
|
||||
expect(GestionnaireMailer).to receive(:new_gestionnaire).and_return(GestionnaireMailer)
|
||||
expect(GestionnaireMailer).to receive(:deliver_now!)
|
||||
expect_any_instance_of(Gestionnaire).to receive(:invite!)
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
|
|
@ -82,4 +82,57 @@ describe ApplicationController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'reject before action' do
|
||||
let(:path_info) { '/one_path' }
|
||||
|
||||
before do
|
||||
allow(@controller).to receive(:redirect_to)
|
||||
allow(@controller).to receive(:sign_out)
|
||||
allow(@controller).to receive(:render)
|
||||
@request.path_info = path_info
|
||||
end
|
||||
|
||||
context 'when no administration is logged in' do
|
||||
before { @controller.send(:reject) }
|
||||
|
||||
it { expect(@controller).to have_received(:sign_out).with(:user) }
|
||||
it { expect(@controller).to have_received(:sign_out).with(:gestionnaire) }
|
||||
it { expect(@controller).to have_received(:sign_out).with(:administrateur) }
|
||||
it { expect(flash[:alert]).to eq(ApplicationController::MAINTENANCE_MESSAGE) }
|
||||
it { expect(@controller).to have_received(:redirect_to).with(root_path) }
|
||||
|
||||
context 'when the path is safe' do
|
||||
%w(/ /manager /administrations).each do |path|
|
||||
let(:path_info) { path }
|
||||
|
||||
it { expect(@controller).not_to have_received(:sign_out) }
|
||||
it { expect(@controller).not_to have_received(:redirect_to) }
|
||||
it { expect(flash.alert).to eq(ApplicationController::MAINTENANCE_MESSAGE) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the path is api related' do
|
||||
let(:path_info) { '/api/some-stuff' }
|
||||
let(:json_error) { { error: ApplicationController::MAINTENANCE_MESSAGE }.to_json }
|
||||
it { expect(@controller).not_to have_received(:sign_out) }
|
||||
it { expect(@controller).not_to have_received(:redirect_to) }
|
||||
it { expect(flash.alert).to be_nil }
|
||||
it { expect(@controller).to have_received(:render).with({ json: json_error, status: :service_unavailable }) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a administration is logged in' do
|
||||
let(:current_administration) { create(:administration) }
|
||||
|
||||
before do
|
||||
sign_in(current_administration)
|
||||
@controller.send(:reject)
|
||||
end
|
||||
|
||||
it { expect(@controller).not_to have_received(:sign_out) }
|
||||
it { expect(@controller).not_to have_received(:redirect_to) }
|
||||
it { expect(flash[:alert]).to eq(ApplicationController::MAINTENANCE_MESSAGE) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
22
spec/serializers/champ_serializer_spec.rb
Normal file
22
spec/serializers/champ_serializer_spec.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
describe ChampSerializer do
|
||||
describe '#attributes' do
|
||||
subject { ChampSerializer.new(champ).serializable_hash }
|
||||
|
||||
context 'when type champ is piece justificative' do
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
let(:champ) { create(:champ, type_de_champ: create(:type_de_champ_piece_justificative)) }
|
||||
|
||||
before { champ.piece_justificative_file.attach({ filename: __FILE__, io: File.open(__FILE__) }) }
|
||||
after { champ.piece_justificative_file.purge }
|
||||
|
||||
it { is_expected.to include(value: url_for(champ.piece_justificative_file)) }
|
||||
end
|
||||
|
||||
context 'when type champ is not piece justificative' do
|
||||
let(:champ) { create(:champ, value: "blah") }
|
||||
|
||||
it { is_expected.to include(value: "blah") }
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue