commit
6a1f95b1f6
26 changed files with 240 additions and 210 deletions
1
Gemfile
1
Gemfile
|
@ -59,6 +59,7 @@ gem 'openid_connect'
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
gem 'phonelib'
|
gem 'phonelib'
|
||||||
gem 'prawn-rails' # PDF Generation
|
gem 'prawn-rails' # PDF Generation
|
||||||
|
gem 'prawn-svg'
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
gem 'puma' # Use Puma as the app server
|
gem 'puma' # Use Puma as the app server
|
||||||
gem 'pundit'
|
gem 'pundit'
|
||||||
|
|
|
@ -459,6 +459,9 @@ GEM
|
||||||
prawn
|
prawn
|
||||||
prawn-table
|
prawn-table
|
||||||
rails (>= 3.1.0)
|
rails (>= 3.1.0)
|
||||||
|
prawn-svg (0.31.0)
|
||||||
|
css_parser (~> 1.6)
|
||||||
|
prawn (>= 0.11.1, < 3)
|
||||||
prawn-table (0.2.2)
|
prawn-table (0.2.2)
|
||||||
prawn (>= 1.3.0, < 3.0.0)
|
prawn (>= 1.3.0, < 3.0.0)
|
||||||
premailer (1.14.2)
|
premailer (1.14.2)
|
||||||
|
@ -837,6 +840,7 @@ DEPENDENCIES
|
||||||
pg
|
pg
|
||||||
phonelib
|
phonelib
|
||||||
prawn-rails
|
prawn-rails
|
||||||
|
prawn-svg
|
||||||
premailer-rails
|
premailer-rails
|
||||||
pry-byebug
|
pry-byebug
|
||||||
puma
|
puma
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
|
@ -1,10 +1,10 @@
|
||||||
module Types
|
module Types
|
||||||
class AddressType < Types::BaseObject
|
class AddressType < Types::BaseObject
|
||||||
class AddressTypeType < Types::BaseEnum
|
class AddressTypeType < Types::BaseEnum
|
||||||
value(:housenumber, "numéro « à la plaque »", value: :housenumber)
|
value(:housenumber, "numéro « à la plaque »", value: "housenumber")
|
||||||
value(:street, "position « à la voie », placé approximativement au centre de celle-ci", value: :street)
|
value(:street, "position « à la voie », placé approximativement au centre de celle-ci", value: "street")
|
||||||
value(:municipality, "numéro « à la commune »", value: :municipality)
|
value(:municipality, "numéro « à la commune »", value: "municipality")
|
||||||
value(:locality, "lieu-dit", value: :locality)
|
value(:locality, "lieu-dit", value: "locality")
|
||||||
end
|
end
|
||||||
|
|
||||||
field :label, String, "libellé complet de l’adresse", null: false
|
field :label, String, "libellé complet de l’adresse", null: false
|
||||||
|
|
|
@ -104,7 +104,7 @@ module Types
|
||||||
def address
|
def address
|
||||||
{
|
{
|
||||||
label: object.adresse,
|
label: object.adresse,
|
||||||
type: :housenumber,
|
type: "housenumber",
|
||||||
street_number: object.numero_voie,
|
street_number: object.numero_voie,
|
||||||
street_name: object.nom_voie,
|
street_name: object.nom_voie,
|
||||||
street_address: object.nom_voie.present? ? [object.numero_voie, object.type_voie, object.nom_voie].compact.join(' ') : nil,
|
street_address: object.nom_voie.present? ? [object.numero_voie, object.type_voie, object.nom_voie].compact.join(' ') : nil,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class ActiveStorage::DownloadableFile
|
class ActiveStorage::DownloadableFile
|
||||||
def self.create_list_from_dossiers(dossiers, for_expert = false)
|
def self.create_list_from_dossiers(dossiers, for_expert = false)
|
||||||
PiecesJustificativesService.generate_dossier_export(dossiers) +
|
dossiers
|
||||||
|
.map { |d| pj_and_path(d.id, PiecesJustificativesService.generate_dossier_export(d)) } +
|
||||||
PiecesJustificativesService.liste_documents(dossiers, for_expert)
|
PiecesJustificativesService.liste_documents(dossiers, for_expert)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -485,10 +485,9 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def motivation
|
def motivation
|
||||||
if termine?
|
return nil if !termine?
|
||||||
traitement&.motivation || read_attribute(:motivation)
|
traitement&.motivation || read_attribute(:motivation)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def update_search_terms
|
def update_search_terms
|
||||||
self.search_terms = [
|
self.search_terms = [
|
||||||
|
|
|
@ -18,8 +18,9 @@ class Export < ApplicationRecord
|
||||||
enum format: {
|
enum format: {
|
||||||
csv: 'csv',
|
csv: 'csv',
|
||||||
ods: 'ods',
|
ods: 'ods',
|
||||||
xlsx: 'xlsx'
|
xlsx: 'xlsx',
|
||||||
}
|
zip: 'zip'
|
||||||
|
}, _prefix: true
|
||||||
|
|
||||||
enum time_span_type: {
|
enum time_span_type: {
|
||||||
everything: 'everything',
|
everything: 'everything',
|
||||||
|
@ -49,11 +50,11 @@ class Export < ApplicationRecord
|
||||||
|
|
||||||
FORMATS_WITH_TIME_SPAN = [:xlsx, :ods, :csv].flat_map do |format|
|
FORMATS_WITH_TIME_SPAN = [:xlsx, :ods, :csv].flat_map do |format|
|
||||||
time_span_types.keys.map do |time_span_type|
|
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
|
||||||
end
|
end
|
||||||
FORMATS = [:xlsx, :ods, :csv].map do |format|
|
FORMATS = [:xlsx, :ods, :csv, :zip].map do |format|
|
||||||
{ format: format.to_sym }
|
{ format: format }
|
||||||
end
|
end
|
||||||
|
|
||||||
def compute_async
|
def compute_async
|
||||||
|
@ -63,13 +64,7 @@ class Export < ApplicationRecord
|
||||||
def compute
|
def compute
|
||||||
load_snapshot!
|
load_snapshot!
|
||||||
|
|
||||||
file.attach(
|
file.attach(blob)
|
||||||
io: io,
|
|
||||||
filename: filename,
|
|
||||||
content_type: content_type,
|
|
||||||
# We generate the exports ourselves, so they are safe
|
|
||||||
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def since
|
def since
|
||||||
|
@ -92,18 +87,6 @@ class Export < ApplicationRecord
|
||||||
procedure_presentation_id.present?
|
procedure_presentation_id.present?
|
||||||
end
|
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)
|
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)
|
create_with(groupe_instructeurs: groupe_instructeurs, procedure_presentation: procedure_presentation, procedure_presentation_snapshot: procedure_presentation&.snapshot)
|
||||||
.includes(:procedure_presentation)
|
.includes(:procedure_presentation)
|
||||||
|
@ -124,16 +107,20 @@ class Export < ApplicationRecord
|
||||||
|
|
||||||
{
|
{
|
||||||
xlsx: {
|
xlsx: {
|
||||||
time_span_type: not_filtered.filter(&:xlsx?).index_by(&:time_span_type),
|
time_span_type: not_filtered.filter(&:format_xlsx?).index_by(&:time_span_type),
|
||||||
statut: filtered.filter(&:xlsx?).index_by(&:statut)
|
statut: filtered.filter(&:format_xlsx?).index_by(&:statut)
|
||||||
},
|
},
|
||||||
ods: {
|
ods: {
|
||||||
time_span_type: not_filtered.filter(&:ods?).index_by(&:time_span_type),
|
time_span_type: not_filtered.filter(&:format_ods?).index_by(&:time_span_type),
|
||||||
statut: filtered.filter(&:ods?).index_by(&:statut)
|
statut: filtered.filter(&:format_ods?).index_by(&:statut)
|
||||||
},
|
},
|
||||||
csv: {
|
csv: {
|
||||||
time_span_type: not_filtered.filter(&:csv?).index_by(&:time_span_type),
|
time_span_type: not_filtered.filter(&:format_csv?).index_by(&:time_span_type),
|
||||||
statut: filtered.filter(&:csv?).index_by(&:statut)
|
statut: filtered.filter(&:format_csv?).index_by(&:statut)
|
||||||
|
},
|
||||||
|
zip: {
|
||||||
|
time_span_type: {},
|
||||||
|
statut: filtered.filter(&:format_zip?).index_by(&:statut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -177,32 +164,18 @@ class Export < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def filename
|
def blob
|
||||||
procedure_identifier = procedure.path || "procedure-#{procedure.id}"
|
|
||||||
"dossiers_#{procedure_identifier}_#{statut}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def io
|
|
||||||
service = ProcedureExportService.new(procedure, dossiers_for_export)
|
service = ProcedureExportService.new(procedure, dossiers_for_export)
|
||||||
|
|
||||||
case format.to_sym
|
case format.to_sym
|
||||||
when :csv
|
when :csv
|
||||||
StringIO.new(service.to_csv)
|
service.to_csv
|
||||||
when :xlsx
|
when :xlsx
|
||||||
StringIO.new(service.to_xlsx)
|
service.to_xlsx
|
||||||
when :ods
|
when :ods
|
||||||
StringIO.new(service.to_ods)
|
service.to_ods
|
||||||
end
|
when :zip
|
||||||
end
|
service.to_zip
|
||||||
|
|
||||||
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'
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ class ArchiveUploader
|
||||||
# when file size is bigger, active storage expects the chunks + a manifest.
|
# 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
|
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
|
uploaded_blob = create_and_upload_blob
|
||||||
begin
|
begin
|
||||||
archive.file.purge if archive.file.attached?
|
archive.file.purge if archive.file.attached?
|
||||||
|
@ -21,9 +21,13 @@ class ArchiveUploader
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def blob
|
||||||
|
create_and_upload_blob
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :procedure, :archive, :filepath
|
attr_reader :procedure, :filename, :filepath
|
||||||
|
|
||||||
def create_and_upload_blob
|
def create_and_upload_blob
|
||||||
if active_storage_service_local? || File.size(filepath) < MAX_FILE_SIZE_FOR_BACKEND_BEFORE_CHUNKING
|
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)
|
def blob_default_params(filepath)
|
||||||
{
|
{
|
||||||
key: namespaced_object_key,
|
key: namespaced_object_key,
|
||||||
filename: archive.filename(procedure),
|
filename: filename,
|
||||||
content_type: 'application/zip',
|
content_type: 'application/zip',
|
||||||
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
|
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)
|
system(ENV.fetch('ACTIVE_STORAGE_BIG_FILE_UPLOADER_WITH_ENCRYPTION_PATH').to_s, filepath, blob.key, exception: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(procedure:, archive:, filepath:)
|
def initialize(procedure:, filename:, filepath:)
|
||||||
@procedure = procedure
|
@procedure = procedure
|
||||||
@archive = archive
|
@filename = filename
|
||||||
@filepath = filepath
|
@filepath = filepath
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
27
app/services/downloadable_file_service.rb
Normal file
27
app/services/downloadable_file_service.rb
Normal file
|
@ -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
|
|
@ -107,44 +107,21 @@ class PiecesJustificativesService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.generate_dossier_export(dossiers)
|
def self.generate_dossier_export(dossier)
|
||||||
return [] if dossiers.empty?
|
|
||||||
|
|
||||||
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
|
pdf = ApplicationController
|
||||||
.render(template: 'dossiers/show', formats: [:pdf],
|
.render(template: 'dossiers/show', formats: [:pdf],
|
||||||
assigns: {
|
assigns: {
|
||||||
include_infos_administration: true,
|
include_infos_administration: true,
|
||||||
dossier: dossier,
|
dossier: dossier
|
||||||
procedure: procedure,
|
|
||||||
tdc_by_id: tdc_by_id
|
|
||||||
})
|
})
|
||||||
|
|
||||||
a = FakeAttachment.new(
|
FakeAttachment.new(
|
||||||
file: StringIO.new(pdf),
|
file: StringIO.new(pdf),
|
||||||
filename: "export-#{dossier.id}.pdf",
|
filename: "export-#{dossier.id}.pdf",
|
||||||
name: 'pdf_export_for_instructeur',
|
name: 'pdf_export_for_instructeur',
|
||||||
id: dossier.id,
|
id: dossier.id,
|
||||||
created_at: dossier.updated_at
|
created_at: dossier.updated_at
|
||||||
)
|
)
|
||||||
|
|
||||||
pdfs << ActiveStorage::DownloadableFile.pj_and_path(dossier.id, a)
|
|
||||||
end
|
|
||||||
|
|
||||||
pdfs
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
class ProcedureArchiveService
|
class ProcedureArchiveService
|
||||||
ARCHIVE_CREATION_DIR = ENV.fetch('ARCHIVE_CREATION_DIR') { '/tmp' }
|
|
||||||
|
|
||||||
def initialize(procedure)
|
def initialize(procedure)
|
||||||
@procedure = procedure
|
@procedure = procedure
|
||||||
end
|
end
|
||||||
|
@ -27,9 +25,9 @@ class ProcedureArchiveService
|
||||||
|
|
||||||
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers)
|
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers)
|
||||||
|
|
||||||
download_and_zip(archive, attachments) do |zip_filepath|
|
DownloadableFileService.download_and_zip(@procedure, attachments, zip_root_folder(archive)) do |zip_filepath|
|
||||||
ArchiveUploader.new(procedure: @procedure, archive: archive, filepath: zip_filepath)
|
ArchiveUploader.new(procedure: @procedure, filename: archive.filename(@procedure), filepath: zip_filepath)
|
||||||
.upload
|
.upload(archive)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,30 +43,6 @@ class ProcedureArchiveService
|
||||||
|
|
||||||
private
|
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)
|
def zip_root_folder(archive)
|
||||||
"procedure-#{@procedure.id}-#{archive.id}"
|
"procedure-#{@procedure.id}-#{archive.id}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class ProcedureExportService
|
class ProcedureExportService
|
||||||
attr_reader :dossiers
|
attr_reader :procedure, :dossiers
|
||||||
|
|
||||||
def initialize(procedure, dossiers)
|
def initialize(procedure, dossiers)
|
||||||
@procedure = procedure
|
@procedure = procedure
|
||||||
|
@ -8,25 +8,72 @@ class ProcedureExportService
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_csv
|
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
|
end
|
||||||
|
|
||||||
def to_xlsx
|
def to_xlsx
|
||||||
# We recursively build multi page spreadsheet
|
# 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)
|
SpreadsheetArchitect.to_axlsx_package(options_for(table, :xlsx), package)
|
||||||
end.to_stream.read
|
end.to_stream
|
||||||
|
create_blob(io, :xlsx)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_ods
|
def to_ods
|
||||||
# We recursively build multi page spreadsheet
|
# 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)
|
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
|
end
|
||||||
|
|
||||||
private
|
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
|
def etablissements
|
||||||
@etablissements ||= dossiers.flat_map do |dossier|
|
@etablissements ||= dossiers.flat_map do |dossier|
|
||||||
[dossier.champs, dossier.champs_private]
|
[dossier.champs, dossier.champs_private]
|
||||||
|
@ -40,12 +87,12 @@ class ProcedureExportService
|
||||||
end
|
end
|
||||||
|
|
||||||
def champs_repetables_options
|
def champs_repetables_options
|
||||||
revision = @procedure.active_revision
|
revision = procedure.active_revision
|
||||||
champs_by_stable_id = dossiers
|
champs_by_stable_id = dossiers
|
||||||
.flat_map { |dossier| (dossier.champs + dossier.champs_private).filter(&:repetition?) }
|
.flat_map { |dossier| (dossier.champs + dossier.champs_private).filter(&:repetition?) }
|
||||||
.group_by(&:stable_id)
|
.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] }
|
.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? }
|
.filter { |(_, types_de_champ)| types_de_champ.present? }
|
||||||
.map do |(type_de_champ_repetition, types_de_champ)|
|
.map do |(type_de_champ_repetition, types_de_champ)|
|
||||||
|
@ -85,7 +132,7 @@ class ProcedureExportService
|
||||||
end
|
end
|
||||||
|
|
||||||
def spreadsheet_columns(format)
|
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|
|
Proc.new do |instance|
|
||||||
instance.send(:"spreadsheet_columns_#{format}", types_de_champ: types_de_champ)
|
instance.send(:"spreadsheet_columns_#{format}", types_de_champ: types_de_champ)
|
||||||
|
|
|
@ -181,7 +181,7 @@ prawn_document(page_size: "A4") do |pdf|
|
||||||
italic: Rails.root.join('lib/prawn/fonts/marianne/marianne-thin.ttf' ),
|
italic: Rails.root.join('lib/prawn/fonts/marianne/marianne-thin.ttf' ),
|
||||||
})
|
})
|
||||||
pdf.font 'marianne'
|
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)
|
pdf.move_down(40)
|
||||||
|
|
||||||
render_in_2_columns(pdf, 'Démarche', @dossier.procedure.libelle)
|
render_in_2_columns(pdf, 'Démarche', @dossier.procedure.libelle)
|
||||||
|
|
|
@ -130,30 +130,28 @@ def add_identite_etablissement(pdf, etablissement)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_single_champ(pdf, champ)
|
def add_single_champ(pdf, champ)
|
||||||
tdc = @tdc_by_id[champ.type_de_champ_id].first
|
|
||||||
|
|
||||||
case champ.type
|
case champ.type
|
||||||
when 'Champs::PieceJustificativeChamp', 'Champs::TitreIdentiteChamp'
|
when 'Champs::PieceJustificativeChamp', 'Champs::TitreIdentiteChamp'
|
||||||
return
|
return
|
||||||
when 'Champs::HeaderSectionChamp'
|
when 'Champs::HeaderSectionChamp'
|
||||||
add_section_title(pdf, tdc.libelle)
|
add_section_title(pdf, champ.libelle)
|
||||||
when 'Champs::ExplicationChamp'
|
when 'Champs::ExplicationChamp'
|
||||||
format_in_2_lines(pdf, tdc.libelle, tdc.description)
|
format_in_2_lines(pdf, champ.libelle, champ.description)
|
||||||
when 'Champs::CarteChamp'
|
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'
|
when 'Champs::SiretChamp'
|
||||||
pdf.font 'marianne', style: :bold do
|
pdf.font 'marianne', style: :bold do
|
||||||
pdf.text tdc.libelle
|
pdf.text champ.libelle
|
||||||
end
|
end
|
||||||
if champ.etablissement.present?
|
if champ.etablissement.present?
|
||||||
add_identite_etablissement(pdf, champ.etablissement)
|
add_identite_etablissement(pdf, champ.etablissement)
|
||||||
end
|
end
|
||||||
when 'Champs::NumberChamp'
|
when 'Champs::NumberChamp'
|
||||||
value = champ.to_s.empty? ? 'Non communiqué' : number_with_delimiter(champ.to_s)
|
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
|
else
|
||||||
value = champ.to_s.empty? ? 'Non communiqué' : champ.to_s
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -207,9 +205,6 @@ def add_etats_dossier(pdf, dossier)
|
||||||
end
|
end
|
||||||
|
|
||||||
prawn_document(page_size: "A4") do |pdf|
|
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' => {
|
pdf.font_families.update( 'marianne' => {
|
||||||
normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf' ),
|
normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf' ),
|
||||||
bold: Rails.root.join('lib/prawn/fonts/marianne/marianne-bold.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.font 'marianne'
|
||||||
|
|
||||||
pdf.pad_bottom(40) do
|
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
|
end
|
||||||
|
|
||||||
format_in_2_columns(pdf, 'Dossier Nº', @dossier.id.to_s)
|
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, 'Démarche', @dossier.procedure.libelle)
|
||||||
format_in_2_columns(pdf, 'Organisme', @procedure.organisation_name)
|
format_in_2_columns(pdf, 'Organisme', @dossier.procedure.organisation_name)
|
||||||
|
|
||||||
add_etat_dossier(pdf, @dossier)
|
add_etat_dossier(pdf, @dossier)
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ DS_ENV="staging"
|
||||||
# PROCEDURE_DEFAULT_LOGO_SRC="republique-francaise-logo.svg"
|
# PROCEDURE_DEFAULT_LOGO_SRC="republique-francaise-logo.svg"
|
||||||
|
|
||||||
# Instance customization: PDF export logo ---> to be put in "app/assets/images"
|
# 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
|
# Instance customization: watermark for identity documents
|
||||||
# WATERMARK_FILE=""
|
# WATERMARK_FILE=""
|
||||||
|
|
|
@ -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")
|
PROCEDURE_DEFAULT_LOGO_SRC = ENV.fetch("PROCEDURE_DEFAULT_LOGO_SRC", "republique-francaise-logo.svg")
|
||||||
|
|
||||||
# Logo in PDF export of a "Dossier"
|
# 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")
|
||||||
|
|
|
@ -5,6 +5,7 @@ fr:
|
||||||
everything_csv_html: Demander un export au format .csv<br>(uniquement les dossiers, sans les champs répétables)
|
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_xlsx_html: Demander un export au format .xlsx
|
||||||
everything_ods_html: Demander un export au format .ods
|
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_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é<br>(demandé il y a %{export_time})
|
everything_pending_html: Un export au format %{export_format} est en train d’être généré<br>(demandé il y a %{export_time})
|
||||||
everything_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
everything_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
||||||
|
|
|
@ -31,6 +31,26 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
let(:dossier) { create(:dossier, :accepte, :with_populated_champs, procedure: procedure) }
|
let(:dossier) { create(:dossier, :accepte, :with_populated_champs, procedure: procedure) }
|
||||||
let(:query) { DOSSIER_WITH_CHAMPS_QUERY }
|
let(:query) { DOSSIER_WITH_CHAMPS_QUERY }
|
||||||
let(:variables) { { number: dossier.id } }
|
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][0][:__typename]).to eq "CommuneChamp" }
|
||||||
it { expect(data[:dossier][:champs][1][:__typename]).to eq "AddressChamp" }
|
it { expect(data[:dossier][:champs][1][:__typename]).to eq "AddressChamp" }
|
||||||
|
@ -86,7 +106,12 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
code
|
code
|
||||||
}
|
}
|
||||||
fragment AddressFragment on Address {
|
fragment AddressFragment on Address {
|
||||||
|
type
|
||||||
|
label
|
||||||
cityName
|
cityName
|
||||||
|
cityCode
|
||||||
|
streetName
|
||||||
|
streetNumber
|
||||||
}
|
}
|
||||||
GRAPHQL
|
GRAPHQL
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,7 @@ describe ArchiveCreationJob, type: :job do
|
||||||
before { expect(InstructeurMailer).not_to receive(:send_archive) }
|
before { expect(InstructeurMailer).not_to receive(:send_archive) }
|
||||||
|
|
||||||
it 'does not send email and forward error for retry' do
|
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 { job.perform_now }.to raise_error(StandardError, "kaboom")
|
||||||
expect(archive.reload.failed?).to eq(true)
|
expect(archive.reload.failed?).to eq(true)
|
||||||
end
|
end
|
||||||
|
@ -20,7 +20,7 @@ describe ArchiveCreationJob, type: :job do
|
||||||
context 'when it works' do
|
context 'when it works' do
|
||||||
let(:mailer) { double('mailer', deliver_later: true) }
|
let(:mailer) { double('mailer', deliver_later: true) }
|
||||||
before do
|
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)
|
expect(InstructeurMailer).to receive(:send_archive).and_return(mailer)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,9 @@ RSpec.describe Export, type: :model do
|
||||||
context 'when an export is made for one groupe instructeur' do
|
context 'when an export is made for one groupe instructeur' do
|
||||||
let!(:export) { create(:export, groupe_instructeurs: [gi_1, gi_2]) }
|
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_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: {} } }) }
|
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: {} } }) }
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,18 +4,18 @@ describe ProcedureArchiveService do
|
||||||
let(:file) { Tempfile.new }
|
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(: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
|
describe '.upload' do
|
||||||
context 'when active storage service is local' do
|
context 'when active storage service is local' do
|
||||||
it 'uploads with upload_with_active_storage' do
|
it 'uploads with upload_with_active_storage' do
|
||||||
expect(uploader).to receive(:active_storage_service_local?).and_return(true)
|
expect(uploader).to receive(:active_storage_service_local?).and_return(true)
|
||||||
expect(uploader).to receive(:upload_with_active_storage).and_return(fixture_blob)
|
expect(uploader).to receive(:upload_with_active_storage).and_return(fixture_blob)
|
||||||
uploader.upload
|
uploader.upload(archive)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'link the created blob as an attachment to the current archive instance' do
|
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)
|
.to change { ActiveStorage::Attachment.where(name: 'file', record_type: 'Archive', record_id: archive.id).count }.by(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -31,7 +31,7 @@ describe ProcedureArchiveService do
|
||||||
|
|
||||||
it 'uploads with upload_with_active_storage' do
|
it 'uploads with upload_with_active_storage' do
|
||||||
expect(uploader).to receive(:upload_with_active_storage).and_return(fixture_blob)
|
expect(uploader).to receive(:upload_with_active_storage).and_return(fixture_blob)
|
||||||
uploader.upload
|
uploader.upload(archive)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,12 +40,12 @@ describe ProcedureArchiveService do
|
||||||
|
|
||||||
it 'uploads with upload_with_chunking_wrapper' do
|
it 'uploads with upload_with_chunking_wrapper' do
|
||||||
expect(uploader).to receive(:upload_with_chunking_wrapper).and_return(fixture_blob)
|
expect(uploader).to receive(:upload_with_chunking_wrapper).and_return(fixture_blob)
|
||||||
uploader.upload
|
uploader.upload(archive)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'link the created blob as an attachment to the current archive instance' do
|
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).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)
|
.to change { ActiveStorage::Attachment.where(name: 'file', record_type: 'Archive', record_id: archive.id).count }.by(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
37
spec/services/downloadable_file_service_spec.rb
Normal file
37
spec/services/downloadable_file_service_spec.rb
Normal file
|
@ -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
|
|
@ -192,7 +192,7 @@ describe PiecesJustificativesService do
|
||||||
describe '.generate_dossier_export' do
|
describe '.generate_dossier_export' do
|
||||||
let(:dossier) { create(:dossier) }
|
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
|
it "doesn't update dossier" do
|
||||||
expect { subject }.not_to change { dossier.updated_at }
|
expect { subject }.not_to change { dossier.updated_at }
|
||||||
|
|
|
@ -172,37 +172,6 @@ describe ProcedureArchiveService do
|
||||||
end
|
end
|
||||||
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
|
private
|
||||||
|
|
||||||
def create_dossier_for_month(year, month)
|
def create_dossier_for_month(year, month)
|
||||||
|
|
|
@ -4,11 +4,9 @@ describe ProcedureExportService do
|
||||||
describe 'to_data' do
|
describe 'to_data' do
|
||||||
let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
|
let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
|
||||||
subject do
|
subject do
|
||||||
Tempfile.create do |f|
|
ProcedureExportService.new(procedure, procedure.dossiers)
|
||||||
f << ProcedureExportService.new(procedure, procedure.dossiers).to_xlsx
|
.to_xlsx
|
||||||
f.rewind
|
.open { |f| SimpleXlsxReader.open(f.path) }
|
||||||
SimpleXlsxReader.open(f.path)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:dossiers_sheet) { subject.sheets.first }
|
let(:dossiers_sheet) { subject.sheets.first }
|
||||||
|
@ -178,11 +176,9 @@ describe ProcedureExportService do
|
||||||
|
|
||||||
context 'as csv' do
|
context 'as csv' do
|
||||||
subject do
|
subject do
|
||||||
Tempfile.create do |f|
|
ProcedureExportService.new(procedure, procedure.dossiers)
|
||||||
f << ProcedureExportService.new(procedure, procedure.dossiers).to_csv
|
.to_csv
|
||||||
f.rewind
|
.open { |f| CSV.read(f.path) }
|
||||||
CSV.read(f.path)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:nominal_headers) do
|
let(:nominal_headers) do
|
||||||
|
|
Loading…
Reference in a new issue