diff --git a/Gemfile b/Gemfile index e9b747f60..81ac050d8 100644 --- a/Gemfile +++ b/Gemfile @@ -64,6 +64,7 @@ gem 'rgeo-geojson' gem 'sanitize-url' gem 'sassc-rails' # Use SCSS for stylesheets gem 'scenic' +gem 'select2-rails' gem 'sentry-raven' gem 'skylight' gem 'smart_listing' diff --git a/Gemfile.lock b/Gemfile.lock index f821df77a..98b4576bf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -592,6 +592,8 @@ GEM scss_lint (0.57.1) rake (>= 0.9, < 13) sass (~> 3.5, >= 3.5.5) + select2-rails (4.0.3) + thor (~> 0.14) selectize-rails (0.12.6) selenium-webdriver (3.141.0) childprocess (~> 0.5) @@ -791,6 +793,7 @@ DEPENDENCIES sassc-rails scenic scss_lint + select2-rails sentry-raven shoulda-matchers simple_xlsx_reader diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 2f3b5b45e..e9dd51d18 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -29,6 +29,7 @@ // = require search // = require site_banner // = require switch_menu +// = require autocomplete // = require users // = require attestation_template_edit diff --git a/app/assets/stylesheets/autocomplete.scss b/app/assets/stylesheets/autocomplete.scss new file mode 100644 index 000000000..b46086c3f --- /dev/null +++ b/app/assets/stylesheets/autocomplete.scss @@ -0,0 +1,33 @@ +.algolia-autocomplete { + width: 100%; +} + +.algolia-autocomplete .aa-input, +.algolia-autocomplete .aa-hint { + width: 100%; +} + +.algolia-autocomplete .aa-hint { + color: #999999; +} + +.algolia-autocomplete .aa-dropdown-menu { + width: 100%; + background-color: #FFFFFF; + border: 1px solid #999999; + border-top: none; +} + +.algolia-autocomplete .aa-dropdown-menu .aa-suggestion { + cursor: pointer; + padding: 5px 4px; +} + +.algolia-autocomplete .aa-dropdown-menu .aa-suggestion.aa-cursor { + background-color: #B2D7FF; +} + +.algolia-autocomplete .aa-dropdown-menu .aa-suggestion em { + font-weight: bold; + font-style: normal; +} diff --git a/app/assets/stylesheets/new_design/forms.scss b/app/assets/stylesheets/new_design/forms.scss index 62d37cb09..07455dfff 100644 --- a/app/assets/stylesheets/new_design/forms.scss +++ b/app/assets/stylesheets/new_design/forms.scss @@ -242,16 +242,6 @@ } } - .select2-selection--single { - min-height: 62px; - - // scss-lint:disable SelectorFormat - .select2-selection__arrow { - display: none; - } - // scss-lint:enable - } - // scss-lint:disable SelectorFormat .select2-selection__rendered { padding: $default-padding; diff --git a/app/assets/stylesheets/new_design/map.scss b/app/assets/stylesheets/new_design/map.scss index 588030137..aa30790d2 100644 --- a/app/assets/stylesheets/new_design/map.scss +++ b/app/assets/stylesheets/new_design/map.scss @@ -63,10 +63,6 @@ width: 200px; margin-right: 10px; } - - .select2-container { - margin-bottom: 0; - } } } diff --git a/app/assets/stylesheets/new_design/new_application.scss b/app/assets/stylesheets/new_design/new_application.scss index af88e9f77..2fffd36b7 100644 --- a/app/assets/stylesheets/new_design/new_application.scss +++ b/app/assets/stylesheets/new_design/new_application.scss @@ -5,5 +5,6 @@ // = require ./fonts // = require leaflet // = require select2 +// = require autocomplete // = require_tree . // = stub ./print.scss diff --git a/app/controllers/address_controller.rb b/app/controllers/address_controller.rb new file mode 100644 index 000000000..6ae345d37 --- /dev/null +++ b/app/controllers/address_controller.rb @@ -0,0 +1,24 @@ +class AddressController < ApplicationController + def suggestions + request = params[:request] + + json = ApiAdresse::AddressAdapter.new(request).get_suggestions.map do |value| + { label: value } + end.to_json + + render json: json + end + + def geocode + request = params[:request] + + point = ApiAdresse::PointAdapter.new(request).geocode + + if point.present? + lon = point.x.to_s + lat = point.y.to_s + end + + render json: { lon: lon, lat: lat, zoom: '14', dossier_id: params[:dossier_id] } + end +end diff --git a/app/controllers/api_geo_test_controller.rb b/app/controllers/api_geo_test_controller.rb deleted file mode 100644 index 9328dc830..000000000 --- a/app/controllers/api_geo_test_controller.rb +++ /dev/null @@ -1,13 +0,0 @@ -class APIGeoTestController < ActionController::Base - def regions - render json: [{ nom: 'Martinique' }] - end - - def departements - render json: [{ nom: 'Aisne', code: '02' }] - end - - def communes - render json: [{ nom: 'Ambléon' }] - end -end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c192c0f75..e5cba17b3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -117,7 +117,6 @@ class ApplicationController < ActionController::Base def setup_javascript_settings gon.autosave = Rails.application.config.ds_autosave - gon.autocomplete = Rails.application.secrets.autocomplete end def setup_tracking diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 7d6ede50c..7f6364605 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -1012,11 +1012,6 @@ enum TypeDeChamp { """ civilite - """ - Communes - """ - communes - """ Date """ diff --git a/app/javascript/new_design/select2.js b/app/javascript/new_design/select2.js index 8de34648d..a9fa8506c 100644 --- a/app/javascript/new_design/select2.js +++ b/app/javascript/new_design/select2.js @@ -1,158 +1,46 @@ import $ from 'jquery'; import 'select2'; -const { api_geo_url, api_adresse_url } = gon.autocomplete || {}; - -const language = { - errorLoading: function() { - return 'Les résultats ne peuvent pas être chargés.'; - }, - inputTooLong: function(args) { - var overChars = args.input.length - args.maximum; - - return 'Supprimez ' + overChars + ' caractère' + (overChars > 1 ? 's' : ''); - }, - inputTooShort: function(args) { - var remainingChars = args.minimum - args.input.length; - - return ( - 'Saisissez au moins ' + - remainingChars + - ' caractère' + - (remainingChars > 1 ? 's' : '') - ); - }, - loadingMore: function() { - return 'Chargement de résultats supplémentaires…'; - }, - maximumSelected: function(args) { - return ( - 'Vous pouvez seulement sélectionner ' + - args.maximum + - ' élément' + - (args.maximum > 1 ? 's' : '') - ); - }, - noResults: function() { - return 'Aucun résultat trouvé'; - }, - searching: function() { - return 'Recherche en cours…'; - }, - removeAllItems: function() { - return 'Supprimer tous les éléments'; - } -}; - -const baseOptions = { - language, - width: '100%' -}; - -const baseAjaxOptions = { - delay: 250, - cache: true, - data({ term: nom }) { - return { - nom, - fields: 'nom,code' - }; - }, - processResults(data) { - return { - results: data.map(({ nom }) => ({ id: nom, text: nom })) - }; - } -}; - -const regionsOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { url: `${api_geo_url}/regions`, ...baseAjaxOptions } -}; - -const communesOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { url: `${api_geo_url}/communes`, ...baseAjaxOptions } -}; - -const etranger99 = { id: '99 - Étranger', text: '99 - Étranger' }; -const departementsOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { - ...baseAjaxOptions, - url: `${api_geo_url}/departements`, - processResults(data) { - return { - results: data - .map(({ nom, code }) => ({ - id: `${code} - ${nom}`, - text: `${code} - ${nom}` - })) - .concat([etranger99]) - }; - } - } -}; - -const adresseOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { - ...baseAjaxOptions, - url: `${api_adresse_url}/search`, - data({ term: q }) { - return { - q, - limit: 5 - }; - }, - processResults(data) { - return { - results: data.features.map(({ properties: { label }, geometry }) => ({ - id: label, - text: label, - geometry - })) - }; - } - } -}; - -const templateOption = ({ text }) => +const optionTemplate = email => $( - `${text}` + '' + + email.text + + '' ); addEventListener('ds:page:update', () => { - $('select.select2').select2(baseOptions); - $('select.select2.departements').select2(departementsOptions); - $('select.select2.regions').select2(regionsOptions); - $('select.select2.communes').select2(communesOptions); - $('select.select2.adresse').select2(adresseOptions); + $('select.select2').select2({ + language: 'fr', + width: '100%' + }); $('.columns-form select.select2-limited').select2({ - width: '300px', + language: 'fr', placeholder: 'Sélectionnez des colonnes', - maximumSelectionLength: '5' + maximumSelectionLength: '5', + width: '300px' }); $('.recipients-form select.select2-limited').select2({ - language, - width: '300px', + language: 'fr', placeholder: 'Sélectionnez des instructeurs', - maximumSelectionLength: '30' + maximumSelectionLength: '30', + width: '300px' }); $('select.select2-limited.select-instructeurs').select2({ - language, + language: 'fr', dropdownParent: $('.instructeur-wrapper'), placeholder: 'Saisir l’adresse email de l’instructeur', tags: true, tokenSeparators: [',', ' '], - templateResult: templateOption, - templateSelection: templateOption + templateResult: optionTemplate, + templateSelection: function(email) { + return $( + '' + + email.text + + '' + ); + } }); }); diff --git a/app/javascript/packs/application-old.js b/app/javascript/packs/application-old.js index a10e991fb..180698e4b 100644 --- a/app/javascript/packs/application-old.js +++ b/app/javascript/packs/application-old.js @@ -8,6 +8,7 @@ import '../shared/page-update-event'; import '../shared/activestorage/ujs'; import '../shared/rails-ujs-fix'; import '../shared/safari-11-file-xhr-workaround'; +import '../shared/autocomplete'; import '../shared/remote-input'; import '../shared/franceconnect'; diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 0e567c58b..5a7e995cf 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -13,6 +13,7 @@ import '../shared/activestorage/ujs'; import '../shared/activestorage/attachment-checker'; import '../shared/rails-ujs-fix'; import '../shared/safari-11-file-xhr-workaround'; +import '../shared/autocomplete'; import '../shared/remote-input'; import '../shared/franceconnect'; import '../shared/toggle-target'; diff --git a/app/javascript/shared/autocomplete.js b/app/javascript/shared/autocomplete.js new file mode 100644 index 000000000..e37dec4dc --- /dev/null +++ b/app/javascript/shared/autocomplete.js @@ -0,0 +1,51 @@ +import autocomplete from 'autocomplete.js'; +import { getJSON, fire } from '@utils'; + +const sources = [ + { + type: 'address', + url: '/address/suggestions' + } +]; + +const options = { + autoselect: true, + minLength: 1 +}; + +function selector(type) { + return `[data-autocomplete=${type}]`; +} + +function source(url) { + return { + source(query, callback) { + getJSON(url, { request: query }).then(callback); + }, + templates: { + suggestion({ label, mine }) { + const mineClass = `path-mine-${mine ? 'true' : 'false'}`; + const openTag = `
`; + return autocomplete.escapeHighlightedString(label, openTag, '
'); + } + }, + debounce: 300 + }; +} + +addEventListener('ds:page:update', function() { + for (let { type, url } of sources) { + for (let element of document.querySelectorAll(selector(type))) { + element.removeAttribute('data-autocomplete'); + autocompleteInitializeElement(element, url); + } + } +}); + +function autocompleteInitializeElement(element, url) { + const select = autocomplete(element, options, [source(url)]); + select.on('autocomplete:selected', ({ target }, suggestion) => { + fire(target, 'autocomplete:select', suggestion); + select.autocomplete.setVal(suggestion.label); + }); +} diff --git a/app/javascript/shared/carte.js b/app/javascript/shared/carte.js index a01a36c78..b6f76a27a 100644 --- a/app/javascript/shared/carte.js +++ b/app/javascript/shared/carte.js @@ -1,6 +1,5 @@ /* globals FreeDraw L */ -import { fire, delegate } from '@utils'; -import $ from 'jquery'; +import { fire, getJSON, delegate } from '@utils'; import polygonArea from './polygon_area'; @@ -114,6 +113,14 @@ function drawParcellesAgricoles(map, { parcellesAgricoles }, editable = false) { ); } +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); + } + }); +} + function getCurrentMap(element) { if (!element.matches('.carte')) { const closestCarteElement = element.closest('.carte'); @@ -239,12 +246,10 @@ delegate('click', '.toolbar .new-area', event => { } }); -$(document).on('select2:select', 'select[data-address]', event => { +delegate('autocomplete:select', '.toolbar [data-address]', event => { const map = getCurrentMap(event.target); - const { geometry } = event.params.data; - if (map && geometry && geometry.type === 'Point') { - const [lon, lat] = geometry.coordinates; - map.setView(new L.LatLng(lat, lon), 14); + if (map) { + geocodeAddress(map, event.detail.label); } }); diff --git a/app/lib/api_adresse/adapter.rb b/app/lib/api_adresse/adapter.rb new file mode 100644 index 000000000..cd012357b --- /dev/null +++ b/app/lib/api_adresse/adapter.rb @@ -0,0 +1,33 @@ +class ApiAdresse::Adapter + private + + def initialize(address, limit, blank_return) + @address = address + @limit = limit + @blank_return = blank_return + end + + def features + @features ||= get_features + end + + def get_features + response = ApiAdresse::API.call(@address, @limit) + result = JSON.parse(response) + result['features'] + rescue RestClient::Exception, JSON::ParserError, TypeError + @blank_return + end + + def handle_result + if features.present? + process_features + else + @blank_return + end + end + + def process_features + raise NoMethodError + end +end diff --git a/app/lib/api_adresse/address_adapter.rb b/app/lib/api_adresse/address_adapter.rb new file mode 100644 index 000000000..68e737cfe --- /dev/null +++ b/app/lib/api_adresse/address_adapter.rb @@ -0,0 +1,17 @@ +class ApiAdresse::AddressAdapter < ApiAdresse::Adapter + def initialize(address) + super(address, 5, []) + end + + def get_suggestions + handle_result + end + + private + + def process_features + features.map do |feature| + feature['properties']['label'] + end + end +end diff --git a/app/lib/api_adresse/api.rb b/app/lib/api_adresse/api.rb new file mode 100644 index 000000000..4470d9008 --- /dev/null +++ b/app/lib/api_adresse/api.rb @@ -0,0 +1,12 @@ +class ApiAdresse::API + def self.call(address, limit = 1) + search_url = [API_ADRESSE_URL, "search"].join("/") + + RestClient::Request.execute(method: :get, + url: search_url, + timeout: 5, + headers: { params: { q: address, limit: limit } }) + rescue RestClient::ServiceUnavailable + nil + end +end diff --git a/app/lib/api_adresse/point_adapter.rb b/app/lib/api_adresse/point_adapter.rb new file mode 100644 index 000000000..ea54079e6 --- /dev/null +++ b/app/lib/api_adresse/point_adapter.rb @@ -0,0 +1,15 @@ +class ApiAdresse::PointAdapter < ApiAdresse::Adapter + def initialize(address) + super(address, 1, nil) + end + + def geocode + handle_result + end + + private + + def process_features + RGeo::GeoJSON.decode(features[0]['geometry'], json_parser: :json) + end +end diff --git a/app/lib/api_geo/api.rb b/app/lib/api_geo/api.rb new file mode 100644 index 000000000..fabafff90 --- /dev/null +++ b/app/lib/api_geo/api.rb @@ -0,0 +1,57 @@ +class ApiGeo::API + TIMEOUT = 15 + CACHE_DURATION = 1.day + + def self.regions + url = [API_GEO_URL, "regions"].join("/") + call(url, { fields: :nom }) + end + + def self.departements + url = [API_GEO_URL, "departements"].join("/") + call(url, { fields: :nom }) + end + + def self.pays + parse(File.open('app/lib/api_geo/pays.json').read) + end + + def self.search_rpg(geojson) + url = [API_GEO_SANDBOX_URL, "rpg", "parcelles", "search"].join("/") + call(url, geojson, :post) + end + + private + + def self.parse(body) + JSON.parse(body, symbolize_names: true) + end + + def self.call(url, body, method = :get) + # The cache engine is stored, because as of Typhoeus 1.3.1 the cache engine instance + # is included in the computed `cache_key`. + # (Which means that when the cache instance changes, the cache is invalidated.) + @typhoeus_cache ||= Typhoeus::Cache::SuccessfulRequestsRailsCache.new + + response = Typhoeus::Request.new( + url, + method: method, + params: method == :get ? body : nil, + body: method == :post ? body : nil, + timeout: TIMEOUT, + accept_encoding: 'gzip', + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip, deflate' + }.merge(method == :post ? { 'Content-Type' => 'application/json' } : {}), + cache: @typhoeus_cache, + cache_ttl: CACHE_DURATION + ).run + + if response.success? + parse(response.body) + else + nil + end + end +end diff --git a/app/lib/api_geo/rpg_adapter.rb b/app/lib/api_geo/rpg_adapter.rb new file mode 100644 index 000000000..095825d6c --- /dev/null +++ b/app/lib/api_geo/rpg_adapter.rb @@ -0,0 +1,27 @@ +class ApiGeo::RPGAdapter + def initialize(coordinates) + @coordinates = GeojsonService.to_json_polygon_for_rpg(coordinates) + end + + def data_source + @data_source ||= ApiGeo::API.search_rpg(@coordinates) + end + + def results + data_source[:features].map do |feature| + feature[:properties] + .stringify_keys + .transform_keys(&:underscore) + .symbolize_keys + .slice( + :culture, + :code_culture, + :surface, + :bio + ).merge({ + geometry: feature[:geometry], + geo_reference_id: feature[:properties][:id] + }) + end + end +end diff --git a/app/models/champs/commune_champ.rb b/app/models/champs/commune_champ.rb deleted file mode 100644 index 9db282844..000000000 --- a/app/models/champs/commune_champ.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Champs::CommuneChamp < Champs::TextChamp -end diff --git a/app/models/champs/departement_champ.rb b/app/models/champs/departement_champ.rb index ee9803389..f211b421c 100644 --- a/app/models/champs/departement_champ.rb +++ b/app/models/champs/departement_champ.rb @@ -1,2 +1,5 @@ class Champs::DepartementChamp < Champs::TextChamp + def self.departements + ApiGeo::API.departements.map { |liste| "#{liste[:code]} - #{liste[:nom]}" }.push('99 - Étranger') + end end diff --git a/app/models/champs/pays_champ.rb b/app/models/champs/pays_champ.rb index 1d8f08ed7..6f916dbce 100644 --- a/app/models/champs/pays_champ.rb +++ b/app/models/champs/pays_champ.rb @@ -1,8 +1,6 @@ class Champs::PaysChamp < Champs::TextChamp - PAYS = JSON.parse(Rails.root.join('app', 'lib', 'api_geo', 'pays.json').read, symbolize_names: true) - def self.pays - PAYS.pluck(:nom) + ApiGeo::API.pays.pluck(:nom) end def self.disabled_options diff --git a/app/models/champs/region_champ.rb b/app/models/champs/region_champ.rb index ba9045087..9ecba7173 100644 --- a/app/models/champs/region_champ.rb +++ b/app/models/champs/region_champ.rb @@ -1,2 +1,5 @@ class Champs::RegionChamp < Champs::TextChamp + def self.regions + ApiGeo::API.regions.sort_by { |e| e[:nom] }.pluck(:nom) + end end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 280e957d1..249c1b6f4 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -19,7 +19,6 @@ class TypeDeChamp < ApplicationRecord pays: 'pays', regions: 'regions', departements: 'departements', - communes: 'communes', engagement: 'engagement', header_section: 'header_section', explication: 'explication', diff --git a/app/models/types_de_champ/commune_type_de_champ.rb b/app/models/types_de_champ/commune_type_de_champ.rb deleted file mode 100644 index 3d7c8a855..000000000 --- a/app/models/types_de_champ/commune_type_de_champ.rb +++ /dev/null @@ -1,2 +0,0 @@ -class TypesDeChamp::CommuneTypeDeChamp < TypesDeChamp::TypeDeChampBase -end diff --git a/app/views/shared/dossiers/editable_champs/_address.html.haml b/app/views/shared/dossiers/editable_champs/_address.html.haml index 95025fc33..b7ae4e032 100644 --- a/app/views/shared/dossiers/editable_champs/_address.html.haml +++ b/app/views/shared/dossiers/editable_champs/_address.html.haml @@ -1,4 +1,4 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 adresse' += form.text_field :value, + data: { address: true, autocomplete: 'address' }, + placeholder: champ.libelle, + required: champ.mandatory? diff --git a/app/views/shared/dossiers/editable_champs/_carte.html.haml b/app/views/shared/dossiers/editable_champs/_carte.html.haml index e15e1f6c6..e55bebec0 100644 --- a/app/views/shared/dossiers/editable_champs/_carte.html.haml +++ b/app/views/shared/dossiers/editable_champs/_carte.html.haml @@ -1,6 +1,6 @@ .toolbar %button.button.primary.new-area Ajouter une zone - %select.select2.adresse{ data: { address: true }, placeholder: 'Saisissez une adresse ou positionner la carte' } + %input.address{ data: { address: true, autocomplete: 'address' }, placeholder: 'Saisissez une adresse ou positionner la carte' } .carte.edit{ data: { geo: geo_data(champ) }, class: "carte-#{form.index}" } diff --git a/app/views/shared/dossiers/editable_champs/_communes.html.haml b/app/views/shared/dossiers/editable_champs/_communes.html.haml deleted file mode 100644 index 0087a725e..000000000 --- a/app/views/shared/dossiers/editable_champs/_communes.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 communes' diff --git a/app/views/shared/dossiers/editable_champs/_departements.html.haml b/app/views/shared/dossiers/editable_champs/_departements.html.haml index 9d0171092..e3084d148 100644 --- a/app/views/shared/dossiers/editable_champs/_departements.html.haml +++ b/app/views/shared/dossiers/editable_champs/_departements.html.haml @@ -1,4 +1,4 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 departements' += form.select :value, + Champs::DepartementChamp.departements, + include_blank: true, + required: champ.mandatory? diff --git a/app/views/shared/dossiers/editable_champs/_pays.html.haml b/app/views/shared/dossiers/editable_champs/_pays.html.haml index 0e686fee9..13062d8e5 100644 --- a/app/views/shared/dossiers/editable_champs/_pays.html.haml +++ b/app/views/shared/dossiers/editable_champs/_pays.html.haml @@ -1,5 +1,5 @@ = form.select :value, Champs::PaysChamp.pays, - { disabled: Champs::PaysChamp.disabled_options, include_blank: true }, - required: champ.mandatory?, - class: 'select2 pays' + disabled: Champs::PaysChamp.disabled_options, + include_blank: true, + required: champ.mandatory? diff --git a/app/views/shared/dossiers/editable_champs/_regions.html.haml b/app/views/shared/dossiers/editable_champs/_regions.html.haml index 4b16bea2d..8920cfc3c 100644 --- a/app/views/shared/dossiers/editable_champs/_regions.html.haml +++ b/app/views/shared/dossiers/editable_champs/_regions.html.haml @@ -1,4 +1,4 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 regions' += form.select :value, + Champs::RegionChamp.regions, + include_blank: true, + required: champ.mandatory? diff --git a/config/env.example b/config/env.example index 608fd59ff..5d9134cec 100644 --- a/config/env.example +++ b/config/env.example @@ -105,7 +105,3 @@ LOGRAGE_ENABLED="disabled" # Service externe d'horodatage des changements de statut des dossiers (effectué quotidiennement) UNIVERSIGN_API_URL="" UNIVERSIGN_USERPWD="" - -# API Geo / Adresse -API_ADRESSE_URL="https://api-adresse.data.gouv.fr" -API_GEO_URL="https://geo.api.gouv.fr" diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 1535e55ba..ee9bff7b4 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -5,7 +5,6 @@ Rails.application.config.assets.version = '1.0' # Add additional assets to the asset load path Rails.application.config.assets.paths << Rails.root.join('node_modules', 'trix', 'dist') -Rails.application.config.assets.paths << Rails.root.join('node_modules', 'select2', 'dist', 'css') # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 588cd5079..960c3cd3d 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -13,7 +13,7 @@ Rails.application.config.content_security_policy do |policy| # c'est trop compliqué pour être rectifié immédiatement (et sans valeur ajoutée: # c'est hardcodé dans les vues, donc pas injectable). policy.style_src :self, "*.crisp.chat", "crisp.chat", :unsafe_inline - policy.connect_src :self, "wss://*.crisp.chat", "*.crisp.chat", "*.demarches-simplifiees.fr", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io", "geo.api.gouv.fr", "api-adresse.data.gouv.fr" + policy.connect_src :self, "wss://*.crisp.chat", "*.crisp.chat", "*.demarches-simplifiees.fr", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io" # Pour tout le reste, par défaut on accepte uniquement ce qui vient de chez nous # et dans la notification on inclue la source de l'erreur policy.default_src :self, :data, :report_sample, "fonts.gstatic.com", "in-automate.sendinblue.com", "player.vimeo.com", "app.franceconnect.gouv.fr", "sentry.io", "static.demarches-simplifiees.fr", "*.crisp.chat", "crisp.chat", "*.crisp.help", "*.sibautomation.com", "sibautomation.com", "data" diff --git a/config/initializers/urls.rb b/config/initializers/urls.rb index 00b747247..53aca743e 100644 --- a/config/initializers/urls.rb +++ b/config/initializers/urls.rb @@ -1,6 +1,9 @@ # API URLs +API_ADRESSE_URL = ENV.fetch("API_ADRESSE_URL", "https://api-adresse.data.gouv.fr") API_CARTO_URL = ENV.fetch("API_CARTO_URL", "https://sandbox.geo.api.gouv.fr/apicarto") API_ENTREPRISE_URL = ENV.fetch("API_ENTREPRISE_URL", "https://entreprise.api.gouv.fr/v2") +API_GEO_URL = ENV.fetch("API_GEO_URL", "https://geo.api.gouv.fr") +API_GEO_SANDBOX_URL = ENV.fetch("API_GEO_SANDBOX_URL", "https://sandbox.geo.api.gouv.fr") HELPSCOUT_API_URL = ENV.fetch("HELPSCOUT_API_URL", "https://api.helpscout.net/v2") PIPEDRIVE_API_URL = ENV.fetch("PIPEDRIVE_API_URL", "https://api.pipedrive.com/v1") SENDINBLUE_API_URL = ENV.fetch("SENDINBLUE_API_URL", "https://in-automate.sendinblue.com/api/v2") diff --git a/config/locales/models/type_de_champ/fr.yml b/config/locales/models/type_de_champ/fr.yml index 9d8b878d3..cf97e106f 100644 --- a/config/locales/models/type_de_champ/fr.yml +++ b/config/locales/models/type_de_champ/fr.yml @@ -24,7 +24,6 @@ fr: pays: 'Pays' regions: 'Régions' departements: 'Départements' - communes: 'Communes' engagement: 'Engagement' header_section: 'Titre de section' explication: 'Explication' diff --git a/config/routes.rb b/config/routes.rb index 8c7994777..ce14ec9ee 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -209,6 +209,13 @@ Rails.application.routes.draw do resources :instructeurs, only: [:index, :create, :destroy] end + # + # Addresses + # + + get 'address/suggestions' => 'address#suggestions' + get 'address/geocode' => 'address#geocode' + resources :invites, only: [:show] do collection do post 'dossier/:dossier_id', to: 'invites#create', as: :dossier @@ -387,14 +394,6 @@ Rails.application.routes.draw do end end - if Rails.env.test? - scope 'test/api_geo' do - get 'regions' => 'api_geo_test#regions' - get 'communes' => 'api_geo_test#communes' - get 'departements' => 'api_geo_test#departements' - end - end - # # Legacy routes # diff --git a/config/secrets.yml b/config/secrets.yml index 3d7ffa9af..6b0afe9dc 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -68,9 +68,6 @@ defaults: &defaults client_key: <%= ENV['CRISP_CLIENT_KEY'] %> universign: userpwd: <%= ENV['UNIVERSIGN_USERPWD'] %> - autocomplete: - api_geo_url: <%= ENV['API_GEO_URL'] %> - api_adresse_url: <%= ENV['API_ADRESSE_URL'] %> @@ -101,8 +98,6 @@ test: logout_endpoint: https://bidon.com/endpoint universign: userpwd: 'fake:fake' - autocomplete: - api_geo_url: /test/api_geo # Do not keep production secrets in the repository, # instead read values from the environment. diff --git a/package.json b/package.json index 94fe7a75b..8ccc7fce8 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@rails/webpacker": "4.0.7", "@sentry/browser": "^5.7.1", "@turf/area": "^6.0.1", + "autocomplete.js": "^0.37.0", "babel-plugin-macros": "^2.6.1", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "chartkick": "^3.1.3", diff --git a/spec/controllers/address_controller_spec.rb b/spec/controllers/address_controller_spec.rb new file mode 100644 index 000000000..99a2e3218 --- /dev/null +++ b/spec/controllers/address_controller_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe AddressController, type: :controller do + describe '#GET suggestions' do + subject { get :suggestions, params: { request: request } } + + before do + subject + end + + context 'when request return result', vcr: { cassette_name: 'api_adresse_search_paris_2' } do + let (:request) { 'Paris' } + + it { expect(response.status).to eq 200 } + it { expect(response.body).to eq '[{"label":"Paris"},{"label":"Paris 63120 Courpière"},{"label":"PARIS (Vaillac) 46240 Cœur de Causse"},{"label":"Paris 40500 Saint-Sever"},{"label":"Paris Buton 37140 Bourgueil"}]' } + end + + context 'when request return nothing', vcr: { cassette_name: 'api_adresse_search_nothing_2' } do + let (:request) { 'je recherche pas grand chose' } + + it { expect(response.status).to eq 200 } + it { expect(response.body).to eq "[]" } + end + end + + describe '#GET geocode' do + let(:dossier_id) { "1" } + subject { get :geocode, params: { request: request, dossier_id: dossier_id } } + + before do + subject + end + + context 'when request return result', vcr: { cassette_name: 'api_adresse_search_paris' } do + let(:request) { 'Paris' } + + it { expect(response.body).to eq ({ lon: '2.3469', lat: '48.8589', zoom: '14', dossier_id: dossier_id }).to_json } + end + + context 'when request return nothing', vcr: { cassette_name: 'api_adresse_search_nothing' } do + let(:request) { 'je recherche pas grand chose' } + + it { expect(response.body).to eq ({ lon: nil, lat: nil, zoom: '14', dossier_id: dossier_id }).to_json } + end + end +end diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index 4b10f249f..b9913a536 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -124,11 +124,6 @@ FactoryBot.define do value { '971 - Guadeloupe' } end - factory :champ_communes, class: 'Champs::CommuneChamp' do - type_de_champ { create(:type_de_champ_communes) } - value { 'Paris' } - end - factory :champ_engagement, class: 'Champs::EngagementChamp' do type_de_champ { create(:type_de_champ_engagement) } value { 'true' } diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb index 597d84c9e..2bc898b09 100644 --- a/spec/factories/type_de_champ.rb +++ b/spec/factories/type_de_champ.rb @@ -71,9 +71,6 @@ FactoryBot.define do factory :type_de_champ_departements do type_champ { TypeDeChamp.type_champs.fetch(:departements) } end - factory :type_de_champ_communes do - type_champ { TypeDeChamp.type_champs.fetch(:communes) } - end factory :type_de_champ_engagement do type_champ { TypeDeChamp.type_champs.fetch(:engagement) } end diff --git a/spec/features/users/brouillon_spec.rb b/spec/features/users/brouillon_spec.rb index f74f6c4f4..90bea2630 100644 --- a/spec/features/users/brouillon_spec.rb +++ b/spec/features/users/brouillon_spec.rb @@ -10,7 +10,10 @@ feature 'The user' do # TODO: check # the order # there are no extraneous input - scenario 'fill a dossier', js: true, vcr: { cassette_name: 'api_geo_departements_regions_et_communes' } do + scenario 'fill a dossier', js: true do + allow(Champs::RegionChamp).to receive(:regions).and_return(['region1', 'region2']).at_least(:once) + allow(Champs::DepartementChamp).to receive(:departements).and_return(['dep1', 'dep2']).at_least(:once) + log_in(user, procedure) fill_individual @@ -30,16 +33,8 @@ feature 'The user' do select('val1', from: form_id_for('multiple_drop_down_list')) select('val3', from: form_id_for('multiple_drop_down_list')) select('AUSTRALIE', from: 'pays') - - select_champ_geo('regions', 'Ma', 'Martinique') - select('Martinique', from: 'regions') - - select_champ_geo('departements', 'Ai', '02 - Aisne') - select('02 - Aisne', from: 'departements') - - select_champ_geo('communes', 'Am', 'Ambléon') - select('Ambléon', from: 'communes') - + select('region2', from: 'regions') + select('dep2', from: 'departements') check('engagement') fill_in('dossier_link', with: '123') find('.editable-champ-piece_justificative input[type=file]').attach_file(Rails.root + 'spec/fixtures/files/file.pdf') @@ -62,9 +57,8 @@ feature 'The user' do expect(champ_value_for('simple_drop_down_list')).to eq('val2') expect(JSON.parse(champ_value_for('multiple_drop_down_list'))).to match(['val1', 'val3']) expect(champ_value_for('pays')).to eq('AUSTRALIE') - expect(champ_value_for('regions')).to eq('Martinique') - expect(champ_value_for('departements')).to eq('02 - Aisne') - expect(champ_value_for('communes')).to eq('Ambléon') + expect(champ_value_for('regions')).to eq('region2') + expect(champ_value_for('departements')).to eq('dep2') expect(champ_value_for('engagement')).to eq('on') expect(champ_value_for('dossier_link')).to eq('123') expect(champ_value_for('piece_justificative')).to be_nil # antivirus hasn't approved the file yet @@ -84,9 +78,8 @@ feature 'The user' do expect(page).to have_selected_value('simple_drop_down_list', selected: 'val2') expect(page).to have_selected_value('multiple_drop_down_list', selected: ['val1', 'val3']) expect(page).to have_selected_value('pays', selected: 'AUSTRALIE') - expect(page).to have_selected_value('regions', selected: 'Martinique') - expect(page).to have_selected_value('departements', selected: '02 - Aisne') - expect(page).to have_selected_value('communes', selected: 'Ambléon') + expect(page).to have_selected_value('regions', selected: 'region2') + expect(page).to have_selected_value('departement', selected: 'dep2') expect(page).to have_checked_field('engagement') expect(page).to have_field('dossier_link', with: '123') expect(page).to have_text('file.pdf') @@ -277,12 +270,4 @@ feature 'The user' do expect(page).to have_selected_value("#{field}_4i", selected: date.strftime('%H')) expect(page).to have_selected_value("#{field}_5i", selected: date.strftime('%M')) end - - def select_champ_geo(champ, fill_with, value) - find(".editable-champ-#{champ} .select2-container").click - id = find('.select2-container--open [role=listbox]')[:id] - find("[aria-controls=#{id}]").fill_in with: fill_with - expect(page).to have_content(value) - find('li', text: value).click - end end diff --git a/spec/features/users/dossier_creation_spec.rb b/spec/features/users/dossier_creation_spec.rb index 662d02918..f6dc8de5b 100644 --- a/spec/features/users/dossier_creation_spec.rb +++ b/spec/features/users/dossier_creation_spec.rb @@ -77,7 +77,7 @@ feature 'Creating a new dossier:' do .to_return(status: 404, body: '') end - scenario 'the user can enter the SIRET of its etablissement and create a new draft' do + scenario 'the user can enter the SIRET of its etablissement and create a new draft', vcr: { cassette_name: 'api_adresse_search_paris_3' } do visit commencer_path(path: procedure.path) click_on 'Commencer la démarche' diff --git a/spec/fixtures/cassettes/api_adresse_octo.yml b/spec/fixtures/cassettes/api_adresse_octo.yml new file mode 100644 index 000000000..28ed2accb --- /dev/null +++ b/spec/fixtures/cassettes/api_adresse_octo.yml @@ -0,0 +1,47 @@ +--- +http_interactions: +- request: + method: get + uri: https://api-adresse.data.gouv.fr/search?limit=1&q=50%20av%20des%20champs%20elysees + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Fri, 16 Dec 2016 16:22:23 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '628' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 1, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "50 av des champs elysees", "type": "FeatureCollection", "features": + [{"geometry": {"type": "Point", "coordinates": [2.306888, 48.870374]}, "properties": + {"citycode": "75108", "postcode": "75008", "name": "50 Avenue des Champs \u00c9lys\u00e9es", + "id": "ADRNIVX_0000000270748251", "type": "housenumber", "context": "75, \u00cele-de-France", + "score": 0.7561038961038961, "label": "50 Avenue des Champs \u00c9lys\u00e9es + 75008 Paris", "city": "Paris", "housenumber": "50", "street": "Avenue des + Champs \u00c9lys\u00e9es"}, "type": "Feature"}]}' + http_version: + recorded_at: Fri, 16 Dec 2016 16:22:23 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/cassettes/api_adresse_search_nothing.yml b/spec/fixtures/cassettes/api_adresse_search_nothing.yml new file mode 100644 index 000000000..d951adbfc --- /dev/null +++ b/spec/fixtures/cassettes/api_adresse_search_nothing.yml @@ -0,0 +1,42 @@ +--- +http_interactions: +- request: + method: get + uri: https://api-adresse.data.gouv.fr/search?limit=1&q=je%20recherche%20pas%20grand%20chose + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Fri, 16 Dec 2016 14:17:40 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '163' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 1, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "je recherche pas grand chose", "type": "FeatureCollection", + "features": []}' + http_version: + recorded_at: Fri, 16 Dec 2016 14:17:40 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/cassettes/api_adresse_search_nothing_2.yml b/spec/fixtures/cassettes/api_adresse_search_nothing_2.yml new file mode 100644 index 000000000..cbb4a0f66 --- /dev/null +++ b/spec/fixtures/cassettes/api_adresse_search_nothing_2.yml @@ -0,0 +1,42 @@ +--- +http_interactions: +- request: + method: get + uri: https://api-adresse.data.gouv.fr/search?limit=5&q=je%20recherche%20pas%20grand%20chose + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Fri, 16 Dec 2016 16:45:53 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '163' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 5, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "je recherche pas grand chose", "type": "FeatureCollection", + "features": []}' + http_version: + recorded_at: Fri, 16 Dec 2016 16:45:53 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/cassettes/api_adresse_search_paris.yml b/spec/fixtures/cassettes/api_adresse_search_paris.yml new file mode 100644 index 000000000..ced667e17 --- /dev/null +++ b/spec/fixtures/cassettes/api_adresse_search_paris.yml @@ -0,0 +1,45 @@ +--- +http_interactions: +- request: + method: get + uri: https://api-adresse.data.gouv.fr/search?limit=1&q=Paris + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Fri, 16 Dec 2016 14:16:43 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '457' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 1, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "Paris", "type": "FeatureCollection", "features": [{"geometry": + {"type": "Point", "coordinates": [2.3469, 48.8589]}, "properties": {"adm_weight": + "6", "citycode": "75056", "name": "Paris", "city": "Paris", "postcode": "75000", + "context": "75, \u00cele-de-France", "score": 1.0, "label": "Paris", "id": + "75056", "type": "city", "population": "2244"}, "type": "Feature"}]}' + http_version: + recorded_at: Fri, 16 Dec 2016 14:16:43 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/cassettes/api_adresse_search_paris_2.yml b/spec/fixtures/cassettes/api_adresse_search_paris_2.yml new file mode 100644 index 000000000..5faf1cd88 --- /dev/null +++ b/spec/fixtures/cassettes/api_adresse_search_paris_2.yml @@ -0,0 +1,63 @@ +--- +http_interactions: +- request: + method: get + uri: https://api-adresse.data.gouv.fr/search?limit=5&q=Paris + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Fri, 16 Dec 2016 16:43:34 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '1887' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 5, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "Paris", "type": "FeatureCollection", "features": [{"geometry": + {"type": "Point", "coordinates": [2.3469, 48.8589]}, "properties": {"adm_weight": + "6", "citycode": "75056", "name": "Paris", "city": "Paris", "postcode": "75000", + "context": "75, \u00cele-de-France", "score": 1.0, "label": "Paris", "id": + "75056", "type": "city", "population": "2244"}, "type": "Feature"}, {"geometry": + {"type": "Point", "coordinates": [3.564293, 45.766413]}, "properties": {"citycode": + "63125", "postcode": "63120", "name": "Paris", "city": "Courpi\u00e8re", "context": + "63, Puy-de-D\u00f4me, Auvergne", "score": 0.8255363636363636, "label": "Paris + 63120 Courpi\u00e8re", "id": "63125_B221_03549b", "type": "locality"}, "type": + "Feature"}, {"geometry": {"type": "Point", "coordinates": [1.550208, 44.673592]}, + "properties": {"citycode": "46138", "postcode": "46240", "name": "PARIS (Vaillac)", + "city": "C\u0153ur de Causse", "context": "46, Lot, Midi-Pyr\u00e9n\u00e9es", + "score": 0.824090909090909, "label": "PARIS (Vaillac) 46240 C\u0153ur de Causse", + "id": "46138_XXXX_6ee4ec", "type": "street"}, "type": "Feature"}, {"geometry": + {"type": "Point", "coordinates": [-0.526884, 43.762253]}, "properties": {"citycode": + "40282", "postcode": "40500", "name": "Paris", "city": "Saint-Sever", "context": + "40, Landes, Aquitaine", "score": 0.8236181818181818, "label": "Paris 40500 + Saint-Sever", "id": "40282_B237_2364e3", "type": "locality"}, "type": "Feature"}, + {"geometry": {"type": "Point", "coordinates": [0.157613, 47.336685]}, "properties": + {"citycode": "37031", "postcode": "37140", "name": "Paris Buton", "city": + "Bourgueil", "context": "37, Indre-et-Loire, Centre Val-de-Loire", "score": + 0.8235454545454545, "label": "Paris Buton 37140 Bourgueil", "id": "37031_X027_0a5e7a", + "type": "locality"}, "type": "Feature"}]}' + http_version: + recorded_at: Fri, 16 Dec 2016 16:43:34 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/cassettes/api_adresse_search_paris_3.yml b/spec/fixtures/cassettes/api_adresse_search_paris_3.yml new file mode 100644 index 000000000..22eca3306 --- /dev/null +++ b/spec/fixtures/cassettes/api_adresse_search_paris_3.yml @@ -0,0 +1,93 @@ +--- +http_interactions: +- request: + method: get + uri: https://api-adresse.data.gouv.fr/search?limit=1&q=50%20AV%20DES%20CHAMPS%20ELYSEES%20complement_adresse%2075008%20PARIS%208 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Tue, 03 Jan 2017 13:00:54 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '660' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 1, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "50 AV DES CHAMPS ELYSEES complement_adresse 75008 PARIS 8", + "type": "FeatureCollection", "features": [{"geometry": {"type": "Point", "coordinates": + [2.306888, 48.870374]}, "properties": {"citycode": "75108", "postcode": "75008", + "name": "50 Avenue des Champs \u00c9lys\u00e9es", "id": "ADRNIVX_0000000270748251", + "type": "housenumber", "context": "75, \u00cele-de-France", "score": 0.596517719568567, + "label": "50 Avenue des Champs \u00c9lys\u00e9es 75008 Paris", "city": "Paris", + "housenumber": "50", "street": "Avenue des Champs \u00c9lys\u00e9es"}, "type": + "Feature"}]}' + http_version: + recorded_at: Tue, 03 Jan 2017 13:00:54 GMT +- request: + method: get + uri: http://api-adresse.data.gouv.fr/search?limit=1&q=50%20AV%20DES%20CHAMPS%20ELYSEES%20complement_adresse%2075008%20PARIS%208 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.0 (darwin15.6.0 x86_64) ruby/2.3.1p112 + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.11.3 + Date: + - Tue, 03 Jan 2017 13:00:55 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '660' + Connection: + - keep-alive + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + body: + encoding: UTF-8 + string: '{"limit": 1, "attribution": "BAN", "version": "draft", "licence": "ODbL + 1.0", "query": "50 AV DES CHAMPS ELYSEES complement_adresse 75008 PARIS 8", + "type": "FeatureCollection", "features": [{"geometry": {"type": "Point", "coordinates": + [2.306888, 48.870374]}, "properties": {"citycode": "75108", "postcode": "75008", + "name": "50 Avenue des Champs \u00c9lys\u00e9es", "id": "ADRNIVX_0000000270748251", + "type": "housenumber", "context": "75, \u00cele-de-France", "score": 0.596517719568567, + "label": "50 Avenue des Champs \u00c9lys\u00e9es 75008 Paris", "city": "Paris", + "housenumber": "50", "street": "Avenue des Champs \u00c9lys\u00e9es"}, "type": + "Feature"}]}' + http_version: + recorded_at: Tue, 03 Jan 2017 13:00:55 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/fixtures/cassettes/api_geo_departements.yml b/spec/fixtures/cassettes/api_geo_departements.yml new file mode 100644 index 000000000..9a7dcd8b3 --- /dev/null +++ b/spec/fixtures/cassettes/api_geo_departements.yml @@ -0,0 +1,51 @@ +--- +http_interactions: +- request: + method: get + uri: https://geo.api.gouv.fr/departements?fields=nom + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - demarches-simplifiees.fr + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Expect: + - '' + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.10.3 (Ubuntu) + Date: + - Tue, 23 Oct 2018 13:11:36 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + X-Powered-By: + - Express + Access-Control-Allow-Origin: + - "*" + Etag: + - W/"cc1-jlb3C7xpXUEaq56Wojrp9rAkoH8" + Strict-Transport-Security: + - max-age=15552000 + Content-Encoding: + - gzip + body: + encoding: ASCII-8BIT + string: !binary |- + W3sibm9tIjoiQWluIiwiY29kZSI6IjAxIn0seyJub20iOiJBaXNuZSIsImNvZGUiOiIwMiJ9LHsibm9tIjoiQWxsaWVyIiwiY29kZSI6IjAzIn0seyJub20iOiJBbHBlcy1kZS1IYXV0ZS1Qcm92ZW5jZSIsImNvZGUiOiIwNCJ9LHsibm9tIjoiSGF1dGVzLUFscGVzIiwiY29kZSI6IjA1In0seyJub20iOiJBbHBlcy1NYXJpdGltZXMiLCJjb2RlIjoiMDYifSx7Im5vbSI6IkFyZMOoY2hlIiwiY29kZSI6IjA3In0seyJub20iOiJBcmRlbm5lcyIsImNvZGUiOiIwOCJ9LHsibm9tIjoiQXJpw6hnZSIsImNvZGUiOiIwOSJ9LHsibm9tIjoiQXViZSIsImNvZGUiOiIxMCJ9LHsibm9tIjoiQXVkZSIsImNvZGUiOiIxMSJ9LHsibm9tIjoiQXZleXJvbiIsImNvZGUiOiIxMiJ9LHsibm9tIjoiQm91Y2hlcy1kdS1SaMO0bmUiLCJjb2RlIjoiMTMifSx7Im5vbSI6IkNhbHZhZG9zIiwiY29kZSI6IjE0In0seyJub20iOiJDYW50YWwiLCJjb2RlIjoiMTUifSx7Im5vbSI6IkNoYXJlbnRlIiwiY29kZSI6IjE2In0seyJub20iOiJDaGFyZW50ZS1NYXJpdGltZSIsImNvZGUiOiIxNyJ9LHsibm9tIjoiQ2hlciIsImNvZGUiOiIxOCJ9LHsibm9tIjoiQ29ycsOoemUiLCJjb2RlIjoiMTkifSx7Im5vbSI6IkPDtHRlLWQnT3IiLCJjb2RlIjoiMjEifSx7Im5vbSI6IkPDtHRlcy1kJ0FybW9yIiwiY29kZSI6IjIyIn0seyJub20iOiJDcmV1c2UiLCJjb2RlIjoiMjMifSx7Im5vbSI6IkRvcmRvZ25lIiwiY29kZSI6IjI0In0seyJub20iOiJEb3VicyIsImNvZGUiOiIyNSJ9LHsibm9tIjoiRHLDtG1lIiwiY29kZSI6IjI2In0seyJub20iOiJFdXJlIiwiY29kZSI6IjI3In0seyJub20iOiJFdXJlLWV0LUxvaXIiLCJjb2RlIjoiMjgifSx7Im5vbSI6IkZpbmlzdMOocmUiLCJjb2RlIjoiMjkifSx7Im5vbSI6IkNvcnNlLWR1LVN1ZCIsImNvZGUiOiIyQSJ9LHsibm9tIjoiSGF1dGUtQ29yc2UiLCJjb2RlIjoiMkIifSx7Im5vbSI6IkdhcmQiLCJjb2RlIjoiMzAifSx7Im5vbSI6IkhhdXRlLUdhcm9ubmUiLCJjb2RlIjoiMzEifSx7Im5vbSI6IkdlcnMiLCJjb2RlIjoiMzIifSx7Im5vbSI6Ikdpcm9uZGUiLCJjb2RlIjoiMzMifSx7Im5vbSI6IkjDqXJhdWx0IiwiY29kZSI6IjM0In0seyJub20iOiJJbGxlLWV0LVZpbGFpbmUiLCJjb2RlIjoiMzUifSx7Im5vbSI6IkluZHJlIiwiY29kZSI6IjM2In0seyJub20iOiJJbmRyZS1ldC1Mb2lyZSIsImNvZGUiOiIzNyJ9LHsibm9tIjoiSXPDqHJlIiwiY29kZSI6IjM4In0seyJub20iOiJKdXJhIiwiY29kZSI6IjM5In0seyJub20iOiJMYW5kZXMiLCJjb2RlIjoiNDAifSx7Im5vbSI6IkxvaXItZXQtQ2hlciIsImNvZGUiOiI0MSJ9LHsibm9tIjoiTG9pcmUiLCJjb2RlIjoiNDIifSx7Im5vbSI6IkhhdXRlLUxvaXJlIiwiY29kZSI6IjQzIn0seyJub20iOiJMb2lyZS1BdGxhbnRpcXVlIiwiY29kZSI6IjQ0In0seyJub20iOiJMb2lyZXQiLCJjb2RlIjoiNDUifSx7Im5vbSI6IkxvdCIsImNvZGUiOiI0NiJ9LHsibm9tIjoiTG90LWV0LUdhcm9ubmUiLCJjb2RlIjoiNDcifSx7Im5vbSI6IkxvesOocmUiLCJjb2RlIjoiNDgifSx7Im5vbSI6Ik1haW5lLWV0LUxvaXJlIiwiY29kZSI6IjQ5In0seyJub20iOiJNYW5jaGUiLCJjb2RlIjoiNTAifSx7Im5vbSI6Ik1hcm5lIiwiY29kZSI6IjUxIn0seyJub20iOiJIYXV0ZS1NYXJuZSIsImNvZGUiOiI1MiJ9LHsibm9tIjoiTWF5ZW5uZSIsImNvZGUiOiI1MyJ9LHsibm9tIjoiTWV1cnRoZS1ldC1Nb3NlbGxlIiwiY29kZSI6IjU0In0seyJub20iOiJNZXVzZSIsImNvZGUiOiI1NSJ9LHsibm9tIjoiTW9yYmloYW4iLCJjb2RlIjoiNTYifSx7Im5vbSI6Ik1vc2VsbGUiLCJjb2RlIjoiNTcifSx7Im5vbSI6Ik5pw6h2cmUiLCJjb2RlIjoiNTgifSx7Im5vbSI6Ik5vcmQiLCJjb2RlIjoiNTkifSx7Im5vbSI6Ik9pc2UiLCJjb2RlIjoiNjAifSx7Im5vbSI6Ik9ybmUiLCJjb2RlIjoiNjEifSx7Im5vbSI6IlBhcy1kZS1DYWxhaXMiLCJjb2RlIjoiNjIifSx7Im5vbSI6IlB1eS1kZS1Ew7RtZSIsImNvZGUiOiI2MyJ9LHsibm9tIjoiUHlyw6luw6llcy1BdGxhbnRpcXVlcyIsImNvZGUiOiI2NCJ9LHsibm9tIjoiSGF1dGVzLVB5csOpbsOpZXMiLCJjb2RlIjoiNjUifSx7Im5vbSI6IlB5csOpbsOpZXMtT3JpZW50YWxlcyIsImNvZGUiOiI2NiJ9LHsibm9tIjoiQmFzLVJoaW4iLCJjb2RlIjoiNjcifSx7Im5vbSI6IkhhdXQtUmhpbiIsImNvZGUiOiI2OCJ9LHsibm9tIjoiUmjDtG5lIiwiY29kZSI6IjY5In0seyJub20iOiJIYXV0ZS1TYcO0bmUiLCJjb2RlIjoiNzAifSx7Im5vbSI6IlNhw7RuZS1ldC1Mb2lyZSIsImNvZGUiOiI3MSJ9LHsibm9tIjoiU2FydGhlIiwiY29kZSI6IjcyIn0seyJub20iOiJTYXZvaWUiLCJjb2RlIjoiNzMifSx7Im5vbSI6IkhhdXRlLVNhdm9pZSIsImNvZGUiOiI3NCJ9LHsibm9tIjoiUGFyaXMiLCJjb2RlIjoiNzUifSx7Im5vbSI6IlNlaW5lLU1hcml0aW1lIiwiY29kZSI6Ijc2In0seyJub20iOiJTZWluZS1ldC1NYXJuZSIsImNvZGUiOiI3NyJ9LHsibm9tIjoiWXZlbGluZXMiLCJjb2RlIjoiNzgifSx7Im5vbSI6IkRldXgtU8OodnJlcyIsImNvZGUiOiI3OSJ9LHsibm9tIjoiU29tbWUiLCJjb2RlIjoiODAifSx7Im5vbSI6IlRhcm4iLCJjb2RlIjoiODEifSx7Im5vbSI6IlRhcm4tZXQtR2Fyb25uZSIsImNvZGUiOiI4MiJ9LHsibm9tIjoiVmFyIiwiY29kZSI6IjgzIn0seyJub20iOiJWYXVjbHVzZSIsImNvZGUiOiI4NCJ9LHsibm9tIjoiVmVuZMOpZSIsImNvZGUiOiI4NSJ9LHsibm9tIjoiVmllbm5lIiwiY29kZSI6Ijg2In0seyJub20iOiJIYXV0ZS1WaWVubmUiLCJjb2RlIjoiODcifSx7Im5vbSI6IlZvc2dlcyIsImNvZGUiOiI4OCJ9LHsibm9tIjoiWW9ubmUiLCJjb2RlIjoiODkifSx7Im5vbSI6IlRlcnJpdG9pcmUgZGUgQmVsZm9ydCIsImNvZGUiOiI5MCJ9LHsibm9tIjoiRXNzb25uZSIsImNvZGUiOiI5MSJ9LHsibm9tIjoiSGF1dHMtZGUtU2VpbmUiLCJjb2RlIjoiOTIifSx7Im5vbSI6IlNlaW5lLVNhaW50LURlbmlzIiwiY29kZSI6IjkzIn0seyJub20iOiJWYWwtZGUtTWFybmUiLCJjb2RlIjoiOTQifSx7Im5vbSI6IlZhbC1kJ09pc2UiLCJjb2RlIjoiOTUifSx7Im5vbSI6Ikd1YWRlbG91cGUiLCJjb2RlIjoiOTcxIn0seyJub20iOiJNYXJ0aW5pcXVlIiwiY29kZSI6Ijk3MiJ9LHsibm9tIjoiR3V5YW5lIiwiY29kZSI6Ijk3MyJ9LHsibm9tIjoiTGEgUsOpdW5pb24iLCJjb2RlIjoiOTc0In0seyJub20iOiJNYXlvdHRlIiwiY29kZSI6Ijk3NiJ9XQ== + http_version: + recorded_at: Tue, 23 Oct 2018 13:11:36 GMT +recorded_with: VCR 4.0.0 diff --git a/spec/fixtures/cassettes/api_geo_regions.yml b/spec/fixtures/cassettes/api_geo_regions.yml new file mode 100644 index 000000000..0d1c6a182 --- /dev/null +++ b/spec/fixtures/cassettes/api_geo_regions.yml @@ -0,0 +1,51 @@ +--- +http_interactions: +- request: + method: get + uri: https://geo.api.gouv.fr/regions?fields=nom + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - demarches-simplifiees.fr + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Expect: + - '' + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.10.3 (Ubuntu) + Date: + - Tue, 23 Oct 2018 13:11:36 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + X-Powered-By: + - Express + Access-Control-Allow-Origin: + - "*" + Etag: + - W/"28d-5OgIzgwL+0K2UaO0foKduqMMBrA" + Strict-Transport-Security: + - max-age=15552000 + Content-Encoding: + - gzip + body: + encoding: ASCII-8BIT + string: !binary |- + W3sibm9tIjoiR3VhZGVsb3VwZSIsImNvZGUiOiIwMSJ9LHsibm9tIjoiTWFydGluaXF1ZSIsImNvZGUiOiIwMiJ9LHsibm9tIjoiR3V5YW5lIiwiY29kZSI6IjAzIn0seyJub20iOiJMYSBSw6l1bmlvbiIsImNvZGUiOiIwNCJ9LHsibm9tIjoiTWF5b3R0ZSIsImNvZGUiOiIwNiJ9LHsibm9tIjoiw45sZS1kZS1GcmFuY2UiLCJjb2RlIjoiMTEifSx7Im5vbSI6IkNlbnRyZS1WYWwgZGUgTG9pcmUiLCJjb2RlIjoiMjQifSx7Im5vbSI6IkJvdXJnb2duZS1GcmFuY2hlLUNvbXTDqSIsImNvZGUiOiIyNyJ9LHsibm9tIjoiTm9ybWFuZGllIiwiY29kZSI6IjI4In0seyJub20iOiJIYXV0cy1kZS1GcmFuY2UiLCJjb2RlIjoiMzIifSx7Im5vbSI6IkdyYW5kIEVzdCIsImNvZGUiOiI0NCJ9LHsibm9tIjoiUGF5cyBkZSBsYSBMb2lyZSIsImNvZGUiOiI1MiJ9LHsibm9tIjoiQnJldGFnbmUiLCJjb2RlIjoiNTMifSx7Im5vbSI6Ik5vdXZlbGxlLUFxdWl0YWluZSIsImNvZGUiOiI3NSJ9LHsibm9tIjoiT2NjaXRhbmllIiwiY29kZSI6Ijc2In0seyJub20iOiJBdXZlcmduZS1SaMO0bmUtQWxwZXMiLCJjb2RlIjoiODQifSx7Im5vbSI6IlByb3ZlbmNlLUFscGVzLUPDtHRlIGQnQXp1ciIsImNvZGUiOiI5MyJ9LHsibm9tIjoiQ29yc2UiLCJjb2RlIjoiOTQifV0= + http_version: + recorded_at: Tue, 23 Oct 2018 13:11:36 GMT +recorded_with: VCR 4.0.0 diff --git a/spec/fixtures/cassettes/api_geo_search_rpg.yml b/spec/fixtures/cassettes/api_geo_search_rpg.yml new file mode 100644 index 000000000..97b72996a --- /dev/null +++ b/spec/fixtures/cassettes/api_geo_search_rpg.yml @@ -0,0 +1,51 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.geo.api.gouv.fr/rpg/parcelles/search + body: + encoding: UTF-8 + string: '{"polygonIntersects":{"type":"Polygon","coordinates":[[[2.3945903778076176,46.53312237252731],[2.394933700561524,46.532590956418076],[2.3948478698730473,46.53170525134736],[2.393732070922852,46.530760483351195],[2.3909854888916016,46.5309376286023],[2.391414642333985,46.531232869403546],[2.3913288116455083,46.53253190986272],[2.39278793334961,46.53329951007484],[2.3945903778076176,46.53312237252731]]]}}' + headers: + User-Agent: + - demarches-simplifiees.fr + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Content-Type: + - application/json + Expect: + - '' + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.10.3 (Ubuntu) + Date: + - Tue, 23 Oct 2018 14:47:12 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + X-Powered-By: + - Express + Access-Control-Allow-Origin: + - "*" + Etag: + - W/"fb0-ripeBc2xednIfUlCdOtrk6Vbny4" + Content-Encoding: + - gzip + body: + encoding: ASCII-8BIT + string: !binary |- + eyJ0eXBlIjoiRmVhdHVyZUNvbGxlY3Rpb24iLCJmZWF0dXJlcyI6W3sidHlwZSI6IkZlYXR1cmUiLCJwcm9wZXJ0aWVzIjp7ImlkIjoiODA2MzQzNSIsInN1cmZhY2UiOjExLjgsImJpbyI6ZmFsc2UsImNvZGVDdWx0dXJlIjoiUFBIIiwiY3VsdHVyZSI6IlByYWlyaWUgcGVybWFuZW50ZSAtIGhlcmJlIChyZXNzb3VyY2VzIGZvdXJyYWfDqHJlcyBsaWduZXVzZXMgYWJzZW50ZXMgb3UgcGV1IHByw6lzZW50ZXMpIn0sImdlb21ldHJ5Ijp7InR5cGUiOiJQb2x5Z29uIiwiY29vcmRpbmF0ZXMiOltbWzIuMzk2Mzg4ODA5NzM4NDQ3LDQ2LjUzMjYyMDU0MzY5NzY5Nl0sWzIuMzk2ODU4MDg0NjQyNDgsNDYuNTMyMzE0MDQ0MzY4NTVdLFsyLjM5NzM4MzQ3MzYzNjMzNSw0Ni41MzE5NjEwMjE0MDQ5NDZdLFsyLjM5NzI1NjI1NTk4MjkxNCw0Ni41MzEzODkxMTc2MTI0OV0sWzIuMzk2ODg4NzQ5MDkxNTM4LDQ2LjUzMTE0NDQ1MjU5MzczNl0sWzIuMzk2MzM3NzA4MjcwMjU1LDQ2LjUzMDQzNjIzMDY5MDg0XSxbMi4zOTYzNDMzNzM4MTI2NjQsNDYuNTMwMTQxNDkxMjY3NDFdLFsyLjM5Njk5MDY1OTkxMTQyMyw0Ni41Mjk1ODE4NTQzNTkxM10sWzIuMzk0OTYxNTY4NjUwODI4LDQ2LjUyODI3ODQwMDkxMzE5NF0sWzIuMzk0NDM4MzY3MjUwMTgsNDYuNTI3NTc1MzE3NjY1OF0sWzIuMzkzMzM3MDUwMTU1MTg1LDQ2LjUyODA0MzU4MTM3OTg1XSxbMi4zOTMwNjgxOTg0MTQxNjQsNDYuNTI4MTgyOTQ0MTk3MDhdLFsyLjM5MjY4NTYyOTQzOTc2NCw0Ni41MjgzOTM3ODU1NjM3NF0sWzIuMzkyNTE1MDIzNDM3MzQxLDQ2LjUyODQ5NzQwNjU3MzNdLFsyLjM5MjQzNzUzMTU2MDc3OSw0Ni41Mjg2MDQ1NDc0NDgwN10sWzIuMzkyNDMyNDg3OTE3MTM1LDQ2LjUyODcxNTIzMzY5NzQ1XSxbMi4zOTI2MTMxOTU1MjgyMDgsNDYuNTI5MTMxMTM5NzEzODldLFsyLjM5Mzc1MTEzODE0NTU5OCw0Ni41MzA3NjM3NzY2OTQyNl0sWzIuMzk0MTA5MDExMjkyNjc0LDQ2LjUzMTQ2Mzk5ODkxMjk3XSxbMi4zOTQyNTAzODg3Njc4MzIsNDYuNTMxNjQ0MjU5MTk2MTVdLFsyLjM5NDg0MDExMjU5NTQ4Nyw0Ni41MzIxMDc4ODcyNzY0NzRdLFsyLjM5NjA2OTc0MzI0MzkyLDQ2LjUzMzA1NzQyMDg2MTA4XSxbMi4zOTYzNjI2NTU4MjAxNTUsNDYuNTMyNzQ3MTQyNTA4ODc1XSxbMi4zOTYzODg4MDk3Mzg0NDcsNDYuNTMyNjIwNTQzNjk3Njk2XV1dfX0seyJ0eXBlIjoiRmVhdHVyZSIsInByb3BlcnRpZXMiOnsiaWQiOiI4MDYzNDM5Iiwic3VyZmFjZSI6NTkuMTgsImJpbyI6ZmFsc2UsImNvZGVDdWx0dXJlIjoiUFBIIiwiY3VsdHVyZSI6IlByYWlyaWUgcGVybWFuZW50ZSAtIGhlcmJlIChyZXNzb3VyY2VzIGZvdXJyYWfDqHJlcyBsaWduZXVzZXMgYWJzZW50ZXMgb3UgcGV1IHByw6lzZW50ZXMpIn0sImdlb21ldHJ5Ijp7InR5cGUiOiJQb2x5Z29uIiwiY29vcmRpbmF0ZXMiOltbWzIuMzg5NDk0MDQzODI1MDI3LDQ2LjUyOTI0Nzc5NzQ3NTUwNl0sWzIuMzkwNzkyNTgzNjgyNzc4LDQ2LjUzMDYzMzg1NjIyMjAyNV0sWzIuMzkwNzQ0ODA3MzE0MzUzLDQ2LjUzMDY1NzY1MjUxNDc2XSxbMi4zODk5OTM4MTM3OTE0MjEsNDYuNTMxMDMxNzA0MDU4MjM2XSxbMi4zODg4ODc5NTc3OTMwNzMsNDYuNTI5OTU3MDE5NzA3MTI2XSxbMi4zODg3OTIxMjIwNTIxNzIsNDYuNTI5ODQ0MTM0MjM4NzZdLFsyLjM4ODc0NDIzNjc1OTU3MSw0Ni41Mjk3OTc4MjgyNjE5Nl0sWzIuMzg4MzIyMTM2MjgzMDYsNDYuNTMwMzQ0MzAyMDA4Ml0sWzIuMzg4MDc2NjM2MjY5MTczLDQ2LjUzMDc5Njk4NzQxNTY0XSxbMi4zODc3MzIwNjY0NDgxNjgsNDYuNTMyMjgwNzE2NDkyMzY2XSxbMi4zODcxMTU4ODI1MjM0OTIsNDYuNTMzMjY4NTU1OTE5NTA2XSxbMi4zODY5NjA1NDI4Njc3NTIsNDYuNTM0MTAzNDM3OTc1Mjc2XSxbMi4zODY2OTc1MTgyMzA5Nyw0Ni41MzYwOTEzMDc2NzQxNTVdLFsyLjM4NzIzODY4NDQ2NDE0Miw0Ni41MzYwNjEyNzIzMzg2NV0sWzIuMzg4MDkxNjcwNDM0ODA0LDQ2LjUzNjE0OTUxNzk2NzQ5NV0sWzIuMzg4NzcyOTExNTQzMDA5LDQ2LjUzNjMzNjc5MjE5ODY2XSxbMi4zODg5MzYwNjQ2MjQxNDQsNDYuNTM2NTQ4MDMxNjc4NzM0XSxbMi4zODg4ODQ1OTQ4MjIyMDMsNDYuNTM2ODMwMTA4NDkxNDRdLFsyLjM4ODQ2MTQwMDc2ODM5OCw0Ni41MzY5NzM5OTM5MzM4OF0sWzIuMzg3NDY5OTA3NzI4MzM3LDQ2LjUzNzM4NjY3MTIxNTA2XSxbMi4zODkzNDI2MzkxMjc2NjIsNDYuNTM3MDE1NzkwNzYyMzA0XSxbMi4zOTAzNDc4MDIyNzQyOTcsNDYuNTM2OTg2NTM2NjQ4MzM1XSxbMi4zOTEzODQ1ODYwNDM3NTYsNDYuNTM3MTY5NDkzNzYxMjldLFsyLjM5MjMxMjQxNzE4NTc2Miw0Ni41MzczNjg5NTM3ODk0MjVdLFsyLjM5MzYxOTE5MTc2NDg4MSw0Ni41Mzc0NTYyMTczOTA4OV0sWzIuMzk0MTQ2OTY0Mzk3NTY0LDQ2LjUzNzQ5NTIyOTk4NjgxXSxbMi4zOTUyMzQyMDk1NDAxMjQsNDYuNTM3NTY5NTYxMzk3Nzk1XSxbMi4zOTYyNzM1Mjc3ODcxOTQsNDYuNTM3NjMzMzgyMjQ3OTJdLFsyLjM5NzI0NjE3Njk4Mjc3LDQ2LjUzNzYxNTAxNjc0OTU4NF0sWzIuMzk4MDYzNTQ2OTc2NDEsNDYuNTM3NTM5NjA5ODg3OTZdLFsyLjQwMDMzNDg1MDcyNjM3Miw0Ni41MzczMTIyMzU4MzAyM10sWzIuNDAwNTQ1ODg2NjQ0OTQ5LDQ2LjUzNzI4OTI4Mjg2NjM5XSxbMi40MDExNTY4MjQwMzU5OCw0Ni41MzYzOTQ0NTk0MjMzOF0sWzIuNDAyNjI5Mzg5NTE5MTY2LDQ2LjUzNjI4ODQ0NTUwNTAxXSxbMi40MDQyOTc1OTkwNjgzMTYsNDYuNTM2MTUxNDM3NzA2MjRdLFsyLjQwNDI5NjYyODUxNzg1OCw0Ni41MzUzNzc4NTQzMjQ2XSxbMi40MDAzMjE2MDkwMzM3MjcsNDYuNTM2MTMxMDQ2OTE2Nl0sWzIuMzk5ODU5OTA4NzQ0Njc1LDQ2LjUzNjA4Mzg5MDg2NjQ4Nl0sWzIuMzk5NjU4OTc5NzIxNzU3LDQ2LjUzNTg5MjY4MTgyMDExXSxbMi40MDAyMTIwNzg5NDE1MzUsNDYuNTM1NTQ4OTA0MTU1NTNdLFsyLjM5OTAzMzAyNzMwNzc1Nyw0Ni41MzQwOTc3MDAxNjE3OF0sWzIuMzk2MzY1MzcyOTQ0MzQ5LDQ2LjUzMjc2Njg3ODk2MDI1XSxbMi4zOTYwNjkwMDE3NTk5MjUsNDYuNTMzMDgyNDEzMTIxMjg1XSxbMi4zOTU5MjU2NDI3OTYwMjYsNDYuNTMzMTMyNzU3MTQ3N10sWzIuMzk0MDcwMjI5MTg5MzYxLDQ2LjUzMTYxNTQ3MzQzMzE0XSxbMi4zOTM2OTAxODM3OTk0Myw0Ni41MzA4Njc0NDE5NDE3NDRdLFsyLjM5MzY4MTAwNTA5MzM1MSw0Ni41MzA4NTQ0MTc1MDQxOV0sWzIuMzkxNTMyMTkyOTYxNTYsNDYuNTMxMzQ5NTg3MDg0NjhdLFsyLjM4OTUzNDIxMDI1NTE2Niw0Ni41MjkyMzUzMjQxNTUyMl0sWzIuMzg5NDk0MDQzODI1MDI3LDQ2LjUyOTI0Nzc5NzQ3NTUwNl1dXX19LHsidHlwZSI6IkZlYXR1cmUiLCJwcm9wZXJ0aWVzIjp7ImlkIjoiODA2MzQ0MyIsInN1cmZhY2UiOjQuMjQsImJpbyI6ZmFsc2UsImNvZGVDdWx0dXJlIjoiUFBIIiwiY3VsdHVyZSI6IlByYWlyaWUgcGVybWFuZW50ZSAtIGhlcmJlIChyZXNzb3VyY2VzIGZvdXJyYWfDqHJlcyBsaWduZXVzZXMgYWJzZW50ZXMgb3UgcGV1IHByw6lzZW50ZXMpIn0sImdlb21ldHJ5Ijp7InR5cGUiOiJQb2x5Z29uIiwiY29vcmRpbmF0ZXMiOltbWzIuMzg5NTM0MjEwMjU1MTY2LDQ2LjUyOTIzNTMyNDE1NTIyXSxbMi4zOTE1MzIxOTI5NjE1Niw0Ni41MzEzNDk1ODcwODQ2OF0sWzIuMzkzNjgxMDA1MDkzMzUxLDQ2LjUzMDg1NDQxNzUwNDE5XSxbMi4zOTM2NzAwMDI0ODQyOSw0Ni41MzA4Mzg4MDM1NDg4M10sWzIuMzkyOTg5NTY3MDI4NjE0LDQ2LjUyOTg3MzIzMTQ2MTU5XSxbMi4zOTI0OTMxMDcyODQ3MjYsNDYuNTI5MTAxMzQ3NTE3OTVdLFsyLjM5MjMyMTkzMjkyOTI2NCw0Ni41Mjg2NzA0NDIzNTI4XSxbMi4zOTE0ODkyMDkyNzIyMzUsNDYuNTI4NzcwODEzMTQ0NzhdLFsyLjM5MDkxNTA4ODU5MTExLDQ2LjUyODg1Njc2OTY4NDM5XSxbMi4zOTA0NjUxMzI5MzMxODQsNDYuNTI4OTQ2MjM5NDQ1NzZdLFsyLjM4OTUzNDIxMDI1NTE2Niw0Ni41MjkyMzUzMjQxNTUyMl1dXX19XX0= + http_version: + recorded_at: Tue, 23 Oct 2018 14:47:12 GMT +recorded_with: VCR 4.0.0 diff --git a/spec/lib/api_adresse/address_adapter_spec.rb b/spec/lib/api_adresse/address_adapter_spec.rb new file mode 100644 index 000000000..31a1d7bc3 --- /dev/null +++ b/spec/lib/api_adresse/address_adapter_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe ApiAdresse::AddressAdapter do + describe '#get_suggestions' do + let(:request) { 'Paris' } + let(:response) { File.open('spec/fixtures/files/api_adresse/search_results.json') } + let(:status) { 200 } + + subject { described_class.new(request).get_suggestions } + + before do + stub_request(:get, "https://api-adresse.data.gouv.fr/search?&q=#{request}&limit=5") + .to_return(status: status, body: response, headers: {}) + end + + context 'when address return a list of address' do + it { expect(subject.size).to eq 5 } + it { is_expected.to be_an_instance_of Array } + end + + context 'when address return an empty list' do + let(:response) { File.open('spec/fixtures/files/api_adresse/search_no_results.json') } + + it { expect(subject.size).to eq 0 } + it { is_expected.to be_an_instance_of Array } + end + + context 'when BAN is unavailable' do + let(:status) { 503 } + let(:response) { '' } + + it { expect(subject.size).to eq 0 } + it { is_expected.to be_an_instance_of Array } + end + + context 'when request is empty' do + let(:response) { 'Missing query' } + let(:request) { '' } + + it { expect(subject.size).to eq 0 } + it { is_expected.to be_an_instance_of Array } + end + end +end diff --git a/spec/lib/api_adresse/point_adapter_spec.rb b/spec/lib/api_adresse/point_adapter_spec.rb new file mode 100644 index 000000000..9f21c8dd5 --- /dev/null +++ b/spec/lib/api_adresse/point_adapter_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe ApiAdresse::PointAdapter do + let(:address) { '50 av des champs elysees' } + + describe '.geocode', vcr: { cassette_name: 'api_adresse_octo' } do + it 'return a point' do + expect(described_class.new(address).geocode.class).to eq(RGeo::Cartesian::PointImpl) + end + + context 'when RestClient::Exception' do + before do + allow(ApiAdresse::API).to receive(:call).and_raise(RestClient::Exception) + end + + it 'return nil' do + expect(described_class.new(address).geocode).to be_nil + end + end + + context 'when JSON::ParserError' do + before do + allow(JSON).to receive(:parse).and_raise(JSON::ParserError) + end + + it 'return nil' do + expect(described_class.new(address).geocode).to be_nil + end + end + end +end diff --git a/spec/lib/api_geo/api_spec.rb b/spec/lib/api_geo/api_spec.rb new file mode 100644 index 000000000..6a046f119 --- /dev/null +++ b/spec/lib/api_geo/api_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe ApiGeo::API do + describe '.regions', vcr: { cassette_name: 'api_geo_regions' } do + subject { described_class.regions } + + it { expect(subject.size).to eq 18 } + end + + describe '.departements', vcr: { cassette_name: 'api_geo_departements' } do + subject { described_class.departements } + + it { expect(subject.size).to eq 101 } + end + + describe '.pays' do + subject { described_class.pays } + let(:pays) { + JSON.parse(File.open('app/lib/api_geo/pays.json').read, symbolize_names: true) + } + + it { is_expected.to eq pays } + end + + describe '.search_rpg', vcr: { cassette_name: 'api_geo_search_rpg' } do + let(:coordinates) do + [ + [ + 2.3945903778076176, + 46.53312237252731 + ], + [ + 2.394933700561524, + 46.532590956418076 + ], + [ + 2.3948478698730473, + 46.53170525134736 + ], + [ + 2.393732070922852, + 46.530760483351195 + ], + [ + 2.3909854888916016, + 46.5309376286023 + ], + [ + 2.391414642333985, + 46.531232869403546 + ], + [ + 2.3913288116455083, + 46.53253190986272 + ], + [ + 2.39278793334961, + 46.53329951007484 + ], + [ + 2.3945903778076176, + 46.53312237252731 + ] + ] + end + + let(:geo_json) { + GeojsonService.to_json_polygon_for_rpg(coordinates) + } + + subject { described_class.search_rpg(geo_json) } + + it { expect(subject[:features].size).to eq 3 } + end +end diff --git a/spec/lib/api_geo/rpg_adapter_spec.rb b/spec/lib/api_geo/rpg_adapter_spec.rb new file mode 100644 index 000000000..5c277a15a --- /dev/null +++ b/spec/lib/api_geo/rpg_adapter_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe ApiGeo::RPGAdapter do + subject { described_class.new(coordinates).results } + + let(:coordinates) do + [ + [ + 2.3945903778076176, + 46.53312237252731 + ], + [ + 2.394933700561524, + 46.532590956418076 + ], + [ + 2.3948478698730473, + 46.53170525134736 + ], + [ + 2.393732070922852, + 46.530760483351195 + ], + [ + 2.3909854888916016, + 46.5309376286023 + ], + [ + 2.391414642333985, + 46.531232869403546 + ], + [ + 2.3913288116455083, + 46.53253190986272 + ], + [ + 2.39278793334961, + 46.53329951007484 + ], + [ + 2.3945903778076176, + 46.53312237252731 + ] + ] + end + + context 'coordinates are filled', vcr: { cassette_name: 'api_geo_search_rpg' } do + describe 'Attribut filter' do + it { expect(subject.size).to eq(3) } + it do + expect(subject.first.keys).to eq([ + :culture, + :code_culture, + :surface, + :bio, + :geometry, + :geo_reference_id + ]) + end + end + end +end diff --git a/spec/models/champ_shared_example.rb b/spec/models/champ_shared_example.rb index d00af9504..31ae546fa 100644 --- a/spec/models/champ_shared_example.rb +++ b/spec/models/champ_shared_example.rb @@ -32,6 +32,12 @@ shared_examples 'champ_spec' do end end + describe '.departement', vcr: { cassette_name: 'api_geo_departements' } do + subject { Champs::DepartementChamp.departements } + + it { expect(subject).to include '99 - Étranger' } + end + context "when type_champ=date" do let(:type_de_champ) { create(:type_de_champ_date) } let(:champ) { type_de_champ.champ.create } diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb index eb58aed07..8be461c80 100644 --- a/spec/services/procedure_export_service_spec.rb +++ b/spec/services/procedure_export_service_spec.rb @@ -69,7 +69,6 @@ describe ProcedureExportService do "pays", "regions", "departements", - "communes", "engagement", "dossier_link", "piece_justificative", @@ -143,7 +142,6 @@ describe ProcedureExportService do "pays", "regions", "departements", - "communes", "engagement", "dossier_link", "piece_justificative", @@ -222,7 +220,6 @@ describe ProcedureExportService do "pays", "regions", "departements", - "communes", "engagement", "dossier_link", "piece_justificative", diff --git a/yarn.lock b/yarn.lock index 8a6b6baaa..ff57a5c76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1521,6 +1521,13 @@ atob@^2.1.1: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +autocomplete.js@^0.37.0: + version "0.37.0" + resolved "https://registry.yarnpkg.com/autocomplete.js/-/autocomplete.js-0.37.0.tgz#bcfbfd7bcabe90e90fad4c2b1aaa931379a10c38" + integrity sha512-MxYfNb89sl7IRhNdEJv6z8dSfA7lVeU7Dk6m/+/ih0/tPLsbxIM7uPVsnWEUh4j7dFqJktlM7hCeU7jmx6VC8A== + dependencies: + immediate "^3.2.3" + autoprefixer@^9.4.9: version "9.5.1" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.5.1.tgz#243b1267b67e7e947f28919d786b50d3bb0fb357" @@ -4355,6 +4362,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +immediate@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" + integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"