diff --git a/Gemfile b/Gemfile index 55ba93826..14407ddc5 100644 --- a/Gemfile +++ b/Gemfile @@ -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' diff --git a/Gemfile.lock b/Gemfile.lock index 224ba4f58..7e80e2d2b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 diff --git a/app/controllers/champs/carte_controller.rb b/app/controllers/champs/carte_controller.rb index 3fdd88b7b..4459ab781 100644 --- a/app/controllers/champs/carte_controller.rb +++ b/app/controllers/champs/carte_controller.rb @@ -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 diff --git a/app/helpers/dossier_helper.rb b/app/helpers/dossier_helper.rb index 1341eeaaa..ab931bb24 100644 --- a/app/helpers/dossier_helper.rb +++ b/app/helpers/dossier_helper.rb @@ -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? diff --git a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js index 5b4dc12fa..3787639e5 100644 --- a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js +++ b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js @@ -136,10 +136,6 @@ const TypeDeChamp = sortableElement( url={typeDeChamp.piece_justificative_template_url} /> - { - 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. diff --git a/app/lib/api_carto/api.rb b/app/lib/api_carto/api.rb index 865a8b192..92730c654 100644 --- a/app/lib/api_carto/api.rb +++ b/app/lib/api_carto/api.rb @@ -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) diff --git a/app/lib/api_carto/quartiers_prioritaires_adapter.rb b/app/lib/api_carto/quartiers_prioritaires_adapter.rb deleted file mode 100644 index 80de6b926..000000000 --- a/app/lib/api_carto/quartiers_prioritaires_adapter.rb +++ /dev/null @@ -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 diff --git a/app/models/administrateur.rb b/app/models/administrateur.rb index 0b982aabf..474ae1982 100644 --- a/app/models/administrateur.rb +++ b/app/models/administrateur.rb @@ -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 diff --git a/app/services/geojson_service.rb b/app/services/geojson_service.rb index bfa717982..a5c98c9ed 100644 --- a/app/services/geojson_service.rb +++ b/app/services/geojson_service.rb @@ -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| diff --git a/app/views/users/_general_footer_row.html.haml b/app/views/users/_general_footer_row.html.haml index 987c199e4..52e27bfe0 100644 --- a/app/views/users/_general_footer_row.html.haml +++ b/app/views/users/_general_footer_row.html.haml @@ -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 diff --git a/app/views/users/dossiers/index.html.haml b/app/views/users/dossiers/index.html.haml index 81d1709ec..0c73c103e 100644 --- a/app/views/users/dossiers/index.html.haml +++ b/app/views/users/dossiers/index.html.haml @@ -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) diff --git a/config/application.rb b/config/application.rb index be10d163e..2ecce58c2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -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 doesn’t 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) diff --git a/config/initializers/graphiql.rb b/config/initializers/graphiql.rb deleted file mode 100644 index b67ca0c50..000000000 --- a/config/initializers/graphiql.rb +++ /dev/null @@ -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' diff --git a/config/initializers/graphql.rb b/config/initializers/graphql.rb index e669da38b..dbf0da270 100644 --- a/config/initializers/graphql.rb +++ b/config/initializers/graphql.rb @@ -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 diff --git a/config/routes.rb b/config/routes.rb index 35f560b5c..456bb92fd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/spec/controllers/champs/carte_controller_spec.rb b/spec/controllers/champs/carte_controller_spec.rb index e1a952714..43861373a 100644 --- a/spec/controllers/champs/carte_controller_spec.rb +++ b/spec/controllers/champs/carte_controller_spec.rb @@ -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) diff --git a/spec/features/new_administrateur/types_de_champ_spec.rb b/spec/features/new_administrateur/types_de_champ_spec.rb index 625fb9b1d..4ef40f750 100644 --- a/spec/features/new_administrateur/types_de_champ_spec.rb +++ b/spec/features/new_administrateur/types_de_champ_spec.rb @@ -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 diff --git a/spec/fixtures/files/api_carto/request_qp.json b/spec/fixtures/files/api_carto/request_qp.json deleted file mode 100644 index 0531fb480..000000000 --- a/spec/fixtures/files/api_carto/request_qp.json +++ /dev/null @@ -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 - ] - ] - ] - } -} diff --git a/spec/fixtures/files/api_carto/response_qp.json b/spec/fixtures/files/api_carto/response_qp.json deleted file mode 100644 index 4cb2b4104..000000000 --- a/spec/fixtures/files/api_carto/response_qp.json +++ /dev/null @@ -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" - } - } - ] -} diff --git a/spec/helpers/dossier_helper_spec.rb b/spec/helpers/dossier_helper_spec.rb index 0bf33c397..7e90e8807 100644 --- a/spec/helpers/dossier_helper_spec.rb +++ b/spec/helpers/dossier_helper_spec.rb @@ -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) } diff --git a/spec/lib/api_carto/api_spec.rb b/spec/lib/api_carto/api_spec.rb index c0c8dd73b..432a11b46 100644 --- a/spec/lib/api_carto/api_spec.rb +++ b/spec/lib/api_carto/api_spec.rb @@ -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) } diff --git a/spec/lib/api_carto/quartiers_prioritaires_adapter_spec.rb b/spec/lib/api_carto/quartiers_prioritaires_adapter_spec.rb deleted file mode 100644 index 4f1988bae..000000000 --- a/spec/lib/api_carto/quartiers_prioritaires_adapter_spec.rb +++ /dev/null @@ -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 diff --git a/spec/models/administrateur_spec.rb b/spec/models/administrateur_spec.rb index c1e4e3320..e0ac8f044 100644 --- a/spec/models/administrateur_spec.rb +++ b/spec/models/administrateur_spec.rb @@ -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 diff --git a/spec/services/geojson_service_spec.rb b/spec/services/geojson_service_spec.rb index bcd9fdea3..7a3bd7c80 100644 --- a/spec/services/geojson_service_spec.rb +++ b/spec/services/geojson_service_spec.rb @@ -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) }