Merge branch 'dev'

This commit is contained in:
Frederic Merizen 2018-04-17 14:23:10 +02:00
commit 9796c26889
21 changed files with 202 additions and 13 deletions

View file

@ -9,12 +9,15 @@ document.addEventListener('turbolinks:load', function() {
break; break;
case 14: case 14:
input.attr('disabled', 'disabled'); input.attr('disabled', 'disabled');
$('.spinner').show();
$.get(url+'?siret='+value).then(function() { $.get(url+'?siret='+value).then(function() {
input.removeAttr('data-invalid'); input.removeAttr('data-invalid');
input.removeAttr('disabled'); input.removeAttr('disabled');
$('.spinner').hide();
}, function() { }, function() {
input.removeAttr('disabled'); input.removeAttr('disabled');
input.attr('data-invalid', true); input.attr('data-invalid', true);
$('.spinner').hide();
}); });
break; break;
default: default:

View file

@ -36,6 +36,8 @@
} }
.editable-champ { .editable-champ {
position: relative;
.updated-at { .updated-at {
@include notice-text-style; @include notice-text-style;
float: right; float: right;

View file

@ -0,0 +1,55 @@
@import "colors";
.spinner {
color: $black;
width: 1em;
height: 1em;
border-radius: 50%;
position: relative;
text-indent: -9999em;
animation: load4 1.3s infinite linear;
transform: translateZ(0);
}
.right-spinner {
display: none;
position: absolute;
bottom: 1.3em;
right: 1.2em;
transform: scale(0.3);
}
@keyframes load4 {
0%,
100% {
box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
}
12.5% {
box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
}
25% {
box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
}
37.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
50% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
62.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
}
75% {
box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
}
87.5% {
box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
}
}

View file

@ -53,9 +53,13 @@ class Admin::GestionnairesController < AdminController
) )
if @gestionnaire.errors.messages.empty? if @gestionnaire.errors.messages.empty?
User.create(attributes) 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!
end
flash.notice = 'Accompagnateur ajouté' flash.notice = 'Accompagnateur ajouté'
GestionnaireMailer.new_gestionnaire(@gestionnaire.email, @gestionnaire.password).deliver_now!
else else
flash.alert = @gestionnaire.errors.full_messages flash.alert = @gestionnaire.errors.full_messages
end end

View file

@ -250,7 +250,7 @@ class Admin::ProceduresController < AdminController
private private
def procedure_params def procedure_params
editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :lien_notice, :web_hook_url, :euro_flag, :logo, :auto_archive_on] editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :notice, :web_hook_url, :euro_flag, :logo, :auto_archive_on]
if @procedure.try(:locked?) if @procedure.try(:locked?)
params.require(:procedure).permit(*editable_params) params.require(:procedure).permit(*editable_params)
else else

View file

@ -11,13 +11,16 @@ class Administrateurs::ActivateController < ApplicationController
end end
def create def create
password = update_administrateur_params[:password]
administrateur = Administrateur.reset_password( administrateur = Administrateur.reset_password(
update_administrateur_params[:reset_password_token], update_administrateur_params[:reset_password_token],
update_administrateur_params[:password] password
) )
if administrateur && administrateur.errors.empty? if administrateur && administrateur.errors.empty?
sign_in(administrateur, scope: :administrateur) sign_in(administrateur, scope: :administrateur)
try_to_authenticate(User, administrateur.email, password)
try_to_authenticate(Gestionnaire, administrateur.email, password)
flash.notice = "Mot de passe enregistré" flash.notice = "Mot de passe enregistré"
redirect_to admin_procedures_path redirect_to admin_procedures_path
else else
@ -31,4 +34,13 @@ class Administrateurs::ActivateController < ApplicationController
def update_administrateur_params def update_administrateur_params
params.require(:administrateur).permit(:reset_password_token, :password) params.require(:administrateur).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

View file

@ -87,7 +87,14 @@ module NewGestionnaire
gestionnaire = Gestionnaire.new(email: email, password: password) gestionnaire = Gestionnaire.new(email: email, password: password)
if gestionnaire.save if gestionnaire.save
user = User.find_by(email: email)
if user.blank?
user = User.create(email: email, password: password)
end
sign_in(user)
sign_in(gestionnaire, scope: :gestionnaire) sign_in(gestionnaire, scope: :gestionnaire)
Avis.link_avis_to_gestionnaire(gestionnaire) Avis.link_avis_to_gestionnaire(gestionnaire)
avis = Avis.find(params[:id]) avis = Avis.find(params[:id])
redirect_to url_for(gestionnaire_avis_index_path) redirect_to url_for(gestionnaire_avis_index_path)

View file

@ -0,0 +1,9 @@
module NoticeUrlHelper
def notice_url(procedure)
if procedure.notice.attached?
url_for(procedure.notice)
elsif procedure.lien_notice.present?
procedure.lien_notice
end
end
end

View file

