Merge pull request #5658 from tchak/graphql-pdf-access

[GraphQL] expose dossier pdf and attestation
This commit is contained in:
Paul Chavard 2020-10-07 09:25:30 +02:00 committed by GitHub
commit 072617fbdf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 166 additions and 25 deletions

View file

@ -0,0 +1,26 @@
class API::V2::DossiersController < API::V2::BaseController
before_action :ensure_dossier_present
def pdf
@include_infos_administration = true
render(file: 'dossiers/show', formats: [:pdf])
end
def geojson
send_data dossier.to_feature_collection.to_json,
type: 'application/json',
filename: "dossier-#{dossier.id}-features.json"
end
private
def ensure_dossier_present
if dossier.blank?
head :unauthorized
end
end
def dossier
@dossier ||= GlobalID::Locator.locate_signed(params[:id].to_s, for: 'api_v2')
end
end

View file

@ -55,7 +55,7 @@ interface Champ {
type ChampDescriptor {
"""
Description des champs d'un bloc répétable.
Description des champs dun bloc répétable.
"""
champDescriptors: [ChampDescriptor!]
@ -71,7 +71,7 @@ type ChampDescriptor {
label: String!
"""
List des options d'un champ avec selection.
List des options dun champ avec selection.
"""
options: [String!]
@ -246,7 +246,7 @@ type Demarche {
datePublication: ISO8601DateTime!
"""
L'état de dossier pour une démarche déclarative
Létat de dossier pour une démarche déclarative
"""
declarative: DossierDeclarativeState
@ -256,7 +256,7 @@ type Demarche {
description: String!
"""
Liste de tous les dossiers d'une démarche.
Liste de tous les dossiers dune démarche.
"""
dossiers(
"""
@ -290,7 +290,7 @@ type Demarche {
last: Int
"""
L'ordre des dossiers.
Lordre des dossiers.
"""
order: Order = ASC
@ -317,7 +317,7 @@ type Demarche {
service: Service!
"""
L'état de la démarche.
Létat de la démarche.
"""
state: DemarcheState!
@ -380,6 +380,11 @@ Un dossier
type Dossier {
annotations: [Champ!]!
archived: Boolean!
"""
LURL de lattestation au format PDF.
"""
attestation: File
avis: [Avis!]!
champs: [Champ!]!
@ -403,6 +408,11 @@ type Dossier {
"""
dateTraitement: ISO8601DateTime
demandeur: Demandeur!
"""
LURL du GeoJSON contenant les données cartographiques du dossier.
"""
geojson: File
groupeInstructeur: GroupeInstructeur!
id: ID!
instructeurs: [Profile!]!
@ -414,10 +424,15 @@ type Dossier {
Le numero du dossier.
"""
number: Int!
"""
LURL du dossier au format PDF.
"""
pdf: File
revision: Revision!
"""
L'état du dossier.
Létat du dossier.
"""
state: DossierState!
usager: Profile!
@ -754,7 +769,7 @@ type Entreprise {
dateCreation: ISO8601Date!
"""
effectif moyen d'une année
effectif moyen dune année
"""
effectifAnnuel: Effectif
@ -829,7 +844,7 @@ Un groupe instructeur avec ces dossiers
"""
type GroupeInstructeurWithDossiers {
"""
Liste de tous les dossiers d'une démarche.
Liste de tous les dossiers dune démarche.
"""
dossiers(
"""
@ -858,7 +873,7 @@ type GroupeInstructeurWithDossiers {
last: Int
"""
L'ordre des dossiers.
Lordre des dossiers.
"""
order: Order = ASC
@ -1107,7 +1122,7 @@ type Query {
): Demarche!
"""
Informations sur un dossier d'une démarche.
Informations sur un dossier dune démarche.
"""
dossier(
"""

View file

@ -14,8 +14,8 @@ module Types
field :description, String, "Description du champ.", null: true
field :required, Boolean, "Est-ce que le champ est obligatoire ?", null: false, method: :mandatory?
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d'un bloc répétable.", null: true
field :options, [String], "List des options d'un champ avec selection.", null: true
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs dun bloc répétable.", null: true
field :options, [String], "List des options dun champ avec selection.", null: true
def champ_descriptors
if object.repetition?

View file

@ -1,6 +1,5 @@
module Types::Champs
class PieceJustificativeChampType < Types::BaseObject
include Rails.application.routes.url_helpers
implements Types::ChampType
field :file, Types::File, null: true, extensions: [

View file

@ -20,8 +20,8 @@ module Types
field :number, Int, "Le numero de la démarche.", null: false, method: :id
field :title, String, "Le titre de la démarche.", null: false, method: :libelle
field :description, String, "Description de la démarche.", null: false
field :state, DemarcheState, "L'état de la démarche.", null: false
field :declarative, DossierDeclarativeState, "L'état de dossier pour une démarche déclarative", null: true, method: :declarative_with_state
field :state, DemarcheState, "Létat de la démarche.", null: false
field :declarative, DossierDeclarativeState, "Létat de dossier pour une démarche déclarative", null: true, method: :declarative_with_state
field :date_creation, GraphQL::Types::ISO8601DateTime, "Date de la création.", null: false, method: :created_at
field :date_publication, GraphQL::Types::ISO8601DateTime, "Date de la publication.", null: false, method: :published_at
@ -32,8 +32,8 @@ module Types
field :groupe_instructeurs, [Types::GroupeInstructeurType], null: false
field :service, Types::ServiceType, null: false
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d'une démarche.", null: false do
argument :order, Types::Order, default_value: :asc, required: false, description: "L'ordre des dossiers."
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers dune démarche.", null: false do
argument :order, Types::Order, default_value: :asc, required: false, description: "Lordre 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."

View file

@ -10,7 +10,7 @@ module Types
global_id_field :id
field :number, Int, "Le numero du dossier.", null: false, method: :id
field :state, DossierState, "L'état du dossier.", null: false
field :state, DossierState, "Létat du dossier.", null: false
field :date_passage_en_construction, GraphQL::Types::ISO8601DateTime, "Date de dépôt.", null: false, method: :en_construction_at
field :date_passage_en_instruction, GraphQL::Types::ISO8601DateTime, "Date de passage en instruction.", null: true, method: :en_instruction_at
@ -24,6 +24,10 @@ module Types
{ Extensions::Attachment => { attachment: :justificatif_motivation } }
]
field :pdf, Types::File, "LURL du dossier au format PDF.", null: true
field :geojson, Types::File, "LURL du GeoJSON contenant les données cartographiques du dossier.", null: true
field :attestation, Types::File, "LURL de lattestation au format PDF.", null: true
field :usager, Types::ProfileType, null: false
field :groupe_instructeur, Types::GroupeInstructeurType, null: false
field :revision, Types::RevisionType, null: false
@ -81,6 +85,30 @@ module Types
Loaders::Association.for(object.class, :champs_private).load(object)
end
def pdf
sgid = object.to_sgid(expires_in: 1.hour, for: 'api_v2')
{
filename: "dossier-#{object.id}.pdf",
content_type: 'application/pdf',
url: Rails.application.routes.url_helpers.api_v2_dossier_pdf_url(id: sgid)
}
end
def geojson
sgid = object.to_sgid(expires_in: 1.hour, for: 'api_v2')
{
filename: "dossier-#{object.id}-features.json",
content_type: 'application/json',
url: Rails.application.routes.url_helpers.api_v2_dossier_geojson_url(id: sgid)
}
end
def attestation
if object.termine? && object.procedure.attestation_template&.activated?
Loaders::Association.for(object.class, attestation: { pdf_attachment: :blob }).load(object).then(&:pdf)
end
end
def self.authorized?(object, context)
authorized_demarche?(object.procedure, context)
end

View file

@ -7,7 +7,11 @@ module Types
field :content_type, String, null: false
def url
object.service_url
if object.is_a?(Hash)
object[:url]
else
object.service_url
end
end
end
end

View file

@ -2,8 +2,8 @@ module Types
class GroupeInstructeurWithDossiersType < GroupeInstructeurType
description "Un groupe instructeur avec ces dossiers"
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers d'une démarche.", null: false do
argument :order, Types::Order, default_value: :asc, required: false, description: "L'ordre des dossiers."
field :dossiers, Types::DossierType.connection_type, "Liste de tous les dossiers dune démarche.", null: false do
argument :order, Types::Order, default_value: :asc, required: false, description: "Lordre 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."

View file

@ -16,7 +16,7 @@ module Types
field :siret_siege_social, String, null: false
field :code_effectif_entreprise, String, null: true
field :effectif_mensuel, EffectifType, null: true, description: "effectif pour un mois donné"
field :effectif_annuel, EffectifType, null: true, description: "effectif moyen d'une année"
field :effectif_annuel, EffectifType, null: true, description: "effectif moyen dune année"
field :date_creation, GraphQL::Types::ISO8601Date, null: false
field :nom, String, null: false
field :prenom, String, null: false

View file

@ -4,7 +4,7 @@ module Types
argument :number, Int, "Numéro de la démarche.", required: true
end
field :dossier, DossierType, null: false, description: "Informations sur un dossier d'une démarche." do
field :dossier, DossierType, null: false, description: "Informations sur un dossier dune démarche." do
argument :number, Int, "Numéro du dossier.", required: true
end

View file

@ -286,7 +286,7 @@ class Dossier < ApplicationRecord
end
scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) }
scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: [], traitements: []) }
scope :for_api_v2, -> { includes(procedure: [:administrateurs, :attestation_template], etablissement: [], individual: [], traitements: []) }
scope :with_notifications, -> do
joins(:follows)

View file

@ -222,6 +222,8 @@ Rails.application.routes.draw do
namespace :v2 do
post :graphql, to: "graphql#execute"
get 'dossiers/pdf/:id', format: :pdf, to: "dossiers#pdf", as: :dossier_pdf
get 'dossiers/geojson/:id', to: "dossiers#geojson", as: :dossier_geojson
end
end

View file

@ -0,0 +1,38 @@
describe API::V2::DossiersController do
let(:dossier) { create(:dossier, :accepte, :with_attestation) }
let(:sgid) { dossier.to_sgid(expires_in: 1.hour, for: 'api_v2') }
describe 'fetch pdf' do
subject { get :pdf, params: { id: sgid } }
it 'should get' do
expect(subject.status).to eq(200)
expect(subject.body).not_to be_nil
end
context 'error' do
let(:sgid) { 'yolo' }
it 'should error' do
expect(subject.status).to eq(401)
end
end
end
describe 'fetch geojson' do
subject { get :geojson, params: { id: sgid } }
it 'should get' do
expect(subject.status).to eq(200)
expect(subject.body).not_to be_nil
end
context 'error' do
let(:sgid) { 'yolo' }
it 'should error' do
expect(subject.status).to eq(401)
end
end
end
end

View file

@ -436,6 +436,35 @@ describe API::V2::GraphqlController do
end
end
context "with links" do
let(:dossier) { create(:dossier, :accepte, :with_attestation, procedure: procedure) }
let(:query) do
"{
dossier(number: #{dossier.id}) {
id
number
pdf {
url
}
geojson {
url
}
attestation {
url
}
}
}"
end
it "urls should be returned" do
expect(gql_errors).to eq(nil)
expect(gql_data[:dossier][:pdf][:url]).not_to be_nil
expect(gql_data[:dossier][:geojson][:url]).not_to be_nil
expect(gql_data[:dossier][:attestation][:url]).not_to be_nil
end
end
context "when there are missing data" do
before do
dossier.etablissement.update!(entreprise_code_effectif_entreprise: nil, entreprise_capital_social: nil,