From 5bc8b5fe12e5de00300fad7402db161376e22011 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 7 Nov 2019 17:20:09 +0100 Subject: [PATCH 1/4] Implement ActiveStorage::FileNotFoundError --- app/lib/active_storage/file_not_found_error.rb | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/lib/active_storage/file_not_found_error.rb diff --git a/app/lib/active_storage/file_not_found_error.rb b/app/lib/active_storage/file_not_found_error.rb new file mode 100644 index 000000000..580d30666 --- /dev/null +++ b/app/lib/active_storage/file_not_found_error.rb @@ -0,0 +1,4 @@ +module ActiveStorage + # activestorage-openstack uses ActiveStorage::FileNotFoundError which only exists in rails 6 + class FileNotFoundError < StandardError; end +end From 6351eabfdd347da9ddacef71807b3ed2647f04a0 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Thu, 7 Nov 2019 17:21:45 +0100 Subject: [PATCH 2/4] remove notification to report-uri in production --- config/initializers/content_security_policy.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index bb61fc264..960c3cd3d 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -1,9 +1,8 @@ Rails.application.config.content_security_policy do |policy| - # En cas de non respect d'une des règles, faire un POST sur cette URL - if Rails.env.production? - policy.report_uri "https://demarchessimplifieestest.report-uri.com/r/d/csp/reportOnly" - else - policy.report_uri "http://#{ENV['APP_HOST']}/csp/" # ne pas notifier report-uri en dev/test + if Rails.env.development? + # les CSP ne sont pas appliquées en dev: on notifie cependant une url quelconque de la violation + # pour détecter les erreurs lors de l'ajout d'une nouvelle brique externe durant le développement + policy.report_uri "http://#{ENV['APP_HOST']}/csp/" end # Whitelist image policy.img_src :self, "*.openstreetmap.org", "static.demarches-simplifiees.fr", "*.cloud.ovh.net", "stats.data.gouv.fr", "*", :data From 990c867c2ef2e7034d5e490ab0e6549afc4200c7 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 26 Sep 2019 14:57:58 +0200 Subject: [PATCH 3/4] [GraphQL] Add more filters to dossiers --- app/controllers/api/v1/dossiers_controller.rb | 2 +- app/graphql/schema.graphql | 36 +++++-- app/graphql/types/demarche_type.rb | 22 +++-- app/graphql/types/order.rb | 6 ++ app/models/dossier.rb | 5 +- app/models/procedure.rb | 2 +- app/services/procedure_export_service.rb | 11 +-- app/services/procedure_export_v2_service.rb | 11 +-- .../api/v2/graphql_controller_spec.rb | 99 ++++++++++++++----- 9 files changed, 130 insertions(+), 64 deletions(-) create mode 100644 app/graphql/types/order.rb diff --git a/app/controllers/api/v1/dossiers_controller.rb b/app/controllers/api/v1/dossiers_controller.rb index 9a990734d..222e786dd 100644 --- a/app/controllers/api/v1/dossiers_controller.rb +++ b/app/controllers/api/v1/dossiers_controller.rb @@ -53,7 +53,7 @@ class API::V1::DossiersController < APIController end order = ORDER_DIRECTIONS.fetch(params[:order], :asc) - @dossiers = @procedure.dossiers.state_not_brouillon.order_for_api(order) + @dossiers = @procedure.dossiers.state_not_brouillon.order_by_created_at(order) rescue ActiveRecord::RecordNotFound render json: {}, status: :not_found diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index a79948d38..c2a558d5b 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -128,25 +128,35 @@ type Demarche { """ before: String + """ + Dossiers déposés depuis la date. + """ + createdSince: ISO8601DateTime + """ Returns the first _n_ elements from the list. """ first: Int - """ - Filtrer les dossiers par ID. - """ - ids: [ID!] - """ Returns the last _n_ elements from the list. """ last: Int """ - Dossiers crées depuis la date. + L'ordre des dossiers. """ - since: ISO8601DateTime + order: Order = ASC + + """ + Dossiers avec statut. + """ + state: DossierState + + """ + Dossiers mis à jour depuis la date. + """ + updatedSince: ISO8601DateTime ): DossierConnection! groupeInstructeurs: [GroupeInstructeur!]! id: ID! @@ -401,6 +411,18 @@ type Mutation { createDirectUpload(input: CreateDirectUploadInput!): CreateDirectUploadPayload } +enum Order { + """ + L‘ordre ascendant. + """ + ASC + + """ + L‘ordre descendant. + """ + DESC +} + """ Information about pagination in a connection. """ diff --git a/app/graphql/types/demarche_type.rb b/app/graphql/types/demarche_type.rb index 37782aafe..665ab28b9 100644 --- a/app/graphql/types/demarche_type.rb +++ b/app/graphql/types/demarche_type.rb @@ -21,8 +21,10 @@ module Types field :groupe_instructeurs, [Types::GroupeInstructeurType], null: false field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d'une démarche.", null: false do - argument :ids, [ID], required: false, description: "Filtrer les dossiers par ID." - argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers crées depuis la date." + argument :order, Types::Order, default_value: :asc, required: false, description: "L'ordre des dossiers." + argument :created_since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers déposés depuis la date." + argument :updated_since, GraphQL::Types::ISO8601DateTime, required: false, description: "Dossiers mis à jour depuis la date." + argument :state, Types::DossierType::DossierState, required: false, description: "Dossiers avec statut." end field :champ_descriptors, [Types::ChampDescriptorType], null: false, method: :types_de_champ @@ -36,15 +38,21 @@ module Types Loaders::Association.for(object.class, groupe_instructeurs: { procedure: [:administrateurs] }).load(object) end - def dossiers(ids: nil, since: nil) + def dossiers(updated_since: nil, created_since: nil, state: nil, order:) dossiers = object.dossiers.for_api_v2 - if ids.present? - dossiers = dossiers.where(id: ids) + if state.present? + dossiers = dossiers.where(state: state) end - if since.present? - dossiers = dossiers.since(since) + if updated_since.present? + dossiers = dossiers.updated_since(updated_since).order_by_updated_at(order) + else + if created_since.present? + dossiers = dossiers.created_since(created_since) + end + + dossiers = dossiers.order_by_created_at(order) end dossiers diff --git a/app/graphql/types/order.rb b/app/graphql/types/order.rb new file mode 100644 index 000000000..885e80c22 --- /dev/null +++ b/app/graphql/types/order.rb @@ -0,0 +1,6 @@ +module Types + class Order < Types::BaseEnum + value('ASC', 'L‘ordre ascendant.', value: :asc) + value('DESC', 'L‘ordre descendant.', value: :desc) + end +end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 466948a7a..0b2bc94a1 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -105,7 +105,9 @@ class Dossier < ApplicationRecord scope :not_archived, -> { where(archived: false) } scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) } - scope :order_for_api, -> (order = :asc) { order(en_construction_at: order, created_at: order, id: order) } + scope :order_by_created_at, -> (order = :asc) { order(en_construction_at: order, created_at: order, id: order) } + scope :updated_since, -> (since) { where('dossiers.updated_at >= ?', since) } + scope :created_since, -> (since) { where('dossiers.en_construction_at >= ?', since) } scope :all_state, -> { not_archived.state_not_brouillon } scope :en_construction, -> { not_archived.state_en_construction } @@ -134,7 +136,6 @@ class Dossier < ApplicationRecord scope :without_followers, -> { left_outer_joins(:follows).where(follows: { id: nil }) } scope :with_champs, -> { includes(champs: :type_de_champ) } scope :nearing_end_of_retention, -> (duration = '1 month') { joins(:procedure).where("en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - now() < interval ?", duration) } - scope :since, -> (since) { where('dossiers.en_construction_at >= ?', since) } scope :for_api, -> { includes(commentaires: { piece_jointe_attachment: :blob }, champs: [ diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 96a427dbb..6abe348c7 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -444,7 +444,7 @@ class Procedure < ApplicationRecord version = options.delete(:version) if version == 'v2' options.delete(:tables) - ProcedureExportV2Service.new(self, dossiers, **options.to_h.symbolize_keys) + ProcedureExportV2Service.new(self, dossiers) else ProcedureExportService.new(self, dossiers, **options.to_h.symbolize_keys) end diff --git a/app/services/procedure_export_service.rb b/app/services/procedure_export_service.rb index f2a192b1b..6d0b1386c 100644 --- a/app/services/procedure_export_service.rb +++ b/app/services/procedure_export_service.rb @@ -49,7 +49,7 @@ class ProcedureExportService :prenom ] - def initialize(procedure, dossiers, tables: [], ids: nil, since: nil, limit: nil) + def initialize(procedure, dossiers, tables: []) @procedure = procedure @attributes = ATTRIBUTES.dup @@ -59,15 +59,6 @@ class ProcedureExportService end @dossiers = dossiers.downloadable_sorted - if ids - @dossiers = @dossiers.where(id: ids) - end - if since - @dossiers = @dossiers.since(since) - end - if limit - @dossiers = @dossiers.limit(limit) - end @dossiers = @dossiers.to_a @tables = tables.map(&:to_sym) end diff --git a/app/services/procedure_export_v2_service.rb b/app/services/procedure_export_v2_service.rb index c8ba3bffe..eae682c1e 100644 --- a/app/services/procedure_export_v2_service.rb +++ b/app/services/procedure_export_v2_service.rb @@ -1,18 +1,9 @@ class ProcedureExportV2Service attr_reader :dossiers - def initialize(procedure, dossiers, ids: nil, since: nil, limit: nil) + def initialize(procedure, dossiers) @procedure = procedure @dossiers = dossiers.downloadable_sorted - if ids - @dossiers = @dossiers.where(id: ids) - end - if since - @dossiers = @dossiers.since(since) - end - if limit - @dossiers = @dossiers.limit(limit) - end @tables = [:dossiers, :etablissements, :avis] + champs_repetables_options end diff --git a/spec/controllers/api/v2/graphql_controller_spec.rb b/spec/controllers/api/v2/graphql_controller_spec.rb index 8aa7c0e7b..048c098f2 100644 --- a/spec/controllers/api/v2/graphql_controller_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_spec.rb @@ -12,6 +12,14 @@ describe API::V2::GraphqlController do create(:commentaire, dossier: dossier, email: 'test@test.com') dossier end + let(:dossier1) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 1.day.ago) } + let(:dossier2) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 3.days.ago) } + let(:dossiers) { [dossier2, dossier1, dossier] } + let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) } + + before do + instructeur.assign_to_procedure(procedure) + end let(:query) do "{ @@ -62,31 +70,65 @@ describe API::V2::GraphqlController do request.env['HTTP_AUTHORIZATION'] = authorization_header end - it "should return demarche" do - expect(gql_errors).to eq(nil) - expect(gql_data).to eq(demarche: { - id: procedure.to_typed_id, - number: procedure.id.to_s, - title: procedure.libelle, - description: procedure.description, - state: 'brouillon', - archivedAt: nil, - createdAt: procedure.created_at.iso8601, - updatedAt: procedure.updated_at.iso8601, - groupeInstructeurs: [{ instructeurs: [], label: "défaut" }], - champDescriptors: procedure.types_de_champ.map do |tdc| - { - id: tdc.to_typed_id, - label: tdc.libelle, - type: tdc.type_champ, - description: tdc.description, - required: tdc.mandatory? + context "demarche" do + it "should be returned" do + expect(gql_errors).to eq(nil) + expect(gql_data).to eq(demarche: { + id: procedure.to_typed_id, + number: procedure.id.to_s, + title: procedure.libelle, + description: procedure.description, + state: 'brouillon', + archivedAt: nil, + createdAt: procedure.created_at.iso8601, + updatedAt: procedure.updated_at.iso8601, + groupeInstructeurs: [ + { + instructeurs: [{ email: instructeur.email }], + label: "défaut" + } + ], + champDescriptors: procedure.types_de_champ.map do |tdc| + { + id: tdc.to_typed_id, + label: tdc.libelle, + type: tdc.type_champ, + description: tdc.description, + required: tdc.mandatory? + } + end, + dossiers: { + nodes: dossiers.map { |dossier| { id: dossier.to_typed_id } } } - end, - dossiers: { - nodes: [] - } - }) + }) + end + + context "filter dossiers" do + let(:query) do + "{ + demarche(number: #{procedure.id}) { + id + number + dossiers(createdSince: \"#{2.days.ago.iso8601}\") { + nodes { + id + } + } + } + }" + end + + it "should be returned" do + expect(gql_errors).to eq(nil) + expect(gql_data).to eq(demarche: { + id: procedure.to_typed_id, + number: procedure.id.to_s, + dossiers: { + nodes: [{ id: dossier1.to_typed_id }, { id: dossier.to_typed_id }] + } + }) + end + end end context "dossier" do @@ -130,7 +172,7 @@ describe API::V2::GraphqlController do }" end - it "should return dossier" do + it "should be returned" do expect(gql_errors).to eq(nil) expect(gql_data).to eq(dossier: { id: dossier.to_typed_id, @@ -146,7 +188,12 @@ describe API::V2::GraphqlController do id: dossier.user.to_typed_id, email: dossier.user.email }, - instructeurs: [], + instructeurs: [ + { + id: instructeur.to_typed_id, + email: instructeur.email + } + ], messages: dossier.commentaires.map do |commentaire| { body: commentaire.body, From fa741c9baee48fb366a9294ec9befe26786488cb Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 7 Nov 2019 15:08:54 +0100 Subject: [PATCH 4/4] [GraphQL]: do not return dossiers brouillons --- app/graphql/types/demarche_type.rb | 2 +- spec/controllers/api/v2/graphql_controller_spec.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/graphql/types/demarche_type.rb b/app/graphql/types/demarche_type.rb index 665ab28b9..b78ea4f14 100644 --- a/app/graphql/types/demarche_type.rb +++ b/app/graphql/types/demarche_type.rb @@ -39,7 +39,7 @@ module Types end def dossiers(updated_since: nil, created_since: nil, state: nil, order:) - dossiers = object.dossiers.for_api_v2 + dossiers = object.dossiers.state_not_brouillon.for_api_v2 if state.present? dossiers = dossiers.where(state: state) diff --git a/spec/controllers/api/v2/graphql_controller_spec.rb b/spec/controllers/api/v2/graphql_controller_spec.rb index 048c098f2..3d1f0a53a 100644 --- a/spec/controllers/api/v2/graphql_controller_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_spec.rb @@ -14,6 +14,7 @@ describe API::V2::GraphqlController do end let(:dossier1) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 1.day.ago) } let(:dossier2) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 3.days.ago) } + let!(:dossier_brouillon) { create(:dossier, procedure: procedure) } let(:dossiers) { [dossier2, dossier1, dossier] } let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) }