diff --git a/app/controllers/admin/instructeurs_controller.rb b/app/controllers/admin/instructeurs_controller.rb deleted file mode 100644 index 1f549756c..000000000 --- a/app/controllers/admin/instructeurs_controller.rb +++ /dev/null @@ -1,63 +0,0 @@ -class Admin::InstructeursController < AdminController - include SmartListing::Helper::ControllerExtensions - helper SmartListing::Helper - - def index - @instructeurs = smart_listing_create :instructeurs, - current_administrateur.instructeurs, - partial: "admin/instructeurs/list", - array: true - end - - def create - email = params[:instructeur][:email].downcase - @instructeur = Instructeur.by_email(email) - procedure_id = params[:procedure_id] - procedure = Procedure.find_by(id: procedure_id) - - if @instructeur.nil? - invite_instructeur(email) - else - assign_instructeur! - end - - if procedure_id.present? - redirect_to admin_procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur) - else - redirect_to admin_instructeurs_path - end - end - - def destroy - Instructeur.find(params[:id]).administrateurs.delete current_administrateur - redirect_to admin_instructeurs_path - end - - private - - def invite_instructeur(email) - user = User.create_or_promote_to_instructeur( - email, - SecureRandom.hex, - administrateurs: [current_administrateur] - ) - - if user.valid? - user.invite! - - flash.notice = 'Instructeur ajouté' - else - flash.alert = user.errors.full_messages - end - end - - def assign_instructeur! - if current_administrateur.instructeurs.include?(@instructeur) - flash.alert = 'Instructeur déjà ajouté' - else - @instructeur.administrateurs.push current_administrateur - flash.notice = 'Instructeur ajouté' - # TODO Mailer no assign_to - end - end -end diff --git a/app/controllers/admin/procedures_controller.rb b/app/controllers/admin/procedures_controller.rb deleted file mode 100644 index 3193ceb7d..000000000 --- a/app/controllers/admin/procedures_controller.rb +++ /dev/null @@ -1,147 +0,0 @@ -class Admin::ProceduresController < AdminController - include SmartListing::Helper::ControllerExtensions - helper SmartListing::Helper - - before_action :retrieve_procedure, only: [:show, :delete_logo, :delete_deliberation, :delete_notice, :publish_validate, :publish] - - def index - if current_administrateur.procedures.count != 0 - @procedures = smart_listing_create :procedures, - current_administrateur.procedures.publiees.order(published_at: :desc), - partial: "admin/procedures/list", - array: true - - active_class - else - redirect_to new_from_existing_admin_procedures_path - end - end - - def show - if @procedure.brouillon? - @procedure_lien = commencer_test_url(path: @procedure.path) - else - @procedure_lien = commencer_url(path: @procedure.path) - end - @procedure.path = @procedure.suggested_path(current_administrateur) - @current_administrateur = current_administrateur - end - - def destroy - procedure = current_administrateur.procedures.find(params[:id]) - - if procedure.can_be_deleted_by_administrateur? - procedure.discard_and_keep_track!(current_administrateur) - - flash.notice = 'Démarche supprimée' - redirect_to admin_procedures_draft_path - else - render json: {}, status: 403 - end - end - - def archive - procedure = current_administrateur.procedures.find(params[:procedure_id]) - procedure.close! - - flash.notice = "Démarche close" - redirect_to admin_procedures_path - - rescue ActiveRecord::RecordNotFound - flash.alert = 'Démarche inexistante' - redirect_to admin_procedures_path - end - - def clone - procedure = Procedure.find(params[:procedure_id]) - new_procedure = procedure.clone(current_administrateur, cloned_from_library?) - - if new_procedure.valid? - flash.notice = 'Démarche clonée' - redirect_to edit_admin_procedure_path(id: new_procedure.id) - else - if cloned_from_library? - flash.alert = new_procedure.errors.full_messages - redirect_to new_from_existing_admin_procedures_path - else - flash.alert = new_procedure.errors.full_messages - redirect_to admin_procedures_path - end - end - - rescue ActiveRecord::RecordNotFound - flash.alert = 'Démarche inexistante' - redirect_to admin_procedures_path - end - - SIGNIFICANT_DOSSIERS_THRESHOLD = 30 - - def new_from_existing - significant_procedure_ids = Procedure - .publiees_ou_closes - .joins(:dossiers) - .group("procedures.id") - .having("count(dossiers.id) >= ?", SIGNIFICANT_DOSSIERS_THRESHOLD) - .pluck('procedures.id') - - @grouped_procedures = Procedure - .includes(:administrateurs, :service) - .where(id: significant_procedure_ids) - .group_by(&:organisation_name) - .sort_by { |_, procedures| procedures.first.created_at } - render layout: 'application' - end - - def active_class - @active_class = 'active' - end - - def archived_class - @archived_class = 'active' - end - - def draft_class - @draft_class = 'active' - end - - def delete_logo - @procedure.logo.purge_later - - flash.notice = 'le logo a bien été supprimé' - redirect_to edit_admin_procedure_path(@procedure) - end - - def delete_deliberation - @procedure.deliberation.purge_later - - flash.notice = 'la délibération a bien été supprimée' - redirect_to edit_admin_procedure_path(@procedure) - end - - def delete_notice - @procedure.notice.purge_later - - flash.notice = 'la notice a bien été supprimée' - redirect_to edit_admin_procedure_path(@procedure) - end - - private - - def cloned_from_library? - params[:from_new_from_existing].present? - end - - def publish_params - params.permit(:path, :lien_site_web) - end - - def procedure_params - editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :web_hook_url, :euro_flag, :logo, :auto_archive_on] - permited_params = if @procedure&.locked? - params.require(:procedure).permit(*editable_params) - else - params.require(:procedure).permit(*editable_params, :duree_conservation_dossiers_dans_ds, :duree_conservation_dossiers_hors_ds, :for_individual, :path) - end - permited_params - end -end diff --git a/app/controllers/new_administrateur/procedures_controller.rb b/app/controllers/new_administrateur/procedures_controller.rb index 1e5a07877..97616ce8c 100644 --- a/app/controllers/new_administrateur/procedures_controller.rb +++ b/app/controllers/new_administrateur/procedures_controller.rb @@ -52,6 +52,23 @@ module NewAdministrateur @procedure ||= Procedure.new(for_individual: true) end + SIGNIFICANT_DOSSIERS_THRESHOLD = 30 + + def new_from_existing + significant_procedure_ids = Procedure + .publiees_ou_closes + .joins(:dossiers) + .group("procedures.id") + .having("count(dossiers.id) >= ?", SIGNIFICANT_DOSSIERS_THRESHOLD) + .pluck('procedures.id') + + @grouped_procedures = Procedure + .includes(:administrateurs, :service) + .where(id: significant_procedure_ids) + .group_by(&:organisation_name) + .sort_by { |_, procedures| procedures.first.created_at } + end + def show @procedure = current_administrateur.procedures.find(params[:id]) @current_administrateur = current_administrateur @@ -93,6 +110,40 @@ module NewAdministrateur end end + def clone + procedure = Procedure.find(params[:procedure_id]) + new_procedure = procedure.clone(current_administrateur, cloned_from_library?) + + if new_procedure.valid? + flash.notice = 'Démarche clonée' + redirect_to edit_admin_procedure_path(id: new_procedure.id) + else + if cloned_from_library? + flash.alert = new_procedure.errors.full_messages + redirect_to new_from_existing_admin_procedures_path + else + flash.alert = new_procedure.errors.full_messages + redirect_to admin_procedures_path + end + end + + rescue ActiveRecord::RecordNotFound + flash.alert = 'Démarche inexistante' + redirect_to admin_procedures_path + end + + def archive + procedure = current_administrateur.procedures.find(params[:procedure_id]) + procedure.close! + + flash.notice = "Démarche close" + redirect_to admin_procedures_path + + rescue ActiveRecord::RecordNotFound + flash.alert = 'Démarche inexistante' + redirect_to admin_procedures_path + end + def destroy procedure = current_administrateur.procedures.find(params[:id]) @@ -219,5 +270,9 @@ module NewAdministrateur def allow_decision_access_params params.require(:experts_procedure).permit(:allow_decision_access) end + + def cloned_from_library? + params[:from_new_from_existing].present? + end end end diff --git a/app/views/admin/instructeurs/_informations.html.haml b/app/views/admin/instructeurs/_informations.html.haml deleted file mode 100644 index 34a4ea5e8..000000000 --- a/app/views/admin/instructeurs/_informations.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.form-group - %p.notice - = 'Email *' - = text_field_tag 'instructeur[email]', nil, class: 'form-control', placeholder: 'ex : laura.azema@exemple.gouv.fr' diff --git a/app/views/admin/instructeurs/_list.html.haml b/app/views/admin/instructeurs/_list.html.haml deleted file mode 100644 index b1d8b2f66..000000000 --- a/app/views/admin/instructeurs/_list.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -- if smart_listing.present? - %table.table#liste-instructeur - %thead - %th#libelle= smart_listing.sortable 'Email', 'email' - %th - - - @instructeurs.each do |instructeur| - %tr - %td{ style: 'padding-top: 11px; font-size: 15px;' }= instructeur.email - %td{ style: 'text-align: right;' } - .delete.btn.btn-sm.fa.fa-trash - - .confirm - = link_to 'Valider', admin_instructeur_path(id: instructeur.id), { method: :delete, class: 'btn btn-sm btn-success' } - .cancel.btn.btn-sm.btn-danger.fa.fa-minus{ style: 'top: 0;' } - - = smart_listing.paginate - = smart_listing.pagination_per_page_links - -- else - %h4.center - Aucun instructeur diff --git a/app/views/admin/instructeurs/index.html.haml b/app/views/admin/instructeurs/index.html.haml deleted file mode 100644 index 1860442f6..000000000 --- a/app/views/admin/instructeurs/index.html.haml +++ /dev/null @@ -1,28 +0,0 @@ -%h1 Instructeurs disponibles - -%p - Cette page vous permet de gérer la liste des instructeurs disponibles pour être affectés à une démarche. - -%p{ style: 'font-style: italic' } - N.B. : cette page ne concerne que la liste des personnes disponibles. Si vous souhaitez affecter ou enlever un instructeur d’une démarche particulière, - utilisez plutôt la - = link_to "page de la démarche", admin_procedures_path - concernée. - -.row - .col-xs-4 - - = smart_listing_render :instructeurs - .col-xs-1 -   - .col-xs-6 - %h3 Ajouter un instructeur - #procedure_new.section.section-label - = form_with url: { controller: 'admin/instructeurs', action: :create } do - .row - .col-xs-5 - = render partial: 'admin/instructeurs/informations' - .col-xs-2 - %br - %br - = submit_tag 'Ajouter', class: 'btn btn-info', style: 'float: left;' diff --git a/app/views/admin/instructeurs/index.js.erb b/app/views/admin/instructeurs/index.js.erb deleted file mode 100644 index 35f7cb74c..000000000 --- a/app/views/admin/instructeurs/index.js.erb +++ /dev/null @@ -1 +0,0 @@ -<%= smart_listing_update :instructeurs %> diff --git a/app/views/new_administrateur/procedures/_publication_form.html.haml b/app/views/new_administrateur/procedures/_publication_form.html.haml index d7f0c8f45..1af036c6a 100644 --- a/app/views/new_administrateur/procedures/_publication_form.html.haml +++ b/app/views/new_administrateur/procedures/_publication_form.html.haml @@ -17,7 +17,6 @@ class: 'form', pattern: '^[a-z0-9_-]{3,200}$', title: "De 3 à 200 caractères; minuscules, chiffres et tiret seulement", - data: { debounce: true, url: admin_procedure_publish_validate_path(procedure)}, autocomplete: 'off', style: 'width: 300px; display: inline;') .text-info.mb-4 diff --git a/app/views/admin/procedures/new_from_existing.html.haml b/app/views/new_administrateur/procedures/new_from_existing.html.haml similarity index 100% rename from app/views/admin/procedures/new_from_existing.html.haml rename to app/views/new_administrateur/procedures/new_from_existing.html.haml diff --git a/config/routes.rb b/config/routes.rb index 52f57517a..f1cc0e1a7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -193,27 +193,9 @@ Rails.application.routes.draw do get 'procedures/archived', to: redirect('/admin/procedures?statut=archivees') get 'procedures/draft', to: redirect('/admin/procedures?statut=brouillons') - resources :procedures, only: [:destroy] do - collection do - get 'new_from_existing' => 'procedures#new_from_existing', as: :new_from_existing - end - - member do - delete :delete_logo - delete :delete_deliberation - delete :delete_notice - end - - put 'archive' => 'procedures#archive', as: :archive - get 'publish_validate' => 'procedures#publish_validate', as: :publish_validate - put 'clone' => 'procedures#clone', as: :clone - end - namespace :assigns do get 'show' # delete after fixed tests admin/instructeurs/show_spec without this line end - - resources :instructeurs, only: [:index, :create, :destroy] end resources :invites, only: [:show, :destroy] do @@ -400,7 +382,11 @@ Rails.application.routes.draw do # namespace :admin, module: 'new_administrateur' do - resources :procedures, except: [:destroy] do + resources :procedures do + collection do + get 'new_from_existing' + end + member do get 'apercu' get 'champs' @@ -413,6 +399,8 @@ Rails.application.routes.draw do put :experts_require_administrateur_invitation end + put 'clone' + put 'archive' get 'publication' => 'procedures#publication', as: :publication put 'publish' => 'procedures#publish', as: :publish get 'transfert' => 'procedures#transfert', as: :transfert diff --git a/spec/controllers/admin/instructeurs_controller_spec.rb b/spec/controllers/admin/instructeurs_controller_spec.rb deleted file mode 100644 index 3bf695cdf..000000000 --- a/spec/controllers/admin/instructeurs_controller_spec.rb +++ /dev/null @@ -1,177 +0,0 @@ -describe Admin::InstructeursController, type: :controller do - let(:admin) { create(:administrateur) } - let(:email_2) { 'plip@octo.com' } - let(:admin_2) { create :administrateur, email: email_2 } - - before do - sign_in(admin.user) - end - - describe 'GET #index' do - subject { get :index } - it { expect(subject.status).to eq(200) } - end - - describe 'GET #index with sorting and pagination' do - subject { - get :index, params: { - 'instructeurs_smart_listing[page]': 1, - 'instructeurs_smart_listing[per_page]': 10, - 'instructeurs_smart_listing[sort][email]': 'asc' - } - } - - it { expect(subject.status).to eq(200) } - end - - describe 'POST #create' do - let(:email) { 'test@plop.com' } - let(:procedure_id) { nil } - subject { post :create, params: { instructeur: { email: email }, procedure_id: procedure_id } } - - context 'When email is valid' do - before do - subject - end - - let(:instructeur) { Instructeur.last } - - it { expect(response.status).to eq(302) } - it { expect(response).to redirect_to admin_instructeurs_path } - - context 'when procedure_id params is not null' do - let(:procedure) { create :procedure } - let(:procedure_id) { procedure.id } - it { expect(response.status).to eq(302) } - it { expect(response).to redirect_to admin_procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur) } - end - - describe 'Instructeur attributs in database' do - it { expect(instructeur.email).to eq(email) } - end - - describe 'New instructeur is assign to the admin' do - it { expect(instructeur.administrateurs).to include admin } - it { expect(admin.instructeurs).to include instructeur } - end - end - - context 'when email is not valid' do - before do - subject - end - let(:email) { 'piou' } - it { expect(response.status).to eq(302) } - it { expect { response }.not_to change(Instructeur, :count) } - it { expect(flash[:alert]).to be_present } - - describe 'Email Notification' do - it { - expect(InstructeurMailer).not_to receive(:new_instructeur) - expect(InstructeurMailer).not_to receive(:deliver_later) - subject - } - end - end - - context 'when email is empty' do - before do - subject - end - let(:email) { '' } - it { expect(response.status).to eq(302) } - it { expect { response }.not_to change(Instructeur, :count) } - - it 'Notification email is not send' do - expect(InstructeurMailer).not_to receive(:new_instructeur) - expect(InstructeurMailer).not_to receive(:deliver_later) - end - end - - context 'when email is already assign at the admin' do - before do - create :instructeur, email: email, administrateurs: [admin] - subject - end - - it { expect(response.status).to eq(302) } - it { expect { response }.not_to change(Instructeur, :count) } - it { expect(flash[:alert]).to be_present } - - describe 'Email notification' do - it 'is not sent when email already exists' do - expect(InstructeurMailer).not_to receive(:new_instructeur) - expect(InstructeurMailer).not_to receive(:deliver_later) - - subject - end - end - end - - context 'when an other admin will add the same email' do - let(:instructeur) { Instructeur.by_email(email) } - - before do - create :instructeur, email: email, administrateurs: [admin] - - sign_out(admin.user) - sign_in(admin_2.user) - - subject - end - - it { expect(response.status).to eq(302) } - it { expect { response }.not_to change(Instructeur, :count) } - it { expect(flash[:notice]).to be_present } - - it { expect(admin_2.instructeurs).to include instructeur } - it { expect(instructeur.administrateurs.size).to eq 2 } - end - - context 'when an other admin will add the same email with some uppercase in it' do - let(:email) { 'Test@Plop.com' } - let(:instructeur) { Instructeur.by_email(email.downcase) } - - before do - create :instructeur, email: email, administrateurs: [admin] - - sign_out(admin.user) - sign_in(admin_2.user) - - subject - end - - it { expect(admin_2.instructeurs).to include instructeur } - end - - context 'Email notification' do - it 'Notification email is sent when instructeur is create' do - expect_any_instance_of(User).to receive(:invite!) - subject - end - end - end - - describe 'DELETE #destroy' do - let(:email) { 'test@plop.com' } - let!(:admin) { create :administrateur } - let!(:instructeur) { create :instructeur, email: email, administrateurs: [admin] } - - subject { delete :destroy, params: { id: instructeur.id } } - - context "when gestionaire_id is valid" do - before do - subject - admin.reload - instructeur.reload - end - - it { expect(response.status).to eq(302) } - it { expect(response).to redirect_to admin_instructeurs_path } - it { expect(admin.instructeurs).not_to include instructeur } - it { expect(instructeur.administrateurs).not_to include admin } - end - - it { expect { subject }.not_to change(Instructeur, :count) } - end -end diff --git a/spec/controllers/admin/procedures_controller_spec.rb b/spec/controllers/admin/procedures_controller_spec.rb deleted file mode 100644 index 2ebfc636f..000000000 --- a/spec/controllers/admin/procedures_controller_spec.rb +++ /dev/null @@ -1,280 +0,0 @@ -require 'uri' - -describe Admin::ProceduresController, type: :controller do - let(:admin) { create(:administrateur) } - - let(:bad_procedure_id) { 100000 } - - let(:path) { 'ma-jolie-demarche' } - let(:libelle) { 'Démarche de test' } - let(:description) { 'Description de test' } - let(:organisation) { 'Organisation de test' } - let(:direction) { 'Direction de test' } - let(:cadre_juridique) { 'cadre juridique' } - let(:duree_conservation_dossiers_dans_ds) { 3 } - let(:duree_conservation_dossiers_hors_ds) { 6 } - let(:monavis_embed) { nil } - let(:lien_site_web) { 'http://mon-site.gouv.fr' } - - let(:procedure_params) { - { - path: path, - libelle: libelle, - description: description, - organisation: organisation, - direction: direction, - cadre_juridique: cadre_juridique, - duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds, - duree_conservation_dossiers_hors_ds: duree_conservation_dossiers_hors_ds, - monavis_embed: monavis_embed, - lien_site_web: lien_site_web - } - } - - before do - sign_in(admin.user) - end - - describe 'GET #published' do - subject { get :published } - - it { expect(response.status).to eq(200) } - end - - describe 'DELETE #destroy' do - let(:procedure_draft) { create(:procedure, administrateurs: [admin]) } - let(:procedure_published) { create(:procedure, :published, administrateurs: [admin]) } - let(:procedure_closed) { create(:procedure, :closed, administrateurs: [admin]) } - let(:procedure) { dossier.procedure } - - subject { delete :destroy, params: { id: procedure } } - - context 'when the procedure is a brouillon' do - let(:dossier) { create(:dossier, :en_instruction, procedure: procedure_draft) } - - before { subject } - - it 'discard the procedure' do - expect(procedure.reload.discarded?).to be_truthy - end - - it 'deletes associated dossiers' do - expect(procedure.dossiers.with_discarded.count).to eq(0) - end - - it 'redirects to the procedure drafts page' do - expect(response).to redirect_to admin_procedures_draft_path - expect(flash[:notice]).to be_present - end - end - - context 'when procedure is published' do - let(:dossier) { create(:dossier, :en_instruction, procedure: procedure_published) } - - before { subject } - - it { expect(response.status).to eq 403 } - - context 'when dossier is en_construction' do - let(:dossier) { create(:dossier, :en_construction, procedure: procedure_published) } - - it { expect(procedure.reload.close?).to be_truthy } - it { expect(procedure.reload.discarded?).to be_truthy } - it { expect(dossier.reload.discarded?).to be_truthy } - end - end - - context 'when procedure is closed' do - let(:dossier) { create(:dossier, :en_instruction, procedure: procedure_closed) } - - before { subject } - - it { expect(response.status).to eq 403 } - - context 'when dossier is en_construction' do - let(:dossier) { create(:dossier, :en_construction, procedure: procedure_published) } - - it { expect(procedure.reload.discarded?).to be_truthy } - it { expect(dossier.reload.discarded?).to be_truthy } - end - end - - context "when administrateur does not own the procedure" do - let(:dossier) { create(:dossier) } - - it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) } - end - end - - describe 'PUT #archive' do - let(:procedure) { create(:procedure, :published, administrateur: admin, lien_site_web: lien_site_web) } - - context 'when admin is the owner of the procedure' do - before do - put :archive, params: { procedure_id: procedure.id } - procedure.reload - end - - context 'when owner want archive procedure' do - it { expect(procedure.close?).to be_truthy } - it { expect(response).to redirect_to :admin_procedures } - it { expect(flash[:notice]).to have_content 'Démarche close' } - end - end - - context 'when admin is not the owner of the procedure' do - let(:admin_2) { create(:administrateur) } - - before do - sign_out(admin.user) - sign_in(admin_2.user) - - put :archive, params: { procedure_id: procedure.id } - procedure.reload - end - - it { expect(response).to redirect_to :admin_procedures } - it { expect(flash[:alert]).to have_content 'Démarche inexistante' } - end - end - - describe 'PUT #clone' do - let!(:procedure) { create(:procedure, :with_notice, :with_deliberation, administrateur: admin) } - let(:params) { { procedure_id: procedure.id } } - subject { put :clone, params: params } - - before do - response = Typhoeus::Response.new(code: 200, body: 'Hello world') - Typhoeus.stub(/active_storage\/disk/).and_return(response) - end - - it { expect { subject }.to change(Procedure, :count).by(1) } - - context 'when admin is the owner of the procedure' do - before { subject } - - it 'creates a new procedure and redirect to it' do - expect(response).to redirect_to edit_admin_procedure_path(id: Procedure.last.id) - expect(Procedure.last.cloned_from_library).to be_falsey - expect(Procedure.last.notice.attached?).to be_truthy - expect(Procedure.last.deliberation.attached?).to be_truthy - expect(flash[:notice]).to have_content 'Démarche clonée' - end - - context 'when the procedure is cloned from the library' do - let(:params) { { procedure_id: procedure.id, from_new_from_existing: true } } - - it { expect(Procedure.last.cloned_from_library).to be(true) } - end - end - - context 'when admin is not the owner of the procedure' do - let(:admin_2) { create(:administrateur) } - - before do - sign_out(admin.user) - sign_in(admin_2.user) - subject - end - - it 'creates a new procedure and redirect to it' do - expect(response).to redirect_to edit_admin_procedure_path(id: Procedure.last.id) - expect(flash[:notice]).to have_content 'Démarche clonée' - end - end - end - - describe 'GET #new_from_existing' do - before do - stub_const("Admin::ProceduresController::SIGNIFICANT_DOSSIERS_THRESHOLD", 2) - end - - subject { get :new_from_existing } - let(:grouped_procedures) { subject; assigns(:grouped_procedures) } - let(:response_procedures) { grouped_procedures.map { |_o, procedures| procedures }.flatten } - - describe 'selecting' do - let!(:large_draft_procedure) { create(:procedure_with_dossiers, dossiers_count: 2) } - let!(:large_published_procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2) } - let!(:large_closed_procedure) { create(:procedure_with_dossiers, :closed, dossiers_count: 2) } - let!(:small_closed_procedure) { create(:procedure_with_dossiers, :closed, dossiers_count: 1) } - - it 'displays published and closed procedures' do - expect(response_procedures).to include(large_published_procedure) - expect(response_procedures).to include(large_closed_procedure) - end - - it 'doesn’t display procedures without a significant number of dossiers' do - expect(response_procedures).not_to include(small_closed_procedure) - end - - it 'doesn’t display draft procedures' do - expect(response_procedures).not_to include(large_draft_procedure) - end - end - - describe 'grouping' do - let(:service_1) { create(:service, nom: 'DDT des Vosges') } - let(:service_2) { create(:service, nom: 'DDT du Loiret') } - let!(:procedure_with_service_1) { create(:procedure_with_dossiers, :published, organisation: nil, service: service_1, dossiers_count: 2) } - let!(:procedure_with_service_2) { create(:procedure_with_dossiers, :published, organisation: nil, service: service_2, dossiers_count: 2) } - let!(:procedure_without_service) { create(:procedure_with_dossiers, :published, organisation: 'DDT du Loiret', dossiers_count: 2) } - - it 'groups procedures with services as well as procedures with organisations' do - expect(grouped_procedures.length).to eq 2 - expect(grouped_procedures.find { |o, _p| o == 'DDT des Vosges' }.last).to contain_exactly(procedure_with_service_1) - expect(grouped_procedures.find { |o, _p| o == 'DDT du Loiret' }.last).to contain_exactly(procedure_with_service_2, procedure_without_service) - end - end - end - - describe "DELETE #delete_deliberation" do - context "with a demarche the admin owns" do - let(:procedure) { create(:procedure, :with_deliberation, administrateur: admin) } - - before do - delete :delete_deliberation, params: { id: procedure.id } - procedure.reload - end - - it { expect(procedure.deliberation.attached?).to eq(false) } - it { expect(response).to redirect_to(edit_admin_procedure_path(procedure)) } - end - - context "with a demarche the admin does not own" do - let(:procedure) { create(:procedure, :with_deliberation) } - - before do - delete :delete_deliberation, params: { id: procedure.id } - procedure.reload - end - - it { expect(response.status).to eq(404) } - end - end - - describe "DELETE #delete_notice" do - context "with a demarche the admin owns" do - let(:procedure) { create(:procedure, :with_notice, administrateur: admin) } - - before do - delete :delete_notice, params: { id: procedure.id } - procedure.reload - end - - it { expect(procedure.notice.attached?).to eq(false) } - it { expect(response).to redirect_to(edit_admin_procedure_path(procedure)) } - end - - context "with a demarche the admin does not own" do - let(:procedure) { create(:procedure, :with_notice) } - - before do - delete :delete_notice, params: { id: procedure.id } - procedure.reload - end - - it { expect(response.status).to eq(404) } - end - end -end diff --git a/spec/controllers/new_administrateur/procedures_controller_spec.rb b/spec/controllers/new_administrateur/procedures_controller_spec.rb index 6dfe388fb..2e5e57e1a 100644 --- a/spec/controllers/new_administrateur/procedures_controller_spec.rb +++ b/spec/controllers/new_administrateur/procedures_controller_spec.rb @@ -64,6 +64,50 @@ describe NewAdministrateur::ProceduresController, type: :controller do it { expect(subject.status).to eq(200) } end + describe 'GET #new_from_existing' do + before do + stub_const("NewAdministrateur::ProceduresController::SIGNIFICANT_DOSSIERS_THRESHOLD", 2) + end + + subject { get :new_from_existing } + let(:grouped_procedures) { subject; assigns(:grouped_procedures) } + let(:response_procedures) { grouped_procedures.map { |_o, procedures| procedures }.flatten } + + describe 'selecting' do + let!(:large_draft_procedure) { create(:procedure_with_dossiers, dossiers_count: 2) } + let!(:large_published_procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2) } + let!(:large_closed_procedure) { create(:procedure_with_dossiers, :closed, dossiers_count: 2) } + let!(:small_closed_procedure) { create(:procedure_with_dossiers, :closed, dossiers_count: 1) } + + it 'displays published and closed procedures' do + expect(response_procedures).to include(large_published_procedure) + expect(response_procedures).to include(large_closed_procedure) + end + + it 'doesn’t display procedures without a significant number of dossiers' do + expect(response_procedures).not_to include(small_closed_procedure) + end + + it 'doesn’t display draft procedures' do + expect(response_procedures).not_to include(large_draft_procedure) + end + end + + describe 'grouping' do + let(:service_1) { create(:service, nom: 'DDT des Vosges') } + let(:service_2) { create(:service, nom: 'DDT du Loiret') } + let!(:procedure_with_service_1) { create(:procedure_with_dossiers, :published, organisation: nil, service: service_1, dossiers_count: 2) } + let!(:procedure_with_service_2) { create(:procedure_with_dossiers, :published, organisation: nil, service: service_2, dossiers_count: 2) } + let!(:procedure_without_service) { create(:procedure_with_dossiers, :published, organisation: 'DDT du Loiret', dossiers_count: 2) } + + it 'groups procedures with services as well as procedures with organisations' do + expect(grouped_procedures.length).to eq 2 + expect(grouped_procedures.find { |o, _p| o == 'DDT des Vosges' }.last).to contain_exactly(procedure_with_service_1) + expect(grouped_procedures.find { |o, _p| o == 'DDT du Loiret' }.last).to contain_exactly(procedure_with_service_2, procedure_without_service) + end + end + end + describe 'GET #edit' do let(:published_at) { nil } let(:procedure) { create(:procedure, administrateur: admin, published_at: published_at) } @@ -250,6 +294,154 @@ describe NewAdministrateur::ProceduresController, type: :controller do end end + describe 'PUT #clone' do + let(:procedure) { create(:procedure, :with_notice, :with_deliberation, administrateur: admin) } + let(:params) { { procedure_id: procedure.id } } + + subject { put :clone, params: params } + + before do + procedure + + response = Typhoeus::Response.new(code: 200, body: 'Hello world') + Typhoeus.stub(/active_storage\/disk/).and_return(response) + end + + it { expect { subject }.to change(Procedure, :count).by(1) } + + context 'when admin is the owner of the procedure' do + before { subject } + + it 'creates a new procedure and redirect to it' do + expect(response).to redirect_to edit_admin_procedure_path(id: Procedure.last.id) + expect(Procedure.last.cloned_from_library).to be_falsey + expect(Procedure.last.notice.attached?).to be_truthy + expect(Procedure.last.deliberation.attached?).to be_truthy + expect(flash[:notice]).to have_content 'Démarche clonée' + end + + context 'when the procedure is cloned from the library' do + let(:params) { { procedure_id: procedure.id, from_new_from_existing: true } } + + it { expect(Procedure.last.cloned_from_library).to be(true) } + end + end + + context 'when admin is not the owner of the procedure' do + let(:admin_2) { create(:administrateur) } + + before do + sign_out(admin.user) + sign_in(admin_2.user) + subject + end + + it 'creates a new procedure and redirect to it' do + expect(response).to redirect_to edit_admin_procedure_path(id: Procedure.last.id) + expect(flash[:notice]).to have_content 'Démarche clonée' + end + end + end + + describe 'PUT #archive' do + let(:procedure) { create(:procedure, :published, administrateur: admin, lien_site_web: lien_site_web) } + + context 'when the admin is an owner of the procedure' do + before do + put :archive, params: { procedure_id: procedure.id } + procedure.reload + end + + it 'archives the procedure' do + expect(procedure.close?).to be_truthy + expect(response).to redirect_to :admin_procedures + expect(flash[:notice]).to have_content 'Démarche close' + end + end + + context 'when the admin is not an owner of the procedure' do + let(:admin_2) { create(:administrateur) } + + before do + sign_out(admin.user) + sign_in(admin_2.user) + + put :archive, params: { procedure_id: procedure.id } + procedure.reload + end + + it 'displays an error message' do + expect(response).to redirect_to :admin_procedures + expect(flash[:alert]).to have_content 'Démarche inexistante' + end + end + end + + describe 'DELETE #destroy' do + let(:procedure_draft) { create(:procedure, administrateurs: [admin]) } + let(:procedure_published) { create(:procedure, :published, administrateurs: [admin]) } + let(:procedure_closed) { create(:procedure, :closed, administrateurs: [admin]) } + let(:procedure) { dossier.procedure } + + subject { delete :destroy, params: { id: procedure } } + + context 'when the procedure is a brouillon' do + let(:dossier) { create(:dossier, :en_instruction, procedure: procedure_draft) } + + before { subject } + + it 'discard the procedure' do + expect(procedure.reload.discarded?).to be_truthy + end + + it 'deletes associated dossiers' do + expect(procedure.dossiers.with_discarded.count).to eq(0) + end + + it 'redirects to the procedure drafts page' do + expect(response).to redirect_to admin_procedures_draft_path + expect(flash[:notice]).to be_present + end + end + + context 'when procedure is published' do + let(:dossier) { create(:dossier, :en_instruction, procedure: procedure_published) } + + before { subject } + + it { expect(response.status).to eq 403 } + + context 'when dossier is en_construction' do + let(:dossier) { create(:dossier, :en_construction, procedure: procedure_published) } + + it { expect(procedure.reload.close?).to be_truthy } + it { expect(procedure.reload.discarded?).to be_truthy } + it { expect(dossier.reload.discarded?).to be_truthy } + end + end + + context 'when procedure is closed' do + let(:dossier) { create(:dossier, :en_instruction, procedure: procedure_closed) } + + before { subject } + + it { expect(response.status).to eq 403 } + + context 'when dossier is en_construction' do + let(:dossier) { create(:dossier, :en_construction, procedure: procedure_published) } + + it { expect(procedure.reload.discarded?).to be_truthy } + it { expect(dossier.reload.discarded?).to be_truthy } + end + end + + context "when administrateur does not own the procedure" do + let(:dossier) { create(:dossier) } + + it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) } + end + end + describe 'PATCH #monavis' do let!(:procedure) { create(:procedure, administrateur: admin) } let(:procedure_params) { diff --git a/spec/features/instructeurs/instructeur_creation_spec.rb b/spec/features/instructeurs/instructeur_creation_spec.rb index 776bb027b..978b068c3 100644 --- a/spec/features/instructeurs/instructeur_creation_spec.rb +++ b/spec/features/instructeurs/instructeur_creation_spec.rb @@ -5,13 +5,14 @@ feature 'As an instructeur', js: true do before do login_as administrateur.user, scope: :user - visit admin_instructeurs_path - fill_in :instructeur_email, with: instructeur_email + visit admin_procedure_path(procedure) + find('#groupe-instructeurs').click - perform_enqueued_jobs do - click_button 'Ajouter' - end + find("input[aria-label='email instructeur'").send_keys(instructeur_email, :enter) + perform_enqueued_jobs { click_on 'Affecter' } + + expect(page).to have_text("Les instructeurs ont bien été affectés à la démarche") end scenario 'I can register' do diff --git a/spec/views/admin/instructeurs/index.html.haml_spec.rb b/spec/views/admin/instructeurs/index.html.haml_spec.rb deleted file mode 100644 index 96d3c4c91..000000000 --- a/spec/views/admin/instructeurs/index.html.haml_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -describe 'admin/instructeurs/index.html.haml', type: :view do - let(:admin) { create(:administrateur) } - - before do - assign(:instructeurs, (smart_listing_create :instructeurs, - admin.instructeurs, - partial: "admin/instructeurs/list", - array: true)) - assign(:instructeur, create(:instructeur)) - end - - context 'Aucun instructeur' do - before do - render - end - it { expect(rendered).to have_content('Aucun instructeur') } - end - - context 'Ajout d\'un instructeur' do - before do - create(:instructeur, administrateurs: [admin]) - admin.reload - assign(:instructeurs, (smart_listing_create :instructeurs, - admin.instructeurs, - partial: "admin/instructeurs/list", - array: true)) - render - end - it { expect(rendered).to match(/inst\d+@inst.com/) } - end -end