From d542bca8de8206f6c29109959d32ed213bdf5f4d Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 16 Oct 2019 15:37:40 +0000 Subject: [PATCH 01/20] admin: relabel the `number` champ Avoid two type de champs having the same label. Soon this champ will even be deprecated and disappear. Ref #4414 --- app/graphql/schema.graphql | 2 +- config/locales/models/type_de_champ/fr.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index a9ce16d5a..6b6c5e355 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -538,7 +538,7 @@ enum TypeDeChamp { multiple_drop_down_list """ - Nombre entier + Nombre """ number diff --git a/config/locales/models/type_de_champ/fr.yml b/config/locales/models/type_de_champ/fr.yml index a76f1ad6b..cf97e106f 100644 --- a/config/locales/models/type_de_champ/fr.yml +++ b/config/locales/models/type_de_champ/fr.yml @@ -9,7 +9,7 @@ fr: textarea: 'Zone de texte' date: 'Date' datetime: 'Date et Heure' - number: 'Nombre entier' + number: 'Nombre' decimal_number: 'Nombre décimal' integer_number: 'Nombre entier' checkbox: 'Case à cocher' From 9088495272cb41b5471affcda154d23bac3c5d59 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 22 Oct 2019 17:34:56 +0200 Subject: [PATCH 02/20] Update activestorage-openstack --- Gemfile | 2 +- Gemfile.lock | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index a7b346436..988861a90 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,7 @@ gem 'aasm' gem 'actiontext', git: 'https://github.com/kobaltz/actiontext.git', branch: 'archive', require: 'action_text' # Port of ActionText to Rails 5 gem 'active_link_to' # Automatically set a class on active links gem 'active_model_serializers' -gem 'activestorage-openstack', git: 'https://github.com/fredZen/activestorage-openstack.git', branch: 'frederic/fix_upload_signature' +gem 'activestorage-openstack' gem 'administrate' gem 'after_party' gem 'anchored' diff --git a/Gemfile.lock b/Gemfile.lock index 1336fb19c..cf449d922 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,14 +1,3 @@ -GIT - remote: https://github.com/fredZen/activestorage-openstack.git - revision: c71d5107a51701eab9d9267dd0000e6c1cf3e39a - branch: frederic/fix_upload_signature - specs: - activestorage-openstack (0.5.0) - fog-openstack (~> 1.0) - marcel - mime-types - rails (~> 5.2.0) - GIT remote: https://github.com/kobaltz/actiontext.git revision: ef59c4ba99d1b7614dd47f5a294eef553224db88 @@ -75,6 +64,11 @@ GEM actionpack (= 5.2.2.1) activerecord (= 5.2.2.1) marcel (~> 0.3.1) + activestorage-openstack (1.0.0) + fog-openstack (~> 1.0) + marcel + mime-types + rails (<= 6) activesupport (5.2.2.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) @@ -717,7 +711,7 @@ DEPENDENCIES actiontext! active_link_to active_model_serializers - activestorage-openstack! + activestorage-openstack administrate after_party anchored From 86b271997bc168c4d2767cd7b85b62fd5264172f Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 21 Aug 2019 09:09:20 +0200 Subject: [PATCH 03/20] Invite experts to linked dossiers closes #3669 --- .../concerns/create_avis_concern.rb | 41 ++++++++++++------- app/models/avis.rb | 6 +-- app/models/champ.rb | 2 +- app/models/dossier.rb | 4 ++ app/models/type_de_champ.rb | 4 ++ .../instructeurs/avis/instruction.html.haml | 2 +- .../instructeurs/dossiers/avis.html.haml | 2 +- .../instructeurs/shared/avis/_form.html.haml | 4 ++ config/locales/models/avis/fr.yml | 5 +++ .../instructeurs/avis_controller_spec.rb | 31 +++++++++++++- spec/factories/dossier.rb | 24 ++++++++++- spec/features/instructeurs/expert_spec.rb | 5 ++- .../features/instructeurs/instruction_spec.rb | 3 +- spec/models/avis_spec.rb | 12 ------ 14 files changed, 105 insertions(+), 40 deletions(-) diff --git a/app/controllers/concerns/create_avis_concern.rb b/app/controllers/concerns/create_avis_concern.rb index e7c34495c..81c7dd3a9 100644 --- a/app/controllers/concerns/create_avis_concern.rb +++ b/app/controllers/concerns/create_avis_concern.rb @@ -10,28 +10,41 @@ module CreateAvisConcern # the :emails parameter is a 1-element array. # Hence the call to first # https://github.com/rails/rails/issues/17225 - emails = create_avis_params[:emails].first.split(',').map(&:strip) + expert_emails = create_avis_params[:emails].first.split(',').map(&:strip) + allowed_dossiers = [dossier] + + if create_avis_params[:invite_linked_dossiers].present? + allowed_dossiers += dossier.linked_dossiers + end create_results = Avis.create( - emails.map do |email| - { - email: email, - introduction: create_avis_params[:introduction], - claimant: current_instructeur, - dossier: dossier, - confidentiel: confidentiel - } + expert_emails.flat_map do |email| + allowed_dossiers.map do |dossier| + { + email: email, + introduction: create_avis_params[:introduction], + claimant: current_instructeur, + dossier: dossier, + confidentiel: confidentiel + } + end end ) persisted, failed = create_results.partition(&:persisted?) if persisted.any? - sent_emails_addresses = persisted.map(&:email_to_display).join(", ") - flash.notice = "Une demande d'avis a été envoyée à #{sent_emails_addresses}" + sent_emails_addresses = [] persisted.each do |avis| - dossier.demander_un_avis!(avis) + avis.dossier.demander_un_avis!(avis) + + if avis.dossier == dossier + AvisMailer.avis_invitation(avis).deliver_later + sent_emails_addresses << avis.email_to_display + end end + + flash.notice = "Une demande d'avis a été envoyée à #{sent_emails_addresses.uniq.join(", ")}" end if failed.any? @@ -41,13 +54,13 @@ module CreateAvisConcern # When an error occurs, return the avis back to the controller # to give the user a chance to correct and resubmit - Avis.new(create_avis_params.merge(emails: [failed.map(&:email).join(", ")])) + Avis.new(create_avis_params.merge(emails: [failed.map(&:email).uniq.join(", ")])) else nil end end def create_avis_params - params.require(:avis).permit(:introduction, :confidentiel, emails: []) + params.require(:avis).permit(:introduction, :confidentiel, :invite_linked_dossiers, emails: []) end end diff --git a/app/models/avis.rb b/app/models/avis.rb index 5696d6411..f30cec28b 100644 --- a/app/models/avis.rb +++ b/app/models/avis.rb @@ -12,7 +12,6 @@ class Avis < ApplicationRecord before_validation -> { sanitize_email(:email) } before_create :try_to_assign_instructeur - after_create :notify_instructeur default_scope { joins(:dossier) } scope :with_answer, -> { where.not(answer: nil) } @@ -24,6 +23,7 @@ class Avis < ApplicationRecord # The form allows subtmitting avis requests to several emails at once, # hence this virtual attribute. attr_accessor :emails + attr_accessor :invite_linked_dossiers def email_to_display instructeur&.email || email @@ -49,10 +49,6 @@ class Avis < ApplicationRecord private - def notify_instructeur - AvisMailer.avis_invitation(self).deliver_later - end - def try_to_assign_instructeur instructeur = Instructeur.find_by(email: email) if instructeur diff --git a/app/models/champ.rb b/app/models/champ.rb index e64ecd583..f2e40be11 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -11,7 +11,7 @@ class Champ < ApplicationRecord belongs_to :etablissement, dependent: :destroy has_many :champs, -> { ordered }, foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy - delegate :libelle, :type_champ, :order_place, :mandatory?, :description, :drop_down_list, :exclude_from_export?, :exclude_from_view?, :repetition?, to: :type_de_champ + delegate :libelle, :type_champ, :order_place, :mandatory?, :description, :drop_down_list, :exclude_from_export?, :exclude_from_view?, :repetition?, :dossier_link?, to: :type_de_champ scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) } scope :public_only, -> { where(private: false) } diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 497ddd0f4..07d5e73fc 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -517,6 +517,10 @@ class Dossier < ApplicationRecord self.individual = Individual.create_from_france_connect(fc_information) end + def linked_dossiers + Dossier.where(id: champs.filter(&:dossier_link?).map(&:value).compact) + end + private def log_dossier_operation(author, operation, subject = nil) diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 6d7903eaa..249c1b6f4 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -157,6 +157,10 @@ class TypeDeChamp < ApplicationRecord type_champ == TypeDeChamp.type_champs.fetch(:repetition) end + def dossier_link? + type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) + end + def public? !private? end diff --git a/app/views/instructeurs/avis/instruction.html.haml b/app/views/instructeurs/avis/instruction.html.haml index b8d5eb2f9..c396cd221 100644 --- a/app/views/instructeurs/avis/instruction.html.haml +++ b/app/views/instructeurs/avis/instruction.html.haml @@ -28,7 +28,7 @@ = f.submit 'Envoyer votre avis', class: 'button send' - if !@dossier.termine? - = render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_avis_path(@avis), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis } + = render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_avis_path(@avis), linked_dossiers: @dossier.linked_dossiers, must_be_confidentiel: @avis.confidentiel?, avis: @new_avis } - if @dossier.avis_for(current_instructeur).present? = render partial: 'instructeurs/shared/avis/list', locals: { avis: @dossier.avis_for(current_instructeur), avis_seen_at: nil } diff --git a/app/views/instructeurs/dossiers/avis.html.haml b/app/views/instructeurs/dossiers/avis.html.haml index 544f6547d..65d661582 100644 --- a/app/views/instructeurs/dossiers/avis.html.haml +++ b/app/views/instructeurs/dossiers/avis.html.haml @@ -4,7 +4,7 @@ .container - if !@dossier.termine? - = render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_dossier_path(@dossier.procedure, @dossier), must_be_confidentiel: false, avis: @avis } + = render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_dossier_path(@dossier.procedure, @dossier), linked_dossiers: @dossier.linked_dossiers, must_be_confidentiel: false, avis: @avis } - if @dossier.avis.present? = render partial: 'instructeurs/shared/avis/list', locals: { avis: @dossier.avis, avis_seen_at: @avis_seen_at } diff --git a/app/views/instructeurs/shared/avis/_form.html.haml b/app/views/instructeurs/shared/avis/_form.html.haml index a23a30ae2..1588633e3 100644 --- a/app/views/instructeurs/shared/avis/_form.html.haml +++ b/app/views/instructeurs/shared/avis/_form.html.haml @@ -6,6 +6,10 @@ = f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);" = f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true + - if linked_dossiers.present? + = f.check_box :invite_linked_dossiers, value: false + = f.label :invite_linked_dossiers, t('helpers.label.invite_linked_dossiers', count: linked_dossiers.length, ids: linked_dossiers.map(&:id).to_sentence) + .flex.justify-between.align-baseline - if must_be_confidentiel %p.confidentiel.flex diff --git a/config/locales/models/avis/fr.yml b/config/locales/models/avis/fr.yml index 9d1c31792..c458dffd9 100644 --- a/config/locales/models/avis/fr.yml +++ b/config/locales/models/avis/fr.yml @@ -5,3 +5,8 @@ fr: attributes: avis: answer: "Réponse" + helpers: + label: + invite_linked_dossiers: + one: Inviter aussi l'expert sur le dossier lié n° %{ids} + other: Inviter aussi l'expert sur les dossiers liés n° %{ids} diff --git a/spec/controllers/instructeurs/avis_controller_spec.rb b/spec/controllers/instructeurs/avis_controller_spec.rb index bd8bd8821..86e7a5bec 100644 --- a/spec/controllers/instructeurs/avis_controller_spec.rb +++ b/spec/controllers/instructeurs/avis_controller_spec.rb @@ -123,9 +123,10 @@ describe Instructeurs::AvisController, type: :controller do let(:intro) { 'introduction' } let(:created_avis) { Avis.last } let!(:old_avis_count) { Avis.count } + let(:invite_linked_dossiers) { nil } before do - post :create_avis, params: { id: previous_avis.id, avis: { emails: emails, introduction: intro, confidentiel: asked_confidentiel } } + post :create_avis, params: { id: previous_avis.id, avis: { emails: emails, introduction: intro, confidentiel: asked_confidentiel, invite_linked_dossiers: invite_linked_dossiers } } end context 'when an invalid email' do @@ -180,6 +181,34 @@ describe Instructeurs::AvisController, type: :controller do it { expect(created_avis.confidentiel).to be(true) } end end + + context 'with linked dossiers' do + let(:asked_confidentiel) { false } + let(:previous_avis_confidentiel) { false } + let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } + + it do + expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com") + expect(Avis.count).to eq(old_avis_count + 1) + expect(created_avis.email).to eq("a@b.com") + expect(created_avis.dossier).to eq(dossier) + end + + context 'checked' do + let(:invite_linked_dossiers) { true } + let(:created_avis) { Avis.last(2).first } + let(:linked_avis) { Avis.last } + let(:linked_dossier) { dossier.reload.linked_dossiers.first } + + it do + expect(flash.notice).to eq("Une demande d'avis a été envoyée à a@b.com") + expect(Avis.count).to eq(old_avis_count + 2) + expect(created_avis.email).to eq("a@b.com") + expect(created_avis.dossier).to eq(dossier) + expect(linked_avis.dossier).to eq(linked_dossier) + end + end + end end end diff --git a/spec/factories/dossier.rb b/spec/factories/dossier.rb index 163109eac..313b49d40 100644 --- a/spec/factories/dossier.rb +++ b/spec/factories/dossier.rb @@ -54,10 +54,30 @@ FactoryBot.define do trait :with_dossier_link do after(:create) do |dossier, _evaluator| + # create linked dossier linked_dossier = create(:dossier) - type_de_champ = dossier.procedure.types_de_champ.find { |t| t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) } - champ = dossier.champs.find { |c| c.type_de_champ == type_de_champ } + # find first type de champ dossier_link + type_de_champ = dossier.procedure.types_de_champ.find do |t| + t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) + end + + # if type de champ does not exist create it + if !type_de_champ + type_de_champ = create(:type_de_champ_dossier_link, procedure: dossier.procedure) + end + + # find champ with the type de champ + champ = dossier.reload.champs.find do |c| + c.type_de_champ == type_de_champ + end + + # if champ does not exist create it + if !champ + champ = create(:champ_dossier_link, dossier: dossier, type_de_champ: type_de_champ) + end + + # set champ value with linked dossier champ.value = linked_dossier.id champ.save! end diff --git a/spec/features/instructeurs/expert_spec.rb b/spec/features/instructeurs/expert_spec.rb index c938c2f6d..08ceae5a3 100644 --- a/spec/features/instructeurs/expert_spec.rb +++ b/spec/features/instructeurs/expert_spec.rb @@ -8,7 +8,7 @@ feature 'Inviting an expert:' do let(:expert) { create(:instructeur, password: expert_password) } let(:expert_password) { 'mot de passe d’expert' } let(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) } - let(:dossier) { create(:dossier, state: Dossier.states.fetch(:en_construction), procedure: procedure) } + let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } context 'as an Instructeur' do scenario 'I can invite an expert' do @@ -20,6 +20,7 @@ feature 'Inviting an expert:' do fill_in 'avis_emails', with: 'expert1@exemple.fr, expert2@exemple.fr' fill_in 'avis_introduction', with: 'Bonjour, merci de me donner votre avis sur ce dossier.' + check 'avis_invite_linked_dossiers' page.select 'confidentiel', from: 'avis_confidentiel' perform_enqueued_jobs do @@ -34,6 +35,8 @@ feature 'Inviting an expert:' do expect(page).to have_content('Bonjour, merci de me donner votre avis sur ce dossier.') end + expect(Avis.count).to eq(4) + expect(all_emails.size).to eq(2) invitation_email = open_email('expert2@exemple.fr') avis = Avis.find_by(email: 'expert2@exemple.fr') sign_up_link = sign_up_instructeur_avis_path(avis.id, avis.email) diff --git a/spec/features/instructeurs/instruction_spec.rb b/spec/features/instructeurs/instruction_spec.rb index 085b39417..52140f952 100644 --- a/spec/features/instructeurs/instruction_spec.rb +++ b/spec/features/instructeurs/instruction_spec.rb @@ -7,8 +7,7 @@ feature 'Instructing a dossier:' do let!(:instructeur) { create(:instructeur, password: password) } let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) } - let!(:dossier) { create(:dossier, state: Dossier.states.fetch(:en_construction), procedure: procedure) } - + let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } context 'the instructeur is also a user' do scenario 'a instructeur can fill a dossier' do visit commencer_path(path: procedure.path) diff --git a/spec/models/avis_spec.rb b/spec/models/avis_spec.rb index 4b807644c..74fb242e7 100644 --- a/spec/models/avis_spec.rb +++ b/spec/models/avis_spec.rb @@ -87,18 +87,6 @@ RSpec.describe Avis, type: :model do end end - describe '#notify_instructeur' do - context 'when an avis is created' do - before do - avis_invitation_double = double('avis_invitation', deliver_later: true) - allow(AvisMailer).to receive(:avis_invitation).and_return(avis_invitation_double) - Avis.create(claimant: claimant, email: 'email@l.com') - end - - it { expect(AvisMailer).to have_received(:avis_invitation) } - end - end - describe '#try_to_assign_instructeur' do let!(:instructeur) { create(:instructeur) } let(:avis) { Avis.create(claimant: claimant, email: email, dossier: create(:dossier)) } From 0ff6c793ae8ebfbeef68ef4fd2f6fa564eb0d4cb Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 23 Oct 2019 12:50:24 +0200 Subject: [PATCH 04/20] Decommission ActiveStorage proxy service and use openstack service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are making these changes in order to always use DS_Proxy. Before this change DS_Proxy was not used to write files when ActiveStorage was used directly and not through “direct upload”. --- .../service/ds_proxy_service.rb | 57 ------------------- config/environments/production.rb | 2 +- config/initializers/active_storage.rb | 30 ++++++++++ config/storage.yml | 3 - 4 files changed, 31 insertions(+), 61 deletions(-) delete mode 100644 app/lib/active_storage/service/ds_proxy_service.rb diff --git a/app/lib/active_storage/service/ds_proxy_service.rb b/app/lib/active_storage/service/ds_proxy_service.rb deleted file mode 100644 index fe540d591..000000000 --- a/app/lib/active_storage/service/ds_proxy_service.rb +++ /dev/null @@ -1,57 +0,0 @@ -module ActiveStorage - # Wraps an ActiveStorage::Service to route direct upload and direct download URLs through our proxy, - # thus avoiding exposing the storage provider’s URL to our end-users. - class Service::DsProxyService < SimpleDelegator - attr_reader :wrapped - - def self.build(wrapped:, configurator:, **options) - new(wrapped: configurator.build(wrapped)) - end - - def initialize(wrapped:) - @wrapped = wrapped - super(wrapped) - end - - def url(*args) - url = wrapped.url(*args) - publicize(url) - end - - def url_for_direct_upload(*args) - url = wrapped.url_for_direct_upload(*args) - publicize(url) - end - - private - - def object_for(key, &block) - blob_url = url(key) - if block_given? - request = Typhoeus::Request.new(blob_url) - request.on_headers do |response| - if response.code != 200 - raise Fog::OpenStack::Storage::NotFound.new - end - end - request.on_body do |chunk| - yield chunk - end - request.run - else - response = Typhoeus.get(blob_url) - if response.success? - response - else - raise Fog::OpenStack::Storage::NotFound.new - end - end - end - - def publicize(url) - search = %r{^https://[^/]+/v1/AUTH_[a-f0-9]{32}} - replace = 'https://static.demarches-simplifiees.fr' - url.gsub(search, replace) - end - end -end diff --git a/config/environments/production.rb b/config/environments/production.rb index 0c93feb51..8837fb88b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -93,7 +93,7 @@ Rails.application.configure do # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true - config.active_storage.service = :proxied + config.active_storage.service = :openstack # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb index 7357c9267..1d600d89c 100644 --- a/config/initializers/active_storage.rb +++ b/config/initializers/active_storage.rb @@ -7,3 +7,33 @@ ActiveStorage::Service.url_expires_in = 1.hour # cleaner (as it allows to enqueue the virus scan on attachment creation, rather # than on blob creation). ActiveSupport.on_load(:active_storage_blob) { include BlobVirusScanner } + +# When an OpenStack service is initialized it makes a request to fetch +# `publicURL` to use for all operations. We intercept the method that reads +# this url and replace the host with DS_Proxy host. This way all the operation +# are performed through DS_Proxy. +# +# https://github.com/fog/fog-openstack/blob/37621bb1d5ca78d037b3c56bd307f93bba022ae1/lib/fog/openstack/auth/catalog/v2.rb#L16 +require 'fog/openstack/auth/catalog/v2' + +module Fog::OpenStack::Auth::Catalog + class V2 + def endpoint_url(endpoint, interface) + url = endpoint["#{interface}URL"] + + if interface == 'public' + publicize(url) + else + url + end + end + + private + + def publicize(url) + search = %r{^https://[^/]+/} + replace = 'https://static.demarches-simplifiees.fr/' + url.gsub(search, replace) + end + end +end diff --git a/config/storage.yml b/config/storage.yml index 11de850f6..0427a3f7a 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -4,9 +4,6 @@ local: test: service: Disk root: <%= Rails.root.join("tmp/storage") %> -proxied: - service: DsProxy - wrapped: openstack openstack: service: OpenStack container: "<%= ENV['FOG_ACTIVESTORAGE_DIRECTORY'] %>" From 4b058001aa71715dd6ebf90082b34a7d7b3b657c Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 9 Oct 2019 18:29:14 +0200 Subject: [PATCH 05/20] Fix active link in left panel --- .../_left_panel_admin_procedurescontroller_navbar.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml index 4429e2052..ecb0a8ca9 100644 --- a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml +++ b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml @@ -27,7 +27,7 @@ %p.missing-steps (à compléter) %a#onglet-administrateurs{ href: url_for(procedure_administrateurs_path(@procedure)) } - .procedure-list-element{ class: ('active' if active == 'Administrateurs') } + .procedure-list-element Administrateurs %a#onglet-instructeurs{ href: url_for(admin_procedure_assigns_path(@procedure)) } From 1fa149575c9707b1e256e871d0c63e001db84e2b Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 9 Oct 2019 18:05:43 +0200 Subject: [PATCH 06/20] Add constraints to GroupeInstructeur --- app/models/groupe_instructeur.rb | 5 ++++ spec/models/groupe_instructeur_spec.rb | 38 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 spec/models/groupe_instructeur_spec.rb diff --git a/app/models/groupe_instructeur.rb b/app/models/groupe_instructeur.rb index e3202bdbd..8ebd1dd27 100644 --- a/app/models/groupe_instructeur.rb +++ b/app/models/groupe_instructeur.rb @@ -4,4 +4,9 @@ class GroupeInstructeur < ApplicationRecord has_many :assign_tos has_many :instructeurs, through: :assign_tos, dependent: :destroy has_many :dossiers + + validates :label, presence: { message: 'doit être renseigné' }, allow_nil: false + validates :label, uniqueness: { scope: :procedure, message: 'existe déjà' } + + before_validation -> { label&.strip! } end diff --git a/spec/models/groupe_instructeur_spec.rb b/spec/models/groupe_instructeur_spec.rb new file mode 100644 index 000000000..4a3b3ce62 --- /dev/null +++ b/spec/models/groupe_instructeur_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe GroupeInstructeur, type: :model do + let(:procedure) { create(:procedure) } + subject { GroupeInstructeur.new(label: label, procedure: procedure) } + + context 'with no label provided' do + let(:label) { '' } + + it { is_expected.to be_invalid } + end + + context 'with a valid label' do + let(:label) { 'Préfecture de la Marne' } + + it { is_expected.to be_valid } + end + + context 'with a label with extra spaces' do + let(:label) { 'Préfecture de la Marne ' } + before do + subject.save + subject.reload + end + + it { is_expected.to be_valid } + it { expect(subject.label).to eq("Préfecture de la Marne") } + end + + context 'with a label already used for this procedure' do + let(:label) { 'Préfecture de la Marne' } + before do + GroupeInstructeur.create!(label: label, procedure: procedure) + end + + it { is_expected.to be_invalid } + end +end From 6a974663b0345615df040c674051b72dd2b06e6a Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 9 Oct 2019 18:28:03 +0200 Subject: [PATCH 07/20] An instructeur owns procedure with groupe instructeur mechanisme --- app/controllers/instructeurs/procedures_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index 9b76145ff..a30a52f7e 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -264,7 +264,7 @@ module Instructeurs end def ensure_ownership! - if !procedure.defaut_groupe_instructeur.instructeurs.include?(current_instructeur) + if !current_instructeur.procedures.include?(procedure) flash[:alert] = "Vous n'avez pas accès à cette démarche" redirect_to root_path end From 2749c00ce30b84ef61ff107de59c8f86eb65de23 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 17 Oct 2019 15:13:50 +0200 Subject: [PATCH 08/20] Groupe instructeur index --- app/assets/stylesheets/new_design/utils.scss | 5 ++++ .../groupe_instructeurs_controller.rb | 24 +++++++++++++++++ .../groupe_instructeurs/index.html.haml | 19 +++++++++++++ config/routes.rb | 2 ++ .../groupe_instructeurs_controller_spec.rb | 27 +++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 app/controllers/new_administrateur/groupe_instructeurs_controller.rb create mode 100644 app/views/new_administrateur/groupe_instructeurs/index.html.haml create mode 100644 spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb diff --git a/app/assets/stylesheets/new_design/utils.scss b/app/assets/stylesheets/new_design/utils.scss index ef32f9f20..9e5b14290 100644 --- a/app/assets/stylesheets/new_design/utils.scss +++ b/app/assets/stylesheets/new_design/utils.scss @@ -1,4 +1,5 @@ @import "colors"; +@import "constants"; .pull-left { float: left; @@ -48,3 +49,7 @@ background: $orange-bg; color: $black; } + +.mt-2 { + margin-top: 2 * $default-spacer; +} diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb new file mode 100644 index 000000000..28193b7c7 --- /dev/null +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -0,0 +1,24 @@ +module NewAdministrateur + class GroupeInstructeursController < AdministrateurController + ITEMS_PER_PAGE = 25 + + def index + @procedure = procedure + + @groupes_instructeurs = procedure + .groupe_instructeurs + .page(params[:page]) + .per(ITEMS_PER_PAGE) + .order(:label) + end + + private + + def procedure + current_administrateur + .procedures + .includes(:groupe_instructeurs) + .find(params[:procedure_id]) + end + end +end diff --git a/app/views/new_administrateur/groupe_instructeurs/index.html.haml b/app/views/new_administrateur/groupe_instructeurs/index.html.haml new file mode 100644 index 000000000..ed1a6de11 --- /dev/null +++ b/app/views/new_administrateur/groupe_instructeurs/index.html.haml @@ -0,0 +1,19 @@ += render partial: 'new_administrateur/breadcrumbs', + locals: { steps: [link_to('Démarches', admin_procedures_path), + link_to(@procedure.libelle, admin_procedure_path(@procedure)), + 'Groupes d’instructeurs'] } + +.container.groupe-instructeur + .card + .card-title Gestion des Groupes + + %table.table.mt-2 + %thead + %tr + %th{ colspan: 2 } Liste des groupes + %tbody + - @groupes_instructeurs.each do |group| + %tr + %td= group.label + + = paginate @groupes_instructeurs diff --git a/config/routes.rb b/config/routes.rb index d60cd0c65..560ab8e69 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -350,6 +350,8 @@ Rails.application.routes.draw do get 'annotations' end + resources :groupe_instructeurs, only: [:index] + resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy] resources :types_de_champ, only: [:create, :update, :destroy] do diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb new file mode 100644 index 000000000..3c803ffb1 --- /dev/null +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -0,0 +1,27 @@ +describe NewAdministrateur::GroupeInstructeursController, type: :controller do + render_views + + let(:admin) { create(:administrateur) } + let(:procedure) { create(:procedure, :published, administrateurs: [admin]) } + let!(:gi_1_1) { procedure.defaut_groupe_instructeur } + + let(:procedure2) { create(:procedure, :published) } + let!(:gi_2_2) { procedure2.groupe_instructeurs.create(label: 'groupe instructeur 2 2') } + + before { sign_in(admin.user) } + + describe '#index' do + context 'of a procedure I own' do + let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') } + + before { get :index, params: { procedure_id: procedure.id } } + + context 'when a procedure has multiple groups' do + it { expect(response).to have_http_status(:ok) } + it { expect(response.body).to include(gi_1_1.label) } + it { expect(response.body).to include(gi_1_2.label) } + it { expect(response.body).not_to include(gi_2_2.label) } + end + end + end +end From 733e83cc54c96d8378f6d1eb00acfc39039d9a1c Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 23 Oct 2019 20:22:56 +0200 Subject: [PATCH 09/20] Groupe instructeur show --- .../new_design/groupe_instructeur.scss | 6 +++++ .../groupe_instructeurs_controller.rb | 14 +++++++++++ .../groupe_instructeurs/index.html.haml | 1 + .../groupe_instructeurs/show.html.haml | 24 +++++++++++++++++++ config/routes.rb | 2 +- .../groupe_instructeurs_controller_spec.rb | 8 +++++++ 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 app/assets/stylesheets/new_design/groupe_instructeur.scss create mode 100644 app/views/new_administrateur/groupe_instructeurs/show.html.haml diff --git a/app/assets/stylesheets/new_design/groupe_instructeur.scss b/app/assets/stylesheets/new_design/groupe_instructeur.scss new file mode 100644 index 000000000..419bf075f --- /dev/null +++ b/app/assets/stylesheets/new_design/groupe_instructeur.scss @@ -0,0 +1,6 @@ +.groupe-instructeur { + .actions { + width: 200px; + text-align: center; + } +} diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb index 28193b7c7..b9736cf37 100644 --- a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -12,6 +12,16 @@ module NewAdministrateur .order(:label) end + def show + @procedure = procedure + @groupe_instructeur = groupe_instructeur + @instructeurs = groupe_instructeur + .instructeurs + .page(params[:page]) + .per(ITEMS_PER_PAGE) + .order(:email) + end + private def procedure @@ -20,5 +30,9 @@ module NewAdministrateur .includes(:groupe_instructeurs) .find(params[:procedure_id]) end + + def groupe_instructeur + procedure.groupe_instructeurs.find(params[:id]) + end end end diff --git a/app/views/new_administrateur/groupe_instructeurs/index.html.haml b/app/views/new_administrateur/groupe_instructeurs/index.html.haml index ed1a6de11..526a8736c 100644 --- a/app/views/new_administrateur/groupe_instructeurs/index.html.haml +++ b/app/views/new_administrateur/groupe_instructeurs/index.html.haml @@ -15,5 +15,6 @@ - @groupes_instructeurs.each do |group| %tr %td= group.label + %td.actions= link_to "voir", procedure_groupe_instructeur_path(@procedure, group) = paginate @groupes_instructeurs diff --git a/app/views/new_administrateur/groupe_instructeurs/show.html.haml b/app/views/new_administrateur/groupe_instructeurs/show.html.haml new file mode 100644 index 000000000..d618a08d5 --- /dev/null +++ b/app/views/new_administrateur/groupe_instructeurs/show.html.haml @@ -0,0 +1,24 @@ += render partial: 'new_administrateur/breadcrumbs', + locals: { steps: [link_to('Démarches', admin_procedures_path), + link_to(@procedure.libelle, admin_procedure_path(@procedure)), + link_to('Groupes d’instructeurs', procedure_groupe_instructeurs_path(@procedure)), + @groupe_instructeur.label] } + +.container.groupe-instructeur + .rename_form_block + .flex.baseline-start + %h1 Groupe « #{@groupe_instructeur.label} » + + .card + .card-title Gestion des instructeurs + + %table.table.mt-2 + %thead + %tr + %th{ colspan: 2 } Instructeurs affectés + %tbody + - @instructeurs.each do |instructeur| + %tr + %td= instructeur.email + + = paginate @instructeurs diff --git a/config/routes.rb b/config/routes.rb index 560ab8e69..3a523e9b9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -350,7 +350,7 @@ Rails.application.routes.draw do get 'annotations' end - resources :groupe_instructeurs, only: [:index] + resources :groupe_instructeurs, only: [:index, :show] resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy] diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb index 3c803ffb1..9c095cc1b 100644 --- a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -24,4 +24,12 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do end end end + + describe '#show' do + context 'of a group I belong to' do + before { get :show, params: { procedure_id: procedure.id, id: gi_1_1.id } } + + it { expect(response).to have_http_status(:ok) } + end + end end From 9a6336f508ee80f406c4a3bf9ac96675a58931c8 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 23 Oct 2019 20:51:25 +0200 Subject: [PATCH 10/20] Groupe instructeur create --- .../groupe_instructeurs_controller.rb | 35 ++++++++++++++++--- .../groupe_instructeurs/index.html.haml | 7 ++++ config/routes.rb | 2 +- .../groupe_instructeurs_controller_spec.rb | 26 ++++++++++++++ 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb index b9736cf37..f25051938 100644 --- a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -5,11 +5,7 @@ module NewAdministrateur def index @procedure = procedure - @groupes_instructeurs = procedure - .groupe_instructeurs - .page(params[:page]) - .per(ITEMS_PER_PAGE) - .order(:label) + @groupes_instructeurs = paginated_groupe_instructeurs end def show @@ -22,6 +18,23 @@ module NewAdministrateur .order(:email) end + def create + @groupe_instructeur = procedure + .groupe_instructeurs + .new(label: label, instructeurs: [current_administrateur.instructeur]) + + if @groupe_instructeur.save + redirect_to procedure_groupe_instructeur_path(procedure, @groupe_instructeur), + notice: "Le groupe d’instructeurs « #{label} » a été créé." + else + @procedure = procedure + @groupes_instructeurs = paginated_groupe_instructeurs + + flash[:alert] = "le nom « #{label} » est déjà pris par un autre groupe." + render :index + end + end + private def procedure @@ -34,5 +47,17 @@ module NewAdministrateur def groupe_instructeur procedure.groupe_instructeurs.find(params[:id]) end + + def label + params[:groupe_instructeur][:label] + end + + def paginated_groupe_instructeurs + procedure + .groupe_instructeurs + .page(params[:page]) + .per(ITEMS_PER_PAGE) + .order(:label) + end end end diff --git a/app/views/new_administrateur/groupe_instructeurs/index.html.haml b/app/views/new_administrateur/groupe_instructeurs/index.html.haml index 526a8736c..479d5ebc8 100644 --- a/app/views/new_administrateur/groupe_instructeurs/index.html.haml +++ b/app/views/new_administrateur/groupe_instructeurs/index.html.haml @@ -7,6 +7,13 @@ .card .card-title Gestion des Groupes + = form_for :groupe_instructeur, html: { class: 'form' } do |f| + = f.label :label do + Ajouter un groupe + %span.notice Ce groupe sera un choix de la liste « #{@procedure.routing_criteria_name} » . + = f.text_field :label, placeholder: 'Ville de Bordeaux', required: true + = f.submit 'Ajouter le groupe', class: 'button primary send' + %table.table.mt-2 %thead %tr diff --git a/config/routes.rb b/config/routes.rb index 3a523e9b9..0d84143ca 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -350,7 +350,7 @@ Rails.application.routes.draw do get 'annotations' end - resources :groupe_instructeurs, only: [:index, :show] + resources :groupe_instructeurs, only: [:index, :show, :create] resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy] diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb index 9c095cc1b..ad850c55e 100644 --- a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -32,4 +32,30 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do it { expect(response).to have_http_status(:ok) } end end + + describe '#create' do + before do + post :create, + params: { + procedure_id: procedure.id, + groupe_instructeur: { label: label } + } + end + + context 'with a valid name' do + let(:label) { "nouveau_groupe" } + + it { expect(flash.notice).to be_present } + it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, procedure.groupe_instructeurs.last)) } + it { expect(procedure.groupe_instructeurs.count).to eq(2) } + end + + context 'with an invalid group name' do + let(:label) { gi_1_1.label } + + it { expect(response).to render_template(:index) } + it { expect(procedure.groupe_instructeurs.count).to eq(1) } + it { expect(flash.alert).to be_present } + end + end end From 3dd3af8482571de2ead2f1449f4a7ed5c0507413 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 23 Oct 2019 20:54:59 +0200 Subject: [PATCH 11/20] Groupe instructeur update --- .../groupe_instructeurs_controller.rb | 29 +++++++++++++++---- .../groupe_instructeurs/show.html.haml | 9 ++++++ config/routes.rb | 2 +- .../groupe_instructeurs_controller_spec.rb | 25 ++++++++++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb index f25051938..50ce654aa 100644 --- a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -11,11 +11,7 @@ module NewAdministrateur def show @procedure = procedure @groupe_instructeur = groupe_instructeur - @instructeurs = groupe_instructeur - .instructeurs - .page(params[:page]) - .per(ITEMS_PER_PAGE) - .order(:email) + @instructeurs = paginated_instructeurs end def create @@ -35,6 +31,21 @@ module NewAdministrateur end end + def update + @groupe_instructeur = groupe_instructeur + + if @groupe_instructeur.update(label: label) + redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur), + notice: "Le nom est à présent « #{label} »." + else + @procedure = procedure + @instructeurs = paginated_instructeurs + + flash[:alert] = "le nom « #{label} » est déjà pris par un autre groupe." + render :show + end + end + private def procedure @@ -59,5 +70,13 @@ module NewAdministrateur .per(ITEMS_PER_PAGE) .order(:label) end + + def paginated_instructeurs + groupe_instructeur + .instructeurs + .page(params[:page]) + .per(ITEMS_PER_PAGE) + .order(:email) + end end end diff --git a/app/views/new_administrateur/groupe_instructeurs/show.html.haml b/app/views/new_administrateur/groupe_instructeurs/show.html.haml index d618a08d5..c08d4399b 100644 --- a/app/views/new_administrateur/groupe_instructeurs/show.html.haml +++ b/app/views/new_administrateur/groupe_instructeurs/show.html.haml @@ -9,6 +9,15 @@ .flex.baseline-start %h1 Groupe « #{@groupe_instructeur.label} » + .card.mt-2 + = form_for @groupe_instructeur, + url: procedure_groupe_instructeur_path(@procedure, @groupe_instructeur), + html: { class: 'form' } do |f| + + = f.label :label, 'Nom du groupe' + = f.text_field :label, placeholder: 'Ville de Bordeaux', required: true + = f.submit 'Renommer', class: 'button primary send' + .card .card-title Gestion des instructeurs diff --git a/config/routes.rb b/config/routes.rb index 0d84143ca..973188fed 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -350,7 +350,7 @@ Rails.application.routes.draw do get 'annotations' end - resources :groupe_instructeurs, only: [:index, :show, :create] + resources :groupe_instructeurs, only: [:index, :show, :create, :update] resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy] diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb index ad850c55e..912a4b2fe 100644 --- a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -58,4 +58,29 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do it { expect(flash.alert).to be_present } end end + + describe '#update' do + let(:new_name) { 'nouveau nom du groupe' } + + before do + patch :update, + params: { + procedure_id: procedure.id, + id: gi_1_1.id, + groupe_instructeur: { label: new_name } + } + end + + it { expect(gi_1_1.reload.label).to eq(new_name) } + it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_1)) } + it { expect(flash.notice).to be_present } + + context 'when the name is already taken' do + let!(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') } + let(:new_name) { gi_1_2.label } + + it { expect(gi_1_1.reload.label).not_to eq(new_name) } + it { expect(flash.alert).to be_present } + end + end end From a6deafd885b3e8c64d365aaf43b8881c803af912 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 10 Oct 2019 19:36:56 +0200 Subject: [PATCH 12/20] Add instructeurs to groupe --- .../groupe_instructeurs_controller.rb | 32 +++++++++++++++++++ app/mailers/groupe_instructeur_mailer.rb | 14 ++++++++ .../add_instructeur.html.haml | 11 +++++++ .../groupe_instructeurs/show.html.haml | 8 +++++ config/routes.rb | 6 +++- .../groupe_instructeurs_controller_spec.rb | 29 +++++++++++++++++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 app/mailers/groupe_instructeur_mailer.rb create mode 100644 app/views/groupe_instructeur_mailer/add_instructeur.html.haml diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb index 50ce654aa..5a280e529 100644 --- a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -46,8 +46,36 @@ module NewAdministrateur end end + def add_instructeur + @instructeur = Instructeur.find_by(email: instructeur_email) || + create_instructeur(instructeur_email) + + if groupe_instructeur.instructeurs.include?(@instructeur) + flash[:alert] = "L’instructeur « #{instructeur_email} » est déjà dans le groupe." + + else + groupe_instructeur.instructeurs << @instructeur + flash[:notice] = "L’instructeur « #{instructeur_email} » a été affecté au groupe." + GroupeInstructeurMailer + .add_instructeur(groupe_instructeur, @instructeur, current_user.email) + .deliver_later + end + + redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur) + end + private + def create_instructeur(email) + user = User.create_or_promote_to_instructeur( + email, + SecureRandom.hex, + administrateurs: [current_administrateur] + ) + user.invite! + user.instructeur + end + def procedure current_administrateur .procedures @@ -59,6 +87,10 @@ module NewAdministrateur procedure.groupe_instructeurs.find(params[:id]) end + def instructeur_email + params[:instructeur][:email].strip.downcase + end + def label params[:groupe_instructeur][:label] end diff --git a/app/mailers/groupe_instructeur_mailer.rb b/app/mailers/groupe_instructeur_mailer.rb new file mode 100644 index 000000000..fec9972e6 --- /dev/null +++ b/app/mailers/groupe_instructeur_mailer.rb @@ -0,0 +1,14 @@ +class GroupeInstructeurMailer < ApplicationMailer + layout 'mailers/layout' + + def add_instructeur(group, instructeur, current_instructeur_email) + @email = instructeur.email + @group = group + @current_instructeur_email = current_instructeur_email + + subject = "Ajout d’un instructeur dans le groupe \"#{group.label}\"" + + emails = @group.instructeurs.pluck(:email) + mail(bcc: emails, subject: subject) + end +end diff --git a/app/views/groupe_instructeur_mailer/add_instructeur.html.haml b/app/views/groupe_instructeur_mailer/add_instructeur.html.haml new file mode 100644 index 000000000..578312cb7 --- /dev/null +++ b/app/views/groupe_instructeur_mailer/add_instructeur.html.haml @@ -0,0 +1,11 @@ +%p + Bonjour, + +%p + L’instructeur « #{@email} » a été affecté au groupe « #{@group.label} » par « #{@current_instructeur_email} », en charge de la démarche « #{@group.procedure.libelle} ». + +%p + Cliquez sur le lien ci-dessous pour voir la liste des instructeurs de ce groupe : + = link_to(@group.label, procedure_groupe_instructeur_url(@group.procedure, @group)) + += render partial: "layouts/mailers/signature" diff --git a/app/views/new_administrateur/groupe_instructeurs/show.html.haml b/app/views/new_administrateur/groupe_instructeurs/show.html.haml index c08d4399b..a569a9c34 100644 --- a/app/views/new_administrateur/groupe_instructeurs/show.html.haml +++ b/app/views/new_administrateur/groupe_instructeurs/show.html.haml @@ -20,6 +20,14 @@ .card .card-title Gestion des instructeurs + = form_for :instructeur, + url: { action: :add_instructeur }, + html: { class: 'form' } do |f| + + = f.label :email do + Affecter un nouvel instructeur + = f.email_field :email, placeholder: 'marie.dupont@exemple.fr', required: true + = f.submit 'Affecter', class: 'button primary send' %table.table.mt-2 %thead diff --git a/config/routes.rb b/config/routes.rb index 973188fed..0ec8fc4d0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -350,7 +350,11 @@ Rails.application.routes.draw do get 'annotations' end - resources :groupe_instructeurs, only: [:index, :show, :create, :update] + resources :groupe_instructeurs, only: [:index, :show, :create, :update] do + member do + post 'add_instructeur' + end + end resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy] diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb index 912a4b2fe..c98718e4b 100644 --- a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -83,4 +83,33 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do it { expect(flash.alert).to be_present } end end + + describe '#add_instructeur' do + let!(:instructeur) { create(:instructeur) } + before do + gi_1_1.instructeurs << instructeur + + post :add_instructeur, + params: { + procedure_id: procedure.id, + id: gi_1_1.id, + instructeur: { email: new_instructeur_email } + } + end + + context 'of a new instructeur' do + let(:new_instructeur_email) { 'new_instructeur@mail.com' } + + it { expect(gi_1_1.instructeurs.pluck(:email)).to include(new_instructeur_email) } + it { expect(flash.notice).to be_present } + it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_1)) } + end + + context 'of an instructeur already in the group' do + let(:new_instructeur_email) { instructeur.email } + + it { expect(flash.alert).to be_present } + it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur)) } + end + end end From a5ffe9f54bf49c954f54b1a74d16144e8d330b4d Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 9 Oct 2019 18:23:29 +0200 Subject: [PATCH 13/20] Remove instructeur from the group --- .../groupe_instructeurs_controller.rb | 20 +++++++++++ app/mailers/groupe_instructeur_mailer.rb | 11 ++++++ .../remove_instructeur.html.haml | 11 ++++++ .../groupe_instructeurs/show.html.haml | 6 ++++ config/routes.rb | 1 + .../groupe_instructeurs_controller_spec.rb | 35 +++++++++++++++++++ 6 files changed, 84 insertions(+) create mode 100644 app/views/groupe_instructeur_mailer/remove_instructeur.html.haml diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb index 5a280e529..f9e1e791a 100644 --- a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -64,6 +64,22 @@ module NewAdministrateur redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur) end + def remove_instructeur + if groupe_instructeur.instructeurs.one? + flash[:alert] = "Suppression impossible : il doit y avoir au moins un instructeur dans le groupe" + + else + @instructeur = Instructeur.find(instructeur_id) + groupe_instructeur.instructeurs.destroy(@instructeur) + flash[:notice] = "L’instructeur « #{@instructeur.email} » a été retiré du groupe." + GroupeInstructeurMailer + .remove_instructeur(groupe_instructeur, @instructeur, current_user.email) + .deliver_later + end + + redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur) + end + private def create_instructeur(email) @@ -91,6 +107,10 @@ module NewAdministrateur params[:instructeur][:email].strip.downcase end + def instructeur_id + params[:instructeur][:id] + end + def label params[:groupe_instructeur][:label] end diff --git a/app/mailers/groupe_instructeur_mailer.rb b/app/mailers/groupe_instructeur_mailer.rb index fec9972e6..f5af9dd3c 100644 --- a/app/mailers/groupe_instructeur_mailer.rb +++ b/app/mailers/groupe_instructeur_mailer.rb @@ -11,4 +11,15 @@ class GroupeInstructeurMailer < ApplicationMailer emails = @group.instructeurs.pluck(:email) mail(bcc: emails, subject: subject) end + + def remove_instructeur(group, instructeur, current_instructeur_email) + @email = instructeur.email + @group = group + @current_instructeur_email = current_instructeur_email + + subject = "Suppression d’un instructeur dans le groupe \"#{group.label}\"" + + emails = @group.instructeurs.pluck(:email) + mail(bcc: emails, subject: subject) + end end diff --git a/app/views/groupe_instructeur_mailer/remove_instructeur.html.haml b/app/views/groupe_instructeur_mailer/remove_instructeur.html.haml new file mode 100644 index 000000000..15a3f15a7 --- /dev/null +++ b/app/views/groupe_instructeur_mailer/remove_instructeur.html.haml @@ -0,0 +1,11 @@ +%p + Bonjour, + +%p + L’instructeur « #{@email} » a été retiré du groupe « #{@group.label} » par « #{@current_instructeur_email} », en charge de la démarche « #{@group.procedure.libelle} ». + +%p + Cliquez sur le lien ci-dessous pour voir la liste des instructeurs de ce groupe : + = link_to(@group.label, procedure_groupe_instructeur_url(@group.procedure, @group)) + += render partial: "layouts/mailers/signature" diff --git a/app/views/new_administrateur/groupe_instructeurs/show.html.haml b/app/views/new_administrateur/groupe_instructeurs/show.html.haml index a569a9c34..40a3df3f4 100644 --- a/app/views/new_administrateur/groupe_instructeurs/show.html.haml +++ b/app/views/new_administrateur/groupe_instructeurs/show.html.haml @@ -37,5 +37,11 @@ - @instructeurs.each do |instructeur| %tr %td= instructeur.email + %td.actions= button_to 'retirer', + { action: :remove_instructeur }, + { method: :delete, + data: { confirm: "Êtes-vous sûr de vouloir retirer l’instructeur « #{instructeur.email} » du groupe  « #{@groupe_instructeur.label} » ?" }, + params: { instructeur: { id: instructeur.id }}, + class: 'button' } = paginate @instructeurs diff --git a/config/routes.rb b/config/routes.rb index 0ec8fc4d0..dd1747482 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -353,6 +353,7 @@ Rails.application.routes.draw do resources :groupe_instructeurs, only: [:index, :show, :create, :update] do member do post 'add_instructeur' + delete 'remove_instructeur' end end diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb index c98718e4b..4ee61c8df 100644 --- a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -112,4 +112,39 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur)) } end end + + describe '#remove_instructeur' do + let!(:instructeur) { create(:instructeur) } + + before { gi_1_1.instructeurs << admin.instructeur << instructeur } + + def remove_instructeur(email) + delete :remove_instructeur, + params: { + procedure_id: procedure.id, + id: gi_1_1.id, + instructeur: { id: admin.instructeur.id } + } + end + + context 'when there are many instructeurs' do + before { remove_instructeur(admin.user.email) } + + it { expect(gi_1_1.instructeurs).to include(instructeur) } + it { expect(gi_1_1.reload.instructeurs.count).to eq(1) } + it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_1)) } + end + + context 'when there is only one instructeur' do + before do + remove_instructeur(admin.user.email) + remove_instructeur(instructeur.email) + end + + it { expect(gi_1_1.instructeurs).to include(instructeur) } + it { expect(gi_1_1.instructeurs.count).to eq(1) } + it { expect(flash.alert).to eq('Suppression impossible : il doit y avoir au moins un instructeur dans le groupe') } + it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_1)) } + end + end end From d136d023cd8d6431133347878bcebda666fdd138 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 14 Oct 2019 15:57:11 +0200 Subject: [PATCH 14/20] Add feature flipped link in admin nav bar --- ...l_admin_procedurescontroller_navbar.html.haml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml index ecb0a8ca9..4f0284677 100644 --- a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml +++ b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml @@ -30,11 +30,17 @@ .procedure-list-element Administrateurs - %a#onglet-instructeurs{ href: url_for(admin_procedure_assigns_path(@procedure)) } - .procedure-list-element{ class: ('active' if active == 'Instructeurs') } - Instructeurs - - if @procedure.missing_steps.include?(:instructeurs) - %p.missing-steps (à compléter) + - if !feature_enabled?(:routage) + %a#onglet-instructeurs{ href: url_for(admin_procedure_assigns_path(@procedure)) } + .procedure-list-element{ class: ('active' if active == 'Instructeurs') } + Instructeurs + - if @procedure.missing_steps.include?(:instructeurs) + %p.missing-steps (à compléter) + + - if feature_enabled?(:routage) + %a#onglet-instructeurs{ href: url_for(procedure_groupe_instructeurs_path(@procedure)) } + .procedure-list-element + Groupe d'instructeurs - if !@procedure.locked? %a#onglet-champs{ href: champs_procedure_path(@procedure) } From 35bba6229736e7c708629b3af31d7840ea0d8a39 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 17 Oct 2019 10:57:58 +0200 Subject: [PATCH 15/20] =?UTF-8?q?Update=20routing=20crit=C3=A9ria=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groupe_instructeurs_controller.rb | 11 +++++++++++ .../groupe_instructeurs/index.html.haml | 11 +++++++++++ config/routes.rb | 4 ++++ .../groupe_instructeurs_controller_spec.rb | 12 ++++++++++++ 4 files changed, 38 insertions(+) diff --git a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb index f9e1e791a..b8923d4a3 100644 --- a/app/controllers/new_administrateur/groupe_instructeurs_controller.rb +++ b/app/controllers/new_administrateur/groupe_instructeurs_controller.rb @@ -80,6 +80,13 @@ module NewAdministrateur redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur) end + def update_routing_criteria_name + procedure.update!(routing_criteria_name: routing_criteria_name) + + redirect_to procedure_groupe_instructeurs_path(procedure), + notice: "Le libellé est maintenant « #{procedure.routing_criteria_name} »." + end + private def create_instructeur(email) @@ -130,5 +137,9 @@ module NewAdministrateur .per(ITEMS_PER_PAGE) .order(:email) end + + def routing_criteria_name + params[:procedure][:routing_criteria_name] + end end end diff --git a/app/views/new_administrateur/groupe_instructeurs/index.html.haml b/app/views/new_administrateur/groupe_instructeurs/index.html.haml index 479d5ebc8..6f9661a11 100644 --- a/app/views/new_administrateur/groupe_instructeurs/index.html.haml +++ b/app/views/new_administrateur/groupe_instructeurs/index.html.haml @@ -4,6 +4,17 @@ 'Groupes d’instructeurs'] } .container.groupe-instructeur + .card + = form_for @procedure, + url: { action: :update_routing_criteria_name }, + html: { class: 'form' } do |f| + + = f.label :routing_criteria_name do + Libellé du routage + %span.notice Ce texte apparaitra sur le formulaire usager comme le libellé d'une liste + = f.text_field :routing_criteria_name, placeholder: 'Votre ville', required: true + = f.submit 'Renommer', class: 'button primary send' + .card .card-title Gestion des Groupes diff --git a/config/routes.rb b/config/routes.rb index dd1747482..5730cf8ef 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -355,6 +355,10 @@ Rails.application.routes.draw do post 'add_instructeur' delete 'remove_instructeur' end + + collection do + patch 'update_routing_criteria_name' + end end resources :administrateurs, controller: 'procedure_administrateurs', only: [:index, :create, :destroy] diff --git a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb index 4ee61c8df..6b0d388a4 100644 --- a/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/new_administrateur/groupe_instructeurs_controller_spec.rb @@ -147,4 +147,16 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_1)) } end end + + describe '#update_routing_criteria_name' do + before do + patch :update_routing_criteria_name, + params: { + procedure_id: procedure.id, + procedure: { routing_criteria_name: 'new name !' } + } + end + + it { expect(procedure.reload.routing_criteria_name).to eq('new name !') } + end end From 38ace037f345294eda7cecc34add44d439c789c0 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Fri, 18 Oct 2019 09:35:54 +0200 Subject: [PATCH 16/20] Update Capybara --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cf449d922..41c577d6b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -74,8 +74,8 @@ GEM i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) administrate (0.11.0) actionpack (>= 4.2, < 6.0) actionview (>= 4.2, < 6.0) @@ -119,18 +119,18 @@ GEM browser (2.5.3) builder (3.2.3) byebug (10.0.2) - capybara (3.12.0) + capybara (3.29.0) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - regexp_parser (~> 1.2) + regexp_parser (~> 1.5) xpath (~> 3.2) capybara-email (3.0.1) capybara (>= 2.4, < 4.0) mail - capybara-screenshot (1.0.22) + capybara-screenshot (1.0.23) capybara (>= 1.0, < 4) launchy capybara-selenium (0.0.6) @@ -373,7 +373,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2018.0812) mimemagic (0.3.3) - mini_mime (1.0.1) + mini_mime (1.0.2) mini_portile2 (2.4.0) minitest (5.11.3) momentjs-rails (2.20.1) @@ -448,7 +448,7 @@ GEM pry-byebug (3.6.0) byebug (~> 10.0) pry (~> 0.10) - public_suffix (3.0.3) + public_suffix (4.0.1) puma (3.12.0) pundit (2.0.1) activesupport (>= 3.0.0) @@ -512,7 +512,7 @@ GEM execjs railties (>= 3.2) tilt - regexp_parser (1.3.0) + regexp_parser (1.6.0) request_store (1.4.1) rack (>= 1.4) responders (3.0.0) From fbe93e0fcea79cd6d47952e651a97d9cd90dd1c0 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 23 Oct 2019 19:19:17 +0200 Subject: [PATCH 17/20] Fix pluralization in search page --- app/views/instructeurs/recherche/index.html.haml | 2 +- config/locales/fr.yml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/instructeurs/recherche/index.html.haml b/app/views/instructeurs/recherche/index.html.haml index 2ccce0994..635895a60 100644 --- a/app/views/instructeurs/recherche/index.html.haml +++ b/app/views/instructeurs/recherche/index.html.haml @@ -3,7 +3,7 @@ .container .page-title Résultat de la recherche : - = pluralize(@dossiers.count, "dossier trouvé", "dossiers trouvés") + = t('pluralize.dossier_trouve', count: @dossiers.count) - if @dossiers.present? %table.table.dossiers-table.hoverable diff --git a/config/locales/fr.yml b/config/locales/fr.yml index c44b18967..5935c6cc9 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -313,3 +313,7 @@ fr: zero: archivé one: archivé other: archivés + dossier_trouve: + zero: 0 dossier trouvé + one: 1 dossier trouvé + other: "%{count} dossiers trouvés" From 90ae4181bfa0352089babf28a7d4c56d41f60b88 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 23 Oct 2019 19:43:37 +0200 Subject: [PATCH 18/20] fix dossier_linked_path in routed procedure --- app/helpers/dossier_link_helper.rb | 2 +- spec/helpers/dossier_link_helper_spec.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/helpers/dossier_link_helper.rb b/app/helpers/dossier_link_helper.rb index 1a3986771..93c9d9c16 100644 --- a/app/helpers/dossier_link_helper.rb +++ b/app/helpers/dossier_link_helper.rb @@ -1,7 +1,7 @@ module DossierLinkHelper def dossier_linked_path(user, dossier) if user.is_a?(Instructeur) - if dossier.procedure.defaut_groupe_instructeur.instructeurs.include?(user) + if user.groupe_instructeurs.include?(dossier.groupe_instructeur) instructeur_dossier_path(dossier.procedure, dossier) else avis = dossier.avis.find_by(instructeur: user) diff --git a/spec/helpers/dossier_link_helper_spec.rb b/spec/helpers/dossier_link_helper_spec.rb index 2c7db4af1..7b43b37ec 100644 --- a/spec/helpers/dossier_link_helper_spec.rb +++ b/spec/helpers/dossier_link_helper_spec.rb @@ -15,10 +15,11 @@ describe DossierLinkHelper do end context "when access as instructeur" do - let(:dossier) { create(:dossier) } + let(:procedure) { create(:procedure, :routee) } + let(:dossier) { create(:dossier, groupe_instructeur: procedure.groupe_instructeurs.last) } let(:instructeur) { create(:instructeur) } - before { dossier.procedure.defaut_groupe_instructeur.instructeurs << instructeur } + before { procedure.groupe_instructeurs.last.instructeurs << instructeur } it { expect(helper.dossier_linked_path(instructeur, dossier)).to eq(instructeur_dossier_path(dossier.procedure, dossier)) } end From e97c70562865ab0db9302a39c5d1dfb23398a484 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Fri, 18 Oct 2019 09:38:50 +0200 Subject: [PATCH 19/20] Add end to end spec --- spec/features/routing/full_scenario_spec.rb | 126 ++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 spec/features/routing/full_scenario_spec.rb diff --git a/spec/features/routing/full_scenario_spec.rb b/spec/features/routing/full_scenario_spec.rb new file mode 100644 index 000000000..86da5f97c --- /dev/null +++ b/spec/features/routing/full_scenario_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +feature 'The routing' do + let(:procedure) { create(:procedure, :with_service, :for_individual) } + let(:administrateur) { create(:administrateur, procedures: [procedure]) } + let(:scientifique_user) { create(:user) } + let(:litteraire_user) { create(:user) } + + before { Flipper.enable_actor(:routage, administrateur.user) } + + scenario 'works' do + login_as administrateur.user, scope: :user + + visit admin_procedure_path(procedure.id) + click_on "Groupe d'instructeurs" + + # rename routing criteria to spécialité + fill_in 'procedure_routing_criteria_name', with: 'spécialité' + click_on 'Renommer' + expect(procedure.reload.routing_criteria_name).to eq('spécialité') + + # rename defaut groupe to littéraire + click_on 'voir' + fill_in 'groupe_instructeur_label', with: 'littéraire' + click_on 'Renommer' + + # add victor to littéraire groupe + fill_in 'instructeur_email', with: 'victor@inst.com' + perform_enqueued_jobs { click_on 'Affecter' } + victor = User.find_by(email: 'victor@inst.com').instructeur + + click_on "Groupes d’instructeurs" + + # add scientifique groupe + fill_in 'groupe_instructeur_label', with: 'scientifique' + click_on 'Ajouter le groupe' + + # add marie to scientifique groupe + fill_in 'instructeur_email', with: 'marie@inst.com' + perform_enqueued_jobs { click_on 'Affecter' } + marie = User.find_by(email: 'marie@inst.com').instructeur + + # publish + publish_procedure(procedure) + log_out + + # 2 users fill a dossier in each group + user_send_dossier(scientifique_user, 'scientifique') + user_send_dossier(litteraire_user, 'littéraire') + + # the litteraires instructeurs only manage the litteraires dossiers + register_instructeur_and_log_in(victor.email) + click_on procedure.libelle + expect(page).to have_text(litteraire_user.email) + expect(page).not_to have_text(scientifique_user.email) + + # the search only show litteraires dossiers + fill_in 'q', with: scientifique_user.email + click_on 'Rechercher' + expect(page).to have_text('0 dossier trouvé') + + fill_in 'q', with: litteraire_user.email + click_on 'Rechercher' + expect(page).to have_text('1 dossier trouvé') + + ## and the result is clickable + click_on litteraire_user.email + expect(page).to have_current_path(instructeur_dossier_path(procedure, litteraire_user.dossiers.first)) + + log_out + + # the scientifiques instructeurs only manage the scientifiques dossiers + register_instructeur_and_log_in(marie.email) + click_on procedure.libelle + expect(page).not_to have_text(litteraire_user.email) + expect(page).to have_text(scientifique_user.email) + log_out + + # TODO: notifications tests + end + + def publish_procedure(procedure) + click_on procedure.libelle + find('#publish-procedure').click + within '#publish-modal' do + fill_in 'lien_site_web', with: 'http://some.website' + click_on 'publish' + end + + expect(page).to have_text('Démarche publiée') + end + + def user_send_dossier(user, groupe) + login_as user, scope: :user + visit commencer_path(path: procedure.reload.path) + click_on 'Commencer la démarche' + + fill_in 'individual_nom', with: 'Nom' + fill_in 'individual_prenom', with: 'Prenom' + click_button('Continuer') + + select(groupe, from: 'dossier_groupe_instructeur_id') + + click_on 'Déposer le dossier' + + log_out + end + + def register_instructeur_and_log_in(email) + confirmation_email = emails_sent_to(email) + .filter { |m| m.subject == 'Activez votre compte instructeur' } + .first + token_params = confirmation_email.body.match(/token=[^"]+/) + + visit "users/activate?#{token_params}" + fill_in :user_password, with: 'démarches-simplifiées-pwd' + + click_button 'Définir le mot de passe' + + expect(page).to have_content 'Mot de passe enregistré' + end + + def log_out + click_on 'Se déconnecter' + end +end From 7a922f46b2c3cbcdb2d7ead4e8285efbf020ebf5 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 23 Oct 2019 20:42:34 +0200 Subject: [PATCH 20/20] =?UTF-8?q?Migration:=20add=20defaut=20value=20to=20?= =?UTF-8?q?routing=20crit=C3=A9ria?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...91023183120_add_default_value_to_routing_criteria_name.rb | 5 +++++ db/schema.rb | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20191023183120_add_default_value_to_routing_criteria_name.rb diff --git a/db/migrate/20191023183120_add_default_value_to_routing_criteria_name.rb b/db/migrate/20191023183120_add_default_value_to_routing_criteria_name.rb new file mode 100644 index 000000000..d9cd9fff7 --- /dev/null +++ b/db/migrate/20191023183120_add_default_value_to_routing_criteria_name.rb @@ -0,0 +1,5 @@ +class AddDefaultValueToRoutingCriteriaName < ActiveRecord::Migration[5.2] + def change + change_column :procedures, :routing_criteria_name, :text, default: "Votre ville" + end +end diff --git a/db/schema.rb b/db/schema.rb index 3736ce621..b4c4e4823 100644 --- a/db/schema.rb +++ b/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: 2019_10_14_160538) do +ActiveRecord::Schema.define(version: 2019_10_23_183120) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -486,7 +486,7 @@ ActiveRecord::Schema.define(version: 2019_10_14_160538) do t.string "path", null: false t.string "declarative_with_state" t.text "monavis_embed" - t.text "routing_criteria_name" + t.text "routing_criteria_name", default: "Votre ville" t.boolean "csv_export_queued" t.boolean "xlsx_export_queued" t.boolean "ods_export_queued"