commit
b8a9e737a5
11 changed files with 140 additions and 70 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
dossiers = object.dossiers.for_api_v2
|
||||
def dossiers(updated_since: nil, created_since: nil, state: nil, order:)
|
||||
dossiers = object.dossiers.state_not_brouillon.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
|
||||
|
|
6
app/graphql/types/order.rb
Normal file
6
app/graphql/types/order.rb
Normal file
|
@ -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
|
4
app/lib/active_storage/file_not_found_error.rb
Normal file
4
app/lib/active_storage/file_not_found_error.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
module ActiveStorage
|
||||
# activestorage-openstack uses ActiveStorage::FileNotFoundError which only exists in rails 6
|
||||
class FileNotFoundError < StandardError; end
|
||||
end
|
|
@ -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: [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,6 +12,15 @@ 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!(:dossier_brouillon) { create(:dossier, procedure: procedure) }
|
||||
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 +71,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 +173,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 +189,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,
|
||||
|
|
Loading…
Reference in a new issue