diff --git a/app/assets/javascripts/new_design/champs/siret.js b/app/assets/javascripts/new_design/champs/siret.js index 8904b05a6..f1d729c03 100644 --- a/app/assets/javascripts/new_design/champs/siret.js +++ b/app/assets/javascripts/new_design/champs/siret.js @@ -9,12 +9,15 @@ document.addEventListener('turbolinks:load', function() { break; case 14: input.attr('disabled', 'disabled'); + $('.spinner').show(); $.get(url+'?siret='+value).then(function() { input.removeAttr('data-invalid'); input.removeAttr('disabled'); + $('.spinner').hide(); }, function() { input.removeAttr('disabled'); input.attr('data-invalid', true); + $('.spinner').hide(); }); break; default: diff --git a/app/assets/stylesheets/new_design/forms.scss b/app/assets/stylesheets/new_design/forms.scss index 8c5191313..8293b37a4 100644 --- a/app/assets/stylesheets/new_design/forms.scss +++ b/app/assets/stylesheets/new_design/forms.scss @@ -36,6 +36,8 @@ } .editable-champ { + position: relative; + .updated-at { @include notice-text-style; float: right; diff --git a/app/assets/stylesheets/new_design/spinner.scss b/app/assets/stylesheets/new_design/spinner.scss new file mode 100644 index 000000000..586bbc16e --- /dev/null +++ b/app/assets/stylesheets/new_design/spinner.scss @@ -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; + } +} diff --git a/app/controllers/admin/gestionnaires_controller.rb b/app/controllers/admin/gestionnaires_controller.rb index 2ca3bdaa9..11e9f52c0 100644 --- a/app/controllers/admin/gestionnaires_controller.rb +++ b/app/controllers/admin/gestionnaires_controller.rb @@ -53,9 +53,13 @@ class Admin::GestionnairesController < AdminController ) 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é' - GestionnaireMailer.new_gestionnaire(@gestionnaire.email, @gestionnaire.password).deliver_now! else flash.alert = @gestionnaire.errors.full_messages end diff --git a/app/controllers/admin/procedures_controller.rb b/app/controllers/admin/procedures_controller.rb index a159762b0..d761f78ec 100644 --- a/app/controllers/admin/procedures_controller.rb +++ b/app/controllers/admin/procedures_controller.rb @@ -250,7 +250,7 @@ class Admin::ProceduresController < AdminController private 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?) params.require(:procedure).permit(*editable_params) else diff --git a/app/controllers/administrateurs/activate_controller.rb b/app/controllers/administrateurs/activate_controller.rb index bd1c1b529..5049a67e7 100644 --- a/app/controllers/administrateurs/activate_controller.rb +++ b/app/controllers/administrateurs/activate_controller.rb @@ -11,13 +11,16 @@ class Administrateurs::ActivateController < ApplicationController end def create + password = update_administrateur_params[:password] administrateur = Administrateur.reset_password( update_administrateur_params[:reset_password_token], - update_administrateur_params[:password] + password ) if administrateur && administrateur.errors.empty? 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é" redirect_to admin_procedures_path else @@ -31,4 +34,13 @@ class Administrateurs::ActivateController < ApplicationController def update_administrateur_params params.require(:administrateur).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 diff --git a/app/controllers/new_gestionnaire/avis_controller.rb b/app/controllers/new_gestionnaire/avis_controller.rb index 3fd9b2376..2ca36e4c6 100644 --- a/app/controllers/new_gestionnaire/avis_controller.rb +++ b/app/controllers/new_gestionnaire/avis_controller.rb @@ -87,7 +87,14 @@ module NewGestionnaire gestionnaire = Gestionnaire.new(email: email, password: password) 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) + Avis.link_avis_to_gestionnaire(gestionnaire) avis = Avis.find(params[:id]) redirect_to url_for(gestionnaire_avis_index_path) diff --git a/app/helpers/notice_url_helper.rb b/app/helpers/notice_url_helper.rb new file mode 100644 index 000000000..337cb228a --- /dev/null +++ b/app/helpers/notice_url_helper.rb @@ -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 diff --git a/app/mailers/gestionnaire_mailer.rb b/app/mailers/gestionnaire_mailer.rb index 4f3c88113..88e67be03 100644 --- a/app/mailers/gestionnaire_mailer.rb +++ b/app/mailers/gestionnaire_mailer.rb @@ -2,7 +2,11 @@ class GestionnaireMailer < ApplicationMailer layout 'mailers/layout' 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 def last_week_overview(gestionnaire) diff --git a/app/models/administration.rb b/app/models/administration.rb index d053a2c0a..d0da076e5 100644 --- a/app/models/administration.rb +++ b/app/models/administration.rb @@ -8,15 +8,21 @@ class Administration < ApplicationRecord end def invite_admin(email) + password = SecureRandom.hex administrateur = Administrateur.new({ email: email, - active: false + active: false, + password: password, + password_confirmation: password }) - administrateur.password = administrateur.password_confirmation = SecureRandom.hex if administrateur.save AdministrationMailer.new_admin_email(administrateur, self).deliver_now! administrateur.invite! + User.create({ + email: email, + password: password + }) end administrateur diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 2c9244d64..b76eb3393 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -22,6 +22,8 @@ class Procedure < ApplicationRecord has_one :refused_mail, class_name: "Mails::RefusedMail", 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 accepts_nested_attributes_for :types_de_champ, :reject_if => proc { |attributes| attributes['libelle'].blank? }, :allow_destroy => true diff --git a/app/views/admin/procedures/_informations.html.haml b/app/views/admin/procedures/_informations.html.haml index ba6ccefde..a42154928 100644 --- a/app/views/admin/procedures/_informations.html.haml +++ b/app/views/admin/procedures/_informations.html.haml @@ -2,7 +2,7 @@ .alert.alert-info 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) .form-group %h4 @@ -16,6 +16,20 @@ - else = 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 .col-md-6 %h4 Logo de la procédure diff --git a/app/views/admin/procedures/edit.html.haml b/app/views/admin/procedures/edit.html.haml index 6ffe6fb12..5efaea830 100644 --- a/app/views/admin/procedures/edit.html.haml +++ b/app/views/admin/procedures/edit.html.haml @@ -3,4 +3,4 @@ = form_for @procedure, url: url_for({ controller: 'admin/procedures', action: :update, id: @procedure.id }), multipart: true do |f| = render partial: 'informations', locals: { f: f } .text-right - = f.submit 'Enregistrer', class: 'btn btn-success' + = f.button 'Enregistrer', class: 'btn btn-success' diff --git a/app/views/admin/procedures/new_from_existing.html.haml b/app/views/admin/procedures/new_from_existing.html.haml index c504d7354..d8b6e1dab 100644 --- a/app/views/admin/procedures/new_from_existing.html.haml +++ b/app/views/admin/procedures/new_from_existing.html.haml @@ -19,3 +19,5 @@ = link_to('Consulter', commencer_path(procedure_path: procedure.path), target: "_blank") %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') + %td{ style: 'padding-left: 10px;' } + = link_to('Contacter', "mailto:#{procedure.administrateur.email}") diff --git a/app/views/gestionnaire_mailer/user_to_gestionnaire.text.haml b/app/views/gestionnaire_mailer/user_to_gestionnaire.text.haml new file mode 100644 index 000000000..f5e10ce94 --- /dev/null +++ b/app/views/gestionnaire_mailer/user_to_gestionnaire.text.haml @@ -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 à l’espace accompagnateur. +\ +Bonne journée, +\ +L'équipe demarches-simplifiees.fr diff --git a/app/views/new_user/dossiers/modifier.html.haml b/app/views/new_user/dossiers/modifier.html.haml index 6728a0974..de6867daa 100644 --- a/app/views/new_user/dossiers/modifier.html.haml +++ b/app/views/new_user/dossiers/modifier.html.haml @@ -4,10 +4,10 @@ %h1= @dossier.procedure.libelle .container - - if @dossier.procedure.lien_notice.present? + - if notice_url(@dossier.procedure).present? %p 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. diff --git a/app/views/shared/dossiers/editable_champs/_siret.html.haml b/app/views/shared/dossiers/editable_champs/_siret.html.haml index 2135b274f..e875564cf 100644 --- a/app/views/shared/dossiers/editable_champs/_siret.html.haml +++ b/app/views/shared/dossiers/editable_champs/_siret.html.haml @@ -3,6 +3,7 @@ class: 'small-margin', data: { siret: champs_siret_path(format: :js, champ_id: champ) }, required: champ.mandatory? +.spinner.right-spinner %div{ id: "etablissement-for-#{champ.id}" } - if champ.etablissement.present? = render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement } diff --git a/app/views/users/description/_show.html.haml b/app/views/users/description/_show.html.haml index 56234b031..e1495c4d9 100644 --- a/app/views/users/description/_show.html.haml +++ b/app/views/users/description/_show.html.haml @@ -1,5 +1,5 @@ .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;' } .panel.panel-info{ style: 'margin-bottom: 0;' } .panel-body.center @@ -8,7 +8,7 @@ .fa.fa-info-circle.text-info{ style: 'font-size: 2em; margin-top: 20%;' } .col-xs-10{ style: 'padding-right: 0px;' } %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 %h2.text-info diff --git a/lib/tasks/2018_04_11_admin_or_gestionnaire_users.rake b/lib/tasks/2018_04_11_admin_or_gestionnaire_users.rake new file mode 100644 index 000000000..ce37c088b --- /dev/null +++ b/lib/tasks/2018_04_11_admin_or_gestionnaire_users.rake @@ -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 diff --git a/spec/controllers/new_gestionnaire/avis_controller_spec.rb b/spec/controllers/new_gestionnaire/avis_controller_spec.rb index 684c5717b..1e429cc2a 100644 --- a/spec/controllers/new_gestionnaire/avis_controller_spec.rb +++ b/spec/controllers/new_gestionnaire/avis_controller_spec.rb @@ -216,6 +216,8 @@ describe NewGestionnaire::AvisController, type: :controller do end 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(:dossier) { create(: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 { 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 context 'when the gestionnaire creation fails' do diff --git a/spec/models/administration_spec.rb b/spec/models/administration_spec.rb index 9f8e0463e..91444ad3b 100644 --- a/spec/models/administration_spec.rb +++ b/spec/models/administration_spec.rb @@ -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('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