@ -2,7 +2,11 @@ class GestionnaireMailer < ApplicationMailer
layout 'mailers/layout' layout 'mailers/layout'
def new_gestionnaire(email, password) def new_gestionnaire(email, password)
send_mail email, password, "Vous avez été nommé accompagnateur sur demarches-simplifiees.fr" send_mail(email, password, "Vous avez été nommé accompagnateur sur demarches-simplifiees.fr")
end
def user_to_gestionnaire(email)
send_mail(email, nil, "Vous avez été nommé accompagnateur sur demarches-simplifiees.fr")
end end
def last_week_overview(gestionnaire) def last_week_overview(gestionnaire)

View file

@ -8,15 +8,21 @@ class Administration < ApplicationRecord
end end
def invite_admin(email) def invite_admin(email)
password = SecureRandom.hex
administrateur = Administrateur.new({ administrateur = Administrateur.new({
email: email, email: email,
active: false active: false,
password: password,
password_confirmation: password
}) })
administrateur.password = administrateur.password_confirmation = SecureRandom.hex
if administrateur.save if administrateur.save
AdministrationMailer.new_admin_email(administrateur, self).deliver_now! AdministrationMailer.new_admin_email(administrateur, self).deliver_now!
administrateur.invite! administrateur.invite!
User.create({
email: email,
password: password
})
end end
administrateur administrateur

View file

@ -22,6 +22,8 @@ class Procedure < ApplicationRecord
has_one :refused_mail, class_name: "Mails::RefusedMail", dependent: :destroy has_one :refused_mail, class_name: "Mails::RefusedMail", dependent: :destroy
has_one :without_continuation_mail, class_name: "Mails::WithoutContinuationMail", dependent: :destroy has_one :without_continuation_mail, class_name: "Mails::WithoutContinuationMail", dependent: :destroy
has_one_attached :notice
delegate :use_api_carto, to: :module_api_carto delegate :use_api_carto, to: :module_api_carto
accepts_nested_attributes_for :types_de_champ, :reject_if => proc { |attributes| attributes['libelle'].blank? }, :allow_destroy => true accepts_nested_attributes_for :types_de_champ, :reject_if => proc { |attributes| attributes['libelle'].blank? }, :allow_destroy => true

View file

@ -2,7 +2,7 @@
.alert.alert-info .alert.alert-info
Cette procédure est publiée, certains éléments de la description ne sont plus modifiables Cette procédure est publiée, certains éléments de la description ne sont plus modifiables
- { libelle: 'Libellé*', description: 'Description*', organisation: 'Organisme*', direction: 'Direction', lien_site_web: 'Lien site internet', lien_notice: 'Lien notice', web_hook_url: 'Lien de rappel HTTP' }.each do |key, value| - { libelle: 'Libellé*', description: 'Description*', organisation: 'Organisme*', direction: 'Direction', lien_site_web: 'Lien site internet', web_hook_url: 'Lien de rappel HTTP' }.each do |key, value|
- if key != :web_hook_url || current_administrateur&.feature_enabled?(:web_hook_allowed) - if key != :web_hook_url || current_administrateur&.feature_enabled?(:web_hook_allowed)
.form-group .form-group
%h4 %h4
@ -16,6 +16,20 @@
- else - else
= f.text_field key, class: 'form-control', placeholder: value = f.text_field key, class: 'form-control', placeholder: value
.form-group
%h4 Notice explicative de la procédure
- notice = @procedure.notice
- if !notice.attached?
= f.file_field :notice,
direct_upload: true
- else
%a{ href: url_for(notice), target: '_blank' }
= notice.filename.to_s
%br
Modifier :
= f.file_field :notice,
direct_upload: true
.row .row
.col-md-6 .col-md-6
%h4 Logo de la procédure %h4 Logo de la procédure

View file

@ -3,4 +3,4 @@
= form_for @procedure, url: url_for({ controller: 'admin/procedures', action: :update, id: @procedure.id }), multipart: true do |f| = form_for @procedure, url: url_for({ controller: 'admin/procedures', action: :update, id: @procedure.id }), multipart: true do |f|
= render partial: 'informations', locals: { f: f } = render partial: 'informations', locals: { f: f }
.text-right .text-right
= f.submit 'Enregistrer', class: 'btn btn-success' = f.button 'Enregistrer', class: 'btn btn-success'

View file

@ -19,3 +19,5 @@
= link_to('Consulter', commencer_path(procedure_path: procedure.path), target: "_blank") = link_to('Consulter', commencer_path(procedure_path: procedure.path), target: "_blank")
%td %td
= link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'btn-sm btn-primary clone-btn') = link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'btn-sm btn-primary clone-btn')
%td{ style: 'padding-left: 10px;' }
= link_to('Contacter', "mailto:#{procedure.administrateur.email}")

View file

