diff --git a/Gemfile b/Gemfile
index 24f8c36c9..e210be466 100644
--- a/Gemfile
+++ b/Gemfile
@@ -59,6 +59,7 @@ gem 'openid_connect'
gem 'pg'
gem 'phonelib'
gem 'prawn-rails' # PDF Generation
+gem 'prawn-svg'
gem 'premailer-rails'
gem 'puma' # Use Puma as the app server
gem 'pundit'
diff --git a/Gemfile.lock b/Gemfile.lock
index 0faaa9859..4485809aa 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -459,6 +459,9 @@ GEM
prawn
prawn-table
rails (>= 3.1.0)
+ prawn-svg (0.31.0)
+ css_parser (~> 1.6)
+ prawn (>= 0.11.1, < 3)
prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0)
premailer (1.14.2)
@@ -837,6 +840,7 @@ DEPENDENCIES
pg
phonelib
prawn-rails
+ prawn-svg
premailer-rails
pry-byebug
puma
diff --git a/app/assets/images/header/logo-ds-wide.png b/app/assets/images/header/logo-ds-wide.png
deleted file mode 100644
index a0ac0f353..000000000
Binary files a/app/assets/images/header/logo-ds-wide.png and /dev/null differ
diff --git a/app/graphql/types/address_type.rb b/app/graphql/types/address_type.rb
index 86a1d8756..60f3370f3 100644
--- a/app/graphql/types/address_type.rb
+++ b/app/graphql/types/address_type.rb
@@ -1,10 +1,10 @@
module Types
class AddressType < Types::BaseObject
class AddressTypeType < Types::BaseEnum
- value(:housenumber, "numéro « à la plaque »", value: :housenumber)
- value(:street, "position « à la voie », placé approximativement au centre de celle-ci", value: :street)
- value(:municipality, "numéro « à la commune »", value: :municipality)
- value(:locality, "lieu-dit", value: :locality)
+ value(:housenumber, "numéro « à la plaque »", value: "housenumber")
+ value(:street, "position « à la voie », placé approximativement au centre de celle-ci", value: "street")
+ value(:municipality, "numéro « à la commune »", value: "municipality")
+ value(:locality, "lieu-dit", value: "locality")
end
field :label, String, "libellé complet de l’adresse", null: false
diff --git a/app/graphql/types/personne_morale_type.rb b/app/graphql/types/personne_morale_type.rb
index c8176befa..2d2d98d2b 100644
--- a/app/graphql/types/personne_morale_type.rb
+++ b/app/graphql/types/personne_morale_type.rb
@@ -104,7 +104,7 @@ module Types
def address
{
label: object.adresse,
- type: :housenumber,
+ type: "housenumber",
street_number: object.numero_voie,
street_name: object.nom_voie,
street_address: object.nom_voie.present? ? [object.numero_voie, object.type_voie, object.nom_voie].compact.join(' ') : nil,
diff --git a/app/lib/active_storage/downloadable_file.rb b/app/lib/active_storage/downloadable_file.rb
index ac1cb2a8d..3f38007be 100644
--- a/app/lib/active_storage/downloadable_file.rb
+++ b/app/lib/active_storage/downloadable_file.rb
@@ -1,7 +1,8 @@
class ActiveStorage::DownloadableFile
def self.create_list_from_dossiers(dossiers, for_expert = false)
- PiecesJustificativesService.generate_dossier_export(dossiers) +
- PiecesJustificativesService.liste_documents(dossiers, for_expert)
+ dossiers
+ .map { |d| pj_and_path(d.id, PiecesJustificativesService.generate_dossier_export(d)) } +
+ PiecesJustificativesService.liste_documents(dossiers, for_expert)
end
private
diff --git a/app/models/dossier.rb b/app/models/dossier.rb
index aa18b21d0..e32aa99db 100644
--- a/app/models/dossier.rb
+++ b/app/models/dossier.rb
@@ -485,9 +485,8 @@ class Dossier < ApplicationRecord
end
def motivation
- if termine?
- traitement&.motivation || read_attribute(:motivation)
- end
+ return nil if !termine?
+ traitement&.motivation || read_attribute(:motivation)
end
def update_search_terms
diff --git a/app/models/export.rb b/app/models/export.rb
index a62872c5b..545935673 100644
--- a/app/models/export.rb
+++ b/app/models/export.rb
@@ -18,8 +18,9 @@ class Export < ApplicationRecord
enum format: {
csv: 'csv',
ods: 'ods',
- xlsx: 'xlsx'
- }
+ xlsx: 'xlsx',
+ zip: 'zip'
+ }, _prefix: true
enum time_span_type: {
everything: 'everything',
@@ -49,11 +50,11 @@ class Export < ApplicationRecord
FORMATS_WITH_TIME_SPAN = [:xlsx, :ods, :csv].flat_map do |format|
time_span_types.keys.map do |time_span_type|
- { format: format.to_sym, time_span_type: time_span_type }
+ { format: format, time_span_type: time_span_type }
end
end
- FORMATS = [:xlsx, :ods, :csv].map do |format|
- { format: format.to_sym }
+ FORMATS = [:xlsx, :ods, :csv, :zip].map do |format|
+ { format: format }
end
def compute_async
@@ -63,13 +64,7 @@ class Export < ApplicationRecord
def compute
load_snapshot!
- file.attach(
- io: io,
- filename: filename,
- content_type: content_type,
- # We generate the exports ourselves, so they are safe
- metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
- )
+ file.attach(blob)
end
def since
@@ -92,18 +87,6 @@ class Export < ApplicationRecord
procedure_presentation_id.present?
end
- def xlsx?
- format == self.class.formats.fetch(:xlsx)
- end
-
- def ods?
- format == self.class.formats.fetch(:ods)
- end
-
- def csv?
- format == self.class.formats.fetch(:csv)
- end
-
def self.find_or_create_export(format, groupe_instructeurs, time_span_type: time_span_types.fetch(:everything), statut: statuts.fetch(:tous), procedure_presentation: nil)
create_with(groupe_instructeurs: groupe_instructeurs, procedure_presentation: procedure_presentation, procedure_presentation_snapshot: procedure_presentation&.snapshot)
.includes(:procedure_presentation)
@@ -124,16 +107,20 @@ class Export < ApplicationRecord
{
xlsx: {
- time_span_type: not_filtered.filter(&:xlsx?).index_by(&:time_span_type),
- statut: filtered.filter(&:xlsx?).index_by(&:statut)
+ time_span_type: not_filtered.filter(&:format_xlsx?).index_by(&:time_span_type),
+ statut: filtered.filter(&:format_xlsx?).index_by(&:statut)
},
ods: {
- time_span_type: not_filtered.filter(&:ods?).index_by(&:time_span_type),
- statut: filtered.filter(&:ods?).index_by(&:statut)
+ time_span_type: not_filtered.filter(&:format_ods?).index_by(&:time_span_type),
+ statut: filtered.filter(&:format_ods?).index_by(&:statut)
},
csv: {
- time_span_type: not_filtered.filter(&:csv?).index_by(&:time_span_type),
- statut: filtered.filter(&:csv?).index_by(&:statut)
+ time_span_type: not_filtered.filter(&:format_csv?).index_by(&:time_span_type),
+ statut: filtered.filter(&:format_csv?).index_by(&:statut)
+ },
+ zip: {
+ time_span_type: {},
+ statut: filtered.filter(&:format_zip?).index_by(&:statut)
}
}
end
@@ -177,32 +164,18 @@ class Export < ApplicationRecord
end
end
- def filename
- procedure_identifier = procedure.path || "procedure-#{procedure.id}"
- "dossiers_#{procedure_identifier}_#{statut}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}"
- end
-
- def io
+ def blob
service = ProcedureExportService.new(procedure, dossiers_for_export)
case format.to_sym
when :csv
- StringIO.new(service.to_csv)
+ service.to_csv
when :xlsx
- StringIO.new(service.to_xlsx)
+ service.to_xlsx
when :ods
- StringIO.new(service.to_ods)
- end
- end
-
- def content_type
- case format.to_sym
- when :csv
- 'text/csv'
- when :xlsx
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
- when :ods
- 'application/vnd.oasis.opendocument.spreadsheet'
+ service.to_ods
+ when :zip
+ service.to_zip
end
end
diff --git a/app/services/archive_uploader.rb b/app/services/archive_uploader.rb
index c3dd7581f..fc644a65e 100644
--- a/app/services/archive_uploader.rb
+++ b/app/services/archive_uploader.rb
@@ -4,7 +4,7 @@ class ArchiveUploader
# when file size is bigger, active storage expects the chunks + a manifest.
MAX_FILE_SIZE_FOR_BACKEND_BEFORE_CHUNKING = ENV.fetch('ACTIVE_STORAGE_FILE_SIZE_THRESHOLD_BEFORE_CUSTOM_UPLOAD') { 4.gigabytes }.to_i
- def upload
+ def upload(archive)
uploaded_blob = create_and_upload_blob
begin
archive.file.purge if archive.file.attached?
@@ -21,9 +21,13 @@ class ArchiveUploader
)
end
+ def blob
+ create_and_upload_blob
+ end
+
private
- attr_reader :procedure, :archive, :filepath
+ attr_reader :procedure, :filename, :filepath
def create_and_upload_blob
if active_storage_service_local? || File.size(filepath) < MAX_FILE_SIZE_FOR_BACKEND_BEFORE_CHUNKING
@@ -62,7 +66,7 @@ class ArchiveUploader
def blob_default_params(filepath)
{
key: namespaced_object_key,
- filename: archive.filename(procedure),
+ filename: filename,
content_type: 'application/zip',
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
}
@@ -89,9 +93,9 @@ class ArchiveUploader
system(ENV.fetch('ACTIVE_STORAGE_BIG_FILE_UPLOADER_WITH_ENCRYPTION_PATH').to_s, filepath, blob.key, exception: true)
end
- def initialize(procedure:, archive:, filepath:)
+ def initialize(procedure:, filename:, filepath:)
@procedure = procedure
- @archive = archive
+ @filename = filename
@filepath = filepath
end
end
diff --git a/app/services/downloadable_file_service.rb b/app/services/downloadable_file_service.rb
new file mode 100644
index 000000000..97909578b
--- /dev/null
+++ b/app/services/downloadable_file_service.rb
@@ -0,0 +1,27 @@
+class DownloadableFileService
+ ARCHIVE_CREATION_DIR = ENV.fetch('ARCHIVE_CREATION_DIR') { '/tmp' }
+
+ def self.download_and_zip(procedure, attachments, filename, &block)
+ Dir.mktmpdir(nil, ARCHIVE_CREATION_DIR) do |tmp_dir|
+ export_dir = File.join(tmp_dir, filename)
+ zip_path = File.join(ARCHIVE_CREATION_DIR, "#{filename}.zip")
+
+ begin
+ FileUtils.remove_entry_secure(export_dir) if Dir.exist?(export_dir)
+ Dir.mkdir(export_dir)
+
+ download_manager = DownloadManager::ProcedureAttachmentsExport.new(procedure, attachments, export_dir)
+ download_manager.download_all
+
+ Dir.chdir(tmp_dir) do
+ File.delete(zip_path) if File.exist?(zip_path)
+ system 'zip', '-0', '-r', zip_path, filename
+ end
+ yield(zip_path)
+ ensure
+ FileUtils.remove_entry_secure(export_dir) if Dir.exist?(export_dir)
+ File.delete(zip_path) if File.exist?(zip_path)
+ end
+ end
+ end
+end
diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb
index 7b8472563..aec2c0378 100644
--- a/app/services/pieces_justificatives_service.rb
+++ b/app/services/pieces_justificatives_service.rb
@@ -107,44 +107,21 @@ class PiecesJustificativesService
end
end
- def self.generate_dossier_export(dossiers)
- return [] if dossiers.empty?
+ def self.generate_dossier_export(dossier)
+ pdf = ApplicationController
+ .render(template: 'dossiers/show', formats: [:pdf],
+ assigns: {
+ include_infos_administration: true,
+ dossier: dossier
+ })
- pdfs = []
-
- procedure = dossiers.first.procedure
- tdc_by_id = TypeDeChamp
- .joins(:revisions)
- .where(revisions: { id: procedure.revisions })
- .to_a
- .group_by(&:id)
-
- dossiers
- .includes(:champs, :champs_private, :commentaires, :individual,
- :traitement, :etablissement,
- user: :france_connect_information, avis: :expert)
- .find_each do |dossier|
- pdf = ApplicationController
- .render(template: 'dossiers/show', formats: [:pdf],
- assigns: {
- include_infos_administration: true,
- dossier: dossier,
- procedure: procedure,
- tdc_by_id: tdc_by_id
- })
-
- a = FakeAttachment.new(
- file: StringIO.new(pdf),
- filename: "export-#{dossier.id}.pdf",
- name: 'pdf_export_for_instructeur',
- id: dossier.id,
- created_at: dossier.updated_at
- )
-
- pdfs << ActiveStorage::DownloadableFile.pj_and_path(dossier.id, a)
- end
-
- pdfs
+ FakeAttachment.new(
+ file: StringIO.new(pdf),
+ filename: "export-#{dossier.id}.pdf",
+ name: 'pdf_export_for_instructeur',
+ id: dossier.id,
+ created_at: dossier.updated_at
+ )
end
private
diff --git a/app/services/procedure_archive_service.rb b/app/services/procedure_archive_service.rb
index 31f0786f6..d0aa7efea 100644
--- a/app/services/procedure_archive_service.rb
+++ b/app/services/procedure_archive_service.rb
@@ -1,8 +1,6 @@
require 'tempfile'
class ProcedureArchiveService
- ARCHIVE_CREATION_DIR = ENV.fetch('ARCHIVE_CREATION_DIR') { '/tmp' }
-
def initialize(procedure)
@procedure = procedure
end
@@ -27,9 +25,9 @@ class ProcedureArchiveService
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers)
- download_and_zip(archive, attachments) do |zip_filepath|
- ArchiveUploader.new(procedure: @procedure, archive: archive, filepath: zip_filepath)
- .upload
+ DownloadableFileService.download_and_zip(@procedure, attachments, zip_root_folder(archive)) do |zip_filepath|
+ ArchiveUploader.new(procedure: @procedure, filename: archive.filename(@procedure), filepath: zip_filepath)
+ .upload(archive)
end
end
@@ -45,30 +43,6 @@ class ProcedureArchiveService
private
- def download_and_zip(archive, attachments, &block)
- Dir.mktmpdir(nil, ARCHIVE_CREATION_DIR) do |tmp_dir|
- archive_dir = File.join(tmp_dir, zip_root_folder(archive))
- zip_path = File.join(ARCHIVE_CREATION_DIR, "#{zip_root_folder(archive)}.zip")
-
- begin
- FileUtils.remove_entry_secure(archive_dir) if Dir.exist?(archive_dir)
- Dir.mkdir(archive_dir)
-
- download_manager = DownloadManager::ProcedureAttachmentsExport.new(@procedure, attachments, archive_dir)
- download_manager.download_all
-
- Dir.chdir(tmp_dir) do
- File.delete(zip_path) if File.exist?(zip_path)
- system 'zip', '-0', '-r', zip_path, zip_root_folder(archive)
- end
- yield(zip_path)
- ensure
- FileUtils.remove_entry_secure(archive_dir) if Dir.exist?(archive_dir)
- File.delete(zip_path) if File.exist?(zip_path)
- end
- end
- end
-
def zip_root_folder(archive)
"procedure-#{@procedure.id}-#{archive.id}"
end
diff --git a/app/services/procedure_export_service.rb b/app/services/procedure_export_service.rb
index 7381b32ea..907426fd6 100644
--- a/app/services/procedure_export_service.rb
+++ b/app/services/procedure_export_service.rb
@@ -1,5 +1,5 @@
class ProcedureExportService
- attr_reader :dossiers
+ attr_reader :procedure, :dossiers
def initialize(procedure, dossiers)
@procedure = procedure
@@ -8,25 +8,72 @@ class ProcedureExportService
end
def to_csv
- SpreadsheetArchitect.to_csv(options_for(:dossiers, :csv))
+ io = StringIO.new(SpreadsheetArchitect.to_csv(options_for(:dossiers, :csv)))
+ create_blob(io, :csv)
end
def to_xlsx
# We recursively build multi page spreadsheet
- @tables.reduce(nil) do |package, table|
+ io = @tables.reduce(nil) do |package, table|
SpreadsheetArchitect.to_axlsx_package(options_for(table, :xlsx), package)
- end.to_stream.read
+ end.to_stream
+ create_blob(io, :xlsx)
end
def to_ods
# We recursively build multi page spreadsheet
- @tables.reduce(nil) do |spreadsheet, table|
+ io = StringIO.new(@tables.reduce(nil) do |spreadsheet, table|
SpreadsheetArchitect.to_rodf_spreadsheet(options_for(table, :ods), spreadsheet)
- end.bytes
+ end.bytes)
+ create_blob(io, :ods)
+ end
+
+ def to_zip
+ attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers, true)
+
+ DownloadableFileService.download_and_zip(procedure, attachments, base_filename) do |zip_filepath|
+ ArchiveUploader.new(procedure: procedure, filename: filename(:zip), filepath: zip_filepath).blob
+ end
end
private
+ def create_blob(io, format)
+ ActiveStorage::Blob.create_and_upload!(
+ io: io,
+ filename: filename(format),
+ content_type: content_type(format),
+ identify: false,
+ # We generate the exports ourselves, so they are safe
+ metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
+ )
+ end
+
+ def base_filename
+ @base_filename ||= "dossiers_#{procedure_identifier}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}"
+ end
+
+ def filename(format)
+ "#{base_filename}.#{format}"
+ end
+
+ def procedure_identifier
+ procedure.path || "procedure-#{procedure.id}"
+ end
+
+ def content_type(format)
+ case format
+ when :csv
+ 'text/csv'
+ when :xlsx
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ when :ods
+ 'application/vnd.oasis.opendocument.spreadsheet'
+ when :zip
+ 'application/zip'
+ end
+ end
+
def etablissements
@etablissements ||= dossiers.flat_map do |dossier|
[dossier.champs, dossier.champs_private]
@@ -40,12 +87,12 @@ class ProcedureExportService
end
def champs_repetables_options
- revision = @procedure.active_revision
+ revision = procedure.active_revision
champs_by_stable_id = dossiers
.flat_map { |dossier| (dossier.champs + dossier.champs_private).filter(&:repetition?) }
.group_by(&:stable_id)
- @procedure.types_de_champ_for_procedure_presentation.repetition
+ procedure.types_de_champ_for_procedure_presentation.repetition
.map { |type_de_champ_repetition| [type_de_champ_repetition, type_de_champ_repetition.types_de_champ_for_revision(revision).to_a] }
.filter { |(_, types_de_champ)| types_de_champ.present? }
.map do |(type_de_champ_repetition, types_de_champ)|
@@ -85,7 +132,7 @@ class ProcedureExportService
end
def spreadsheet_columns(format)
- types_de_champ = @procedure.types_de_champ_for_procedure_presentation.not_repetition.to_a
+ types_de_champ = procedure.types_de_champ_for_procedure_presentation.not_repetition.to_a
Proc.new do |instance|
instance.send(:"spreadsheet_columns_#{format}", types_de_champ: types_de_champ)
diff --git a/app/views/dossiers/dossier_vide.pdf.prawn b/app/views/dossiers/dossier_vide.pdf.prawn
index f941d0537..5678ee1b0 100644
--- a/app/views/dossiers/dossier_vide.pdf.prawn
+++ b/app/views/dossiers/dossier_vide.pdf.prawn
@@ -181,7 +181,7 @@ prawn_document(page_size: "A4") do |pdf|
italic: Rails.root.join('lib/prawn/fonts/marianne/marianne-thin.ttf' ),
})
pdf.font 'marianne'
- pdf.image DOSSIER_PDF_EXPORT_LOGO_SRC, width: 300, position: :center
+ pdf.svg IO.read(DOSSIER_PDF_EXPORT_LOGO_SRC), width: 300, position: :center
pdf.move_down(40)
render_in_2_columns(pdf, 'Démarche', @dossier.procedure.libelle)
diff --git a/app/views/dossiers/show.pdf.prawn b/app/views/dossiers/show.pdf.prawn
index 182d60fc0..b3b86eba6 100644
--- a/app/views/dossiers/show.pdf.prawn
+++ b/app/views/dossiers/show.pdf.prawn
@@ -130,30 +130,28 @@ def add_identite_etablissement(pdf, etablissement)
end
def add_single_champ(pdf, champ)
- tdc = @tdc_by_id[champ.type_de_champ_id].first
-
case champ.type
when 'Champs::PieceJustificativeChamp', 'Champs::TitreIdentiteChamp'
return
when 'Champs::HeaderSectionChamp'
- add_section_title(pdf, tdc.libelle)
+ add_section_title(pdf, champ.libelle)
when 'Champs::ExplicationChamp'
- format_in_2_lines(pdf, tdc.libelle, tdc.description)
+ format_in_2_lines(pdf, champ.libelle, champ.description)
when 'Champs::CarteChamp'
- format_in_2_lines(pdf, tdc.libelle, champ.to_feature_collection.to_json)
+ format_in_2_lines(pdf, champ.libelle, champ.to_feature_collection.to_json)
when 'Champs::SiretChamp'
pdf.font 'marianne', style: :bold do
- pdf.text tdc.libelle
+ pdf.text champ.libelle
end
if champ.etablissement.present?
add_identite_etablissement(pdf, champ.etablissement)
end
when 'Champs::NumberChamp'
value = champ.to_s.empty? ? 'Non communiqué' : number_with_delimiter(champ.to_s)
- format_in_2_lines(pdf, tdc.libelle, value)
+ format_in_2_lines(pdf, champ.libelle, value)
else
value = champ.to_s.empty? ? 'Non communiqué' : champ.to_s
- format_in_2_lines(pdf, tdc.libelle, value)
+ format_in_2_lines(pdf, champ.libelle, value)
end
end
@@ -207,9 +205,6 @@ def add_etats_dossier(pdf, dossier)
end
prawn_document(page_size: "A4") do |pdf|
- @procedure ||= @dossier.procedure
- @tdc_by_id ||= @dossier.champs.map(&:type_de_champ).group_by(&:id)
-
pdf.font_families.update( 'marianne' => {
normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf' ),
bold: Rails.root.join('lib/prawn/fonts/marianne/marianne-bold.ttf' ),
@@ -217,12 +212,12 @@ prawn_document(page_size: "A4") do |pdf|
pdf.font 'marianne'
pdf.pad_bottom(40) do
- pdf.image DOSSIER_PDF_EXPORT_LOGO_SRC, width: 300, position: :center
+ pdf.svg IO.read(DOSSIER_PDF_EXPORT_LOGO_SRC), width: 300, position: :center
end
format_in_2_columns(pdf, 'Dossier Nº', @dossier.id.to_s)
- format_in_2_columns(pdf, 'Démarche', @procedure.libelle)
- format_in_2_columns(pdf, 'Organisme', @procedure.organisation_name)
+ format_in_2_columns(pdf, 'Démarche', @dossier.procedure.libelle)
+ format_in_2_columns(pdf, 'Organisme', @dossier.procedure.organisation_name)
add_etat_dossier(pdf, @dossier)
diff --git a/config/env.example.optional b/config/env.example.optional
index 8cee6a933..51b05c16d 100644
--- a/config/env.example.optional
+++ b/config/env.example.optional
@@ -69,7 +69,7 @@ DS_ENV="staging"
# PROCEDURE_DEFAULT_LOGO_SRC="republique-francaise-logo.svg"
# Instance customization: PDF export logo ---> to be put in "app/assets/images"
-# DOSSIER_PDF_EXPORT_LOGO_SRC="app/assets/images/header/logo-ds-wide.png"
+# DOSSIER_PDF_EXPORT_LOGO_SRC="app/assets/images/header/logo-ds-wide.svg"
# Instance customization: watermark for identity documents
# WATERMARK_FILE=""
diff --git a/config/initializers/images.rb b/config/initializers/images.rb
index 161c9fc24..c488aa279 100644
--- a/config/initializers/images.rb
+++ b/config/initializers/images.rb
@@ -17,4 +17,4 @@ MAILER_FOOTER_LOGO_SRC = ENV.fetch("MAILER_FOOTER_LOGO_SRC", "mailer/instructeur
PROCEDURE_DEFAULT_LOGO_SRC = ENV.fetch("PROCEDURE_DEFAULT_LOGO_SRC", "republique-francaise-logo.svg")
# Logo in PDF export of a "Dossier"
-DOSSIER_PDF_EXPORT_LOGO_SRC = ENV.fetch("DOSSIER_PDF_EXPORT_LOGO_SRC", "app/assets/images/header/logo-ds-wide.png")
+DOSSIER_PDF_EXPORT_LOGO_SRC = ENV.fetch("DOSSIER_PDF_EXPORT_LOGO_SRC", "app/assets/images/header/logo-ds-wide.svg")
diff --git a/config/locales/views/instructeurs/procedures/fr.yml b/config/locales/views/instructeurs/procedures/fr.yml
index 9cf758507..b4139e687 100644
--- a/config/locales/views/instructeurs/procedures/fr.yml
+++ b/config/locales/views/instructeurs/procedures/fr.yml
@@ -5,6 +5,7 @@ fr:
everything_csv_html: Demander un export au format .csv
(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
+ everything_zip_html: Demander un export au format .zip
everything_short: Demander un export au format %{export_format}
everything_pending_html: Un export au format %{export_format} est en train d’être généré
(demandé il y a %{export_time})
everything_ready_html: Télécharger l’export au format %{export_format}
(généré il y a %{export_time})
diff --git a/spec/graphql/dossier_spec.rb b/spec/graphql/dossier_spec.rb
index 7ff4cc1c3..6aba97515 100644
--- a/spec/graphql/dossier_spec.rb
+++ b/spec/graphql/dossier_spec.rb
@@ -31,6 +31,26 @@ RSpec.describe Types::DossierType, type: :graphql do
let(:dossier) { create(:dossier, :accepte, :with_populated_champs, procedure: procedure) }
let(:query) { DOSSIER_WITH_CHAMPS_QUERY }
let(:variables) { { number: dossier.id } }
+ let(:address) do
+ {
+ "type" => "housenumber",
+ "label" => "33 Rue Rébeval 75019 Paris",
+ "city_code" => "75119",
+ "city_name" => "Paris",
+ "postal_code" => "75019",
+ "region_code" => "11",
+ "region_name" => "Île-de-France",
+ "street_name" => "Rue Rébeval",
+ "street_number" => "33",
+ "street_address" => "33 Rue Rébeval",
+ "department_code" => "75",
+ "department_name" => "Paris"
+ }
+ end
+
+ before do
+ dossier.champs.second.update(data: address)
+ end
it { expect(data[:dossier][:champs][0][:__typename]).to eq "CommuneChamp" }
it { expect(data[:dossier][:champs][1][:__typename]).to eq "AddressChamp" }
@@ -86,7 +106,12 @@ RSpec.describe Types::DossierType, type: :graphql do
code
}
fragment AddressFragment on Address {
+ type
+ label
cityName
+ cityCode
+ streetName
+ streetNumber
}
GRAPHQL
end
diff --git a/spec/jobs/archive_creation_job_spec.rb b/spec/jobs/archive_creation_job_spec.rb
index 2f4f38425..985a0d1d8 100644
--- a/spec/jobs/archive_creation_job_spec.rb
+++ b/spec/jobs/archive_creation_job_spec.rb
@@ -11,7 +11,7 @@ describe ArchiveCreationJob, type: :job do
before { expect(InstructeurMailer).not_to receive(:send_archive) }
it 'does not send email and forward error for retry' do
- allow_any_instance_of(ProcedureArchiveService).to receive(:download_and_zip).and_raise(StandardError, "kaboom")
+ allow(DownloadableFileService).to receive(:download_and_zip).and_raise(StandardError, "kaboom")
expect { job.perform_now }.to raise_error(StandardError, "kaboom")
expect(archive.reload.failed?).to eq(true)
end
@@ -20,7 +20,7 @@ describe ArchiveCreationJob, type: :job do
context 'when it works' do
let(:mailer) { double('mailer', deliver_later: true) }
before do
- allow_any_instance_of(ProcedureArchiveService).to receive(:download_and_zip).and_return(true)
+ allow(DownloadableFileService).to receive(:download_and_zip).and_return(true)
expect(InstructeurMailer).to receive(:send_archive).and_return(mailer)
end
diff --git a/spec/models/export_spec.rb b/spec/models/export_spec.rb
index 2bfdec18a..3511895e5 100644
--- a/spec/models/export_spec.rb
+++ b/spec/models/export_spec.rb
@@ -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], nil)).to eq({ csv: { statut: {}, time_span_type: {} }, xlsx: { statut: {}, time_span_type: {} }, ods: { statut: {}, time_span_type: {} } }) }
- it { expect(Export.find_for_groupe_instructeurs([gi_2.id, gi_1.id], nil)).to eq({ csv: { statut: {}, time_span_type: { 'everything' => export } }, xlsx: { statut: {}, time_span_type: {} }, ods: { statut: {}, time_span_type: {} } }) }
- it { expect(Export.find_for_groupe_instructeurs([gi_1.id, gi_2.id, gi_3.id], nil)).to eq({ csv: { statut: {}, time_span_type: {} }, xlsx: { statut: {}, time_span_type: {} }, ods: { statut: {}, time_span_type: {} } }) }
+ it { expect(Export.find_for_groupe_instructeurs([gi_1.id], nil)).to eq({ csv: { statut: {}, time_span_type: {} }, xlsx: { statut: {}, time_span_type: {} }, ods: { statut: {}, time_span_type: {} }, zip: { statut: {}, time_span_type: {} } }) }
+ it { expect(Export.find_for_groupe_instructeurs([gi_2.id, gi_1.id], nil)).to eq({ csv: { statut: {}, time_span_type: { 'everything' => export } }, xlsx: { statut: {}, time_span_type: {} }, ods: { statut: {}, time_span_type: {} }, zip: { statut: {}, time_span_type: {} } }) }
+ it { expect(Export.find_for_groupe_instructeurs([gi_1.id, gi_2.id, gi_3.id], nil)).to eq({ csv: { statut: {}, time_span_type: {} }, xlsx: { statut: {}, time_span_type: {} }, ods: { statut: {}, time_span_type: {} }, zip: { statut: {}, time_span_type: {} } }) }
end
end
end
diff --git a/spec/services/archive_uploader_spec.rb b/spec/services/archive_uploader_spec.rb
index eb6a41f0b..c916d7e2b 100644
--- a/spec/services/archive_uploader_spec.rb
+++ b/spec/services/archive_uploader_spec.rb
@@ -4,18 +4,18 @@ describe ProcedureArchiveService do
let(:file) { Tempfile.new }
let(:fixture_blob) { ActiveStorage::Blob.create_before_direct_upload!(filename: File.basename(file.path), byte_size: file.size, checksum: 'osf') }
- let(:uploader) { ArchiveUploader.new(procedure: procedure, archive: archive, filepath: file.path) }
+ let(:uploader) { ArchiveUploader.new(procedure: procedure, filename: archive.filename(procedure), filepath: file.path) }
describe '.upload' do
context 'when active storage service is local' do
it 'uploads with upload_with_active_storage' do
expect(uploader).to receive(:active_storage_service_local?).and_return(true)
expect(uploader).to receive(:upload_with_active_storage).and_return(fixture_blob)
- uploader.upload
+ uploader.upload(archive)
end
it 'link the created blob as an attachment to the current archive instance' do
- expect { uploader.upload }
+ expect { uploader.upload(archive) }
.to change { ActiveStorage::Attachment.where(name: 'file', record_type: 'Archive', record_id: archive.id).count }.by(1)
end
end
@@ -31,7 +31,7 @@ describe ProcedureArchiveService do
it 'uploads with upload_with_active_storage' do
expect(uploader).to receive(:upload_with_active_storage).and_return(fixture_blob)
- uploader.upload
+ uploader.upload(archive)
end
end
@@ -40,12 +40,12 @@ describe ProcedureArchiveService do
it 'uploads with upload_with_chunking_wrapper' do
expect(uploader).to receive(:upload_with_chunking_wrapper).and_return(fixture_blob)
- uploader.upload
+ uploader.upload(archive)
end
it 'link the created blob as an attachment to the current archive instance' do
expect(uploader).to receive(:upload_with_chunking_wrapper).and_return(fixture_blob)
- expect { uploader.upload }
+ expect { uploader.upload(archive) }
.to change { ActiveStorage::Attachment.where(name: 'file', record_type: 'Archive', record_id: archive.id).count }.by(1)
end
end
diff --git a/spec/services/downloadable_file_service_spec.rb b/spec/services/downloadable_file_service_spec.rb
new file mode 100644
index 000000000..5e8c3c497
--- /dev/null
+++ b/spec/services/downloadable_file_service_spec.rb
@@ -0,0 +1,37 @@
+describe DownloadableFileService do
+ let(:procedure) { create(:procedure, :published) }
+ let(:service) { ProcedureArchiveService.new(procedure) }
+
+ describe '#download_and_zip' do
+ let(:archive) { build(:archive, id: '3') }
+ let(:filename) { service.send(:zip_root_folder, archive) }
+
+ it 'create a tmpdir while block is running' do
+ previous_dir_list = Dir.entries(DownloadableFileService::ARCHIVE_CREATION_DIR)
+
+ DownloadableFileService.download_and_zip(procedure, [], filename) do |_zip_file|
+ new_dir_list = Dir.entries(DownloadableFileService::ARCHIVE_CREATION_DIR)
+ expect(previous_dir_list).not_to eq(new_dir_list)
+ end
+ end
+
+ it 'cleans up its tmpdir after block execution' do
+ expect { DownloadableFileService.download_and_zip(procedure, [], filename) { |zip_file| } }
+ .not_to change { Dir.entries(DownloadableFileService::ARCHIVE_CREATION_DIR) }
+ end
+
+ it 'creates a zip with zip utility' do
+ expected_zip_path = File.join(DownloadableFileService::ARCHIVE_CREATION_DIR, "#{service.send(:zip_root_folder, archive)}.zip")
+ expect(DownloadableFileService).to receive(:system).with('zip', '-0', '-r', expected_zip_path, an_instance_of(String))
+ DownloadableFileService.download_and_zip(procedure, [], filename) { |zip_path| }
+ end
+
+ it 'cleans up its generated zip' do
+ expected_zip_path = File.join(DownloadableFileService::ARCHIVE_CREATION_DIR, "#{service.send(:zip_root_folder, archive)}.zip")
+ DownloadableFileService.download_and_zip(procedure, [], filename) do |_zip_path|
+ expect(File.exist?(expected_zip_path)).to be_truthy
+ end
+ expect(File.exist?(expected_zip_path)).to be_falsey
+ end
+ end
+end
diff --git a/spec/services/pieces_justificatives_service_spec.rb b/spec/services/pieces_justificatives_service_spec.rb
index a262d6817..a7b715786 100644
--- a/spec/services/pieces_justificatives_service_spec.rb
+++ b/spec/services/pieces_justificatives_service_spec.rb
@@ -192,7 +192,7 @@ describe PiecesJustificativesService do
describe '.generate_dossier_export' do
let(:dossier) { create(:dossier) }
- subject { PiecesJustificativesService.generate_dossier_export(Dossier.where(id: dossier.id)) }
+ subject { PiecesJustificativesService.generate_dossier_export(dossier) }
it "doesn't update dossier" do
expect { subject }.not_to change { dossier.updated_at }
diff --git a/spec/services/procedure_archive_service_spec.rb b/spec/services/procedure_archive_service_spec.rb
index 72c99a62a..73b7c7917 100644
--- a/spec/services/procedure_archive_service_spec.rb
+++ b/spec/services/procedure_archive_service_spec.rb
@@ -172,37 +172,6 @@ describe ProcedureArchiveService do
end
end
- describe '#download_and_zip' do
- let(:archive) { build(:archive, id: '3') }
- it 'create a tmpdir while block is running' do
- previous_dir_list = Dir.entries(ProcedureArchiveService::ARCHIVE_CREATION_DIR)
-
- service.send(:download_and_zip, archive, []) do |_zip_file|
- new_dir_list = Dir.entries(ProcedureArchiveService::ARCHIVE_CREATION_DIR)
- expect(previous_dir_list).not_to eq(new_dir_list)
- end
- end
-
- it 'cleans up its tmpdir after block execution' do
- expect { service.send(:download_and_zip, archive, []) { |zip_file| } }
- .not_to change { Dir.entries(ProcedureArchiveService::ARCHIVE_CREATION_DIR) }
- end
-
- it 'creates a zip with zip utility' do
- expected_zip_path = File.join(ProcedureArchiveService::ARCHIVE_CREATION_DIR, "#{service.send(:zip_root_folder, archive)}.zip")
- expect(service).to receive(:system).with('zip', '-0', '-r', expected_zip_path, an_instance_of(String))
- service.send(:download_and_zip, archive, []) { |zip_path| }
- end
-
- it 'cleans up its generated zip' do
- expected_zip_path = File.join(ProcedureArchiveService::ARCHIVE_CREATION_DIR, "#{service.send(:zip_root_folder, archive)}.zip")
- service.send(:download_and_zip, archive, []) do |_zip_path|
- expect(File.exist?(expected_zip_path)).to be_truthy
- end
- expect(File.exist?(expected_zip_path)).to be_falsey
- end
- end
-
private
def create_dossier_for_month(year, month)
diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb
index c91dace09..1021691b6 100644
--- a/spec/services/procedure_export_service_spec.rb
+++ b/spec/services/procedure_export_service_spec.rb
@@ -4,11 +4,9 @@ describe ProcedureExportService do
describe 'to_data' do
let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
subject do
- Tempfile.create do |f|
- f << ProcedureExportService.new(procedure, procedure.dossiers).to_xlsx
- f.rewind
- SimpleXlsxReader.open(f.path)
- end
+ ProcedureExportService.new(procedure, procedure.dossiers)
+ .to_xlsx
+ .open { |f| SimpleXlsxReader.open(f.path) }
end
let(:dossiers_sheet) { subject.sheets.first }
@@ -178,11 +176,9 @@ describe ProcedureExportService do
context 'as csv' do
subject do
- Tempfile.create do |f|
- f << ProcedureExportService.new(procedure, procedure.dossiers).to_csv
- f.rewind
- CSV.read(f.path)
- end
+ ProcedureExportService.new(procedure, procedure.dossiers)
+ .to_csv
+ .open { |f| CSV.read(f.path) }
end
let(:nominal_headers) do