commit
9b9c03fc35
25 changed files with 175 additions and 92 deletions
2
.github/workflows/rebase.yml
vendored
2
.github/workflows/rebase.yml
vendored
|
@ -13,6 +13,6 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
- name: Automatic Rebase
|
||||
uses: cirrus-actions/rebase@1.3.1
|
||||
uses: cirrus-actions/rebase@1.5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -45,11 +45,7 @@ Les informations nécessaire à l'initialisation de la base doivent être pré-c
|
|||
|
||||
Sous Ubuntu, certains packages doivent être installés au préalable :
|
||||
|
||||
sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev libcurl4-gnutls-dev zlib1g-dev libgeos-dev
|
||||
|
||||
Sous Mac, certains packages doivent être installés au préalable :
|
||||
|
||||
brew install geos
|
||||
sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev libcurl4-gnutls-dev zlib1g-dev
|
||||
|
||||
Afin d'initialiser l'environnement de développement, exécutez la commande suivante :
|
||||
|
||||
|
|
|
@ -5,9 +5,6 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
MAINTENANCE_MESSAGE = 'Le site est actuellement en maintenance. Il sera à nouveau disponible dans un court instant.'
|
||||
|
||||
# Prevent CSRF attacks by raising an exception.
|
||||
# For APIs, you may want to use :null_session instead.
|
||||
protect_from_forgery with: :exception, if: -> { !Rails.env.test? }
|
||||
before_action :set_current_roles
|
||||
before_action :set_sentry_user
|
||||
before_action :redirect_if_untrusted
|
||||
|
|
|
@ -146,6 +146,7 @@ module Instructeurs
|
|||
|
||||
def download_export
|
||||
export_format = params[:export_format]
|
||||
time_span_type = params[:time_span_type] || Export.time_span_types.fetch(:everything)
|
||||
groupe_instructeurs = current_instructeur
|
||||
.groupe_instructeurs
|
||||
.where(procedure: procedure)
|
||||
|
@ -155,11 +156,11 @@ module Instructeurs
|
|||
.fetch_values('tous', 'archives')
|
||||
.sum
|
||||
|
||||
export = Export.find_or_create_export(export_format, groupe_instructeurs)
|
||||
export = Export.find_or_create_export(export_format, time_span_type, groupe_instructeurs)
|
||||
|
||||
if export.ready? && export.old? && params[:force_export]
|
||||
export.destroy
|
||||
export = Export.find_or_create_export(export_format, groupe_instructeurs)
|
||||
export = Export.find_or_create_export(export_format, time_span_type, groupe_instructeurs)
|
||||
end
|
||||
|
||||
if export.ready?
|
||||
|
@ -221,7 +222,7 @@ module Instructeurs
|
|||
end
|
||||
|
||||
def assign_exports
|
||||
@xlsx_export, @csv_export, @ods_export = Export.find_for_groupe_instructeurs(groupe_instructeur_ids)
|
||||
@exports = Export.find_for_groupe_instructeurs(groupe_instructeur_ids)
|
||||
end
|
||||
|
||||
def assign_to
|
||||
|
|
|
@ -173,12 +173,18 @@ module NewAdministrateur
|
|||
groupes_emails = CSV.new(group_csv_file.read.force_encoding("UTF-8"), headers: true, header_converters: :downcase)
|
||||
.map { |r| r.to_h.slice('groupe', 'email') }
|
||||
|
||||
add_instructeurs_and_get_errors = InstructeursImportService.import(procedure, groupes_emails)
|
||||
groupes_emails_has_keys = groupes_emails.first.has_key?("groupe") && groupes_emails.first.has_key?("email")
|
||||
|
||||
if add_instructeurs_and_get_errors.empty?
|
||||
flash[:notice] = "La liste des instructeurs a été importée avec succès"
|
||||
if groupes_emails_has_keys.blank?
|
||||
flash[:alert] = "Importation impossible, veuillez importer un csv #{view_context.link_to('suivant ce modèle', "/import-groupe-test.csv")}"
|
||||
else
|
||||
flash[:alert] = "Import terminé. Cependant les emails suivants ne sont pas pris en compte: #{add_instructeurs_and_get_errors.join(', ')}"
|
||||
add_instructeurs_and_get_errors = InstructeursImportService.import(procedure, groupes_emails)
|
||||
|
||||
if add_instructeurs_and_get_errors.empty?
|
||||
flash[:notice] = "La liste des instructeurs a été importée avec succès"
|
||||
else
|
||||
flash[:alert] = "Import terminé. Cependant les emails suivants ne sont pas pris en compte: #{add_instructeurs_and_get_errors.join(', ')}"
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||
|
|
|
@ -107,4 +107,10 @@ module DossierHelper
|
|||
return base_url if siren.blank?
|
||||
"#{base_url}/entreprise/#{siren}"
|
||||
end
|
||||
|
||||
def exports_list(exports)
|
||||
Export::FORMATS.map do |(format, time_span_type)|
|
||||
[format, time_span_type, exports[format] && exports[format][time_span_type]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
#
|
||||
# Table name: exports
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# format :string not null
|
||||
# key :text not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# id :bigint not null, primary key
|
||||
# format :string not null
|
||||
# key :text not null
|
||||
# time_span_type :string default("everything"), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
class Export < ApplicationRecord
|
||||
MAX_DUREE_CONSERVATION_EXPORT = 3.hours
|
||||
|
@ -17,6 +18,11 @@ class Export < ApplicationRecord
|
|||
xlsx: 'xlsx'
|
||||
}
|
||||
|
||||
enum time_span_type: {
|
||||
everything: 'everything',
|
||||
monthly: 'monthly'
|
||||
}
|
||||
|
||||
has_and_belongs_to_many :groupe_instructeurs
|
||||
|
||||
has_one_attached :file
|
||||
|
@ -27,13 +33,19 @@ class Export < ApplicationRecord
|
|||
|
||||
after_create_commit :compute_async
|
||||
|
||||
FORMATS = [:xlsx, :ods, :csv].flat_map do |format|
|
||||
Export.time_span_types.values.map do |time_span_type|
|
||||
[format, time_span_type]
|
||||
end
|
||||
end
|
||||
|
||||
def compute_async
|
||||
ExportJob.perform_later(self)
|
||||
end
|
||||
|
||||
def compute
|
||||
file.attach(
|
||||
io: io,
|
||||
io: io(since: since),
|
||||
filename: filename,
|
||||
content_type: content_type,
|
||||
# We generate the exports ourselves, so they are safe
|
||||
|
@ -41,6 +53,10 @@ class Export < ApplicationRecord
|
|||
)
|
||||
end
|
||||
|
||||
def since
|
||||
time_span_type == Export.time_span_types.fetch(:monthly) ? 30.days.ago : nil
|
||||
end
|
||||
|
||||
def ready?
|
||||
file.attached?
|
||||
end
|
||||
|
@ -49,16 +65,24 @@ class Export < ApplicationRecord
|
|||
updated_at < 20.minutes.ago
|
||||
end
|
||||
|
||||
def self.find_or_create_export(format, groupe_instructeurs)
|
||||
def self.find_or_create_export(format, time_span_type, groupe_instructeurs)
|
||||
create_with(groupe_instructeurs: groupe_instructeurs)
|
||||
.create_or_find_by(format: format, key: generate_cache_key(groupe_instructeurs.map(&:id)))
|
||||
.create_or_find_by(format: format,
|
||||
time_span_type: time_span_type,
|
||||
key: generate_cache_key(groupe_instructeurs.map(&:id)))
|
||||
end
|
||||
|
||||
def self.find_for_groupe_instructeurs(groupe_instructeurs_ids)
|
||||
exports = where(key: generate_cache_key(groupe_instructeurs_ids))
|
||||
|
||||
['xlsx', 'csv', 'ods']
|
||||
.map { |format| exports.find { |export| export.format == format } }
|
||||
[:xlsx, :csv, :ods].map do |format|
|
||||
[
|
||||
format,
|
||||
Export.time_span_types.values.map do |time_span_type|
|
||||
[time_span_type, exports.find { |export| export.format == format.to_s && export.time_span_type == time_span_type }]
|
||||
end.filter { |(_, export)| export.present? }.to_h
|
||||
]
|
||||
end.filter { |(_, exports)| exports.present? }.to_h
|
||||
end
|
||||
|
||||
def self.generate_cache_key(groupe_instructeurs_ids)
|
||||
|
@ -72,8 +96,11 @@ class Export < ApplicationRecord
|
|||
"dossiers_#{procedure_identifier}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}"
|
||||
end
|
||||
|
||||
def io
|
||||
def io(since: nil)
|
||||
dossiers = Dossier.where(groupe_instructeur: groupe_instructeurs)
|
||||
if since.present?
|
||||
dossiers = dossiers.where('dossiers.en_construction_at > ?', since)
|
||||
end
|
||||
service = ProcedureExportService.new(procedure, dossiers)
|
||||
|
||||
case format.to_sym
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
- elsif weight < 1.gigabyte
|
||||
= link_to instructeur_archives_path(@procedure, type:'monthly', month: month.strftime('%Y-%m')), method: :post, class: "button" do
|
||||
%span.icon.new-folder
|
||||
Démander la création
|
||||
Demander la création
|
||||
- else
|
||||
Archive trop volumineuse
|
||||
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
%span.dropdown
|
||||
%button.button.dropdown-button{ 'aria-expanded' => 'false', 'aria-controls' => 'download-menu' }
|
||||
Télécharger tous les dossiers
|
||||
#download-menu.dropdown-content.fade-in-down{ style: 'width: 330px' }
|
||||
#download-menu.dropdown-content.fade-in-down{ style: 'width: 450px' }
|
||||
%ul.dropdown-items
|
||||
- [[xlsx_export, :xlsx], [ods_export, :ods], [csv_export, :csv]].each do |(export, format)|
|
||||
- exports_list(exports).each do |(format, time_span_type, export)|
|
||||
%li
|
||||
- if export.nil?
|
||||
= link_to t("#{format}_html", scope: [:instructeurs, :procedure, :export_stale]), download_export_instructeur_procedure_path(procedure, export_format: format), remote: true
|
||||
= link_to t("#{time_span_type}_#{format}_html", scope: [:instructeurs, :procedure, :export_stale]), download_export_instructeur_procedure_path(procedure, time_span_type: time_span_type, export_format: format), remote: true
|
||||
- elsif export.ready?
|
||||
= link_to t(:export_ready_html, export_time: time_ago_in_words(export.updated_at), export_format: ".#{format}", scope: [:instructeurs, :procedure]), export.file.service_url, target: "_blank", rel: "noopener"
|
||||
= link_to t("export_#{time_span_type}_ready_html", export_time: time_ago_in_words(export.updated_at), export_format: ".#{format}", scope: [:instructeurs, :procedure]), export.file.service_url, target: "_blank", rel: "noopener"
|
||||
- if export.old?
|
||||
= button_to download_export_instructeur_procedure_path(procedure, export_format: format, force_export: true), class: "button small", style: "padding-right: 2px", title: t(:short, export_format: ".#{format}", scope: [:instructeurs, :procedure, :export_stale]), remote: true, method: :get, params: { export_format: format, force_export: true } do
|
||||
= button_to download_export_instructeur_procedure_path(procedure, export_format: format, time_span_type: time_span_type, force_export: true), class: "button small", style: "padding-right: 2px", title: t("#{time_span_type}_short", export_format: ".#{format}", scope: [:instructeurs, :procedure, :export_stale]), remote: true, method: :get, params: { export_format: format, time_span_type: time_span_type, force_export: true } do
|
||||
.icon.retry
|
||||
- else
|
||||
%span{ 'data-export-poll-url': download_export_instructeur_procedure_path(procedure, export_format: format, no_progress_notification: true) }
|
||||
= t(:export_pending_html, export_time: time_ago_in_words(export.created_at), export_format: ".#{format}", scope: [:instructeurs, :procedure])
|
||||
= t("export_#{time_span_type}_pending_html", export_time: time_ago_in_words(export.created_at), export_format: ".#{format}", scope: [:instructeurs, :procedure])
|
||||
- if procedure.feature_enabled?(:archive_zip_globale)
|
||||
%li
|
||||
= link_to t(:download_archive, scope: [:instructeurs, :procedure]), instructeur_archives_path(procedure)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<%= render_to_element('.procedure-actions', partial: "download_dossiers",
|
||||
locals: { procedure: @procedure, xlsx_export: @xlsx_export, csv_export: @csv_export, ods_export: @ods_export, dossier_count: @dossier_count }) %>
|
||||
<%= render_to_element('.procedure-actions', partial: "download_dossiers", locals: { procedure: @procedure, exports: @exports, dossier_count: @dossier_count }) %>
|
||||
|
||||
<% [[@xlsx_export, :xlsx], [@csv_export, :csv], [@ods_export, :ods]].each do |(export, format)| %>
|
||||
<% if export && !export.ready? %>
|
||||
<%= fire_event('export:update', { url: download_export_instructeur_procedure_path(@procedure, export_format: format, no_progress_notification: true) }.to_json ) %>
|
||||
<% @exports.each do |format, exports| %>
|
||||
<% exports.each do |time_span_type, export| %>
|
||||
<% if !export.ready? %>
|
||||
<%= fire_event('export:update', { url: download_export_instructeur_procedure_path(@procedure, export_format: format, time_span_type: time_span_type, no_progress_notification: true) }.to_json) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -49,8 +49,7 @@
|
|||
badge: number_with_html_delimiter(@archives_count))
|
||||
|
||||
.procedure-actions
|
||||
= render partial: "download_dossiers",
|
||||
locals: { procedure: @procedure, xlsx_export: @xlsx_export, csv_export: @csv_export, ods_export: @ods_export, dossier_count: @tous_count + @archives_count }
|
||||
= render partial: "download_dossiers", locals: { procedure: @procedure, exports: @exports, dossier_count: @tous_count + @archives_count }
|
||||
|
||||
.container
|
||||
- if @statut == 'a-suivre'
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"check_name": "SQL",
|
||||
"message": "Possible SQL injection",
|
||||
"file": "app/models/procedure_presentation.rb",
|
||||
"line": 111,
|
||||
"line": 114,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||
"code": "dossiers.with_type_de_champ_private(column).order(\"champs.value #{order}\")",
|
||||
"render_path": null,
|
||||
|
@ -35,7 +35,7 @@
|
|||
"type": "controller",
|
||||
"class": "Users::DossiersController",
|
||||
"method": "merci",
|
||||
"line": 195,
|
||||
"line": 188,
|
||||
"file": "app/controllers/users/dossiers_controller.rb",
|
||||
"rendered": {
|
||||
"name": "users/dossiers/merci",
|
||||
|
@ -54,20 +54,20 @@
|
|||
{
|
||||
"warning_type": "Redirect",
|
||||
"warning_code": 18,
|
||||
"fingerprint": "8b22d0fa97c6b32921a3383a60dd63f1d2c0723c48f30bdc2d4abe41fe4abccc",
|
||||
"fingerprint": "7e27a03f04576569601d7ec70bddd05c21c4f2de17448e6e093f76844c59e0a0",
|
||||
"check_name": "Redirect",
|
||||
"message": "Possible unprotected redirect",
|
||||
"file": "app/controllers/instructeurs/procedures_controller.rb",
|
||||
"line": 176,
|
||||
"line": 175,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
||||
"code": "redirect_to(Export.find_or_create_export(params[:export_format], current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url)",
|
||||
"code": "redirect_to(Export.find_or_create_export(params[:export_format], (params[:time_span_type] or Export.time_span_types.fetch(:everything)), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url)",
|
||||
"render_path": null,
|
||||
"location": {
|
||||
"type": "method",
|
||||
"class": "Instructeurs::ProceduresController",
|
||||
"method": "download_export"
|
||||
},
|
||||
"user_input": "Export.find_or_create_export(params[:export_format], current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url",
|
||||
"user_input": "Export.find_or_create_export(params[:export_format], (params[:time_span_type] or Export.time_span_types.fetch(:everything)), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url",
|
||||
"confidence": "High",
|
||||
"note": ""
|
||||
},
|
||||
|
@ -98,7 +98,7 @@
|
|||
"check_name": "SQL",
|
||||
"message": "Possible SQL injection",
|
||||
"file": "app/models/procedure_presentation.rb",
|
||||
"line": 106,
|
||||
"line": 109,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||
"code": "dossiers.with_type_de_champ(column).order(\"champs.value #{order}\")",
|
||||
"render_path": null,
|
||||
|
@ -118,7 +118,7 @@
|
|||
"check_name": "SQL",
|
||||
"message": "Possible SQL injection",
|
||||
"file": "app/models/procedure_presentation.rb",
|
||||
"line": 123,
|
||||
"line": 127,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||
"code": "((\"self\" == \"self\") ? (dossiers) : (dossiers.includes(\"self\"))).order(\"#{self.class.sanitized_column(\"self\", column)} #{order}\")",
|
||||
"render_path": null,
|
||||
|
@ -138,7 +138,7 @@
|
|||
"check_name": "SQL",
|
||||
"message": "Possible SQL injection",
|
||||
"file": "app/models/procedure_presentation.rb",
|
||||
"line": 119,
|
||||
"line": 122,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||
"code": "dossiers.includes(:followers_instructeurs).joins(\"LEFT OUTER JOIN users instructeurs_users ON instructeurs_users.instructeur_id = instructeurs.id\").order(\"instructeurs_users.email #{order}\")",
|
||||
"render_path": null,
|
||||
|
@ -152,6 +152,6 @@
|
|||
"note": "`table`, `column` and `order` come from the model, which is validated to prevent injection attacks. Furthermore, `table` and `column` are escaped."
|
||||
}
|
||||
],
|
||||
"updated": "2020-09-17 13:28:51 +0200",
|
||||
"brakeman_version": "4.8.1"
|
||||
"updated": "2021-06-17 09:26:40 +0200",
|
||||
"brakeman_version": "5.0.0"
|
||||
}
|
||||
|
|
|
@ -2,12 +2,18 @@ fr:
|
|||
instructeurs:
|
||||
procedure:
|
||||
export_stale:
|
||||
short: Demander un export au format %{export_format}
|
||||
csv_html: Demander un export au format .csv<br>(uniquement les dossiers, sans les champs répétables)
|
||||
xlsx_html: Demander un export au format .xlsx
|
||||
ods_html: Demander un export au format .ods
|
||||
export_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
||||
export_pending_html: Un export au format %{export_format} est en train d’être généré<br>(demandé il y a %{export_time})
|
||||
everything_short: Demander un export au format %{export_format}
|
||||
everything_csv_html: Demander un export au format .csv<br>(uniquement les dossiers, sans les champs répétables)
|
||||
everything_xlsx_html: Demander un export au format .xlsx
|
||||
everything_ods_html: Demander un export au format .ods
|
||||
monthly_short: Demander un export des 30 derniers jours au format %{export_format}
|
||||
monthly_csv_html: Demander un export des 30 derniers jours au format .csv<br>(uniquement les dossiers, sans les champs répétables)
|
||||
monthly_xlsx_html: Demander un export des 30 derniers jours au format .xlsx
|
||||
monthly_ods_html: Demander un export des 30 derniers jours au format .ods
|
||||
export_everything_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
||||
export_everything_pending_html: Un export au format %{export_format} est en train d’être généré<br>(demandé il y a %{export_time})
|
||||
export_monthly_ready_html: Télécharger l’export des 30 derniers jours au format %{export_format}<br>(généré il y a %{export_time})
|
||||
export_monthly_pending_html: Un export des 30 derniers jours au format %{export_format} est en train d’être généré<br>(demandé il y a %{export_time})
|
||||
download_archive: Télécharger une archive au format .zip de tous les dossiers et leurs pièces jointes
|
||||
archive_pending_html: Archive en cours de création<br>(demandée il y a %{created_period})
|
||||
archive_ready_html: Télécharger l’archive<br>(demandée il y a %{generated_period})
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
class AddTimeSpanTypeToExports < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :exports, :time_span_type, :string, default: 'everything', null: false
|
||||
remove_index :exports, [:format, :key]
|
||||
add_index :exports, [:format, :time_span_type, :key], unique: true
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_06_04_095054) do
|
||||
ActiveRecord::Schema.define(version: 2021_06_05_095054) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -374,7 +374,8 @@ ActiveRecord::Schema.define(version: 2021_06_04_095054) do
|
|||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "key", null: false
|
||||
t.index ["format", "key"], name: "index_exports_on_format_and_key", unique: true
|
||||
t.string "time_span_type", default: "everything", null: false
|
||||
t.index ["format", "time_span_type", "key"], name: "index_exports_on_format_and_time_span_type_and_key", unique: true
|
||||
end
|
||||
|
||||
create_table "exports_groupe_instructeurs", force: :cascade do |t|
|
||||
|
|
|
@ -12,7 +12,7 @@ describe AttachmentsController, type: :controller do
|
|||
|
||||
subject do
|
||||
request.headers['HTTP_REFERER'] = dossier_url(dossier)
|
||||
get :show, params: { id: attachment.id, signed_id: signed_id }, format: format
|
||||
get :show, params: { id: attachment.id, signed_id: signed_id }, format: format, xhr: (format == :js)
|
||||
end
|
||||
|
||||
context 'when authenticated' do
|
||||
|
|
|
@ -116,21 +116,19 @@ describe Champs::CarteController, type: :controller do
|
|||
describe 'GET #index' do
|
||||
render_views
|
||||
|
||||
let(:params) do
|
||||
{ champ_id: champ.id }
|
||||
end
|
||||
|
||||
before do
|
||||
request.accept = "application/javascript"
|
||||
request.content_type = "application/javascript"
|
||||
get :index, params: params
|
||||
get :index, params: params, format: :js, xhr: true
|
||||
end
|
||||
|
||||
context "update list" do
|
||||
it {
|
||||
context 'without focus' do
|
||||
let(:params) do
|
||||
{ champ_id: champ.id }
|
||||
end
|
||||
|
||||
it 'updates the list' do
|
||||
expect(response.body).not_to include("DS.fire('map:feature:focus'")
|
||||
expect(response.status).to eq 200
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context "update list and focus" do
|
||||
|
@ -141,10 +139,10 @@ describe Champs::CarteController, type: :controller do
|
|||
}
|
||||
end
|
||||
|
||||
it {
|
||||
it 'updates the list and focuses the map' do
|
||||
expect(response.body).to include("DS.fire('map:feature:focus'")
|
||||
expect(response.status).to eq 200
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,9 +22,9 @@ describe Champs::DossierLinkController, type: :controller do
|
|||
let(:dossier_id) { dossier.id }
|
||||
|
||||
context 'when the dossier exist' do
|
||||
before {
|
||||
get :show, params: params, format: 'js'
|
||||
}
|
||||
before do
|
||||
get :show, params: params, format: :js, xhr: true
|
||||
end
|
||||
|
||||
it 'renders the procedure name' do
|
||||
expect(response.body).to include('Dossier en brouillon')
|
||||
|
@ -36,9 +36,9 @@ describe Champs::DossierLinkController, type: :controller do
|
|||
|
||||
context 'when the dossier does not exist' do
|
||||
let(:dossier_id) { '13' }
|
||||
before {
|
||||
get :show, params: params, format: 'js'
|
||||
}
|
||||
before do
|
||||
get :show, params: params, format: :js, xhr: true
|
||||
end
|
||||
|
||||
it 'renders error message' do
|
||||
expect(response.body).to include('Ce dossier est inconnu')
|
||||
|
@ -48,9 +48,9 @@ describe Champs::DossierLinkController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not connected' do
|
||||
before {
|
||||
get :show, params: { position: '1' }, format: 'js'
|
||||
}
|
||||
before do
|
||||
get :show, params: { position: '1' }, format: :js, xhr: true
|
||||
end
|
||||
|
||||
it { expect(response.code).to eq('401') }
|
||||
end
|
||||
|
|
|
@ -38,7 +38,7 @@ describe Champs::SiretController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when the SIRET is empty' do
|
||||
subject! { get :show, params: params, format: 'js' }
|
||||
subject! { get :show, params: params, format: :js, xhr: true }
|
||||
|
||||
it 'clears the etablissement and SIRET on the model' do
|
||||
champ.reload
|
||||
|
@ -55,7 +55,7 @@ describe Champs::SiretController, type: :controller do
|
|||
context 'when the SIRET is invalid' do
|
||||
let(:siret) { '1234' }
|
||||
|
||||
subject! { get :show, params: params, format: 'js' }
|
||||
subject! { get :show, params: params, format: :js, xhr: true }
|
||||
|
||||
it 'clears the etablissement and SIRET on the model' do
|
||||
champ.reload
|
||||
|
@ -72,7 +72,7 @@ describe Champs::SiretController, type: :controller do
|
|||
let(:siret) { '82161143100015' }
|
||||
let(:api_etablissement_status) { 503 }
|
||||
|
||||
subject! { get :show, params: params, format: 'js' }
|
||||
subject! { get :show, params: params, format: :js, xhr: true }
|
||||
|
||||
it 'clears the etablissement and SIRET on the model' do
|
||||
champ.reload
|
||||
|
@ -89,7 +89,7 @@ describe Champs::SiretController, type: :controller do
|
|||
let(:siret) { '00000000000000' }
|
||||
let(:api_etablissement_status) { 404 }
|
||||
|
||||
subject! { get :show, params: params, format: 'js' }
|
||||
subject! { get :show, params: params, format: :js, xhr: true }
|
||||
|
||||
it 'clears the etablissement and SIRET on the model' do
|
||||
champ.reload
|
||||
|
@ -107,7 +107,7 @@ describe Champs::SiretController, type: :controller do
|
|||
let(:api_etablissement_status) { 200 }
|
||||
let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
|
||||
|
||||
subject! { get :show, params: params, format: 'js' }
|
||||
subject! { get :show, params: params, format: :js, xhr: true }
|
||||
|
||||
it 'populates the etablissement and SIRET on the model' do
|
||||
champ.reload
|
||||
|
@ -120,7 +120,7 @@ describe Champs::SiretController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not signed in' do
|
||||
subject! { get :show, params: { position: '1' }, format: 'js' }
|
||||
subject! { get :show, params: { position: '1' }, format: :js, xhr: true }
|
||||
|
||||
it { expect(response.code).to eq('401') }
|
||||
end
|
||||
|
|
|
@ -385,6 +385,15 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
|
|||
it { expect(flash.alert).to be_present }
|
||||
it { expect(flash.alert).to eq("Importation impossible : veuillez importer un fichier CSV") }
|
||||
end
|
||||
|
||||
context 'when the headers are wrong' do
|
||||
let(:csv_file) { fixture_file_upload('spec/fixtures/files/invalid-group-file.csv', 'text/csv') }
|
||||
|
||||
before { subject }
|
||||
|
||||
it { expect(flash.alert).to be_present }
|
||||
it { expect(flash.alert).to eq("Importation impossible, veuillez importer un csv <a href=\"/import-groupe-test.csv\">suivant ce modèle</a>") }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_routing_criteria_name' do
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
FactoryBot.define do
|
||||
factory :export do
|
||||
format { :csv }
|
||||
time_span_type { Export.time_span_types.fetch(:everything) }
|
||||
groupe_instructeurs { [association(:groupe_instructeur)] }
|
||||
|
||||
after(:build) do |export, _evaluator|
|
||||
|
|
|
@ -99,6 +99,32 @@ feature 'Instructing a dossier:', js: true do
|
|||
expect(page).to have_text('Aucun dossier')
|
||||
end
|
||||
|
||||
scenario 'A instructeur can request an export' do
|
||||
log_in(instructeur.email, password)
|
||||
|
||||
click_on procedure.libelle
|
||||
test_statut_bar(a_suivre: 1, tous_les_dossiers: 1)
|
||||
assert_performed_jobs 1
|
||||
|
||||
click_on "Télécharger tous les dossiers"
|
||||
click_on "Demander un export au format .xlsx"
|
||||
expect(page).to have_text('Nous générons cet export.')
|
||||
expect(page).to have_text('Un export au format .xlsx est en train d’être généré')
|
||||
|
||||
click_on "Télécharger tous les dossiers"
|
||||
click_on "Demander un export des 30 derniers jours au format .xlsx"
|
||||
expect(page).to have_text('Nous générons cet export.')
|
||||
expect(page).to have_text('Un export des 30 derniers jours au format .xlsx est en train d’être généré')
|
||||
|
||||
perform_enqueued_jobs(only: ExportJob)
|
||||
assert_performed_jobs 3
|
||||
page.driver.browser.navigate.refresh
|
||||
|
||||
click_on "Télécharger tous les dossiers"
|
||||
expect(page).to have_text('Télécharger l’export au format .xlsx')
|
||||
expect(page).to have_text('Télécharger l’export des 30 derniers jours au format .xlsx')
|
||||
end
|
||||
|
||||
scenario 'A instructeur can see the personnes impliquées' do
|
||||
instructeur2 = create(:instructeur, password: password)
|
||||
|
||||
|
|
2
spec/fixtures/files/invalid-group-file.csv
vendored
Normal file
2
spec/fixtures/files/invalid-group-file.csv
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
groupé,email
|
||||
auvergne,kara@gmail.com
|
|
|
@ -48,9 +48,9 @@ RSpec.describe Export, type: :model do
|
|||
context 'when an export is made for one groupe instructeur' do
|
||||
let!(:export) { create(:export, groupe_instructeurs: [gi_1, gi_2]) }
|
||||
|
||||
it { expect(Export.find_for_groupe_instructeurs([gi_1.id])[1]).to eq(nil) }
|
||||
it { expect(Export.find_for_groupe_instructeurs([gi_2.id, gi_1.id])[1]).to eq(export) }
|
||||
it { expect(Export.find_for_groupe_instructeurs([gi_1.id, gi_2.id, gi_3.id])[1]).to eq(nil) }
|
||||
it { expect(Export.find_for_groupe_instructeurs([gi_1.id])).to eq({}) }
|
||||
it { expect(Export.find_for_groupe_instructeurs([gi_2.id, gi_1.id])).to eq({ csv: { 'everything' => export } }) }
|
||||
it { expect(Export.find_for_groupe_instructeurs([gi_1.id, gi_2.id, gi_3.id])).to eq({}) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ describe 'instructeurs/procedures/_download_dossiers.html.haml', type: :view do
|
|||
let(:procedure) { create(:procedure) }
|
||||
let(:dossier_count) { 0 }
|
||||
|
||||
subject { render 'instructeurs/procedures/download_dossiers.html.haml', procedure: procedure, dossier_count: dossier_count, xlsx_export: nil, csv_export: nil, ods_export: nil }
|
||||
subject { render 'instructeurs/procedures/download_dossiers.html.haml', procedure: procedure, dossier_count: dossier_count, exports: {} }
|
||||
|
||||
context "when procedure has 0 dossier" do
|
||||
it { is_expected.not_to include("Télécharger tous les dossiers") }
|
||||
|
|
Loading…
Reference in a new issue