@ -0,0 +1,8 @@
Bienvenue sur demarches-simplifiees.fr,
\
Vous venez d'être nommé accompagnateur sur demarches-simplifiees.fr.
Votre compte (#{@email}) vous donnera désormais aussi accès à lespace accompagnateur.
\
Bonne journée,
\
L'équipe demarches-simplifiees.fr

View file

@ -4,10 +4,10 @@
%h1= @dossier.procedure.libelle %h1= @dossier.procedure.libelle
.container .container
- if @dossier.procedure.lien_notice.present? - if notice_url(@dossier.procedure).present?
%p %p
Pour vous aider à remplir votre dossier, vous pouvez consulter Pour vous aider à remplir votre dossier, vous pouvez consulter
= link_to 'le guide de cette démarche', @dossier.procedure.lien_notice, { target: '_blank' } = link_to 'le guide de cette démarche', notice_url(@dossier.procedure), { target: '_blank' }
%p.thanks Les champs avec une asterisque (*) sont obligatoires. %p.thanks Les champs avec une asterisque (*) sont obligatoires.

View file

@ -3,6 +3,7 @@
class: 'small-margin', class: 'small-margin',
data: { siret: champs_siret_path(format: :js, champ_id: champ) }, data: { siret: champs_siret_path(format: :js, champ_id: champ) },
required: champ.mandatory? required: champ.mandatory?
.spinner.right-spinner
%div{ id: "etablissement-for-#{champ.id}" } %div{ id: "etablissement-for-#{champ.id}" }
- if champ.etablissement.present? - if champ.etablissement.present?
= render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement } = render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement }

View file

@ -1,5 +1,5 @@
.container#description-page .container#description-page
- if @dossier.procedure.lien_notice.present? - if notice_url(@dossier.procedure).present?
#lien_notice_panel.row{ style: 'width: 280px; position: fixed; background-color: white; right: 5%; top: 80px; z-index: 200;' } #lien_notice_panel.row{ style: 'width: 280px; position: fixed; background-color: white; right: 5%; top: 80px; z-index: 200;' }
.panel.panel-info{ style: 'margin-bottom: 0;' } .panel.panel-info{ style: 'margin-bottom: 0;' }
.panel-body.center .panel-body.center
@ -8,7 +8,7 @@
.fa.fa-info-circle.text-info{ style: 'font-size: 2em; margin-top: 20%;' } .fa.fa-info-circle.text-info{ style: 'font-size: 2em; margin-top: 20%;' }
.col-xs-10{ style: 'padding-right: 0px;' } .col-xs-10{ style: 'padding-right: 0px;' }
%b %b
= link_to 'Accéder au guide', @dossier.procedure.lien_notice, { target: '_blank' } = link_to 'Accéder au guide', notice_url(@dossier.procedure), { target: '_blank' }
pour remplir pour votre dossier pour remplir pour votre dossier
%h2.text-info %h2.text-info

View file

@ -0,0 +1,31 @@
namespace :'2018_04_11_admin_or_gestionnaire_users' do
task create_missing: :environment do
create_missing_users(Administrateur)
create_missing_users(Gestionnaire)
end
def create_missing_users(klass)
klasses = klass.name.downcase.pluralize
accounts = klass.joins("LEFT JOIN users on users.email = #{klasses}.email").where('users.id is null')
processed_count = 0
accounts.find_each(batch_size: 100) do |account|
# To pass validation, we need to set dummy password even though
# we override encrypted_password afterwards
user = User.create({
email: account.email,
password: SecureRandom.hex(5),
encrypted_password: account.encrypted_password
})
if user.persisted?
processed_count += 1
else
print "Failed to create user for #{account.email}\n"
end
end
print "Created users for #{processed_count} #{klasses}\n"
end
end

View file

@ -216,6 +216,8 @@ describe NewGestionnaire::AvisController, type: :controller do
end end
describe '#create_gestionnaire' do describe '#create_gestionnaire' do
let(:existing_user_mail) { 'dummy@example.org' }
let!(:existing_user) { create(:user, email: existing_user_mail) }
let(:invited_email) { 'invited@avis.com' } let(:invited_email) { 'invited@avis.com' }
let(:dossier) { create(:dossier) } let(:dossier) { create(:dossier) }
let!(:avis) { create(:avis, email: invited_email, dossier: dossier) } let!(:avis) { create(:avis, email: invited_email, dossier: dossier) }
@ -254,6 +256,19 @@ describe NewGestionnaire::AvisController, type: :controller do
it { expect(subject.current_gestionnaire).to eq(created_gestionnaire) } it { expect(subject.current_gestionnaire).to eq(created_gestionnaire) }
it { is_expected.to redirect_to gestionnaire_avis_index_path } it { is_expected.to redirect_to gestionnaire_avis_index_path }
it 'creates a corresponding user account for the email' do
user = User.find_by(email: invited_email)
expect(user).to be_present
end
context 'when there already is a user account with the same email' do
let(:existing_user_mail) { invited_email }
it 'still creates a gestionnaire account' do
expect(created_gestionnaire).to be_present
end
end
end end
context 'when the gestionnaire creation fails' do context 'when the gestionnaire creation fails' do

View file

@ -13,5 +13,19 @@ describe Administration, type: :model do
} }
it { expect(administration.invite_admin(nil).errors).not_to be_empty } it { expect(administration.invite_admin(nil).errors).not_to be_empty }
it { expect(administration.invite_admin('toto').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
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
end end