Merge pull request #8045 from tchak/feat-export-geojson
feat(export): add GeoJSON export
This commit is contained in:
commit
c200e03771
14 changed files with 94 additions and 36 deletions
|
@ -1,7 +1,8 @@
|
|||
@import "placeholders";
|
||||
|
||||
turbo-events {
|
||||
display: none;
|
||||
html,
|
||||
body {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-wrapper {
|
||||
|
|
|
@ -8,7 +8,27 @@ class Dossiers::ExportComponent < ApplicationComponent
|
|||
end
|
||||
|
||||
def exports
|
||||
helpers.exports_list(@exports, @statut)
|
||||
if @statut
|
||||
Export::FORMATS.filter(&method(:allowed_format?)).map do |item|
|
||||
export = @exports
|
||||
.fetch(item.fetch(:format))
|
||||
.fetch(:statut)
|
||||
.fetch(@statut, nil)
|
||||
item.merge(export: export)
|
||||
end
|
||||
else
|
||||
Export::FORMATS_WITH_TIME_SPAN.map do |item|
|
||||
export = @exports
|
||||
.fetch(item.fetch(:format))
|
||||
.fetch(:time_span_type)
|
||||
.fetch(item.fetch(:time_span_type), nil)
|
||||
item.merge(export: export)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_format?(item)
|
||||
item.fetch(:format) != :json || @procedure.active_revision.carte?
|
||||
end
|
||||
|
||||
def download_export_path(export_format:, force_export: false, no_progress_notification: nil)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
---
|
||||
en:
|
||||
everything_csv_html: Ask an export in format .csv<br>(only folders, without repeatable fields)
|
||||
everything_xlsx_html: Ask an export in format .xlsx
|
||||
everything_ods_html: Ask an export in format .ods
|
||||
everything_zip_html: Ask an export in format .zip<br>(does not contains timestamp nor operation logs )
|
||||
everything_short: Ask an export in format%{export_format}
|
||||
everything_pending_html: Ask an export in format %{export_format} is being generated<br>(ask %{export_time} ago)
|
||||
everything_ready_html: Download the export in format %{export_format}<br>(generated %{export_time} ago)
|
||||
everything_csv_html: Request an export in .csv format<br>(only files, without repeatable fields)
|
||||
everything_xlsx_html: Request an export in .xlsx format
|
||||
everything_ods_html: Request an export in .ods format
|
||||
everything_zip_html: Request an export in .zip format<br>(does not contains timestamp nor operation logs)
|
||||
everything_json_html: Request an export in .json format (GeoJSON)
|
||||
everything_short: Request an export in %{export_format} format
|
||||
everything_pending_html: An export in %{export_format} format is being generated<br>(ask %{export_time} ago)
|
||||
everything_ready_html: Download the export in %{export_format} format<br>(generated %{export_time} ago)
|
||||
download_all: Download all files
|
||||
download:
|
||||
one: Download a file
|
||||
|
|
|
@ -4,6 +4,7 @@ fr:
|
|||
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<br>(ne contient pas l'horodatage ni le journal de log)
|
||||
everything_json_html: Demander un export au format .json (GeoJSON)
|
||||
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_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
||||
|
|
|
@ -96,26 +96,6 @@ module DossierHelper
|
|||
"#{base_url}/rechercher?terme=#{siren_or_siret}"
|
||||
end
|
||||
|
||||
def exports_list(exports, statut = nil)
|
||||
if statut
|
||||
Export::FORMATS.map do |item|
|
||||
export = exports
|
||||
.fetch(item.fetch(:format))
|
||||
.fetch(:statut)
|
||||
.fetch(statut, nil)
|
||||
item.merge(export: export)
|
||||
end
|
||||
else
|
||||
Export::FORMATS_WITH_TIME_SPAN.map do |item|
|
||||
export = exports
|
||||
.fetch(item.fetch(:format))
|
||||
.fetch(:time_span_type)
|
||||
.fetch(item.fetch(:time_span_type), nil)
|
||||
item.merge(export: export)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def france_connect_informations(user_information)
|
||||
if user_information.full_name.empty?
|
||||
t("shared.dossiers.france_connect_informations.details_no_name")
|
||||
|
|
|
@ -61,6 +61,7 @@ class Champ < ApplicationRecord
|
|||
:mesri?,
|
||||
:rna?,
|
||||
:siret?,
|
||||
:carte?,
|
||||
:stable_id,
|
||||
:mandatory?,
|
||||
to: :type_de_champ
|
||||
|
|
|
@ -1144,6 +1144,13 @@ class Dossier < ApplicationRecord
|
|||
}
|
||||
end
|
||||
|
||||
def self.to_feature_collection
|
||||
{
|
||||
type: 'FeatureCollection',
|
||||
features: GeoArea.joins(:champ).where(champ: { dossier: ids }).map(&:to_feature)
|
||||
}
|
||||
end
|
||||
|
||||
def log_api_entreprise_job_exception(exception)
|
||||
exceptions = self.api_entreprise_job_exceptions ||= []
|
||||
exceptions << exception.inspect
|
||||
|
|
|
@ -23,7 +23,8 @@ class Export < ApplicationRecord
|
|||
csv: 'csv',
|
||||
ods: 'ods',
|
||||
xlsx: 'xlsx',
|
||||
zip: 'zip'
|
||||
zip: 'zip',
|
||||
json: 'json'
|
||||
}, _prefix: true
|
||||
|
||||
enum time_span_type: {
|
||||
|
@ -53,7 +54,7 @@ class Export < ApplicationRecord
|
|||
FORMATS_WITH_TIME_SPAN = [:xlsx, :ods, :csv].flat_map do |format|
|
||||
[{ format: format, time_span_type: 'everything' }]
|
||||
end
|
||||
FORMATS = [:xlsx, :ods, :csv, :zip].map do |format|
|
||||
FORMATS = [:xlsx, :ods, :csv, :zip, :json].map do |format|
|
||||
{ format: format }
|
||||
end
|
||||
|
||||
|
@ -127,6 +128,10 @@ class Export < ApplicationRecord
|
|||
zip: {
|
||||
time_span_type: {},
|
||||
statut: filtered.filter(&:format_zip?).index_by(&:statut)
|
||||
},
|
||||
json: {
|
||||
time_span_type: {},
|
||||
statut: filtered.filter(&:format_json?).index_by(&:statut)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
@ -195,6 +200,8 @@ class Export < ApplicationRecord
|
|||
service.to_ods
|
||||
when :zip
|
||||
service.to_zip
|
||||
when :json
|
||||
service.to_geo_json
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -64,7 +64,10 @@ class GeoArea < ApplicationRecord
|
|||
description: description,
|
||||
filename: filename,
|
||||
id: id,
|
||||
champ_label: champ.libelle,
|
||||
champ_id: champ.stable_id,
|
||||
champ_row: champ.row,
|
||||
champ_private: champ.private?,
|
||||
dossier_id: champ.dossier_id
|
||||
).compact
|
||||
}
|
||||
|
|
|
@ -200,6 +200,10 @@ class ProcedureRevision < ApplicationRecord
|
|||
revision_types_de_champ.find_by!(type_de_champ: tdc)
|
||||
end
|
||||
|
||||
def carte?
|
||||
types_de_champ_public.any?(&:carte?)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compute_estimated_fill_duration
|
||||
|
|
|
@ -42,6 +42,11 @@ class ProcedureExportService
|
|||
end
|
||||
end
|
||||
|
||||
def to_geo_json
|
||||
io = StringIO.new(dossiers.to_feature_collection.to_json)
|
||||
create_blob(io, :json)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_blob(io, format)
|
||||
|
@ -77,6 +82,8 @@ class ProcedureExportService
|
|||
'application/vnd.oasis.opendocument.spreadsheet'
|
||||
when :zip
|
||||
'application/zip'
|
||||
when :json
|
||||
'application/json'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1444,7 +1444,9 @@ describe Dossier do
|
|||
},
|
||||
properties: {
|
||||
area: 103.6,
|
||||
champ_label: champ_carte.libelle,
|
||||
champ_id: champ_carte.stable_id,
|
||||
champ_private: false,
|
||||
dossier_id: dossier.id,
|
||||
id: geo_area.id,
|
||||
source: 'selection_utilisateur'
|
||||
|
|
|
@ -61,9 +61,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: {} }, 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: {} } }) }
|
||||
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: {} }, json: { 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: {} }, json: { 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: {} }, json: { statut: {}, time_span_type: {} } }) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -78,7 +78,8 @@ RSpec.describe Export, type: :model do
|
|||
csv: { statut: { Export.statuts.fetch(:suivis) => export_with_filter }, time_span_type: { 'everything' => export_global } },
|
||||
xlsx: { statut: {}, time_span_type: {} },
|
||||
ods: { statut: {}, time_span_type: {} },
|
||||
zip: { statut: {}, time_span_type: {} }
|
||||
zip: { statut: {}, time_span_type: {} },
|
||||
json: { statut: {}, time_span_type: {} }
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -467,4 +467,27 @@ describe ProcedureExportService do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'to_geo_json' do
|
||||
subject do
|
||||
service
|
||||
.to_geo_json
|
||||
.open { |f| JSON.parse(f.read) }
|
||||
end
|
||||
|
||||
let(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure) }
|
||||
let(:champ_carte) { dossier.champs_public.find(&:carte?) }
|
||||
let(:properties) { subject['features'].first['properties'] }
|
||||
|
||||
before do
|
||||
create(:geo_area, :polygon, champ: champ_carte)
|
||||
end
|
||||
|
||||
it 'should have features' do
|
||||
expect(subject['features'].size).to eq(1)
|
||||
expect(properties['dossier_id']).to eq(dossier.id)
|
||||
expect(properties['champ_id']).to eq(champ_carte.stable_id)
|
||||
expect(properties['champ_label']).to eq(champ_carte.libelle)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue