feat(demarche): create and prefill a dossier with POST request (#8233)
* add base controller for public api * add dossiers controller with basic checks * create the dossier * ensure content-type is json * prefill dossier with given values * mark a dossier as prefilled When a dossier is prefilled, it's allowed not to have a user. Plus, we add a secure token to the dossier, which we will need later to set a user after sign in / sign up. * set user as owner of an orphan prefilled dossier When a visitor comes from the dossier_url answered by the public api, the dossier is orphan: - when the user is already authenticated: they become the owner - when the user is not authenticated: they can sign in / sign up / france_connect and then they become the owner So here is the procedure: - allow to sign in / sign up / france connect when user is unauthenticated - set dossier ownership when the dossier is orphan - check dossier ownership when the dossier is not - redirect to brouillon path when user is signed in and owner * mark the dossier as prefilled when it's prefilled (even with a GET request, because it will be useful later on, for exmample in order to cleanup the unused prefilled dossiers) * system spec: prefilling dossier with post request
This commit is contained in:
parent
3f4e7ab1f5
commit
20136b7ac8
33 changed files with 760 additions and 111 deletions
29
app/controllers/api/public/v1/base_controller.rb
Normal file
29
app/controllers/api/public/v1/base_controller.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
class API::Public::V1::BaseController < APIController
|
||||
skip_forgery_protection
|
||||
|
||||
before_action :check_content_type_is_json
|
||||
|
||||
protected
|
||||
|
||||
def render_missing_param(param_name)
|
||||
render_error("#{param_name} is missing", :bad_request)
|
||||
end
|
||||
|
||||
def render_bad_request(error_message)
|
||||
render_error(error_message, :bad_request)
|
||||
end
|
||||
|
||||
def render_not_found(resource_name, resource_id)
|
||||
render_error("#{resource_name} #{resource_id} is not found", :not_found)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_content_type_is_json
|
||||
render_error("Content-Type should be json", :bad_request) unless request.headers['Content-Type'] == 'application/json'
|
||||
end
|
||||
|
||||
def render_error(message, status)
|
||||
render json: { error: message }, status: status
|
||||
end
|
||||
end
|
26
app/controllers/api/public/v1/dossiers_controller.rb
Normal file
26
app/controllers/api/public/v1/dossiers_controller.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
class API::Public::V1::DossiersController < API::Public::V1::BaseController
|
||||
before_action :retrieve_procedure
|
||||
|
||||
def create
|
||||
dossier = Dossier.new(
|
||||
revision: @procedure.active_revision,
|
||||
groupe_instructeur: @procedure.defaut_groupe_instructeur_for_new_dossier,
|
||||
state: Dossier.states.fetch(:brouillon),
|
||||
prefilled: true
|
||||
)
|
||||
dossier.build_default_individual
|
||||
if dossier.save
|
||||
dossier.prefill!(PrefillParams.new(dossier, params.to_unsafe_h).to_a)
|
||||
render json: { dossier_url: commencer_url(@procedure.path, prefill_token: dossier.prefill_token) }, status: :created
|
||||
else
|
||||
render_bad_request(dossier.errors.full_messages.to_sentence)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def retrieve_procedure
|
||||
@procedure = Procedure.publiees_ou_brouillons.find_by(id: params[:id])
|
||||
render_not_found("procedure", params[:id]) if @procedure.blank?
|
||||
end
|
||||
end
|
|
@ -5,12 +5,14 @@ module ProcedureContextConcern
|
|||
include Devise::StoreLocationExtension
|
||||
|
||||
def restore_procedure_context
|
||||
if has_stored_procedure_path?
|
||||
@procedure = find_procedure_in_context
|
||||
return unless has_stored_procedure_path?
|
||||
|
||||
if @procedure.blank?
|
||||
invalid_procedure_context
|
||||
end
|
||||
@procedure = find_procedure_in_context
|
||||
|
||||
if @procedure.blank?
|
||||
invalid_procedure_context
|
||||
else
|
||||
@prefill_token = find_prefill_token_in_context
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -33,6 +35,11 @@ module ProcedureContextConcern
|
|||
end
|
||||
end
|
||||
|
||||
def find_prefill_token_in_context
|
||||
uri = URI(get_stored_location_for(:user))
|
||||
CGI.parse(uri.query).dig("prefill_token")&.first if uri.query
|
||||
end
|
||||
|
||||
def invalid_procedure_context
|
||||
clear_stored_location_for(:user)
|
||||
flash.alert = t('errors.messages.procedure_not_found')
|
||||
|
|
|
@ -4,6 +4,10 @@ module Users
|
|||
|
||||
layout 'procedure_context'
|
||||
|
||||
before_action :retrieve_prefilled_dossier, if: -> { params[:prefill_token].present? }, only: :commencer
|
||||
before_action :set_prefilled_dossier_ownership, if: -> { user_signed_in? && @prefilled_dossier&.orphan? }, only: :commencer
|
||||
before_action :check_prefilled_dossier_ownership, if: -> { user_signed_in? && @prefilled_dossier }, only: :commencer
|
||||
|
||||
def commencer
|
||||
@procedure = retrieve_procedure
|
||||
return procedure_not_found if @procedure.blank? || @procedure.brouillon?
|
||||
|
@ -74,6 +78,21 @@ module Users
|
|||
Procedure.publiees.or(Procedure.brouillons).or(Procedure.closes).find_by(path: params[:path])
|
||||
end
|
||||
|
||||
def retrieve_prefilled_dossier
|
||||
@prefilled_dossier = Dossier.state_brouillon.prefilled.find_by!(prefill_token: params[:prefill_token])
|
||||
end
|
||||
|
||||
# The prefilled dossier is not owned yet, and the user is signed in: they become the new owner
|
||||
def set_prefilled_dossier_ownership
|
||||
@prefilled_dossier.update!(user: current_user)
|
||||
DossierMailer.with(dossier: @prefilled_dossier).notify_new_draft.deliver_later
|
||||
end
|
||||
|
||||
# The prefilled dossier is owned by another user: raise an exception
|
||||
def check_prefilled_dossier_ownership
|
||||
raise ActiveRecord::RecordNotFound unless @prefilled_dossier.owned_by?(current_user)
|
||||
end
|
||||
|
||||
def procedure_not_found
|
||||
procedure = Procedure.find_by(path: params[:path])
|
||||
|
||||
|
@ -92,7 +111,7 @@ module Users
|
|||
end
|
||||
|
||||
def store_user_location!(procedure)
|
||||
store_location_for(:user, helpers.procedure_lien(procedure))
|
||||
store_location_for(:user, helpers.procedure_lien(procedure, prefill_token: params[:prefill_token]))
|
||||
end
|
||||
|
||||
def generate_empty_pdf(revision)
|
||||
|
|
|
@ -45,7 +45,7 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
|
|||
end
|
||||
|
||||
if procedure_from_params
|
||||
commencer_path(path: procedure_from_params.path)
|
||||
commencer_path(path: procedure_from_params.path, prefill_token: params[:prefill_token])
|
||||
elsif signed_in?
|
||||
# Will try to use `stored_location_for` to find a path
|
||||
after_sign_in_path_for(resource_name)
|
||||
|
|
|
@ -26,6 +26,7 @@ class Users::RegistrationsController < Devise::RegistrationsController
|
|||
# all Devise code.
|
||||
# So instead we use a per-request global variable.
|
||||
CurrentConfirmation.procedure_after_confirmation = @procedure
|
||||
CurrentConfirmation.prefill_token = @prefill_token
|
||||
|
||||
# Handle existing user trying to sign up again
|
||||
existing_user = User.find_by(email: params[:user][:email])
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
module ProcedureHelper
|
||||
def procedure_lien(procedure)
|
||||
def procedure_lien(procedure, prefill_token: nil)
|
||||
if procedure.brouillon?
|
||||
commencer_test_url(path: procedure.path)
|
||||
commencer_test_url(path: procedure.path, prefill_token: prefill_token)
|
||||
else
|
||||
commencer_url(path: procedure.path)
|
||||
commencer_url(path: procedure.path, prefill_token: prefill_token)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ class DeviseUserMailer < Devise::Mailer
|
|||
def confirmation_instructions(record, token, opts = {})
|
||||
opts[:from] = NO_REPLY_EMAIL
|
||||
@procedure = opts[:procedure_after_confirmation] || nil
|
||||
@prefill_token = opts[:prefill_token]
|
||||
super
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
module DossierPrefillableConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def prefill!(champs_attributes)
|
||||
return if champs_attributes.empty?
|
||||
def prefill!(champs_public_attributes)
|
||||
attr = { prefilled: true }
|
||||
attr[:champs_public_attributes] = champs_public_attributes.map { |h| h.merge(prefilled: true) } if champs_public_attributes.any?
|
||||
|
||||
assign_attributes(champs_attributes: champs_attributes.map { |h| h.merge(prefilled: true) })
|
||||
assign_attributes(attr)
|
||||
save(validate: false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
class CurrentConfirmation < ActiveSupport::CurrentAttributes
|
||||
attribute :procedure_after_confirmation
|
||||
attribute :prefill_token
|
||||
end
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
# last_champ_updated_at :datetime
|
||||
# last_commentaire_updated_at :datetime
|
||||
# motivation :text
|
||||
# prefill_token :string
|
||||
# prefilled :boolean
|
||||
# private_search_terms :text
|
||||
# processed_at :datetime
|
||||
# search_terms :text
|
||||
|
@ -70,6 +72,8 @@ class Dossier < ApplicationRecord
|
|||
DAYS_AFTER_EXPIRATION = 5
|
||||
INTERVAL_EXPIRATION = "#{MONTHS_AFTER_EXPIRATION} month #{DAYS_AFTER_EXPIRATION} days"
|
||||
|
||||
has_secure_token :prefill_token
|
||||
|
||||
has_one :etablissement, dependent: :destroy
|
||||
has_one :individual, validate: false, dependent: :destroy
|
||||
has_one :attestation, dependent: :destroy
|
||||
|
@ -218,11 +222,12 @@ class Dossier < ApplicationRecord
|
|||
scope :state_termine, -> { where(state: TERMINE) }
|
||||
scope :state_not_termine, -> { where.not(state: TERMINE) }
|
||||
|
||||
scope :archived, -> { where(archived: true) }
|
||||
scope :not_archived, -> { where(archived: false) }
|
||||
scope :hidden_by_user, -> { where.not(hidden_by_user_at: nil) }
|
||||
scope :hidden_by_administration, -> { where.not(hidden_by_administration_at: nil) }
|
||||
scope :visible_by_user, -> { where(for_procedure_preview: false).or(where(for_procedure_preview: nil)).where(hidden_by_user_at: nil) }
|
||||
scope :archived, -> { where(archived: true) }
|
||||
scope :not_archived, -> { where(archived: false) }
|
||||
scope :prefilled, -> { where(prefilled: true) }
|
||||
scope :hidden_by_user, -> { where.not(hidden_by_user_at: nil) }
|
||||
scope :hidden_by_administration, -> { where.not(hidden_by_administration_at: nil) }
|
||||
scope :visible_by_user, -> { where(for_procedure_preview: false).or(where(for_procedure_preview: nil)).where(hidden_by_user_at: nil) }
|
||||
scope :visible_by_administration, -> {
|
||||
state_not_brouillon
|
||||
.where(hidden_by_administration_at: nil)
|
||||
|
@ -435,7 +440,7 @@ class Dossier < ApplicationRecord
|
|||
|
||||
after_save :send_web_hook
|
||||
|
||||
validates :user, presence: true, if: -> { deleted_user_email_never_send.nil? }
|
||||
validates :user, presence: true, if: -> { deleted_user_email_never_send.nil? }, unless: -> { prefilled }
|
||||
validates :individual, presence: true, if: -> { revision.procedure.for_individual? }
|
||||
validates :groupe_instructeur, presence: true, if: -> { !brouillon? }
|
||||
|
||||
|
@ -718,6 +723,17 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def orphan?
|
||||
prefilled? && user.nil?
|
||||
end
|
||||
|
||||
def owned_by?(a_user)
|
||||
return false if a_user.nil?
|
||||
return false if orphan?
|
||||
|
||||
user == a_user
|
||||
end
|
||||
|
||||
def log_operations?
|
||||
!procedure.brouillon? && !brouillon?
|
||||
end
|
||||
|
|
|
@ -206,7 +206,7 @@ class Procedure < ApplicationRecord
|
|||
|
||||
scope :brouillons, -> { where(aasm_state: :brouillon) }
|
||||
scope :publiees, -> { where(aasm_state: :publiee) }
|
||||
scope :publiees_ou_brouillons, -> { publiees.or(brouillons) }
|
||||
scope :publiees_ou_brouillons, -> { where(aasm_state: [:publiee, :brouillon]) }
|
||||
scope :closes, -> { where(aasm_state: [:close, :depubliee]) }
|
||||
scope :opendata, -> { where(opendata: true) }
|
||||
scope :publiees_ou_closes, -> { where(aasm_state: [:publiee, :close, :depubliee]) }
|
||||
|
|
|
@ -80,6 +80,7 @@ class User < ApplicationRecord
|
|||
|
||||
# Make our procedure_after_confirmation available to the Mailer
|
||||
opts[:procedure_after_confirmation] = CurrentConfirmation.procedure_after_confirmation
|
||||
opts[:prefill_token] = CurrentConfirmation.prefill_token
|
||||
|
||||
send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
|
||||
end
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
.commencer.form
|
||||
- if !user_signed_in?
|
||||
%h2.huge-title= t('views.commencer.show.start_procedure')
|
||||
= render partial: 'shared/france_connect_login', locals: { url: commencer_france_connect_path(path: @procedure.path) }
|
||||
= link_to commencer_sign_up_path(path: @procedure.path), class: 'fr-btn fr-btn--lg fr-my-2w' do
|
||||
= render partial: 'shared/france_connect_login', locals: { url: commencer_france_connect_path(path: @procedure.path, prefill_token: @prefilled_dossier&.prefill_token) }
|
||||
= link_to commencer_sign_up_path(path: @procedure.path, prefill_token: @prefilled_dossier&.prefill_token), class: 'fr-btn fr-btn--lg fr-my-2w' do
|
||||
= t('views.shared.account.create')
|
||||
%span.optional-on-small-screens.fr-ml-1v
|
||||
#{APPLICATION_NAME}
|
||||
= link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path), class: 'fr-btn fr-btn--secondary fr-btn--lg fr-my-2w'
|
||||
= link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path, prefill_token: @prefilled_dossier&.prefill_token), class: 'fr-btn fr-btn--secondary fr-btn--lg fr-my-2w'
|
||||
|
||||
- else
|
||||
- revision = @revision.draft? ? @revision : @procedure.revisions.where.not(id: @procedure.draft_revision_id)
|
||||
|
@ -19,6 +19,13 @@
|
|||
- if dossiers.empty?
|
||||
= link_to t('views.commencer.show.start_procedure'), url_for_new_dossier(@revision), class: 'fr-btn fr-btn--lg fr-my-2w'
|
||||
|
||||
- elsif @prefilled_dossier
|
||||
%h2.huge-title= t('views.commencer.show.prefilled_draft')
|
||||
%p
|
||||
= t('views.commencer.show.prefilled_draft_detail_html', time_ago: time_ago_in_words(@prefilled_dossier.created_at), procedure: @prefilled_dossier.procedure.libelle)
|
||||
= link_to t('views.commencer.show.continue_file'), brouillon_dossier_path(@prefilled_dossier), class: 'fr-btn fr-btn--lg fr-my-2w'
|
||||
= link_to t('views.commencer.show.start_new_file'), url_for_new_dossier(@revision), class: 'fr-btn fr-btn--lg fr-btn--secondary fr-my-2w'
|
||||
|
||||
- elsif drafts.size == 1 && not_drafts.empty?
|
||||
- dossier = drafts.first
|
||||
%h2.huge-title= t('views.commencer.show.already_draft')
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
%p
|
||||
Pour activer votre compte sur #{APPLICATION_NAME}, veuillez cliquer sur le lien suivant :
|
||||
- link = confirmation_url(@user, confirmation_token: @token, procedure_id: @procedure&.id)
|
||||
- link = confirmation_url(@user, confirmation_token: @token, procedure_id: @procedure&.id, prefill_token: @prefill_token)
|
||||
= link_to(link, link)
|
||||
|
||||
- else
|
||||
|
|
|
@ -92,6 +92,8 @@ en:
|
|||
start_procedure: Start the procedure
|
||||
existing_dossiers: You already have files for this procedure
|
||||
show_dossiers: View my current files
|
||||
prefilled_draft: "You have a prefilled file"
|
||||
prefilled_draft_detail_html: "You prefilled a file for the \"%{procedure}\" procedure <strong>%{time_ago} ago</strong>"
|
||||
already_draft: "You already started to fill a file"
|
||||
already_draft_detail_html: "You started to fill a file for the \"%{procedure}\" procedure <strong>%{time_ago} ago</strong>"
|
||||
already_not_draft: "You already submitted a file"
|
||||
|
|
|
@ -82,6 +82,8 @@ fr:
|
|||
start_procedure: Commencer la démarche
|
||||
existing_dossiers: Vous avez déjà des dossiers pour cette démarche
|
||||
show_dossiers: Voir mes dossiers en cours
|
||||
prefilled_draft: "Vous avez un dossier prérempli"
|
||||
prefilled_draft_detail_html: "Il y a <strong>%{time_ago}</strong>, vous avez prérempli un dossier sur la démarche « %{procedure} »."
|
||||
already_draft: "Vous avez déjà commencé à remplir un dossier"
|
||||
already_draft_detail_html: "Il y a <strong>%{time_ago}</strong>, vous avez commencé à remplir un dossier sur la démarche « %{procedure} »."
|
||||
already_not_draft: "Vous avez déjà déposé un dossier"
|
||||
|
|
|
@ -263,7 +263,11 @@ Rails.application.routes.draw do
|
|||
|
||||
namespace :public do
|
||||
namespace :v1 do
|
||||
resources :dossiers, only: :create
|
||||
resources :demarches, only: [] do
|
||||
member do
|
||||
resources :dossiers, only: :create
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class AddPrefillFieldsToDossiers < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :dossiers, :prefill_token, :string
|
||||
add_column :dossiers, :prefilled, :boolean
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
class AddPrefillTokenIndexToDossiers < ActiveRecord::Migration[6.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :dossiers, :prefill_token, unique: true, algorithm: :concurrently
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_12_05_144624) do
|
||||
ActiveRecord::Schema.define(version: 2022_12_13_084442) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pgcrypto"
|
||||
|
@ -298,13 +298,13 @@ ActiveRecord::Schema.define(version: 2022_12_05_144624) do
|
|||
t.boolean "automatic_operation", default: false, null: false
|
||||
t.bigint "bill_signature_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.jsonb "data"
|
||||
t.text "digest"
|
||||
t.bigint "dossier_id"
|
||||
t.datetime "executed_at"
|
||||
t.datetime "keep_until"
|
||||
t.string "operation", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.jsonb "data"
|
||||
t.index ["bill_signature_id"], name: "index_dossier_operation_logs_on_bill_signature_id"
|
||||
t.index ["dossier_id"], name: "index_dossier_operation_logs_on_dossier_id"
|
||||
t.index ["keep_until"], name: "index_dossier_operation_logs_on_keep_until"
|
||||
|
@ -363,6 +363,8 @@ ActiveRecord::Schema.define(version: 2022_12_05_144624) do
|
|||
t.datetime "last_commentaire_updated_at"
|
||||
t.text "motivation"
|
||||
t.bigint "parent_dossier_id"
|
||||
t.string "prefill_token"
|
||||
t.boolean "prefilled"
|
||||
t.string "private_search_terms"
|
||||
t.datetime "processed_at"
|
||||
t.bigint "revision_id"
|
||||
|
@ -376,6 +378,7 @@ ActiveRecord::Schema.define(version: 2022_12_05_144624) do
|
|||
t.index ["dossier_transfer_id"], name: "index_dossiers_on_dossier_transfer_id"
|
||||
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
||||
t.index ["hidden_at"], name: "index_dossiers_on_hidden_at"
|
||||
t.index ["prefill_token"], name: "index_dossiers_on_prefill_token", unique: true
|
||||
t.index ["revision_id"], name: "index_dossiers_on_revision_id"
|
||||
t.index ["state"], name: "index_dossiers_on_state"
|
||||
t.index ["user_id"], name: "index_dossiers_on_user_id"
|
||||
|
@ -807,6 +810,7 @@ ActiveRecord::Schema.define(version: 2022_12_05_144624) do
|
|||
t.datetime "reset_password_sent_at"
|
||||
t.string "reset_password_token"
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.boolean "team_account", default: false
|
||||
t.string "unlock_token"
|
||||
t.datetime "updated_at"
|
||||
t.index ["email"], name: "index_super_admins_on_email", unique: true
|
||||
|
@ -885,7 +889,6 @@ ActiveRecord::Schema.define(version: 2022_12_05_144624) do
|
|||
t.string "reset_password_token"
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.string "siret"
|
||||
t.boolean "team_account", default: false
|
||||
t.text "unconfirmed_email"
|
||||
t.string "unlock_token"
|
||||
t.datetime "updated_at"
|
||||
|
|
135
spec/controllers/api/public/v1/dossiers_controller_spec.rb
Normal file
135
spec/controllers/api/public/v1/dossiers_controller_spec.rb
Normal file
|
@ -0,0 +1,135 @@
|
|||
RSpec.describe API::Public::V1::DossiersController, type: :controller do
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
describe '#create' do
|
||||
# Request prototype:
|
||||
# curl --request POST 'http://localhost:3000/api/public/v1/demarches/2/dossiers' \
|
||||
# --header 'Content-Type: application/json' \
|
||||
# --data '{"champ_Q2hhbXAtMjI=": "personne@fournisseur.fr"}'
|
||||
|
||||
context 'when the request content type is json' do
|
||||
let(:params) { { id: procedure.id } }
|
||||
subject(:create_request) do
|
||||
request.headers["Content-Type"] = "application/json"
|
||||
post :create, params: params
|
||||
end
|
||||
|
||||
shared_examples 'the procedure is found' do
|
||||
context 'when the dossier can be saved' do
|
||||
it { expect(create_request).to have_http_status(:created) }
|
||||
|
||||
it { expect { create_request }.to change { Dossier.count }.by(1) }
|
||||
|
||||
it "marks the created dossier as prefilled" do
|
||||
create_request
|
||||
expect(Dossier.last.prefilled).to eq(true)
|
||||
end
|
||||
|
||||
it "creates the dossier without a user" do
|
||||
create_request
|
||||
expect(Dossier.last.user).to eq(nil)
|
||||
end
|
||||
|
||||
it "responds with the brouillon dossier path" do
|
||||
create_request
|
||||
expect(JSON.parse(response.body)["dossier_url"]).to eq(
|
||||
"http://test.host#{commencer_path(procedure.path, prefill_token: Dossier.last.prefill_token)}"
|
||||
)
|
||||
end
|
||||
|
||||
context 'when prefill values are given' do
|
||||
let!(:type_de_champ_1) { create(:type_de_champ_text, procedure: procedure) }
|
||||
let(:value_1) { "any value" }
|
||||
|
||||
let!(:type_de_champ_2) { create(:type_de_champ_textarea, procedure: procedure) }
|
||||
let(:value_2) { "another value" }
|
||||
|
||||
let(:params) {
|
||||
{
|
||||
id: procedure.id,
|
||||
"champ_#{type_de_champ_1.to_typed_id}" => value_1,
|
||||
"champ_#{type_de_champ_2.to_typed_id}" => value_2
|
||||
}
|
||||
}
|
||||
|
||||
it "prefills the dossier's champs with the given values" do
|
||||
create_request
|
||||
|
||||
dossier = Dossier.last
|
||||
expect(find_champ_by_stable_id(dossier, type_de_champ_1.stable_id).value).to eq(value_1)
|
||||
expect(find_champ_by_stable_id(dossier, type_de_champ_2.stable_id).value).to eq(value_2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier can not be saved' do
|
||||
before do
|
||||
allow_any_instance_of(Dossier).to receive(:save).and_return(false)
|
||||
allow_any_instance_of(Dossier).to receive(:errors).and_return(
|
||||
ActiveModel::Errors.new(Dossier.new).tap { |e| e.add(:base, "something went wrong") }
|
||||
)
|
||||
|
||||
create_request
|
||||
end
|
||||
|
||||
it { expect(response).to have_http_status(:bad_request) }
|
||||
|
||||
it { expect(response).to have_failed_with("something went wrong") }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'the procedure is not found' do
|
||||
before { create_request }
|
||||
|
||||
it { expect(response).to have_http_status(:not_found) }
|
||||
|
||||
it { expect(response).to have_failed_with("procedure #{procedure.id} is not found") }
|
||||
end
|
||||
|
||||
context 'when the procedure is found' do
|
||||
context 'when the procedure is publiee' do
|
||||
it_behaves_like 'the procedure is found' do
|
||||
let(:procedure) { create(:procedure, :published) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure is brouillon' do
|
||||
it_behaves_like 'the procedure is found' do
|
||||
let(:procedure) { create(:procedure, :draft) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure is not publiee and not brouillon' do
|
||||
it_behaves_like 'the procedure is not found' do
|
||||
let(:procedure) { create(:procedure, :closed) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the procedure is not found' do
|
||||
it_behaves_like 'the procedure is not found' do
|
||||
let(:procedure) { double(Procedure, id: -1) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the request content type is not json' do
|
||||
subject(:create_request) do
|
||||
request.headers["Content-Type"] = "application/xhtml+xml"
|
||||
post :create, params: { id: 0 }
|
||||
end
|
||||
|
||||
before { create_request }
|
||||
|
||||
it { expect(response).to have_http_status(:bad_request) }
|
||||
|
||||
it { expect(response).to have_failed_with("Content-Type should be json") }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_champ_by_stable_id(dossier, stable_id)
|
||||
dossier.champs_public.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id })
|
||||
end
|
||||
end
|
|
@ -69,6 +69,19 @@ RSpec.describe ProcedureContextConcern, type: :controller do
|
|||
expect(subject.status).to eq 200
|
||||
expect(assigns(:procedure)).to eq test_procedure
|
||||
end
|
||||
|
||||
context 'when a prefill token has been stored' do
|
||||
let(:dossier) { create :dossier, :prefilled, procedure: test_procedure }
|
||||
|
||||
before do
|
||||
controller.store_location_for(:user, commencer_test_path(path: test_procedure.path, prefill_token: dossier.prefill_token))
|
||||
end
|
||||
|
||||
it 'succeeds, and assigns the prefill token on the controller' do
|
||||
expect(subject.status).to eq 200
|
||||
expect(assigns(:prefill_token)).to eq dossier.prefill_token
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the stored procedure is published' do
|
||||
|
@ -82,6 +95,19 @@ RSpec.describe ProcedureContextConcern, type: :controller do
|
|||
expect(subject.status).to eq 200
|
||||
expect(assigns(:procedure)).to eq published_procedure
|
||||
end
|
||||
|
||||
context 'when a prefill token has been stored' do
|
||||
let(:dossier) { create :dossier, :prefilled, procedure: published_procedure }
|
||||
|
||||
before do
|
||||
controller.store_location_for(:user, commencer_path(path: published_procedure.path, prefill_token: dossier.prefill_token))
|
||||
end
|
||||
|
||||
it 'succeeds, and assigns the prefill token on the controller' do
|
||||
expect(subject.status).to eq 200
|
||||
expect(assigns(:prefill_token)).to eq dossier.prefill_token
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,6 +72,85 @@ describe Users::CommencerController, type: :controller do
|
|||
expect(subject).to redirect_to(commencer_path(path: replaced_by_procedure.path))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a dossier has been prefilled' do
|
||||
let(:dossier) { create(:dossier, :brouillon, :prefilled, user: user) }
|
||||
let(:path) { dossier.procedure.path }
|
||||
|
||||
subject { get :commencer, params: { path: path, prefill_token: dossier.prefill_token } }
|
||||
|
||||
shared_examples 'a prefilled brouillon dossier retriever' do
|
||||
context 'when the dossier is a prefilled brouillon and the prefill token is present' do
|
||||
it 'retrieves the dossier' do
|
||||
subject
|
||||
expect(assigns(:prefilled_dossier)).to eq(dossier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier is not prefilled' do
|
||||
before do
|
||||
dossier.prefilled = false
|
||||
dossier.save(validate: false)
|
||||
end
|
||||
|
||||
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
|
||||
end
|
||||
|
||||
context 'when the dossier is not a brouillon' do
|
||||
before { dossier.en_construction! }
|
||||
|
||||
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
|
||||
end
|
||||
|
||||
context 'when the prefill token does not match any dossier' do
|
||||
before { dossier.prefill_token = "totoro" }
|
||||
|
||||
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is unauthenticated' do
|
||||
let(:user) { nil }
|
||||
|
||||
it_behaves_like 'a prefilled brouillon dossier retriever'
|
||||
end
|
||||
|
||||
context 'when the user is authenticated' do
|
||||
context 'when the dossier already has an owner' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context 'when the user is the dossier owner' do
|
||||
before { sign_in user }
|
||||
|
||||
it_behaves_like 'a prefilled brouillon dossier retriever'
|
||||
end
|
||||
|
||||
context 'when the user is not the dossier owner' do
|
||||
before { sign_in create(:user) }
|
||||
|
||||
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier does not have an owner yet' do
|
||||
let(:user) { nil }
|
||||
let(:newly_authenticated_user) { create(:user) }
|
||||
|
||||
before { sign_in newly_authenticated_user }
|
||||
|
||||
it { expect { subject }.to change { dossier.reload.user }.from(nil).to(newly_authenticated_user) }
|
||||
|
||||
it 'sends the notify_new_draft email' do
|
||||
expect { perform_enqueued_jobs { subject } }.to change { ActionMailer::Base.deliveries.count }.by(1)
|
||||
|
||||
dossier = Dossier.last
|
||||
mail = ActionMailer::Base.deliveries.last
|
||||
expect(mail.subject).to eq("Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »")
|
||||
expect(mail.html_part.body).to include(dossier_path(dossier))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#commencer_test' do
|
||||
|
@ -105,6 +184,13 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'a prefill token storage' do
|
||||
it 'stores the prefill token' do
|
||||
subject
|
||||
expect(controller.stored_location_for(:user)).to include('prefill_token')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#sign_in' do
|
||||
context 'for a published procedure' do
|
||||
subject { get :sign_in, params: { path: published_procedure.path } }
|
||||
|
@ -115,6 +201,12 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(subject).to redirect_to(new_user_session_path) }
|
||||
|
||||
context 'when a prefill token is given' do
|
||||
subject { get :sign_in, params: { path: published_procedure.path, prefill_token: 'prefill_token' } }
|
||||
|
||||
it_behaves_like 'a prefill token storage'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a draft procedure' do
|
||||
|
@ -126,6 +218,12 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(subject).to redirect_to(new_user_session_path) }
|
||||
|
||||
context 'when a prefill token is given' do
|
||||
subject { get :sign_in, params: { path: draft_procedure.path, prefill_token: 'prefill_token' } }
|
||||
|
||||
it_behaves_like 'a prefill token storage'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the path doesn’t exist' do
|
||||
|
@ -147,6 +245,12 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(subject).to redirect_to(new_user_registration_path) }
|
||||
|
||||
context 'when a prefill token is given' do
|
||||
subject { get :sign_up, params: { path: published_procedure.path, prefill_token: 'prefill_token' } }
|
||||
|
||||
it_behaves_like 'a prefill token storage'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a draft procedure' do
|
||||
|
@ -158,6 +262,12 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(subject).to redirect_to(new_user_registration_path) }
|
||||
|
||||
context 'when a prefill token is given' do
|
||||
subject { get :sign_up, params: { path: draft_procedure.path, prefill_token: 'prefill_token' } }
|
||||
|
||||
it_behaves_like 'a prefill token storage'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the path doesn’t exist' do
|
||||
|
@ -179,6 +289,12 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(subject).to redirect_to(france_connect_particulier_path) }
|
||||
|
||||
context 'when a prefill token is given' do
|
||||
subject { get :france_connect, params: { path: published_procedure.path, prefill_token: 'prefill_token' } }
|
||||
|
||||
it_behaves_like 'a prefill token storage'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a draft procedure' do
|
||||
|
@ -190,6 +306,12 @@ describe Users::CommencerController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(subject).to redirect_to(france_connect_particulier_path) }
|
||||
|
||||
context 'when a prefill token is given' do
|
||||
subject { get :france_connect, params: { path: draft_procedure.path, prefill_token: 'prefill_token' } }
|
||||
|
||||
it_behaves_like 'a prefill token storage'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the path doesn’t exist' do
|
||||
|
|
|
@ -256,5 +256,9 @@ FactoryBot.define do
|
|||
dossier.save!
|
||||
end
|
||||
end
|
||||
|
||||
trait :prefilled do
|
||||
prefilled { true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,6 +8,10 @@ class DeviseUserMailerPreview < ActionMailer::Preview
|
|||
DeviseUserMailer.confirmation_instructions(user, "faketoken", {})
|
||||
end
|
||||
|
||||
def confirmation_instructions___with_procedure_and_prefill_token
|
||||
DeviseUserMailer.confirmation_instructions(user, "faketoken", procedure_after_confirmation: procedure, prefill_token: "prefill_token")
|
||||
end
|
||||
|
||||
def reset_password_instructions
|
||||
DeviseUserMailer.reset_password_instructions(user, "faketoken", {})
|
||||
end
|
||||
|
|
|
@ -8,12 +8,19 @@ RSpec.describe DossierPrefillableConcern do
|
|||
|
||||
subject(:fill) { dossier.prefill!(values); dossier.reload }
|
||||
|
||||
shared_examples 'a dossier marked as prefilled' do
|
||||
it 'marks the dossier as prefilled' do
|
||||
expect { fill }.to change { dossier.reload.prefilled }.from(nil).to(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when champs_public_attributes is empty' do
|
||||
let(:values) { [] }
|
||||
|
||||
it "does nothing" do
|
||||
expect(dossier).not_to receive(:save)
|
||||
fill
|
||||
it_behaves_like 'a dossier marked as prefilled'
|
||||
|
||||
it "doesn't change champs_public" do
|
||||
expect { fill }.not_to change { dossier.champs_public.to_a }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -30,6 +37,8 @@ RSpec.describe DossierPrefillableConcern do
|
|||
|
||||
let(:values) { [{ id: champ_id_1, value: value_1 }, { id: champ_id_2, value: value_2 }] }
|
||||
|
||||
it_behaves_like 'a dossier marked as prefilled'
|
||||
|
||||
it "updates the champs with the new values and mark them as prefilled" do
|
||||
fill
|
||||
|
||||
|
@ -48,6 +57,8 @@ RSpec.describe DossierPrefillableConcern do
|
|||
|
||||
let(:values) { [{ id: champ_id, value: value }] }
|
||||
|
||||
it_behaves_like 'a dossier marked as prefilled'
|
||||
|
||||
it "still updates the champ" do
|
||||
expect { fill }.to change { dossier.champs_public.first.value }.from(nil).to(value)
|
||||
end
|
||||
|
|
|
@ -25,6 +25,20 @@ describe Dossier do
|
|||
subject(:dossier) { create(:dossier, procedure: procedure) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:individual) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:user) }
|
||||
|
||||
context 'when dossier has deleted_user_email_never_send' do
|
||||
subject(:dossier) { create(:dossier, procedure: procedure, deleted_user_email_never_send: "seb@totoro.org") }
|
||||
|
||||
it { is_expected.not_to validate_presence_of(:user) }
|
||||
end
|
||||
|
||||
context 'when dossier is prefilled' do
|
||||
subject(:dossier) { create(:dossier, procedure: procedure, prefilled: true) }
|
||||
|
||||
it { is_expected.not_to validate_presence_of(:user) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with_champs' do
|
||||
|
@ -1928,6 +1942,70 @@ describe Dossier do
|
|||
it { is_expected.to belong_to(:batch_operation).optional }
|
||||
end
|
||||
|
||||
describe '#orphan?' do
|
||||
subject(:orphan) { dossier.orphan? }
|
||||
|
||||
context 'when the dossier is prefilled' do
|
||||
context 'when the dossier has a user' do
|
||||
let(:dossier) { build(:dossier, :prefilled) }
|
||||
|
||||
it { expect(orphan).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when the dossier does not have a user' do
|
||||
let(:dossier) { build(:dossier, :prefilled, user: nil) }
|
||||
|
||||
it { expect(orphan).to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dossier is not prefilled' do
|
||||
context 'when the dossier has a user' do
|
||||
let(:dossier) { build(:dossier) }
|
||||
|
||||
it { expect(orphan).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when the dossier does not have a user' do
|
||||
let(:dossier) { build(:dossier, user: nil) }
|
||||
|
||||
it { expect(orphan).to be_falsey }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#owned_by?' do
|
||||
subject(:owned_by) { dossier.owned_by?(user) }
|
||||
|
||||
context 'when the dossier is orphan' do
|
||||
let(:dossier) { build(:dossier, user: nil) }
|
||||
let(:user) { build(:user) }
|
||||
|
||||
it { expect(owned_by).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when the given user is nil' do
|
||||
let(:dossier) { build(:dossier) }
|
||||
let(:user) { nil }
|
||||
|
||||
it { expect(owned_by).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when the dossier has a user and it is not the given user' do
|
||||
let(:dossier) { build(:dossier) }
|
||||
let(:user) { build(:user) }
|
||||
|
||||
it { expect(owned_by).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when the dossier has a user and it is the given user' do
|
||||
let(:dossier) { build(:dossier, user: user) }
|
||||
let(:user) { build(:user) }
|
||||
|
||||
it { expect(owned_by).to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def count_for_month(processed_by_month, month)
|
||||
|
|
5
spec/support/public_api_matchers.rb
Normal file
5
spec/support/public_api_matchers.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
RSpec::Matchers.define :have_failed_with do |expected|
|
||||
match do |response|
|
||||
JSON.parse(response.body).with_indifferent_access.dig(:error) == expected
|
||||
end
|
||||
end
|
22
spec/support/shared_examples_for_prefilled_dossier.rb
Normal file
22
spec/support/shared_examples_for_prefilled_dossier.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
shared_examples "the user has got a prefilled dossier, owned by themselves" do
|
||||
scenario "the user has got a prefilled dossier, owned by themselves" do
|
||||
siret = '41816609600051'
|
||||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}/)
|
||||
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/etablissements.json'))
|
||||
|
||||
expect(dossier.user).to eq(user)
|
||||
|
||||
expect(page).to have_current_path siret_dossier_path(procedure.dossiers.last)
|
||||
fill_in 'Numéro SIRET', with: siret
|
||||
click_on 'Valider'
|
||||
|
||||
expect(page).to have_current_path(etablissement_dossier_path(dossier))
|
||||
expect(page).to have_content('OCTO TECHNOLOGY')
|
||||
click_on 'Continuer avec ces informations'
|
||||
|
||||
expect(page).to have_current_path(brouillon_dossier_path(dossier))
|
||||
expect(page).to have_field(type_de_champ_text.libelle, with: text_value)
|
||||
expect(page).to have_field(type_de_champ_phone.libelle, with: phone_value)
|
||||
expect(page).to have_css('.field_with_errors', text: type_de_champ_phone.libelle)
|
||||
end
|
||||
end
|
87
spec/system/users/dossier_prefill_get_spec.rb
Normal file
87
spec/system/users/dossier_prefill_get_spec.rb
Normal file
|
@ -0,0 +1,87 @@
|
|||
describe 'Prefilling a dossier (with a GET request):' do
|
||||
let(:password) { 'my-s3cure-p4ssword' }
|
||||
|
||||
let(:procedure) { create(:procedure, :published, opendata: true) }
|
||||
let(:dossier) { procedure.dossiers.last }
|
||||
|
||||
let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) }
|
||||
let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) }
|
||||
let(:text_value) { "My Neighbor Totoro is the best movie ever" }
|
||||
let(:phone_value) { "invalid phone value" }
|
||||
|
||||
context 'when authenticated' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user) { create(:user, password: password) }
|
||||
|
||||
before do
|
||||
visit "/users/sign_in"
|
||||
sign_in_with user.email, password
|
||||
|
||||
visit commencer_path(
|
||||
path: procedure.path,
|
||||
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
|
||||
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
|
||||
)
|
||||
|
||||
click_on "Commencer la démarche"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when unauthenticated' do
|
||||
before do
|
||||
visit commencer_path(
|
||||
path: procedure.path,
|
||||
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
|
||||
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
|
||||
)
|
||||
end
|
||||
|
||||
context 'when the user signs in with email and password' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let!(:user) { create(:user, password: password) }
|
||||
|
||||
before do
|
||||
click_on "J’ai déjà un compte"
|
||||
sign_in_with user.email, password
|
||||
|
||||
click_on "Commencer la démarche"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs up with email and password' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user_email) { generate :user_email }
|
||||
let(:user) { User.find_by(email: user_email) }
|
||||
|
||||
before do
|
||||
click_on "Créer un compte #{APPLICATION_NAME}"
|
||||
|
||||
sign_up_with user_email, password
|
||||
expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}"
|
||||
|
||||
click_confirmation_link_for user_email
|
||||
expect(page).to have_content('Votre compte a bien été confirmé.')
|
||||
|
||||
click_on "Commencer la démarche"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs up with FranceConnect' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user) { User.last }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(FranceConnectParticulierClient).to receive(:authorization_uri).and_return(france_connect_particulier_callback_path(code: "c0d3"))
|
||||
allow(FranceConnectService).to receive(:retrieve_user_informations_particulier).and_return(build(:france_connect_information))
|
||||
|
||||
page.find('.fr-connect').click
|
||||
|
||||
click_on "Commencer la démarche"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
102
spec/system/users/dossier_prefill_post_spec.rb
Normal file
102
spec/system/users/dossier_prefill_post_spec.rb
Normal file
|
@ -0,0 +1,102 @@
|
|||
describe 'Prefilling a dossier (with a POST request):' do
|
||||
let(:password) { 'my-s3cure-p4ssword' }
|
||||
|
||||
let(:procedure) { create(:procedure, :published) }
|
||||
let(:dossier) { procedure.dossiers.last }
|
||||
|
||||
let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) }
|
||||
let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) }
|
||||
let(:text_value) { "My Neighbor Totoro is the best movie ever" }
|
||||
let(:phone_value) { "invalid phone value" }
|
||||
|
||||
scenario "the user get the URL of a prefilled orphan brouillon dossier" do
|
||||
dossier_url = create_and_prefill_dossier_with_post_request
|
||||
|
||||
expect(dossier_url).to eq(commencer_path(procedure.path, prefill_token: dossier.prefill_token))
|
||||
end
|
||||
|
||||
describe 'visit the dossier URL' do
|
||||
context 'when authenticated' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user) { create(:user, password: password) }
|
||||
|
||||
before do
|
||||
visit "/users/sign_in"
|
||||
sign_in_with user.email, password
|
||||
|
||||
visit create_and_prefill_dossier_with_post_request
|
||||
|
||||
expect(page).to have_content('Vous avez un dossier prérempli')
|
||||
click_on 'Continuer à remplir mon dossier'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when unauthenticated' do
|
||||
before { visit create_and_prefill_dossier_with_post_request }
|
||||
|
||||
context 'when the user signs in with email and password' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user) { create(:user, password: password) }
|
||||
|
||||
before do
|
||||
click_on "J’ai déjà un compte"
|
||||
sign_in_with user.email, password
|
||||
|
||||
expect(page).to have_content('Vous avez un dossier prérempli')
|
||||
click_on 'Continuer à remplir mon dossier'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs up with email and password' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user_email) { generate :user_email }
|
||||
let(:user) { User.find_by(email: user_email) }
|
||||
|
||||
before do
|
||||
click_on "Créer un compte #{APPLICATION_NAME}"
|
||||
|
||||
sign_up_with user_email, password
|
||||
expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}"
|
||||
|
||||
click_confirmation_link_for user_email
|
||||
expect(page).to have_content('Votre compte a bien été confirmé.')
|
||||
|
||||
expect(page).to have_content('Vous avez un dossier prérempli')
|
||||
click_on 'Continuer à remplir mon dossier'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs up with FranceConnect' do
|
||||
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
|
||||
let(:user) { User.last }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(FranceConnectParticulierClient).to receive(:authorization_uri).and_return(france_connect_particulier_callback_path(code: "c0d3"))
|
||||
allow(FranceConnectService).to receive(:retrieve_user_informations_particulier).and_return(build(:france_connect_information))
|
||||
|
||||
page.find('.fr-connect').click
|
||||
|
||||
expect(page).to have_content('Vous avez un dossier prérempli')
|
||||
click_on 'Continuer à remplir mon dossier'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_and_prefill_dossier_with_post_request
|
||||
session = ActionDispatch::Integration::Session.new(Rails.application)
|
||||
session.post api_public_v1_dossiers_path(procedure),
|
||||
headers: { "Content-Type" => "application/json" },
|
||||
params: {
|
||||
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
|
||||
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
|
||||
}.to_json
|
||||
JSON.parse(session.response.body)["dossier_url"].gsub("http://www.example.com", "")
|
||||
end
|
||||
end
|
|
@ -1,80 +0,0 @@
|
|||
describe 'Prefilling a dossier:' do
|
||||
let(:password) { 'my-s3cure-p4ssword' }
|
||||
let(:siret) { '41816609600051' }
|
||||
|
||||
let(:procedure) { create(:procedure, :published, opendata: true) }
|
||||
let(:dossier) { procedure.dossiers.last }
|
||||
|
||||
let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) }
|
||||
let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) }
|
||||
let(:text_value) { "My Neighbor Totoro is the best movie ever" }
|
||||
let(:phone_value) { "invalid phone value" }
|
||||
|
||||
before do
|
||||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}/)
|
||||
.to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/etablissements.json'))
|
||||
|
||||
visit commencer_path(
|
||||
path: procedure.path,
|
||||
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
|
||||
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
|
||||
)
|
||||
end
|
||||
|
||||
shared_examples "the user has got a prefilled dossier" do
|
||||
scenario "the user has got a prefilled dossier" do
|
||||
click_on "Commencer la démarche"
|
||||
|
||||
expect(page).to have_current_path siret_dossier_path(procedure.dossiers.last)
|
||||
fill_in 'Numéro SIRET', with: siret
|
||||
click_on 'Valider'
|
||||
|
||||
expect(page).to have_current_path(etablissement_dossier_path(dossier))
|
||||
expect(page).to have_content('OCTO TECHNOLOGY')
|
||||
click_on 'Continuer avec ces informations'
|
||||
|
||||
expect(page).to have_current_path(brouillon_dossier_path(dossier))
|
||||
expect(page).to have_field(type_de_champ_text.libelle, with: text_value)
|
||||
expect(page).to have_field(type_de_champ_phone.libelle, with: phone_value)
|
||||
expect(page).to have_css('.field_with_errors', text: type_de_champ_phone.libelle)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs in with email and password' do
|
||||
it_behaves_like "the user has got a prefilled dossier" do
|
||||
let!(:user) { create(:user, password: password) }
|
||||
|
||||
before do
|
||||
click_on "J’ai déjà un compte"
|
||||
sign_in_with user.email, password
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs up with email and password' do
|
||||
it_behaves_like "the user has got a prefilled dossier" do
|
||||
let(:user_email) { generate :user_email }
|
||||
|
||||
before do
|
||||
click_on "Créer un compte #{APPLICATION_NAME}"
|
||||
|
||||
sign_up_with user_email, password
|
||||
expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}"
|
||||
|
||||
click_confirmation_link_for user_email
|
||||
expect(page).to have_content('Votre compte a bien été confirmé.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user signs up with FranceConnect' do
|
||||
it_behaves_like "the user has got a prefilled dossier" do
|
||||
before do
|
||||
allow_any_instance_of(FranceConnectParticulierClient).to receive(:authorization_uri).and_return(france_connect_particulier_callback_path(code: "c0d3"))
|
||||
allow(FranceConnectService).to receive(:retrieve_user_informations_particulier).and_return(build(:france_connect_information))
|
||||
|
||||
page.find('.fr-connect').click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue