Merge branch 'dev'
This commit is contained in:
commit
b7d7138c1a
59 changed files with 779 additions and 275 deletions
|
@ -10,6 +10,7 @@ module.exports = {
|
|||
plugins: ['prettier'],
|
||||
extends: ['eslint:recommended', 'prettier'],
|
||||
env: {
|
||||
es6: true,
|
||||
browser: true
|
||||
},
|
||||
rules: {
|
||||
|
|
|
@ -27,6 +27,7 @@ $(document).on('change', 'select.form-control.type-champ', function() {
|
|||
parent.removeClass('header-section');
|
||||
parent.children('.drop-down-list').removeClass('show-inline');
|
||||
parent.children('.pj-template').removeClass('show-inline');
|
||||
parent.children('.carte-options').removeClass('show-inline');
|
||||
|
||||
$('.mandatory', parent).show();
|
||||
|
||||
|
@ -42,6 +43,9 @@ $(document).on('change', 'select.form-control.type-champ', function() {
|
|||
case 'piece_justificative':
|
||||
parent.children('.pj-template').addClass('show-inline');
|
||||
break;
|
||||
case 'carte':
|
||||
parent.children('.carte-options').addClass('show-inline');
|
||||
break;
|
||||
case 'explication':
|
||||
$('.mandatory', parent).hide();
|
||||
break;
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
}
|
||||
|
||||
.form-group.drop-down-list,
|
||||
.form-group.pj-template {
|
||||
.form-group.pj-template,
|
||||
.form-group.carte-options {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -228,8 +228,14 @@
|
|||
// scss-lint:enable
|
||||
}
|
||||
|
||||
.algolia-autocomplete {
|
||||
margin-bottom: 2 * $default-padding;
|
||||
.editable-champ {
|
||||
&:not(.editable-champ-carte) .algolia-autocomplete {
|
||||
margin-bottom: 2 * $default-padding;
|
||||
}
|
||||
|
||||
.geo-areas {
|
||||
margin-bottom: 2 * $default-padding;
|
||||
}
|
||||
}
|
||||
|
||||
input.aa-input,
|
||||
|
|
|
@ -1,4 +1,77 @@
|
|||
#map {
|
||||
#map,
|
||||
.carte {
|
||||
height: 400px;
|
||||
margin-bottom: 16px;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.leaflet-container path {
|
||||
cursor: url("/assets/edit.png"), default !important;
|
||||
}
|
||||
|
||||
.carte {
|
||||
&.edit {
|
||||
g path.leaflet-polygon {
|
||||
transition: all 0.25s;
|
||||
stroke-width: 4px;
|
||||
stroke-opacity: 1;
|
||||
stroke: #D7217E;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
fill: #D7217E;
|
||||
fill-opacity: 0.75;
|
||||
}
|
||||
|
||||
div.leaflet-edge {
|
||||
box-shadow: 0 0 0 2px #FFFFFF, 0 0 10px rgba(0, 0, 0, 0.35);
|
||||
border: 5px solid #D7217E;
|
||||
border-radius: 10px;
|
||||
transition: opacity 0.25s;
|
||||
cursor: move;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.mode-create {
|
||||
cursor: url("/assets/pencil.png"), crosshair !important;
|
||||
}
|
||||
|
||||
&.mode-edit div.leaflet-edge {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&.mode-delete path.leaflet-polygon {
|
||||
cursor: no-drop !important;
|
||||
|
||||
&:hover {
|
||||
fill: #4D4D4D !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.editable-champ-carte {
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.button {
|
||||
width: 200px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.areas-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.areas {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
|
|
@ -276,7 +276,7 @@ class Admin::ProceduresController < AdminController
|
|||
if @procedure&.locked?
|
||||
params.require(:procedure).permit(*editable_params)
|
||||
else
|
||||
params.require(:procedure).permit(*editable_params, :duree_conservation_dossiers_dans_ds, :duree_conservation_dossiers_hors_ds, :lien_demarche, :for_individual, :individual_with_siret, :ask_birthday, module_api_carto_attributes: [:id, :use_api_carto, :quartiers_prioritaires, :cadastre]).merge(administrateur_id: current_administrateur.id)
|
||||
params.require(:procedure).permit(*editable_params, :duree_conservation_dossiers_dans_ds, :duree_conservation_dossiers_hors_ds, :for_individual, :individual_with_siret, :ask_birthday, module_api_carto_attributes: [:id, :use_api_carto, :quartiers_prioritaires, :cadastre]).merge(administrateur_id: current_administrateur.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ class API::V1::ProceduresController < APIController
|
|||
before_action :fetch_procedure_and_check_token
|
||||
|
||||
def show
|
||||
render json: { procedure: ProcedureSerializer.new(@procedure.decorate).as_json }
|
||||
render json: { procedure: ProcedureSerializer.new(@procedure).as_json }
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -37,6 +37,10 @@ class ApplicationController < ActionController::Base
|
|||
logged_user.present?
|
||||
end
|
||||
|
||||
def logged_user_ids
|
||||
logged_users.map(&:id)
|
||||
end
|
||||
|
||||
helper_method :logged_in?
|
||||
|
||||
protected
|
||||
|
|
61
app/controllers/champs/carte_controller.rb
Normal file
61
app/controllers/champs/carte_controller.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
class Champs::CarteController < ApplicationController
|
||||
before_action :authenticate_logged_user!
|
||||
|
||||
def show
|
||||
@selector = ".carte-#{params[:position]}"
|
||||
|
||||
if params[:dossier].key?(:champs_attributes)
|
||||
geo_json = params[:dossier][:champs_attributes][params[:position]][:value]
|
||||
else
|
||||
geo_json = params[:dossier][:champs_private_attributes][params[:position]][:value]
|
||||
end
|
||||
|
||||
if params[:champ_id].present?
|
||||
@champ = Champ
|
||||
.joins(:dossier)
|
||||
.where(dossiers: { user_id: logged_user_ids })
|
||||
.find_by(id: params[:champ_id])
|
||||
else
|
||||
@champ = Champs::CarteChamp.new(type_de_champ: TypeDeChamp.new(
|
||||
type_champ: TypeDeChamp.type_champs.fetch(:carte),
|
||||
options: {
|
||||
quartiers_prioritaires: true,
|
||||
cadastres: true
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
geo_areas = []
|
||||
geo_json = geo_json.blank? ? [] : JSON.parse(geo_json)
|
||||
|
||||
if geo_json.first == ["error", "TooManyPolygons"]
|
||||
@error = true
|
||||
elsif geo_json.present?
|
||||
if @champ.cadastres?
|
||||
cadastres = ModuleApiCartoService.generate_cadastre(geo_json)
|
||||
geo_areas += cadastres.map do |cadastre|
|
||||
cadastre[:source] = GeoArea.sources.fetch(:cadastre)
|
||||
cadastre
|
||||
end
|
||||
end
|
||||
|
||||
if @champ.quartiers_prioritaires?
|
||||
quartiers_prioritaires = ModuleApiCartoService.generate_qp(geo_json)
|
||||
geo_areas += quartiers_prioritaires.map do |qp|
|
||||
qp[:source] = GeoArea.sources.fetch(:quartier_prioritaire)
|
||||
qp
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@champ.geo_areas = geo_areas.map do |geo_area|
|
||||
GeoArea.new(geo_area)
|
||||
end
|
||||
|
||||
@champ.value = geo_json.to_json
|
||||
|
||||
if @champ.persisted?
|
||||
@champ.save
|
||||
end
|
||||
end
|
||||
end
|
|
@ -65,9 +65,13 @@ class Users::CarteController < UsersController
|
|||
# https://tools.ietf.org/html/rfc7946#section-3.1.6
|
||||
if json_latlngs.present?
|
||||
multipolygone = JSON.parse(json_latlngs)
|
||||
multipolygone.reject! { |polygone| polygone.count < 4 }
|
||||
if multipolygone.present?
|
||||
multipolygone.to_json
|
||||
if multipolygone.first == ["error", "TooManyPolygons"]
|
||||
[].to_json
|
||||
else
|
||||
multipolygone.reject! { |polygone| polygone.count < 4 }
|
||||
if multipolygone.present?
|
||||
multipolygone.to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,8 +22,4 @@ class ProcedureDecorator < Draper::Decorator
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def geographic_information
|
||||
module_api_carto
|
||||
end
|
||||
end
|
||||
|
|
|
@ -91,7 +91,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def ensure_safe_json(json)
|
||||
JSON.parse(json).to_json
|
||||
json.present? ? JSON.parse(json).to_json : '[]'
|
||||
rescue Exception => e
|
||||
Raven.capture_exception(e)
|
||||
{}
|
||||
|
|
|
@ -3,4 +3,15 @@ module ChampHelper
|
|||
types_without_label = [TypeDeChamp.type_champs.fetch(:header_section), TypeDeChamp.type_champs.fetch(:explication)]
|
||||
!types_without_label.include?(champ.type_champ)
|
||||
end
|
||||
|
||||
def geo_data(champ)
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
raw({
|
||||
position: champ.position,
|
||||
selection: champ.value.present? ? JSON.parse(champ.value) : [],
|
||||
quartiersPrioritaires: champ.quartiers_prioritaires? ? champ.quartiers_prioritaires : [],
|
||||
cadastres: champ.cadastres? ? champ.cadastres : []
|
||||
}.to_json)
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import { getData } from '../shared/data';
|
||||
import { initMap } from '../shared/carto';
|
||||
import {
|
||||
initMap,
|
||||
drawCadastre,
|
||||
drawQuartiersPrioritaires,
|
||||
drawUserSelection
|
||||
} from './carto/draw';
|
||||
} from '../shared/carte';
|
||||
|
||||
function initialize() {
|
||||
if (document.getElementById('map')) {
|
||||
const position = getData('carto').position;
|
||||
const map = initMap(position);
|
||||
const element = document.getElementById('map');
|
||||
|
||||
if (element) {
|
||||
const data = getData('carto');
|
||||
const map = initMap(element, data.position);
|
||||
|
||||
// draw external polygons
|
||||
drawCadastre(map, data);
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import L from 'leaflet';
|
||||
import {
|
||||
drawLayer,
|
||||
noEditStyle,
|
||||
CADASTRE_POLYGON_STYLE,
|
||||
QP_POLYGON_STYLE
|
||||
} from '../../shared/carto';
|
||||
|
||||
export function drawCadastre(map, data) {
|
||||
drawLayer(
|
||||
map,
|
||||
data.cadastres,
|
||||
noEditStyle(CADASTRE_POLYGON_STYLE),
|
||||
'cadastres'
|
||||
);
|
||||
}
|
||||
|
||||
export function drawQuartiersPrioritaires(map, data) {
|
||||
drawLayer(
|
||||
map,
|
||||
data.quartiersPrioritaires,
|
||||
noEditStyle(QP_POLYGON_STYLE),
|
||||
'quartiersPrioritaires'
|
||||
);
|
||||
}
|
||||
|
||||
export function drawUserSelection(map, data) {
|
||||
if (data.selection.length > 0) {
|
||||
const polygon = L.polygon(data.selection, {
|
||||
color: 'red',
|
||||
zIndex: 3
|
||||
}).addTo(map);
|
||||
map.fitBounds(polygon.getBounds());
|
||||
}
|
||||
}
|
62
app/javascript/new_design/champs/carte.js
Normal file
62
app/javascript/new_design/champs/carte.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { CREATE } from 'leaflet-freedraw';
|
||||
import { delegate } from '@utils';
|
||||
import {
|
||||
initMap,
|
||||
getCurrentMap,
|
||||
geocodeAddress,
|
||||
drawCadastre,
|
||||
drawQuartiersPrioritaires,
|
||||
drawUserSelection,
|
||||
addFreeDrawEvents
|
||||
} from '../../shared/carte';
|
||||
|
||||
function initialize() {
|
||||
for (let element of document.querySelectorAll('.carte')) {
|
||||
diplayMap(element, null, true);
|
||||
}
|
||||
|
||||
window.DS.drawMapData = (selector, data) => {
|
||||
let element = document.querySelector(selector);
|
||||
diplayMap(element, data);
|
||||
};
|
||||
}
|
||||
|
||||
function diplayMap(element, data, initial = false) {
|
||||
data = data || JSON.parse(element.dataset.geo);
|
||||
let editable = element.classList.contains('edit');
|
||||
|
||||
let map = initMap(element, data.position, editable);
|
||||
|
||||
// draw external polygons
|
||||
drawCadastre(map, data, editable);
|
||||
drawQuartiersPrioritaires(map, data, editable);
|
||||
|
||||
// draw user polygon
|
||||
if (initial) {
|
||||
drawUserSelection(map, data, editable);
|
||||
|
||||
if (editable) {
|
||||
let input = element.parentElement.querySelector('input[data-remote]');
|
||||
addFreeDrawEvents(map, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('turbolinks:load', initialize);
|
||||
|
||||
delegate('click', '.toolbar .new-area', event => {
|
||||
event.preventDefault();
|
||||
let map = getCurrentMap(event.target);
|
||||
|
||||
if (map) {
|
||||
map.freeDraw.mode(CREATE);
|
||||
}
|
||||
});
|
||||
|
||||
delegate('autocomplete:select', '.toolbar [data-address]', event => {
|
||||
let map = getCurrentMap(event.target);
|
||||
|
||||
if (map) {
|
||||
geocodeAddress(map, event.detail.label);
|
||||
}
|
||||
});
|
|
@ -1,81 +1,52 @@
|
|||
import L from 'leaflet';
|
||||
|
||||
import FreeDraw, { NONE, CREATE } from 'leaflet-freedraw';
|
||||
import { fire, on, getJSON } from '@utils';
|
||||
|
||||
import { CREATE } from 'leaflet-freedraw';
|
||||
import { on } from '@utils';
|
||||
import { getData } from '../shared/data';
|
||||
import { initMap } from '../shared/carto';
|
||||
|
||||
import polygonArea from './carto/polygon_area';
|
||||
import drawFactory from './carto/draw';
|
||||
import {
|
||||
initMap,
|
||||
geocodeAddress,
|
||||
drawUserSelection,
|
||||
drawCadastre,
|
||||
drawQuartiersPrioritaires,
|
||||
addFreeDrawEvents
|
||||
} from '../shared/carte';
|
||||
|
||||
function initialize() {
|
||||
if (document.getElementById('map')) {
|
||||
const data = getData('carto');
|
||||
const position = data.position;
|
||||
const element = document.getElementById('map');
|
||||
|
||||
const map = initMap(position);
|
||||
const freeDraw = new FreeDraw({
|
||||
mode: NONE,
|
||||
smoothFactor: 4,
|
||||
mergePolygons: false
|
||||
if (element) {
|
||||
const data = getData('carto');
|
||||
const map = initMap(element, data.position, true);
|
||||
|
||||
addAddressSelectEvent(map);
|
||||
|
||||
on('#new', 'click', () => {
|
||||
map.freeDraw.mode(CREATE);
|
||||
});
|
||||
|
||||
map.addLayer(freeDraw);
|
||||
const cartoDrawZones = data => {
|
||||
drawCadastre(map, data, true);
|
||||
drawQuartiersPrioritaires(map, data, true);
|
||||
};
|
||||
|
||||
addEventFreeDraw(freeDraw);
|
||||
addEventSearchAddress(map);
|
||||
|
||||
const cartoDrawZones = drawFactory(map, freeDraw);
|
||||
window.DS = { cartoDrawZones };
|
||||
|
||||
// draw external polygons
|
||||
cartoDrawZones(data);
|
||||
|
||||
if (freeDraw.polygons[0]) {
|
||||
map.setZoom(18);
|
||||
map.fitBounds(freeDraw.polygons[0].getBounds());
|
||||
}
|
||||
// draw user polygon
|
||||
drawUserSelection(map, data, true);
|
||||
addFreeDrawEvents(map, 'input[name=selection]');
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('turbolinks:load', initialize);
|
||||
|
||||
function addEventFreeDraw(freeDraw) {
|
||||
freeDraw.on('markers', ({ latLngs }) => {
|
||||
const input = document.querySelector('input[name=selection]');
|
||||
|
||||
if (polygonArea(latLngs) < 300000) {
|
||||
input.value = JSON.stringify(latLngs);
|
||||
} else {
|
||||
input.value = '{ "error": "TooManyPolygons" }';
|
||||
}
|
||||
|
||||
fire(input, 'change');
|
||||
});
|
||||
|
||||
on('#map', 'click', () => {
|
||||
freeDraw.mode(NONE);
|
||||
});
|
||||
|
||||
on('#new', 'click', () => {
|
||||
freeDraw.mode(CREATE);
|
||||
});
|
||||
}
|
||||
|
||||
function getAddressPoint(map, request) {
|
||||
getJSON('/address/geocode', { request }).then(data => {
|
||||
if (data.lat !== null) {
|
||||
map.setView(new L.LatLng(data.lat, data.lon), data.zoom);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addEventSearchAddress(map) {
|
||||
function addAddressSelectEvent(map) {
|
||||
on(
|
||||
'#search-by-address input[type=address]',
|
||||
'autocomplete:select',
|
||||
(_, seggestion) => {
|
||||
getAddressPoint(map, seggestion['label']);
|
||||
(_, { label }) => {
|
||||
geocodeAddress(map, label);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import { EDIT, DELETE } from 'leaflet-freedraw';
|
||||
import { on } from '@utils';
|
||||
|
||||
import {
|
||||
drawLayer,
|
||||
CADASTRE_POLYGON_STYLE,
|
||||
QP_POLYGON_STYLE
|
||||
} from '../../shared/carto';
|
||||
|
||||
const SOURCES = {
|
||||
cadastres: CADASTRE_POLYGON_STYLE,
|
||||
quartiersPrioritaires: QP_POLYGON_STYLE
|
||||
};
|
||||
|
||||
export default function draw(map, freeDraw) {
|
||||
return data => {
|
||||
if (data.selection) {
|
||||
drawSelection(freeDraw, data.selection);
|
||||
}
|
||||
for (let source of Object.keys(SOURCES)) {
|
||||
if (data[source]) {
|
||||
drawLayer(map, data[source], SOURCES[source], source);
|
||||
}
|
||||
}
|
||||
addEventEdit(freeDraw);
|
||||
};
|
||||
}
|
||||
|
||||
function drawSelection(selection, freeDraw) {
|
||||
for (let polygon of selection) {
|
||||
freeDraw.createPolygon(polygon);
|
||||
}
|
||||
}
|
||||
|
||||
function addEventEdit(freeDraw) {
|
||||
document
|
||||
.querySelector('.leaflet-container svg')
|
||||
.removeAttribute('pointer-events');
|
||||
|
||||
on('.leaflet-container g path', 'click', () => {
|
||||
setTimeout(() => {
|
||||
freeDraw.mode(EDIT | DELETE);
|
||||
}, 50);
|
||||
});
|
||||
}
|
|
@ -18,6 +18,7 @@ import '../new_design/form-validation';
|
|||
import '../new_design/carto';
|
||||
import '../new_design/select2';
|
||||
|
||||
import '../new_design/champs/carte';
|
||||
import '../new_design/champs/linked-drop-down-list';
|
||||
|
||||
import { toggleCondidentielExplanation } from '../new_design/avis';
|
||||
|
|
188
app/javascript/shared/carte.js
Normal file
188
app/javascript/shared/carte.js
Normal file
|
@ -0,0 +1,188 @@
|
|||
import L from 'leaflet';
|
||||
import FreeDraw, { NONE, EDIT, DELETE } from 'leaflet-freedraw';
|
||||
import { fire, getJSON, delegate } from '@utils';
|
||||
|
||||
import polygonArea from './polygon_area';
|
||||
|
||||
const LAYERS = {};
|
||||
const MAPS = new WeakMap();
|
||||
|
||||
export function initMap(element, position, editable = false) {
|
||||
if (MAPS.has(element)) {
|
||||
return MAPS.get(element);
|
||||
} else {
|
||||
const map = L.map(element, {
|
||||
scrollWheelZoom: false
|
||||
}).setView([position.lat, position.lon], editable ? 18 : position.zoom);
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
if (editable) {
|
||||
const freeDraw = new FreeDraw({
|
||||
mode: NONE,
|
||||
smoothFactor: 4,
|
||||
mergePolygons: false
|
||||
});
|
||||
map.addLayer(freeDraw);
|
||||
map.freeDraw = freeDraw;
|
||||
}
|
||||
|
||||
MAPS.set(element, map);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
export function drawCadastre(map, { cadastres }, editable = false) {
|
||||
drawLayer(
|
||||
map,
|
||||
cadastres,
|
||||
editable ? CADASTRE_POLYGON_STYLE : noEditStyle(CADASTRE_POLYGON_STYLE),
|
||||
'cadastres'
|
||||
);
|
||||
}
|
||||
|
||||
export function drawQuartiersPrioritaires(
|
||||
map,
|
||||
{ quartiersPrioritaires },
|
||||
editable = false
|
||||
) {
|
||||
drawLayer(
|
||||
map,
|
||||
quartiersPrioritaires,
|
||||
editable ? QP_POLYGON_STYLE : noEditStyle(QP_POLYGON_STYLE),
|
||||
'quartiersPrioritaires'
|
||||
);
|
||||
}
|
||||
|
||||
export function drawUserSelection(map, { selection }, editable = false) {
|
||||
let hasSelection = selection && selection.length > 0;
|
||||
|
||||
if (editable) {
|
||||
if (hasSelection) {
|
||||
selection.forEach(polygon => map.freeDraw.create(polygon));
|
||||
let polygon = map.freeDraw.all()[0];
|
||||
if (polygon) {
|
||||
map.fitBounds(polygon.getBounds());
|
||||
}
|
||||
}
|
||||
} else if (hasSelection) {
|
||||
const polygon = L.polygon(selection, {
|
||||
color: 'red',
|
||||
zIndex: 3
|
||||
}).addTo(map);
|
||||
|
||||
map.fitBounds(polygon.getBounds());
|
||||
}
|
||||
}
|
||||
|
||||
export function geocodeAddress(map, query) {
|
||||
getJSON('/address/geocode', { request: query }).then(data => {
|
||||
if (data.lat !== null) {
|
||||
map.setView(new L.LatLng(data.lat, data.lon), data.zoom);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getCurrentMap(input) {
|
||||
let element = input.closest('.toolbar').parentElement.querySelector('.carte');
|
||||
|
||||
if (MAPS.has(element)) {
|
||||
return MAPS.get(element);
|
||||
}
|
||||
}
|
||||
|
||||
export function addFreeDrawEvents(map, selector) {
|
||||
const input = findInput(selector);
|
||||
map.freeDraw.on('markers', ({ latLngs }) => {
|
||||
if (latLngs.length === 0) {
|
||||
input.value = '';
|
||||
} else if (polygonArea(latLngs) < 300000) {
|
||||
input.value = JSON.stringify(latLngs);
|
||||
} else {
|
||||
input.value = '{ "error": "TooManyPolygons" }';
|
||||
}
|
||||
|
||||
fire(input, 'change');
|
||||
});
|
||||
}
|
||||
|
||||
function findInput(selector) {
|
||||
return typeof selector === 'string'
|
||||
? document.querySelector(selector)
|
||||
: selector;
|
||||
}
|
||||
|
||||
function createLayer(map, layerName) {
|
||||
const layer = (LAYERS[layerName] = new L.GeoJSON(undefined, {
|
||||
interactive: false
|
||||
}));
|
||||
layer.addTo(map);
|
||||
return layer;
|
||||
}
|
||||
|
||||
function removeLayer(map, layerName) {
|
||||
const layer = LAYERS[layerName];
|
||||
|
||||
if (layer) {
|
||||
delete LAYERS[layerName];
|
||||
map.removeLayer(layer);
|
||||
}
|
||||
}
|
||||
|
||||
function drawLayer(map, data, style, layerName = 'default') {
|
||||
removeLayer(map, layerName);
|
||||
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
const layer = createLayer(map, layerName);
|
||||
|
||||
data.forEach(function(item) {
|
||||
layer.addData(item.geometry);
|
||||
});
|
||||
|
||||
layer.setStyle(style).addTo(map);
|
||||
}
|
||||
}
|
||||
|
||||
function noEditStyle(style) {
|
||||
return Object.assign({}, style, {
|
||||
opacity: 0.7,
|
||||
fillOpacity: 0.5,
|
||||
color: style.fillColor
|
||||
});
|
||||
}
|
||||
|
||||
const POLYGON_STYLE = {
|
||||
weight: 2,
|
||||
opacity: 0.3,
|
||||
color: 'white',
|
||||
dashArray: '3',
|
||||
fillOpacity: 0.7
|
||||
};
|
||||
|
||||
const CADASTRE_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
|
||||
fillColor: '#8a6d3b'
|
||||
});
|
||||
|
||||
const QP_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
|
||||
fillColor: '#31708f'
|
||||
});
|
||||
|
||||
delegate('click', '.carte.edit', event => {
|
||||
let element = event.target;
|
||||
let isPath = element.matches('.leaflet-container g path');
|
||||
let map = element.matches('.carte') ? element : element.closest('.carte');
|
||||
let freeDraw = MAPS.has(map) ? MAPS.get(map).freeDraw : null;
|
||||
|
||||
if (freeDraw) {
|
||||
if (isPath) {
|
||||
setTimeout(() => {
|
||||
freeDraw.mode(EDIT | DELETE);
|
||||
}, 50);
|
||||
} else {
|
||||
freeDraw.mode(NONE);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,71 +0,0 @@
|
|||
import L from 'leaflet';
|
||||
|
||||
const LAYERS = {};
|
||||
|
||||
export function initMap(position) {
|
||||
const map = L.map('map', {
|
||||
scrollWheelZoom: false
|
||||
}).setView([position.lat, position.lon], position.zoom);
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
export function drawLayer(map, data, style, layerName = 'default') {
|
||||
removeLayer(map, layerName);
|
||||
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
const layer = createLayer(map, layerName);
|
||||
|
||||
data.forEach(function(item) {
|
||||
layer.addData(item.geometry);
|
||||
});
|
||||
|
||||
layer.setStyle(style).addTo(map);
|
||||
}
|
||||
}
|
||||
|
||||
export function noEditStyle(style) {
|
||||
return Object.assign({}, style, {
|
||||
opacity: 0.7,
|
||||
fillOpacity: 0.5,
|
||||
color: style.fillColor
|
||||
});
|
||||
}
|
||||
|
||||
const POLYGON_STYLE = {
|
||||
weight: 2,
|
||||
opacity: 0.3,
|
||||
color: 'white',
|
||||
dashArray: '3',
|
||||
fillOpacity: 0.7
|
||||
};
|
||||
|
||||
export const CADASTRE_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
|
||||
fillColor: '#8a6d3b'
|
||||
});
|
||||
|
||||
export const QP_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
|
||||
fillColor: '#31708f'
|
||||
});
|
||||
|
||||
function createLayer(map, layerName) {
|
||||
const layer = (LAYERS[layerName] = new L.GeoJSON(undefined, {
|
||||
interactive: false
|
||||
}));
|
||||
layer.addTo(map);
|
||||
return layer;
|
||||
}
|
||||
|
||||
function removeLayer(map, layerName) {
|
||||
const layer = LAYERS[layerName];
|
||||
|
||||
if (layer) {
|
||||
delete LAYERS[layerName];
|
||||
map.removeLayer(layer);
|
||||
}
|
||||
}
|
|
@ -17,7 +17,16 @@ class Champ < ApplicationRecord
|
|||
end
|
||||
|
||||
def mandatory_and_blank?
|
||||
mandatory? && value.blank?
|
||||
if mandatory?
|
||||
case type_de_champ.type_champ
|
||||
when TypeDeChamp.type_champs.fetch(:carte)
|
||||
value.blank? || value == '[]'
|
||||
else
|
||||
value.blank?
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def search_terms
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Champs::CarteChamp < Champ
|
||||
has_many :geo_areas, dependent: :destroy
|
||||
has_many :geo_areas, foreign_key: :champ_id, dependent: :destroy
|
||||
|
||||
# We are not using scopes here as we want to access
|
||||
# the following collections on unsaved records.
|
||||
|
@ -15,6 +15,14 @@ class Champs::CarteChamp < Champ
|
|||
end
|
||||
end
|
||||
|
||||
def cadastres?
|
||||
type_de_champ&.cadastres && type_de_champ.cadastres != '0'
|
||||
end
|
||||
|
||||
def quartiers_prioritaires?
|
||||
type_de_champ&.quartiers_prioritaires && type_de_champ.quartiers_prioritaires != '0'
|
||||
end
|
||||
|
||||
def position
|
||||
if dossier.present?
|
||||
dossier.geo_position
|
||||
|
@ -26,4 +34,8 @@ class Champs::CarteChamp < Champ
|
|||
{ lon: lon, lat: lat, zoom: zoom }
|
||||
end
|
||||
end
|
||||
|
||||
def zones
|
||||
value.blank? ? [] : JSON.parse(value)
|
||||
end
|
||||
end
|
||||
|
|
11
app/serializers/champs/carte_champ_serializer.rb
Normal file
11
app/serializers/champs/carte_champ_serializer.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
class Champs::CarteChampSerializer < ChampSerializer
|
||||
has_many :geo_areas
|
||||
|
||||
def value
|
||||
if object.value.present?
|
||||
JSON.parse(object.value)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
12
app/serializers/champs/siret_champ_serializer.rb
Normal file
12
app/serializers/champs/siret_champ_serializer.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
class Champs::SiretChampSerializer < ChampSerializer
|
||||
has_one :etablissement
|
||||
has_one :entreprise
|
||||
|
||||
def etablissement
|
||||
object.etablissement
|
||||
end
|
||||
|
||||
def entreprise
|
||||
object.etablissement&.entreprise
|
||||
end
|
||||
end
|
16
app/serializers/geo_area_serializer.rb
Normal file
16
app/serializers/geo_area_serializer.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class GeoAreaSerializer < ActiveModel::Serializer
|
||||
attributes :geometry,
|
||||
:source,
|
||||
:surface_intersection,
|
||||
:surface_parcelle,
|
||||
:numero,
|
||||
:feuille,
|
||||
:section,
|
||||
:code_dep,
|
||||
:nom_com,
|
||||
:code_com,
|
||||
:code_arr,
|
||||
:code,
|
||||
:nom,
|
||||
:commune
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
class ProcedureSerializer < ActiveModel::Serializer
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
attribute :libelle, key: :label
|
||||
attribute :lien_demarche, key: :link
|
||||
|
||||
attributes :id,
|
||||
:description,
|
||||
|
@ -8,10 +9,30 @@ class ProcedureSerializer < ActiveModel::Serializer
|
|||
:direction,
|
||||
:archived_at,
|
||||
:geographic_information,
|
||||
:total_dossier
|
||||
:total_dossier,
|
||||
:link,
|
||||
:state
|
||||
|
||||
has_one :geographic_information, serializer: ModuleApiCartoSerializer
|
||||
has_many :types_de_champ, serializer: TypeDeChampSerializer
|
||||
has_many :types_de_champ_private, serializer: TypeDeChampSerializer
|
||||
has_many :types_de_piece_justificative, serializer: TypeDePieceJustificativeSerializer
|
||||
|
||||
def link
|
||||
if object.path.present?
|
||||
if object.brouillon_avec_lien?
|
||||
commencer_test_url(procedure_path: object.path)
|
||||
else
|
||||
commencer_url(procedure_path: object.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def state
|
||||
object.aasm_state
|
||||
end
|
||||
|
||||
def geographic_information
|
||||
object.module_api_carto
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,8 @@ class TypesDeChampService
|
|||
:id,
|
||||
:mandatory,
|
||||
:piece_justificative_template,
|
||||
:quartiers_prioritaires,
|
||||
:cadastres,
|
||||
drop_down_list_attributes: [:value, :id]
|
||||
])
|
||||
|
||||
|
|
|
@ -38,6 +38,16 @@
|
|||
= ff.file_field :piece_justificative_template,
|
||||
direct_upload: true
|
||||
|
||||
.form-group.carte-options{ class: (type_champ == TypeDeChamp.type_champs.fetch(:carte)) ? 'show-inline' : nil }
|
||||
%h4 Utilisation de la cartographie
|
||||
%label
|
||||
= ff.check_box :quartiers_prioritaires
|
||||
Quartiers prioritaires
|
||||
%br
|
||||
%label
|
||||
= ff.check_box :cadastres
|
||||
Cadastre
|
||||
|
||||
- hide_mandatory = (ff.object.object.private? || type_champ == TypeDeChamp.type_champs.fetch(:explication))
|
||||
.form-group.mandatory{ style: hide_mandatory ? 'visibility: hidden;' : nil }
|
||||
%h4 Obligatoire ?
|
||||
|
|
|
@ -7,19 +7,29 @@
|
|||
Je vous remercie de l’intérêt que vous portez à notre outil de dématérialisation de démarches.
|
||||
|
||||
%p
|
||||
Votre compte administrateur a été créé pour l'adresse email #{@admin.email}. Pour l’activer, je vous invite à cliquer sur le lien suivant :
|
||||
= link_to(admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token))
|
||||
Votre compte administrateur a été créé pour l'adresse email #{@admin.email}.
|
||||
|
||||
%p
|
||||
%b
|
||||
Pour l’activer, cliquez sur le lien suivant :
|
||||
= link_to(admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token))
|
||||
|
||||
%p
|
||||
Afin de vous accompagner dans la découverte de demarches-simplifiees.fr, je vous propose de m’appeler pour faire un point sur vos besoins de dématérialisation.
|
||||
%br
|
||||
Vous pouvez me joindre au numéro suivant :
|
||||
= CONTACT_PHONE
|
||||
= link_to(CONTACT_PHONE, "tel:#{CONTACT_PHONE}")
|
||||
\.
|
||||
|
||||
%p
|
||||
Je vous invite également à consulter notre site de documentation qui regroupe l'ensemble des informations relatives à demarches-simplifiees.fr ainsi que des tutoriels d’utilisation :
|
||||
= link_to(DOC_URL, DOC_URL)
|
||||
Je vous invite également à prendre quelques minutes pour consulter notre tutoriel à destination des nouveaux administrateurs :
|
||||
= link_to(ADMINISTRATEUR_TUTORIAL_URL, ADMINISTRATEUR_TUTORIAL_URL)
|
||||
\.
|
||||
|
||||
%p
|
||||
Enfin, vous pouvez vous inscrire à notre prochain webinaire en ligne pour découvrir les fonctionnalités de notre outil :
|
||||
= link_to(WEBINAIRE_URL, WEBINAIRE_URL)
|
||||
\.
|
||||
|
||||
%p
|
||||
= render partial: "layouts/mailers/bizdev_signature", locals: { author_name: @author_name }
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
Pour les usagers qui souhaitent remplir une démarche, l’entrée dans demarches-simplifiees.fr se fait via un lien fourni par l’administration responsable, sur son propre site web. Ce lien vous permettra de créer un compte et de remplir le formulaire dans la foulée.
|
||||
|
||||
%p
|
||||
Si par contre vous rencontrez des problèmes lors de l'utilisation de demarches-simplifiees.fr en tant qu'usager, merci d'expliciter le problème rencontré.
|
||||
Si par contre vous rencontrez des problèmes lors de l'utilisation de demarches-simplifiees.fr en tant qu'usager, merci d'expliciter le problème rencontré sur notre
|
||||
= link_to("formulaire de contact", contact_url)
|
||||
\.
|
||||
|
||||
%p
|
||||
Cordialement,
|
||||
|
|
5
app/views/champs/carte/show.js.erb
Normal file
5
app/views/champs/carte/show.js.erb
Normal file
|
@ -0,0 +1,5 @@
|
|||
<%= render_to_element("#{@selector} + .geo-areas",
|
||||
partial: 'shared/champs/carte/geo_areas',
|
||||
locals: { champ: @champ, error: @error }) %>
|
||||
|
||||
DS.drawMapData("<%= @selector %>", <%= geo_data(@champ) %>);
|
|
@ -11,8 +11,8 @@
|
|||
= link_to(gestionnaire_activate_url(token: @reset_password_token), gestionnaire_activate_url(token: @reset_password_token))
|
||||
|
||||
%p
|
||||
Par ailleurs, notre site de documentation qui regroupe l'ensemble des informations relatives à demarches-simplifiees.fr ainsi que des tutoriels d’utilisation est à votre disposition :
|
||||
= link_to(DOC_URL, DOC_URL)
|
||||
Par ailleurs, nous vous invitons à prendre quelques minutes pour consulter notre tutoriel à destination des nouveaux instructeurs :
|
||||
= link_to(INSTRUCTEUR_TUTORIAL_URL, INSTRUCTEUR_TUTORIAL_URL)
|
||||
|
||||
%p
|
||||
Bonne journée,
|
||||
|
|
|
@ -23,15 +23,10 @@
|
|||
%span.badge.warning= avis_counter
|
||||
%li
|
||||
.tab-link.contact-link
|
||||
Contact
|
||||
Aide
|
||||
.contact-details
|
||||
Vous avez besoin d’aide ? Contactez-nous :
|
||||
%br
|
||||
– par téléphone :
|
||||
= link_to CONTACT_PHONE, "tel:#{CONTACT_PHONE}"
|
||||
%br
|
||||
– par email :
|
||||
= contact_link CONTACT_EMAIL
|
||||
Besoin d’aide technique ? Contactez-nous
|
||||
= contact_link("par email")
|
||||
|
||||
- if nav_bar_profile == :user
|
||||
%ul.header-tabs
|
||||
|
|
27
app/views/shared/champs/carte/_geo_areas.html.haml
Normal file
27
app/views/shared/champs/carte/_geo_areas.html.haml
Normal file
|
@ -0,0 +1,27 @@
|
|||
- if champ.quartiers_prioritaires?
|
||||
.areas-title Quartiers prioritaires
|
||||
.areas
|
||||
- if error.present?
|
||||
.error Merci de dessiner une surface plus petite afin de récupérer les quartiers prioritaires.
|
||||
- elsif champ.value.blank?
|
||||
Aucune zone tracée
|
||||
- elsif champ.quartiers_prioritaires.blank?
|
||||
= t('errors.messages.quartiers_prioritaires_empty', count: champ.zones.size)
|
||||
- else
|
||||
%ul
|
||||
- champ.quartiers_prioritaires.each do |qp|
|
||||
%li #{qp.commune} : #{qp.nom}
|
||||
|
||||
- if champ.cadastres?
|
||||
.areas-title Parcelles cadastrales
|
||||
.areas
|
||||
- if error.present?
|
||||
.error Merci de dessiner une surface plus petite afin de récupérer les parcelles cadastrales.
|
||||
- elsif champ.value.blank?
|
||||
Aucune zone tracée
|
||||
- elsif champ.cadastres.blank?
|
||||
= t('errors.messages.cadastres_empty', count: champ.zones.size)
|
||||
- else
|
||||
%ul
|
||||
- champ.cadastres.each do |pc|
|
||||
%li Parcelle n° #{pc.numero} - Feuille #{pc.code_arr} #{pc.section} #{pc.feuille}
|
3
app/views/shared/champs/carte/_show.html.haml
Normal file
3
app/views/shared/champs/carte/_show.html.haml
Normal file
|
@ -0,0 +1,3 @@
|
|||
.carte{ data: { geo: geo_data(champ) } }
|
||||
.geo-areas
|
||||
= render partial: 'shared/champs/carte/geo_areas', locals: { champ: champ, error: false }
|
|
@ -56,6 +56,13 @@
|
|||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
- if c.etablissement.present?
|
||||
= render partial: "shared/dossiers/identite_entreprise", locals: { etablissement: c.etablissement, profile: profile }
|
||||
- when TypeDeChamp.type_champs.fetch(:carte)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
- if c.value.present?
|
||||
= render partial: "shared/champs/carte/show", locals: { champ: c }
|
||||
- else
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
%li
|
||||
= "Parcelle n° #{p.numero} - Feuille #{p.code_arr} #{p.section} #{p.feuille}"
|
||||
|
||||
= render partial: 'shared/champs/carto/init', locals: { dossier: dossier }
|
||||
= render partial: 'shared/champs/carte/init', locals: { dossier: dossier }
|
||||
|
|
11
app/views/shared/dossiers/editable_champs/_carte.html.haml
Normal file
11
app/views/shared/dossiers/editable_champs/_carte.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
|||
.toolbar
|
||||
%button.button.primary.new-area Ajouter une zone
|
||||
%input.address{ data: { address: true, autocomplete: 'address' }, placeholder: 'Saissisez une adresse ou positionner la carte' }
|
||||
|
||||
.carte.edit{ data: { geo: geo_data(champ) }, class: "carte-#{form.index}" }
|
||||
|
||||
.geo-areas
|
||||
= render partial: 'shared/champs/carte/geo_areas', locals: { champ: champ, error: false }
|
||||
|
||||
= form.hidden_field :value,
|
||||
data: { remote: true, url: champs_carte_path(form.index), params: { champ_id: champ&.id }.to_query, method: 'post' }
|
|
@ -1,8 +1,8 @@
|
|||
#carte-page.row
|
||||
.col-md-12.col-lg-12
|
||||
#map.edit
|
||||
#map.carte.edit
|
||||
|
||||
%span.zones
|
||||
= render partial: 'zones', locals: { dossier: dossier, error: @error }
|
||||
|
||||
= render partial: 'shared/champs/carto/init', locals: { dossier: dossier }
|
||||
= render partial: 'shared/champs/carte/init', locals: { dossier: dossier }
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
{
|
||||
"ignored_warnings": [
|
||||
{
|
||||
"warning_type": "Cross-Site Scripting",
|
||||
"warning_code": 2,
|
||||
"fingerprint": "0d61a1267d264f1e61cc2398a2683703ac60878129dc9515542f246a80ad575b",
|
||||
"check_name": "CrossSiteScripting",
|
||||
"message": "Unescaped model attribute",
|
||||
"file": "app/views/champs/carto/show.js.erb",
|
||||
"line": 5,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
|
||||
"code": "geo_data((Champ.joins(:dossier).where(:dossiers => ({ :user_id => logged_user_ids })).find_by(:id => params.permit(:champ_id)) or CartoChamp.new))",
|
||||
"render_path": [{"type":"controller","class":"Champs::CartoController","method":"show","line":48,"file":"app/controllers/champs/carto_controller.rb"}],
|
||||
"location": {
|
||||
"type": "template",
|
||||
"template": "champs/carto/show"
|
||||
},
|
||||
"user_input": "Champ.joins(:dossier).where(:dossiers => ({ :user_id => logged_user_ids }))",
|
||||
"confidence": "Weak",
|
||||
"note": "Not an injection because logged_user_ids have no user input"
|
||||
},
|
||||
{
|
||||
"warning_type": "SQL Injection",
|
||||
"warning_code": 0,
|
||||
|
@ -61,6 +80,6 @@
|
|||
"note": "Not an injection because of `sanitized_column`"
|
||||
}
|
||||
],
|
||||
"updated": "2018-10-11 12:09:03 +0200",
|
||||
"updated": "2018-10-16 11:28:34 +0300",
|
||||
"brakeman_version": "4.3.1"
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ FOG_BASE_URL = "https://storage.apientreprise.fr"
|
|||
|
||||
# External services URLs
|
||||
DOC_URL = "https://doc.demarches-simplifiees.fr"
|
||||
ADMINISTRATEUR_TUTORIAL_URL = "https://doc.demarches-simplifiees.fr/tutoriels/tutoriel-administrateur"
|
||||
INSTRUCTEUR_TUTORIAL_URL = "https://doc.demarches-simplifiees.fr/tutoriels/tutoriel-accompagnateur"
|
||||
WEBINAIRE_URL = "https://doc.demarches-simplifiees.fr/pour-aller-plus-loin/webinaires"
|
||||
LISTE_DES_DEMARCHES_URL = [DOC_URL, "listes-des-demarches"].join("/")
|
||||
CGU_URL = [DOC_URL, "cgu"].join("/")
|
||||
MENTIONS_LEGALES_URL = [CGU_URL, "4-mentions-legales"].join("#")
|
||||
|
|
|
@ -177,6 +177,12 @@ fr:
|
|||
connexion: "Erreur lors de la connexion à France Connect."
|
||||
extension_white_list_error: "Le format de fichier de la pièce jointe n'est pas valide."
|
||||
procedure_archived: "Cette démarche en ligne a été fermée, il n'est plus possible de déposer de dossier."
|
||||
cadastres_empty:
|
||||
one: "Aucune parcelle cadastrale sur la zone séléctionnée"
|
||||
other: "Aucune parcelle cadastrale sur les zones séléctionnées"
|
||||
quartiers_prioritaires_empty:
|
||||
one: "Aucun quartier prioritaire sur la zone séléctionnée"
|
||||
other: "Aucun quartier prioritaire sur les zones séléctionnées"
|
||||
|
||||
date:
|
||||
abbr_day_names:
|
||||
|
|
|
@ -28,3 +28,4 @@ fr:
|
|||
dossier_link: 'Lien vers un autre dossier'
|
||||
piece_justificative: 'Pièce justificative'
|
||||
siret: 'SIRET'
|
||||
carte: 'Carte'
|
||||
|
|
|
@ -125,6 +125,7 @@ Rails.application.routes.draw do
|
|||
namespace :champs do
|
||||
get ':position/siret', to: 'siret#show', as: :siret
|
||||
get ':position/dossier_link', to: 'dossier_link#show', as: :dossier_link
|
||||
post ':position/carte', to: 'carte#show', as: :carte
|
||||
end
|
||||
|
||||
namespace :commencer do
|
||||
|
|
|
@ -11,7 +11,6 @@ describe Admin::ProceduresController, type: :controller do
|
|||
let(:description) { 'Description de test' }
|
||||
let(:organisation) { 'Organisation de test' }
|
||||
let(:direction) { 'Direction de test' }
|
||||
let(:lien_demarche) { 'http://localhost.com' }
|
||||
let(:cadre_juridique) { 'cadre juridique' }
|
||||
let(:use_api_carto) { '0' }
|
||||
let(:quartiers_prioritaires) { '0' }
|
||||
|
@ -26,7 +25,6 @@ describe Admin::ProceduresController, type: :controller do
|
|||
description: description,
|
||||
organisation: organisation,
|
||||
direction: direction,
|
||||
lien_demarche: lien_demarche,
|
||||
cadre_juridique: cadre_juridique,
|
||||
duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds,
|
||||
duree_conservation_dossiers_hors_ds: duree_conservation_dossiers_hors_ds,
|
||||
|
@ -198,7 +196,6 @@ describe Admin::ProceduresController, type: :controller do
|
|||
it { expect(subject.description).to eq(description) }
|
||||
it { expect(subject.organisation).to eq(organisation) }
|
||||
it { expect(subject.direction).to eq(direction) }
|
||||
it { expect(subject.lien_demarche).to eq(lien_demarche) }
|
||||
it { expect(subject.administrateur_id).to eq(admin.id) }
|
||||
it { expect(subject.duree_conservation_dossiers_dans_ds).to eq(duree_conservation_dossiers_dans_ds) }
|
||||
it { expect(subject.duree_conservation_dossiers_hors_ds).to eq(duree_conservation_dossiers_hors_ds) }
|
||||
|
@ -270,7 +267,6 @@ describe Admin::ProceduresController, type: :controller do
|
|||
let(:description) { 'blabla' }
|
||||
let(:organisation) { 'plop' }
|
||||
let(:direction) { 'plap' }
|
||||
let(:lien_demarche) { 'http://plip.com' }
|
||||
let(:use_api_carto) { '1' }
|
||||
let(:cadastre) { '1' }
|
||||
let(:duree_conservation_dossiers_dans_ds) { 7 }
|
||||
|
@ -285,7 +281,6 @@ describe Admin::ProceduresController, type: :controller do
|
|||
it { expect(subject.description).to eq(description) }
|
||||
it { expect(subject.organisation).to eq(organisation) }
|
||||
it { expect(subject.direction).to eq(direction) }
|
||||
it { expect(subject.lien_demarche).to eq(lien_demarche) }
|
||||
it { expect(subject.duree_conservation_dossiers_dans_ds).to eq(duree_conservation_dossiers_dans_ds) }
|
||||
it { expect(subject.duree_conservation_dossiers_hors_ds).to eq(duree_conservation_dossiers_hors_ds) }
|
||||
end
|
||||
|
@ -349,7 +344,6 @@ describe Admin::ProceduresController, type: :controller do
|
|||
it { expect(subject.organisation).to eq procedure_params[:organisation] }
|
||||
it { expect(subject.direction).to eq procedure_params[:direction] }
|
||||
|
||||
it { expect(subject.lien_demarche).not_to eq procedure_params[:lien_demarche] }
|
||||
it { expect(subject.for_individual).not_to eq procedure_params[:for_individual] }
|
||||
it { expect(subject.individual_with_siret).not_to eq procedure_params[:individual_with_siret] }
|
||||
it { expect(subject.use_api_carto).not_to eq procedure_params[:module_api_carto_attributes][:use_api_carto] }
|
||||
|
|
|
@ -36,7 +36,6 @@ describe API::V1::ProceduresController, type: :controller do
|
|||
it { expect(subject[:description]).to eq(procedure.description) }
|
||||
it { expect(subject[:organisation]).to eq(procedure.organisation) }
|
||||
it { expect(subject[:direction]).to eq(procedure.direction) }
|
||||
it { expect(subject[:link]).to eq(procedure.lien_demarche) }
|
||||
it { expect(subject[:archived_at]).to eq(procedure.archived_at) }
|
||||
it { expect(subject[:total_dossier]).to eq(procedure.total_dossier) }
|
||||
it { is_expected.to have_key(:types_de_champ) }
|
||||
|
|
51
spec/controllers/champs/carte_controller_spec.rb
Normal file
51
spec/controllers/champs/carte_controller_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Champs::CarteController, type: :controller do
|
||||
let(:user) { create(:user) }
|
||||
let(:procedure) { create(:procedure, :published) }
|
||||
let(:dossier) { create(:dossier, user: user, procedure: procedure) }
|
||||
let(:params) do
|
||||
{
|
||||
dossier: {
|
||||
champs_attributes: {
|
||||
'1' => { value: selection.to_json }
|
||||
}
|
||||
},
|
||||
position: '1',
|
||||
champ_id: champ.id
|
||||
}
|
||||
end
|
||||
let(:champ) do
|
||||
create(:type_de_champ_carte, options: {
|
||||
quartiers_prioritaires: true
|
||||
}).champ.create(dossier: dossier)
|
||||
end
|
||||
|
||||
describe 'POST #show' do
|
||||
render_views
|
||||
|
||||
before { sign_in user }
|
||||
before do
|
||||
allow_any_instance_of(ApiCarto::QuartiersPrioritairesAdapter)
|
||||
.to receive(:results)
|
||||
.and_return([{ code: "QPCODE1234", geometry: { type: "MultiPolygon", coordinates: [[[[2.38715792094576, 48.8723062632126], [2.38724851642619, 48.8721392348061]]]] } }])
|
||||
|
||||
post :show, params: params, format: 'js'
|
||||
end
|
||||
|
||||
context 'when coordinates are empty' do
|
||||
let(:selection) { [] }
|
||||
|
||||
it { expect(response.body).to include("DS.drawMapData(\".carte-1\", {\"position\":{\"lon\":\"2.428462\",\"lat\":\"46.538192\",\"zoom\":\"13\"},\"selection\":[],\"quartiersPrioritaires\":[],\"cadastres\":[]});") }
|
||||
end
|
||||
|
||||
context 'when coordinates are informed' do
|
||||
let(:selection) { [[{ "lat": 48.87442541960633, "lng": 2.3859214782714844 }, { "lat": 48.87273183590832, "lng": 2.3850631713867183 }, { "lat": 48.87081237174292, "lng": 2.3809432983398438 }, { "lat": 48.8712640169951, "lng": 2.377510070800781 }, { "lat": 48.87510283703279, "lng": 2.3778533935546875 }, { "lat": 48.87544154230615, "lng": 2.382831573486328 }, { "lat": 48.87442541960633, "lng": 2.3859214782714844 }]] }
|
||||
|
||||
it { expect(response.body).not_to be_nil }
|
||||
it { expect(response.body).to include('QPCODE1234') }
|
||||
it { expect(response.body).to include('MultiPolygon') }
|
||||
it { expect(response.body).to include('[2.38715792094576,48.8723062632126]') }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,11 +26,4 @@ describe ProcedureDecorator do
|
|||
subject { super().logo_img }
|
||||
it { is_expected.to match(/http.*#{ActionController::Base.helpers.image_url("marianne.svg")}/) }
|
||||
end
|
||||
|
||||
describe 'geographic_information' do
|
||||
subject { super().geographic_information }
|
||||
it { expect(subject.use_api_carto).to be_falsey }
|
||||
it { expect(subject.quartiers_prioritaires).to be_falsey }
|
||||
it { expect(subject.cadastre).to be_falsey }
|
||||
end
|
||||
end
|
||||
|
|
7
spec/factories/geo_area.rb
Normal file
7
spec/factories/geo_area.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
FactoryBot.define do
|
||||
factory :geo_area do
|
||||
source { GeoArea.sources.fetch(:cadastre) }
|
||||
numero { '42' }
|
||||
feuille { 'A11' }
|
||||
end
|
||||
end
|
|
@ -1,7 +1,6 @@
|
|||
FactoryBot.define do
|
||||
sequence(:published_path) { |n| "fake_path#{n}" }
|
||||
factory :procedure do
|
||||
lien_demarche { 'http://localhost' }
|
||||
sequence(:libelle) { |n| "Procedure #{n}" }
|
||||
description { "Demande de subvention à l'intention des associations" }
|
||||
organisation { "Orga DINSIC" }
|
||||
|
|
|
@ -9,6 +9,12 @@ shared_examples 'champ_spec' do
|
|||
it { expect(champ.mandatory_and_blank?).to be(true) }
|
||||
end
|
||||
|
||||
context 'when carte mandatory and blank' do
|
||||
let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) }
|
||||
let(:value) { '[]' }
|
||||
it { expect(champ.mandatory_and_blank?).to be(true) }
|
||||
end
|
||||
|
||||
context 'when not blank' do
|
||||
let(:value) { 'yop' }
|
||||
it { expect(champ.mandatory_and_blank?).to be(false) }
|
||||
|
|
|
@ -164,12 +164,6 @@ describe Procedure do
|
|||
it { is_expected.to allow_value('Description Demande de subvention').for(:description) }
|
||||
end
|
||||
|
||||
context 'lien_demarche' do
|
||||
it { is_expected.to allow_value(nil).for(:lien_demarche) }
|
||||
it { is_expected.to allow_value('').for(:lien_demarche) }
|
||||
it { is_expected.to allow_value('http://localhost').for(:lien_demarche) }
|
||||
end
|
||||
|
||||
context 'organisation' do
|
||||
it { is_expected.to allow_value('URRSAF').for(:organisation) }
|
||||
end
|
||||
|
|
18
spec/serializers/champs/carte_champ_serializer_spec.rb
Normal file
18
spec/serializers/champs/carte_champ_serializer_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
describe Champs::CarteChampSerializer do
|
||||
describe '#attributes' do
|
||||
subject { Champs::CarteChampSerializer.new(champ).serializable_hash }
|
||||
|
||||
context 'when type champ is carte' do
|
||||
let(:geo_area) { create(:geo_area) }
|
||||
let(:champ) { create(:type_de_champ_carte).champ.create(geo_areas: [geo_area]) }
|
||||
|
||||
it {
|
||||
expect(subject[:geo_areas].first).to include(
|
||||
source: GeoArea.sources.fetch(:cadastre),
|
||||
numero: '42',
|
||||
feuille: 'A11'
|
||||
)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
16
spec/serializers/champs/siret_champ_serializer_spec.rb
Normal file
16
spec/serializers/champs/siret_champ_serializer_spec.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
describe Champs::SiretChampSerializer do
|
||||
describe '#attributes' do
|
||||
subject { Champs::SiretChampSerializer.new(champ).serializable_hash }
|
||||
|
||||
context 'when type champ is siret' do
|
||||
let(:etablissement) { create(:etablissement) }
|
||||
let(:champ) { create(:type_de_champ_siret).champ.create(etablissement: etablissement, value: etablissement.siret) }
|
||||
|
||||
it {
|
||||
is_expected.to include(value: etablissement.siret)
|
||||
expect(subject[:etablissement]).to include(siret: etablissement.siret)
|
||||
expect(subject[:entreprise]).to include(capital_social: etablissement.entreprise_capital_social)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
11
spec/serializers/procedure_serializer_spec.rb
Normal file
11
spec/serializers/procedure_serializer_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
describe ProcedureSerializer do
|
||||
describe '#attributes' do
|
||||
subject { ProcedureSerializer.new(procedure).serializable_hash }
|
||||
let(:procedure) { create(:procedure, :published) }
|
||||
|
||||
it {
|
||||
is_expected.to include(link: "http://localhost:3000/commencer/#{procedure.path}")
|
||||
is_expected.to include(state: "publiee")
|
||||
}
|
||||
end
|
||||
end
|
|
@ -27,7 +27,7 @@ describe 'layouts/_new_header.html.haml', type: :view do
|
|||
|
||||
it "displays the contact infos" do
|
||||
expect(rendered).to have_text("Contact")
|
||||
expect(rendered).to have_link(CONTACT_EMAIL, href: contact_url)
|
||||
expect(rendered).to have_link("par email", href: contact_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue