Merge pull request #5045 from betagouv/dev

2020-04-15-01
This commit is contained in:
Pierre de La Morinerie 2020-04-15 09:35:39 +02:00 committed by GitHub
commit 0fdcf2b4d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 102 additions and 333 deletions

View file

@ -31,10 +31,10 @@ gem 'flipper-ui'
gem 'fugit'
gem 'geocoder'
gem 'gon'
gem 'graphiql-rails'
gem 'graphql'
gem 'graphql-batch'
gem 'graphql-rails_logger'
gem 'graphql_playground-rails'
gem 'groupdate'
gem 'haml-rails'
gem 'hashie'

View file

@ -248,9 +248,6 @@ GEM
i18n (>= 0.7)
multi_json
request_store (>= 1.0)
graphiql-rails (1.7.0)
railties
sprockets-rails
graphql (1.10.6)
graphql-batch (0.4.2)
graphql (>= 1.3, < 2)
@ -264,6 +261,8 @@ GEM
bundler (>= 1.14)
graphql (~> 1.10)
thor (>= 0.19, < 2.0)
graphql_playground-rails (2.1.0)
rails (>= 5.1.0)
groupdate (5.0.0)
activesupport (>= 5)
guard (2.15.0)
@ -755,11 +754,11 @@ DEPENDENCIES
fugit
geocoder
gon
graphiql-rails
graphql
graphql-batch
graphql-rails_logger
graphql-schema_comparator
graphql_playground-rails
groupdate
guard
guard-livereload

View file

@ -39,14 +39,6 @@ class Champs::CarteController < ApplicationController
end
end
if @champ.quartiers_prioritaires?
quartiers_prioritaires = ApiCartoService.generate_qp(coordinates)
geo_areas += quartiers_prioritaires.map do |qp|
qp[:source] = GeoArea.sources.fetch(:quartier_prioritaire)
qp
end
end
selection_utilisateur = ApiCartoService.generate_selection_utilisateur(coordinates)
selection_utilisateur[:source] = GeoArea.sources.fetch(:selection_utilisateur)
geo_areas << selection_utilisateur

View file

@ -1,4 +1,6 @@
module DossierHelper
include EtablissementHelper
def button_or_label_class(dossier)
if dossier.accepte?
'accepted'
@ -101,6 +103,18 @@ module DossierHelper
content_tag(:span, status_text, class: "label #{status_class} ")
end
def demandeur_dossier(dossier)
if dossier.procedure.for_individual?
"#{dossier&.individual&.nom} #{dossier&.individual&.prenom}"
else
if dossier.etablissement.present?
raison_sociale_or_name(dossier.etablissement)
else
""
end
end
end
private
def dinum_instance?

View file

