Add compatibility cadsatre layer with old API GEO

This commit is contained in:
Paul Chavard 2021-05-06 18:50:06 +02:00
parent e74dcb0056
commit 3b85ade440
11 changed files with 206 additions and 155 deletions

View file

@ -4,29 +4,26 @@ class Champs::CarteController < ApplicationController
def index
@selector = ".carte-#{params[:champ_id]}"
@champ = policy_scope(Champ).find(params[:champ_id])
@update_cadastres = params[:cadastres]
if @champ.cadastres? && @update_cadastres
@champ.geo_areas.cadastres.destroy_all
@champ.geo_areas += GeoArea.from_feature_collection(cadastres_features_collection(@champ.to_feature_collection))
@champ.save!
end
rescue APICarto::API::ResourceNotFound
flash.alert = 'Les données cartographiques sont temporairement indisponibles. Réessayez dans un instant.'
response.status = 503
@focus = params[:focus].present?
end
def create
champ = policy_scope(Champ).find(params[:champ_id])
geo_area = champ.geo_areas.selections_utilisateur.new
save_feature!(geo_area, params_feature)
geo_area = if params_source == GeoArea.sources.fetch(:cadastre)
champ.geo_areas.find_by("properties->>'id' = :id", id: params_feature[:properties][:id])
end
if geo_area.nil?
geo_area = champ.geo_areas.build(source: params_source, properties: {})
save_feature!(geo_area, params_feature)
end
render json: { feature: geo_area.to_feature }, status: :created
end
def update
champ = policy_scope(Champ).find(params[:champ_id])
geo_area = champ.geo_areas.selections_utilisateur.find(params[:id])
geo_area = champ.geo_areas.find(params[:id])
save_feature!(geo_area, params_feature)
head :no_content
@ -34,66 +31,42 @@ class Champs::CarteController < ApplicationController
def destroy
champ = policy_scope(Champ).find(params[:champ_id])
champ.geo_areas.selections_utilisateur.find(params[:id]).destroy!
champ.geo_areas.find(params[:id]).destroy!
head :no_content
end
def import
champ = policy_scope(Champ).find(params[:champ_id])
params_features.each do |feature|
geo_area = champ.geo_areas.selections_utilisateur.new
save_feature!(geo_area, feature)
end
render json: champ.to_feature_collection, status: :created
end
private
def params_feature
params[:feature]
def params_source
params[:source]
end
def params_features
params[:features]
def params_feature
params.require(:feature).permit(properties: [
:filename,
:description,
:arpente,
:commune,
:contenance,
:created,
:id,
:numero,
:prefixe,
:section,
:updated
]).tap do |feature|
feature[:geometry] = params[:feature][:geometry]
end
end
def save_feature!(geo_area, feature)
if feature[:geometry]
geo_area.geometry = feature[:geometry]
end
if feature[:properties] && feature[:properties][:description]
geo_area.description = feature[:properties][:description]
if feature[:properties]
geo_area.properties.merge!(feature[:properties])
end
geo_area.save!
end
def cadastres_features_collection(feature_collection)
coordinates = feature_collection[:features].filter do |feature|
feature[:properties][:source] == GeoArea.sources.fetch(:selection_utilisateur) && feature[:geometry] && feature[:geometry]['type'] == 'Polygon'
end.map do |feature|
feature[:geometry]['coordinates'][0].map { |(lng, lat)| { 'lng' => lng, 'lat' => lat } }
end
if coordinates.present?
cadastres = APICartoService.generate_cadastre(coordinates)
{
type: 'FeatureCollection',
features: cadastres.map do |cadastre|
{
type: 'Feature',
geometry: cadastre.delete(:geometry),
properties: cadastre.merge(source: GeoArea.sources.fetch(:cadastre))
}
end
}
else
{
type: 'FeatureCollection',
features: []
}
end
end
end

View file