@ -136,10 +136,6 @@ const TypeDeChamp = sortableElement(
url={typeDeChamp.piece_justificative_template_url}
/>
<TypeDeChampCarteOptions isVisible={isCarte}>
<TypeDeChampCarteOption
label="Quartiers prioritaires"
handler={updateHandlers.quartiers_prioritaires}
/>
<TypeDeChampCarteOption
label="Cadastres"
handler={updateHandlers.cadastres}

View file

@ -1,20 +1,5 @@
import Rails from '@rails/ujs';
import jQuery from 'jquery';
import { delegate } from '@utils';
// We use `jQuery.active` in our capybara suit to wait for ajax requests.
// Newer jQuery-less version of rails-ujs is breaking it.
// We have to set `ajax:complete` listener on the same element as the one
// we catch ajax:send on as by the end of the request
// the old element may be removed from DOM.
delegate('ajax:send', '[data-remote]', ({ target }) => {
let callback = () => {
jQuery.active--;
target.removeEventListener('ajax:complete', callback);
};
target.addEventListener('ajax:complete', callback);
jQuery.active++;
});
// `smart_listing` gem is overriding `$.rails.href` method. When using newer
// jQuery-less version of rails-ujs it breaks.

View file

@ -2,11 +2,6 @@ class ApiCarto::API
class ResourceNotFound < StandardError
end
def self.search_qp(geojson)
url = [API_CARTO_URL, "quartiers-prioritaires", "search"].join("/")
call(url, geojson)
end
def self.search_cadastre(geojson)
url = [API_CARTO_URL, "cadastre", "geometrie"].join("/")
call(url, geojson)

View file

@ -1,15 +0,0 @@
class ApiCarto::QuartiersPrioritairesAdapter
def initialize(coordinates)
@coordinates = GeojsonService.to_json_polygon_for_qp(coordinates)
end
def data_source
@data_source ||= JSON.parse(ApiCarto::API.search_qp(@coordinates), symbolize_names: true)
end
def results
data_source[:features].map do |feature|
feature[:properties].merge({ geometry: feature[:geometry] })
end
end
end

View file

@ -81,13 +81,14 @@ class Administrateur < ApplicationRecord
fail "Impossible de supprimer cet administrateur car il a des démarches où il est le seul administrateur"
end
procedures.each do |procedure|
procedures.with_discarded.each do |procedure|
next_administrateur = procedure.administrateurs.where.not(id: self.id).first
procedure.service.update(administrateur: next_administrateur)
end
services.each do |service|
service.destroy unless service.procedures.any?
# We can't destroy a service if it has procedures, even if those procedures are archived
service.destroy unless service.procedures.with_discarded.any?
end
destroy

View file

@ -1,15 +1,4 @@
class GeojsonService
def self.to_json_polygon_for_qp(coordinates)
polygon = {
geo: {
type: "Polygon",
coordinates: [coordinates]
}
}
polygon.to_json
end
def self.to_json_polygon_for_cadastre(coordinates)
polygon = {
geom: {
@ -26,17 +15,6 @@ class GeojsonService
polygon.to_json
end
def self.to_json_polygon_for_rpg(coordinates)
polygon = {
polygonIntersects: {
type: "Polygon",
coordinates: [coordinates]
}
}
polygon.to_json
end
def self.to_json_polygon_for_selection_utilisateur(coordinates)
coordinates = coordinates.map do |lat_longs|
outbounds = lat_longs.map do |lat_long|

View file

@ -1,7 +1,7 @@
%ul.footer-row.footer-bottom-line.footer-site-links
%li>= link_to "Accessibilité", accessibilite_path
%li>= link_to "CGU", CGU_URL, target: "_blank", rel: "noopener noreferrer"
%li>= link_to "Mentions légales", MENTIONS_LEGALES_URL, target: "_blank", rel: "noopener noreferrer"
%li>= link_to 'Documentation', DOC_URL
%li>= contact_link "Contact technique", dossier_id: dossier&.id
%li>= link_to 'Aide', FAQ_URL
%li.footer-link-accessibilite>= link_to "Accessibilité", accessibilite_path
%li.footer-link-cgu>= link_to "CGU", CGU_URL, target: "_blank", rel: "noopener noreferrer"
%li.footer-link-mentions-legales>= link_to "Mentions légales", MENTIONS_LEGALES_URL, target: "_blank", rel: "noopener noreferrer"
%li.footer-link-doc>= link_to 'Documentation', DOC_URL
%li.footer-link-contact>= contact_link "Contact technique", dossier_id: dossier&.id
%li.footer-link-aide>= link_to 'Aide', FAQ_URL

View file

@ -32,6 +32,8 @@
%th.notification-col
%th.number-col Nº dossier
%th Démarche
- if @dossiers.count > 1
%th Demandeur
%th.status-col Statut
%th.updated-at-col Mis à jour
%th
@ -47,6 +49,9 @@
%td
= link_to(url_for_dossier(dossier), class: 'cell-link') do
= procedure_libelle(dossier.procedure)
- if @dossiers.count > 1
%td.number-col
= demandeur_dossier(dossier)
%td.status-col
= link_to(url_for_dossier(dossier), class: 'cell-link') do
= status_badge(dossier.state)

View file

@ -35,6 +35,18 @@ module TPS
config.action_view.sanitized_allowed_tags = ActionView::Base.sanitized_allowed_tags + ['u']
# Some mobile browsers have a behaviour where, although they will delete the session
# cookie when the browser shutdowns, they will still serve a cached version
# of the page on relaunch.
# The CSRF token in the HTML is then mismatched with the CSRF token in the session cookie
# (because the session cookie has been cleared). This causes form submissions to fail with
# a "ActionController::InvalidAuthenticityToken" exception.
# To prevent this, tell browsers to never cache the HTML of a page.
# (This doesnt affect assets files, which are still sent with the proper cache headers).
#
# See https://github.com/rails/rails/issues/21948
config.action_dispatch.default_headers['Cache-Control'] = 'no-store, no-cache'
config.to_prepare do
# Make main application helpers available in administrate
Administrate::ApplicationController.helper(TPS::Application.helpers)

View file

@ -1,81 +0,0 @@
DEFAULT_QUERY = "# La documentation officielle de la spécification (Anglais) : https://graphql.org/
# Une introduction aux concepts et raisons d'être de GraphQL (Français) : https://blog.octo.com/graphql-et-pourquoi-faire/
# Le schema GraphQL de demarches-simplifiees.fr : https://demarches-simplifiees-graphql.netlify.com
# Le endpoint GraphQL de demarches-simplifiees.fr : https://www.demarches-simplifiees.fr/api/v2/graphql
query getDemarche($demarcheNumber: Int!) {
demarche(number: $demarcheNumber) {
id
number
title
champDescriptors {
id
type
label
}
dossiers(first: 3) {
nodes {
id
number
datePassageEnConstruction
datePassageEnInstruction
dateTraitement
usager {
email
}
champs {
id
label
... on TextChamp {
value
}
... on DecimalNumberChamp {
value
}
... on IntegerNumberChamp {
value
}
... on CheckboxChamp {
value
}
... on DateChamp {
value
}
... on DossierLinkChamp {
dossier {
id
}
}
... on MultipleDropDownListChamp {
values
}
... on LinkedDropDownListChamp {
primaryValue
secondaryValue
}
... on PieceJustificativeChamp {
file {
url
}
}
... on CarteChamp {
geoAreas {
source
geometry {
type
coordinates
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}"
GraphiQL::Rails.config.initial_query = DEFAULT_QUERY
GraphiQL::Rails.config.title = 'demarches-simplifiees.fr'

View file

@ -3,3 +3,10 @@ GraphQL::RailsLogger.configure do |config|
'API::V2::GraphqlController' => ['execute']
}
end
GraphqlPlayground::Rails.configure do |config|
config.title = "demarches-simplifiees.fr"
config.settings = {
"schema.polling.enable": false
}
end

View file

@ -224,7 +224,7 @@ Rails.application.routes.draw do
#
authenticated :user, lambda { |user| user.administrateur_id && Flipper.enabled?(:administrateur_graphql, user) } do
mount GraphiQL::Rails::Engine, at: "/graphql", graphql_path: "/api/v2/graphql", via: :get
mount GraphqlPlayground::Rails::Engine, at: "/graphql", graphql_path: "/api/v2/graphql"
end
namespace :api do

View file

@ -16,7 +16,7 @@ describe Champs::CarteController, type: :controller do
let(:geojson) { [] }
let(:champ) do
create(:type_de_champ_carte, options: {
quartiers_prioritaires: true
cadastres: true
}).champ.create(dossier: dossier, value: geojson.to_json)
end
@ -29,9 +29,9 @@ describe Champs::CarteController, type: :controller do
before do
sign_in user
allow_any_instance_of(ApiCarto::QuartiersPrioritairesAdapter)
allow_any_instance_of(ApiCarto::CadastreAdapter)
.to receive(:results)
.and_return([{ code: "QPCODE1234", geometry: { type: "MultiPolygon", coordinates: [[[[2.38715792094576, 48.8723062632126], [2.38724851642619, 48.8721392348061]]]] } }])
.and_return([{ code: "QPCODE1234", surface_parcelle: 4, geometry: { type: "MultiPolygon", coordinates: [[[[2.38715792094576, 48.8723062632126], [2.38724851642619, 48.8721392348061]]]] } }])
post :show, params: params, format: 'js'
end
@ -71,7 +71,7 @@ describe Champs::CarteController, type: :controller do
before do
sign_in user
allow_any_instance_of(ApiCarto::QuartiersPrioritairesAdapter)
allow_any_instance_of(ApiCarto::CadastreAdapter)
.to receive(:results)
.and_raise(ApiCarto::API::ResourceNotFound)

View file

@ -120,16 +120,15 @@ feature 'As an administrateur I can edit types de champ', js: true do
select('Carte', from: 'champ-0-type_champ')
fill_in 'champ-0-libelle', with: 'Libellé de champ carte', fill_options: { clear: :backspace }
check 'Quartiers prioritaires'
check 'Cadastres'
wait_until { procedure.types_de_champ.first.quartiers_prioritaires == true }
wait_until { procedure.types_de_champ.first.cadastres == true }
expect(page).to have_content('Formulaire enregistré')
preview_window = window_opened_by { click_on 'Prévisualiser le formulaire' }
within_window(preview_window) do
expect(page).to have_content('Libellé de champ carte')
expect(page).to have_content('Quartiers prioritaires')
expect(page).not_to have_content('Cadastres')
expect(page).to have_content('Parcelles cadastrales')
end
end

View file

@ -1,29 +0,0 @@
{
"geo": {
"type": "Polygon",
"coordinates": [
[
[
5.93536376953125,
48.91888968903368
],
[
5.93536376953125,
49.26780455063753
],
[
7.094421386718749,
49.26780455063753
],
[
7.094421386718749,
48.91888968903368
],
[
5.93536376953125,
48.91888968903368
]
]
]
}
}

View file

@ -1,30 +0,0 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
6.2136923480551,
49.1342109827851
],
[
6.21416055031881,
49.1338823553928
]
]
]
]
},
"properties": {
"code": "QP057019",
"nom": "Hauts De Vallières",
"commune": "Metz"
}
}
]
}

View file

@ -38,6 +38,40 @@ RSpec.describe DossierHelper, type: :helper do
end
end
describe ".demandeur_dossier" do
subject { demandeur_dossier(dossier) }
let(:individual) { create(:individual) }
let(:etablissement) { create(:etablissement) }
let(:dossier) { create(:dossier, procedure: procedure, individual: individual, etablissement: etablissement) }
context "when the dossier is for an individual" do
let(:procedure) { create(:simple_procedure, :for_individual) }
context "when the individual is not provided" do
let(:individual) { nil }
it { is_expected.to be_blank }
end
context "when the individual has name information" do
it { is_expected.to eq "#{individual.nom} #{individual.prenom}" }
end
end
context "when the dossier is for a company" do
let(:procedure) { create(:procedure, for_individual: false) }
context "when the company is not provided" do
let(:etablissement) { nil }
it { is_expected.to be_blank }
end
context "when the company has name information" do
it { is_expected.to eq raison_sociale_or_name(etablissement) }
end
end
end
describe ".dossier_submission_is_closed?" do
let(:dossier) { create(:dossier, state: state) }
let(:state) { Dossier.states.fetch(:brouillon) }

View file

@ -1,52 +1,4 @@
describe ApiCarto::API do
describe '.search_qp' do
subject { described_class.search_qp(geojson) }
before do
stub_request(:post, "https://sandbox.geo.api.gouv.fr/apicarto/quartiers-prioritaires/search")
.with(:body => /.*/,
:headers => { 'Content-Type' => 'application/json' })
.to_return(status: status, body: body)
end
context 'when geojson is empty' do
let(:geojson) { '' }
let(:status) { 404 }
let(:body) { '' }
it 'raises ApiCarto::API::ResourceNotFound' do
expect { subject }.to raise_error(ApiCarto::API::ResourceNotFound)
end
end
context 'when request return 500' do
let(:geojson) { File.read('spec/fixtures/files/api_carto/request_qp.json') }
let(:status) { 500 }
let(:body) { 'toto' }
it 'raises ApiCarto::API::ResourceNotFound' do
expect { subject }.to raise_error(ApiCarto::API::ResourceNotFound)
end
end
context 'when geojson exist' do
let(:geojson) { File.read('spec/fixtures/files/api_carto/request_qp.json') }
let(:status) { 200 }
let(:body) { 'toto' }
it 'returns response body' do
expect(subject).to eq(body)
end
context 'when geojson is at format JSON' do
let(:geojson) { JSON.parse(File.read('spec/fixtures/files/api_carto/request_qp.json')) }
it 'returns response body' do
expect(subject).to eq(body)
end
end
end
end
describe '.search_cadastre' do
subject { described_class.search_cadastre(geojson) }

View file

@ -1,36 +0,0 @@
describe ApiCarto::QuartiersPrioritairesAdapter do
subject { described_class.new(coordinates).results }
before do
stub_request(:post, "https://sandbox.geo.api.gouv.fr/apicarto/quartiers-prioritaires/search")
.with(:body => /.*/,
:headers => { 'Content-Type' => 'application/json' })
.to_return(status: status, body: body)
end
context 'coordinates are filled' do
let(:coordinates) { '[[2.252728, 43.27151][2.323223, 32.835332]]' }
let(:status) { 200 }
let(:body) { File.read('spec/fixtures/files/api_carto/response_qp.json') }
it { expect(subject).to be_a_instance_of(Array) }
context 'Attributes' do
let(:qp_code) { 'QP057019' }
it { expect(subject.first[:code]).to eq(qp_code) }
it { expect(subject.first[:nom]).to eq('Hauts De Vallières') }
it { expect(subject.first[:commune]).to eq('Metz') }
it { expect(subject.first[:geometry]).to eq({ :type => "MultiPolygon", :coordinates => [[[[6.2136923480551, 49.1342109827851], [6.21416055031881, 49.1338823553928]]]] }) }
end
end
context 'coordinates are empty' do
let(:coordinates) { '' }
let(:status) { 404 }
let(:body) { '' }
it { expect { subject }.to raise_error(ApiCarto::API::ResourceNotFound) }
end
end

View file

@ -65,6 +65,15 @@ describe Administrateur, type: :model do
expect(Service.find_by(id: service_without_procedure.id)).to be_nil
expect(Administrateur.find_by(id: administrateur.id)).to be_nil
end
it "does not delete service if associated to an archived procedure" do
service.update(administrateur: administrateur)
procedure.discard!
administrateur.delete_and_transfer_services
expect(Service.find_by(id: procedure.service.id)).not_to be_nil
expect(Administrateur.find_by(id: administrateur.id)).to be_nil
end
end
# describe '#password_complexity' do

View file

@ -9,24 +9,6 @@ describe GeojsonService do
]
}
describe '.toGeoJsonPolygonForQp' do
subject { JSON.parse(described_class.to_json_polygon_for_qp coordinates) }
describe 'coordinates are empty' do
let(:coordinates) { '' }
it { expect(subject['geo']['type']).to eq('Polygon') }
it { expect(subject['geo']['coordinates']).to eq([coordinates]) }
end
describe 'coordinates are informed' do
let(:coordinates) { good_coordinates }
it { expect(subject['geo']['type']).to eq('Polygon') }
it { expect(subject['geo']['coordinates']).to eq([coordinates]) }
end
end
describe '.toGeoJsonPolygonForCadastre' do
subject { JSON.parse(described_class.to_json_polygon_for_cadastre coordinates) }