@ -1467,18 +1467,21 @@ type PageInfo {
}
type ParcelleCadastrale implements GeoArea {
codeArr: String!
codeCom: String!
codeDep: String!
feuille: Int!
codeArr: String! @deprecated(reason: "Utilisez le champ `prefixe` à la place.")
codeCom: String! @deprecated(reason: "Utilisez le champ `commune` à la place.")
codeDep: String! @deprecated(reason: "Utilisez le champ `commune` à la place.")
commune: String!
feuille: Int! @deprecated(reason: "Linformation nest plus disponible.")
geometry: GeoJSON!
id: ID!
nomCom: String!
nomCom: String! @deprecated(reason: "Utilisez le champ `commune` à la place.")
numero: String!
prefixe: String!
section: String!
source: GeoAreaSource!
surfaceIntersection: Float!
surfaceParcelle: Float!
surface: String!
surfaceIntersection: Float! @deprecated(reason: "Linformation nest plus disponible.")
surfaceParcelle: Float! @deprecated(reason: "Utilisez le champ `surface` à la place.")
}
type PersonneMorale implements Demandeur {
@ -1587,6 +1590,7 @@ type Revision {
}
type SelectionUtilisateur implements GeoArea {
description: String!
geometry: GeoJSON!
id: ID!
source: GeoAreaSource!

View file

@ -2,14 +2,18 @@ module Types::GeoAreas
class ParcelleCadastraleType < Types::BaseObject
implements Types::GeoAreaType
field :surface_intersection, Float, null: false
field :surface_parcelle, Float, null: false
field :numero, String, null: false
field :feuille, Int, null: false
field :section, String, null: false
field :code_dep, String, null: false
field :nom_com, String, null: false
field :code_com, String, null: false
field :code_arr, String, null: false
field :surface, String, null: false
field :prefixe, String, null: false
field :commune, String, null: false
field :code_dep, String, null: false, deprecation_reason: 'Utilisez le champ `commune` à la place.'
field :nom_com, String, null: false, deprecation_reason: 'Utilisez le champ `commune` à la place.'
field :code_com, String, null: false, deprecation_reason: 'Utilisez le champ `commune` à la place.'
field :code_arr, String, null: false, deprecation_reason: 'Utilisez le champ `prefixe` à la place.'
field :feuille, Int, null: false, deprecation_reason: 'Linformation nest plus disponible.'
field :surface_intersection, Float, null: false, deprecation_reason: 'Linformation nest plus disponible.'
field :surface_parcelle, Float, null: false, deprecation_reason: 'Utilisez le champ `surface` à la place.'
end
end

View file

@ -1,5 +1,7 @@
module Types::GeoAreas
class SelectionUtilisateurType < Types::BaseObject
implements Types::GeoAreaType
field :description, String, null: false
end
end

View file

@ -36,7 +36,7 @@ module ChampHelper
case geo_area.source
when GeoArea.sources.fetch(:cadastre)
capture do
concat "Parcelle n° #{geo_area.numero} - Feuille #{geo_area.code_arr} #{geo_area.section} #{geo_area.feuille} - #{geo_area.surface_parcelle.round} m"
concat "Parcelle n° #{geo_area.numero} - Feuille #{geo_area.prefixe} #{geo_area.section} - #{geo_area.surface.round} m"
concat tag.sup("2")
end
when GeoArea.sources.fetch(:selection_utilisateur)

View file

@ -14,25 +14,33 @@
class GeoArea < ApplicationRecord
belongs_to :champ, optional: false
store :properties, accessors: [
:description,
:surface_intersection,
:surface_parcelle,
:numero,
:feuille,
:section,
:code_dep,
:nom_com,
:code_com,
:code_arr,
:code,
:nom,
:commune,
:culture,
:code_culture,
:surface,
:bio
]
# FIXME: once geo_areas are migrated to not use YAML serialization we can enable store_accessor
# store_accessor :properties, :description, :numero, :section
def properties
value = read_attribute(:properties)
if value.is_a? String
ActiveRecord::Coders::YAMLColumn.new(:properties).load(value)
else
value
end
end
def description
properties['description']
end
def numero
properties['numero']
end
def section
properties['section']
end
def filename
properties['filename']
end
enum source: {
cadastre: 'cadastre',
@ -48,10 +56,12 @@ class GeoArea < ApplicationRecord
{
type: 'Feature',
geometry: safe_geometry,
properties: properties.symbolize_keys.merge(
properties: cadastre_properties.merge(
source: source,
area: area,
length: length,
description: description,
filename: filename,
id: id,
champ_id: champ.stable_id,
dossier_id: champ.dossier_id
@ -69,16 +79,6 @@ class GeoArea < ApplicationRecord
nil
end
def self.from_feature_collection(feature_collection)
feature_collection[:features].map do |feature|
GeoArea.new(
source: feature[:properties].delete(:source),
properties: feature[:properties],
geometry: feature[:geometry]
)
end
end
def area
if polygon?
GeojsonService.area(geometry.deep_symbolize_keys).round(1)
@ -108,4 +108,107 @@ class GeoArea < ApplicationRecord
def point?
geometry['type'] == 'Point'
end
def legacy_cadastre?
cadastre? && properties['surface_intersection'].present?
end
def cadastre?
source == GeoArea.sources.fetch(:cadastre)
end
def cadastre_properties
if cadastre?
{
cid: cid,
numero: numero,
section: section,
prefixe: prefixe,
commune: commune,
surface: surface
}
else
{}
end
end
def code_dep
if legacy_cadastre?
properties['code_dep']
else
properties['commune'][0..1]
end
end
def code_com
if legacy_cadastre?
properties['code_com']
else
properties['commune'][2...commune.size]
end
end
def nom_com
if legacy_cadastre?
properties['nom_com']
else
''
end
end
def surface_intersection
if legacy_cadastre?
properties['surface_intersection']
else
''
end
end
def feuille
if legacy_cadastre?
properties['feuille']
else
1
end
end
def code_arr
prefixe
end
def surface_parcelle
surface
end
def surface
if legacy_cadastre?
properties['surface_parcelle']
else
properties['contenance']
end
end
def prefixe
if legacy_cadastre?
properties['code_arr']
else
properties['prefixe']
end
end
def commune
if legacy_cadastre?
"#{properties['code_dep']}#{properties['code_com']}"
else
properties['commune']
end
end
def cid
if legacy_cadastre?
"#{code_dep}#{code_com}#{code_arr}#{section}#{numero}"
else
properties['id']
end
end
end

View file

@ -4,6 +4,6 @@
partial: 'shared/champs/carte/geo_areas',
locals: { champ: @champ, editing: true }) %>
<% if @update_cadastres %>
<%= fire_event('cadastres:update', { featureCollection: @champ.to_feature_collection }.to_json) %>
<% if @focus %>
<%= fire_event('map:feature:focus', { bbox: @champ.bounding_box }.to_json) %>
<% end %>

View file

@ -7,7 +7,7 @@
- if editing
= link_to '#', data: { geo_area: geo_area.id } do
= geo_area_label(geo_area)
= text_field_tag :description, geo_area.description, data: { geo_area: geo_area.id }, placeholder: 'Description de la sélection'
= text_field_tag :description, geo_area.description, data: { geo_area: geo_area.id }, placeholder: 'Description de la sélection', class: 'no-margin'
- else
= link_to '#', data: { geo_area: geo_area.id } do
= geo_area_label(geo_area)

View file

@ -25,7 +25,8 @@ describe Champs::CarteController, type: :controller do
let(:params) do
{
champ_id: champ.id,
feature: feature
feature: feature,
source: GeoArea.sources.fetch(:selection_utilisateur)
}
end
@ -98,67 +99,37 @@ describe Champs::CarteController, type: :controller do
it { expect(response.status).to eq 204 }
end
describe 'POST #import' do
describe 'GET #index' do
render_views
let(:params) do
{
champ_id: champ.id,
features: [feature]
}
{ champ_id: champ.id }
end
before do
post :import, params: params
end
it {
expect(response.status).to eq 201
expect(response.body).to include("bbox")
}
end
describe 'GET #index' do
render_views
before do
request.accept = "application/javascript"
request.content_type = "application/javascript"
get :index, params: params
end
context 'with cadastres update' do
let(:params) do
{
champ_id: champ.id,
cadastres: 'update'
}
end
before do
get :index, params: params
end
context "update list" do
it {
expect(response.body).not_to include("DS.fire('map:feature:focus'")
expect(response.status).to eq 200
expect(response.body).to include("DS.fire('cadastres:update'")
}
end
context 'without cadastres update' do
context "update list and focus" do
let(:params) do
{
champ_id: champ.id
champ_id: champ.id,
focus: true
}
end
before do
get :index, params: params
end
it {
expect(response.body).to include("DS.fire('map:feature:focus'")
expect(response.status).to eq 200
expect(response.body).not_to include("DS.fire('cadastres:update'")
}
end
end

View file

@ -1,17 +1,11 @@
FactoryBot.define do
factory :geo_area do
association :champ
properties { {} }
trait :cadastre do
source { GeoArea.sources.fetch(:cadastre) }
numero { '42' }
feuille { 'A11' }
end
trait :quartier_prioritaire do
source { GeoArea.sources.fetch(:quartier_prioritaire) }
nom { 'XYZ' }
commune { 'Paris' }
properties { { numero: '42', section: 'A11', commune: '75127' } }
end
trait :selection_utilisateur do

View file

@ -85,7 +85,7 @@ describe ChampSerializer do
source: GeoArea.sources.fetch(:cadastre),
geometry: geo_json,
numero: '42',
feuille: 'A11'
section: 'A11'
)
expect(subject[:geo_areas].first.key?(:nom)).to be_falsey
}