Merge branch 'main' into poc-self_hosted_runners

This commit is contained in:
kleph 2023-08-30 18:41:01 +02:00 committed by GitHub
commit 4214c31f08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
229 changed files with 1086 additions and 2782 deletions

View file

@ -59,6 +59,7 @@ gem 'lograge'
gem 'logstash-event'
gem 'mailjet', require: false
gem 'matrix' # needed by prawn and not default in ruby 3.1
gem 'mini_magick'
gem 'net-imap', require: false # See https://github.com/mikel/mail/pull/1439
gem 'net-pop', require: false # same
gem 'net-smtp', require: false # same
@ -105,6 +106,7 @@ group :test do
gem 'rack_session_access'
gem 'rails-controller-testing'
gem 'rspec_junit_formatter'
gem 'rspec-retry'
gem 'selenium-devtools'
gem 'selenium-webdriver'
gem 'shoulda-matchers', require: false
@ -114,7 +116,6 @@ group :test do
end
group :development do
gem 'annotate'
gem 'brakeman', require: false
gem 'haml-lint'
gem 'letter_opener_web'

View file

@ -101,9 +101,6 @@ GEM
aes_key_wrap (1.1.0)
after_party (1.11.2)
anchored (1.1.0)
annotate (3.2.0)
activerecord (>= 3.2, < 8.0)
rake (>= 10.4, < 14.0)
ast (2.4.2)
attr_required (1.0.1)
axe-core-api (4.2.1)
@ -490,7 +487,7 @@ GEM
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (5.0.1)
puma (6.1.1)
puma (6.3.1)
nio4r (~> 2.0)
pundit (2.2.0)
activesupport (>= 3.0.0)
@ -604,6 +601,8 @@ GEM
rspec-expectations (~> 3.11)
rspec-mocks (~> 3.11)
rspec-support (~> 3.11)
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.12.0)
rspec_junit_formatter (0.4.1)
rspec-core (>= 2, < 4, != 2.12.0)
@ -813,7 +812,6 @@ DEPENDENCIES
administrate-field-enum
after_party
anchored
annotate
axe-core-rspec
bcrypt
bootsnap (>= 1.4.4)
@ -872,6 +870,7 @@ DEPENDENCIES
matrix
memory_profiler
mina
mini_magick
net-imap
net-pop
net-smtp
@ -898,6 +897,7 @@ DEPENDENCIES
rexml
rqrcode
rspec-rails
rspec-retry
rspec_junit_formatter
rubocop
rubocop-performance

View file

@ -102,6 +102,10 @@
white-space: nowrap;
}
.width-max-content {
width: max-content;
}
// sizing
.width-100 {
width: 100%;

View file

@ -2,7 +2,7 @@
// overwrite DSFR style for SimpleFormatComponent, some user use markdown with
// ordered list having paragraph between list item
.fr-ol-content--override {
ol.fr-ol-content--override {
list-style-type: decimal;
li::marker {

View file

@ -1,34 +1,6 @@
@import "constants";
#invites-form {
padding: $default-padding;
text-align: left;
form {
display: flex;
margin-top: $default-padding;
}
h4 {
font-weight: bold;
margin-bottom: $default-spacer;
}
p {
margin-bottom: $default-spacer;
}
ul {
list-style-position: inside;
list-style-type: disc;
margin-bottom: $default-padding;
}
input[type=email] {
margin-bottom: $default-spacer;
}
.button {
margin-left: $default-spacer;
@media (min-width: 48em) {
min-width: 400px;
}
}

View file

@ -1,10 +1,13 @@
module Dsfr
module InputErrorable
extend ActiveSupport::Concern
included do
delegate :object, to: :@form
delegate :errors, to: :object
renders_one :hint
private
# lookup for edge case from `form.rich_text_area`
@ -89,6 +92,10 @@ module Dsfr
end
def hint
get_slot(:hint).presence || default_hint
end
def default_hint
I18n.t("activerecord.attributes.#{object.class.name.underscore}.hints.#{@attribute}")
end
@ -101,6 +108,8 @@ module Dsfr
end
def hint?
return true if get_slot(:hint).present?
I18n.exists?("activerecord.attributes.#{object.class.name.underscore}.hints.#{@attribute}")
end
end

View file

@ -0,0 +1,6 @@
class Instructeurs::ActivateAccountFormComponent < ApplicationComponent
attr_reader :user
def initialize(user:)
@user = user
end
end

View file

@ -0,0 +1,6 @@
---
en:
title: Create your account for %{application_name}
activate: Activate your account %{email}
email_disabled: Instructor email address not changeable
submit: Choose password

View file

@ -0,0 +1,7 @@
---
fr:
title: Création de compte sur %{application_name}
activate: Se créer un compte pour %{email} en choissant un mot de passe
email_disabled: Adresse instructeur non modifiable
submit: Définir le mot de passe

View file

@ -0,0 +1,23 @@
= form_for user, url: { controller: 'users/activate', action: :create }, html: { class: "fr-py-5w" } do |f|
%h1.fr-h2.fr-mb-7w= t('.title', application_name: APPLICATION_NAME)
.fr-background-alt--grey.fr-px-12w.fr-py-7w
%fieldset.fr-mb-0.fr-fieldset{ aria: { labelledby: 'activate-account-legend' } }
%legend.fr-fieldset__legend#activate-account-legend
%h2.fr-h6.fr-mb-0= t('.activate', email: user.email)
.fr-fieldset__element
%p.fr-text--sm= t('utils.mandatory_champs')
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: :disabled, class: 'fr-input-group--disabled', value: t('.email_disabled') })
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'current-password' })
= f.hidden_field :reset_password_token, value: params[:token]
.fr-fieldset__element
.fr-btns-group--right.fr-btns-group.fr-btns-group--inline.fr-btns-group.fr-btns-group--inline
%ul
%li= f.submit t('.submit'), class: 'fr-mt-2v fr-btn fr-btn'

View file

@ -4,7 +4,7 @@ fr:
Le routage permet dacheminer les dossiers vers différents groupes dinstructeurs.
routing_configuration_notice_2_html: |
<p>Pour le configurer, votre formulaire doit comporter
au moins un champ « choix simple ».</p>
au moins un champ de type « choix simple » ou « départements ».</p>
<p>Ajoutez ce champ dans la page <a href="%{path}">« Configuration des champs »</a>.</p>
delete_title: Aucun dossier ne sera supprimé. Les groupes d'instructeurs vont être supprimés. Seuls les instructeurs du groupe « %{defaut_label} » resteront affectés à la démarche.
delete_confirmation: |

View file

@ -27,7 +27,7 @@
class: 'fr-btn',
method: :delete,
title: t('.delete_title', defaut_label: @procedure.defaut_groupe_instructeur.label),
data: ( @procedure.publiee? ? { disable_with: "Suppression...", confirm: t('.delete_confirmation', defaut_label: @procedure.defaut_groupe_instructeur.label) } : nil)
data: ( @procedure.publiee? ? { disable_with: "Suppression", confirm: t('.delete_confirmation', defaut_label: @procedure.defaut_groupe_instructeur.label) } : nil)
- elsif @state == 'choix'
= form_for :choice,

View file

@ -58,8 +58,18 @@ class Procedure::OneGroupeManagementComponent < ApplicationComponent
def available_values_for_select(targeted_champ)
return [] if targeted_champ.is_a?(Logic::Empty)
case @revision.types_de_champ_public.find_by(stable_id: targeted_champ.stable_id).type_champ
when TypeDeChamp.type_champs.fetch(:departements)
departements_for_select
when TypeDeChamp.type_champs.fetch(:drop_down_list)
targeted_champ
.options(@revision.types_de_champ_public)
.map { |tdc| [tdc.first, constant(tdc.first).to_json] }
.map { |(label, value)| [label, constant(value).to_json] }
end
end
def departements_for_select
APIGeoService.departements.map { ["#{_1[:code]} #{_1[:name]}", constant(_1[:code]).to_json] }
end
end

View file

@ -9,6 +9,7 @@ fr:
other: "%{count} dossiers en cours de traitement portent ce champ. Les <strong>données</strong> associées avec ce champ seront <strong>supprimées</strong>."
add_option: "ajoutés : %{items}"
remove_option: "supprimés : %{items}"
invalid_routing_rules_alert: "Certains groupes d'instructeurs ont une règle de routage invalide. Veuillez mettre à jour la configuration des groupes d'instructeurs après avoir publié les modifications."
public:
add: Le champ « %{label} » a été ajouté.
add_mandatory: Le champ obligatoire « %{label} » a été ajouté.

View file

@ -74,7 +74,7 @@
- if !total_dossiers.zero? && !change.can_rebase?
.fr-alert.fr-alert--warning.fr-mt-1v
%p= t('.breaking_change', count: total_dossiers)
- if removed.present? && change.type_de_champ.used_by_routing_rules?
- if (removed.present? || added.present? ) && change.type_de_champ.used_by_routing_rules?
.fr-alert.fr-alert--warning.fr-mt-1v
= t(".#{prefix}.update_drop_down_options_alert", label: change.label)
- when :drop_down_other
@ -148,3 +148,7 @@
- if @private_move_changes.present?
- list.with_item do
= t(".private.move", count: @private_move_changes.size)
- if @previous_revision.procedure.routing_enabled? && @previous_revision.procedure.groupe_instructeurs.any?(&:invalid_rule?)
- list.with_item do
.fr-alert.fr-alert--warning.fr-mt-1v
= t(".invalid_routing_rules_alert")

View file

@ -1,11 +1,10 @@
= form_tag(search_admin_procedures_path, data: { turbo: true }, method: :post, class: 'form') do
= label_tag :query, 'Rechercher une procédure'
= form_tag(search_admin_procedures_path, data: { turbo: true }, method: :post) do
.fr-input-group
= label_tag :query, class: "fr-label" do
Rechercher une démarche
%span.fr-hint-text Saisissez au moins 3 lettres
.notice
%p Entrez au minimum 3 lettres
= text_field_tag :query, params[:query], required: true, placeholder: 'politique de la ville', minlength: "3"
= text_field_tag :query, params[:query], required: true, placeholder: 'politique de la ville', minlength: "3", class: "fr-input"
= submit_tag 'Rechercher', class: 'fr-btn'

View file

@ -40,12 +40,34 @@ module Administrateurs
tdc = @procedure.active_revision.routable_types_de_champ.find { |tdc| tdc.stable_id == stable_id }
tdc_options = tdc.options["drop_down_options"].reject(&:empty?)
case tdc.type_champ
when TypeDeChamp.type_champs.fetch(:departements)
tdc_options = APIGeoService.departements.map { ["#{_1[:code]} #{_1[:name]}", _1[:code]] }
tdc_options.each do |code_and_name, code|
routing_rule = ds_eq(champ_value(stable_id), constant(code))
@procedure
.groupe_instructeurs
.find_or_create_by(label: code_and_name)
.update(instructeurs: [current_administrateur.instructeur], routing_rule:)
end
when TypeDeChamp.type_champs.fetch(:drop_down_list)
tdc_options = tdc.drop_down_options.reject(&:empty?)
tdc_options.each do |option_label|
gi = @procedure.groupe_instructeurs.find_by({ label: option_label }) || @procedure.groupe_instructeurs
.create({ label: option_label, instructeurs: [current_administrateur.instructeur] })
gi.update(routing_rule: ds_eq(champ_value(stable_id), constant(gi.label)))
routing_rule = ds_eq(champ_value(stable_id), constant(option_label))
@procedure
.groupe_instructeurs
.find_or_create_by(label: option_label)
.update(instructeurs: [current_administrateur.instructeur], routing_rule:)
end
end
if tdc.drop_down_other?
routing_rule = ds_eq(champ_value(stable_id), constant(Champs::DropDownListChamp::OTHER))
@procedure
.groupe_instructeurs
.find_or_create_by(label: 'Autre')
.update(instructeurs: [current_administrateur.instructeur], routing_rule:)
end
@procedure.toggle_routing

View file

@ -4,7 +4,6 @@ class API::Public::V1::DossiersController < API::Public::V1::BaseController
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
)

View file

@ -39,7 +39,9 @@ class API::V2::BaseController < ApplicationController
def api_token
if @api_token.nil?
@api_token = APIToken.find_and_verify(authorization_bearer_token) || false
@api_token = APIToken
.find_and_verify(authorization_bearer_token)
&.tap { _1.touch(:last_v2_authenticated_at) } || false
end
@api_token
end

View file

@ -6,6 +6,7 @@ class APIController < ApplicationController
def find_administrateur_for_token(procedure)
api_token = APIToken.find_and_verify(authorization_bearer_token, procedure.administrateurs)
if api_token.present? && api_token.context.fetch(:procedure_ids).include?(procedure.id)
api_token.touch(:last_v1_authenticated_at)
api_token.administrateur
end
end

View file

@ -1,8 +1,12 @@
class Champs::OptionsController < ApplicationController
include TurboChampsConcern
before_action :authenticate_logged_user!
def remove
@champ = policy_scope(Champ).includes(:champs).find(params[:champ_id])
@champ.remove_option([params[:option]].compact)
champ = policy_scope(Champ).includes(:champs).find(params[:champ_id])
champ.remove_option([params[:option]].compact)
champs = champ.private? ? champ.dossier.champs_private_all : champ.dossier.champs_public_all
@to_show, @to_hide, @to_update = champs_to_turbo_update({ params[:champ_id] => true }, champs)
end
end

View file

@ -85,7 +85,8 @@ module Instructeurs
end
def personnes_impliquees
@following_instructeurs_emails = dossier.followers_instructeurs.map(&:email)
# sort following_instructeurs (last follower on top) for the API of Agence de l'Eau Loire-Bretagne
@following_instructeurs_emails = dossier.followers_instructeurs.joins(:follows).merge(Follow.order(id: :desc)).map(&:email)
previous_followers = dossier.previous_followers_instructeurs - dossier.followers_instructeurs
@previous_following_instructeurs_emails = previous_followers.map(&:email)
@avis_emails = dossier.experts.map(&:email)

View file

@ -224,19 +224,18 @@ module Instructeurs
def email_usagers
@procedure = procedure
@commentaire = Commentaire.new
@email_usagers_dossiers = email_usagers_dossiers
@dossiers_count = @email_usagers_dossiers.count
@groupe_instructeurs = email_usagers_groupe_instructeurs_label
@bulk_messages = BulkMessage.includes(:groupe_instructeurs).where(groupe_instructeurs: { id: current_instructeur.groupe_instructeur_ids, procedure: procedure })
@bulk_messages = BulkMessage.includes(:groupe_instructeurs).where(groupe_instructeurs: { procedure: procedure })
@bulk_message = current_instructeur.bulk_messages.build
@dossiers_without_groupe_count = procedure.dossiers.state_brouillon.for_groupe_instructeur(nil).count
end
def create_multiple_commentaire
@procedure = procedure
errors = []
email_usagers_dossiers.each do |dossier|
commentaire = CommentaireService.create(current_instructeur, dossier, commentaire_params)
bulk_message = current_instructeur.bulk_messages.build(bulk_message_params)
dossiers = procedure.dossiers.state_brouillon.for_groupe_instructeur(nil)
dossiers.each do |dossier|
commentaire = CommentaireService.create(current_instructeur, dossier, bulk_message_params.except(:targets))
if commentaire.errors.empty?
commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
else
@ -244,8 +243,15 @@ module Instructeurs
end
end
valid_dossiers_count = email_usagers_dossiers.count - errors.count
create_bulk_message_mail(valid_dossiers_count, Dossier.states.fetch(:brouillon))
valid_dossiers_count = dossiers.count - errors.count
bulk_message.assign_attributes(
dossier_count: valid_dossiers_count,
dossier_state: Dossier.states.fetch(:brouillon),
sent_at: Time.zone.now,
instructeur_id: current_instructeur.id,
groupe_instructeurs: GroupeInstructeur.for_dossiers(dossiers)
)
bulk_message.save!
if errors.empty?
flash[:notice] = "Tous les messages ont été envoyés avec succès"
@ -262,18 +268,6 @@ module Instructeurs
private
def create_bulk_message_mail(dossier_count, dossier_state)
BulkMessage.create(
dossier_count: dossier_count,
dossier_state: dossier_state,
body: commentaire_params[:body],
sent_at: Time.zone.now,
instructeur_id: current_instructeur.id,
piece_jointe: commentaire_params[:piece_jointe],
groupe_instructeurs: email_usagers_groupe_instructeurs
)
end
def assign_to_params
params.require(:assign_to)
.permit(:instant_expert_avis_email_notifications_enabled, :instant_email_dossier_notifications_enabled, :instant_email_message_notifications_enabled, :daily_email_notifications_enabled, :weekly_email_notifications_enabled)
@ -355,20 +349,8 @@ module Instructeurs
@current_filters ||= procedure_presentation.filters.fetch(statut, [])
end
def email_usagers_dossiers
procedure.dossiers.state_brouillon.where(groupe_instructeur: current_instructeur.groupe_instructeur_ids).includes(:groupe_instructeur)
end
def email_usagers_groupe_instructeurs_label
email_usagers_dossiers.map(&:groupe_instructeur).uniq.map(&:label)
end
def email_usagers_groupe_instructeurs
email_usagers_dossiers.map(&:groupe_instructeur).uniq
end
def commentaire_params
params.require(:commentaire).permit(:body, :piece_jointe)
def bulk_message_params
params.require(:bulk_message).permit(:body)
end
end
end

View file

@ -1,62 +0,0 @@
module Manager
class DemandesController < Manager::ApplicationController
def index
@pending_demandes = pending_demandes
end
def create_administrateur
administrateur = current_super_admin.invite_admin(create_administrateur_params[:email])
if administrateur.errors.empty?
PipedriveAcceptsDealsJob.perform_later(
create_administrateur_params[:person_id],
current_super_admin.id,
create_administrateur_params[:stage_id]
)
flash.notice = "Administrateur créé"
redirect_to manager_demandes_path
else
flash.now.alert = administrateur.errors.full_messages.to_sentence
@pending_demandes = pending_demandes
render :index
end
end
def refuse_administrateur
PipedriveRefusesDealsJob.perform_later(
refuse_administrateur_params[:person_id],
current_super_admin.id
)
AdministrationMailer
.refuse_admin(refuse_administrateur_params[:email])
.deliver_later
flash.notice = "La demande de #{refuse_administrateur_params[:email]} va être refusée"
redirect_to manager_demandes_path
end
private
def create_administrateur_params
params.permit(:email, :person_id, :stage_id)
end
def refuse_administrateur_params
params.permit(:email, :person_id)
end
def pending_demandes
already_approved_emails = Administrateur.eager_load(:user)
.where(users: { email: demandes.map { |d| d[:email] } })
.map(&:email)
demandes.reject { |demande| already_approved_emails.include?(demande[:email]) }
end
def demandes
@demandes ||= PipedriveService.get_demandes
end
end
end

View file

@ -0,0 +1,17 @@
class ProceduresController < ApplicationController
before_action :retrieve_procedure
def logo
if @procedure.logo.attached?
redirect_to url_for(@procedure.logo.variant(:email))
else
redirect_to ActionController::Base.helpers.image_url(PROCEDURE_DEFAULT_LOGO_SRC)
end
end
private
def retrieve_procedure
@procedure = Procedure.find(params[:id])
end
end

View file

@ -20,6 +20,8 @@ module Users
check_prefilled_dossier_ownership if @prefilled_dossier
end
@usual_traitement_time = @procedure.stats_usual_traitement_time
render 'commencer/show'
end
@ -94,7 +96,6 @@ module Users
def build_prefilled_dossier
@prefilled_dossier = Dossier.new(
revision: @revision,
groupe_instructeur: @procedure.defaut_groupe_instructeur_for_new_dossier,
state: Dossier.states.fetch(:brouillon),
prefilled: true
)

View file

@ -375,7 +375,6 @@ module Users
dossier = Dossier.new(
revision: params[:brouillon] ? procedure.draft_revision : procedure.active_revision,
groupe_instructeur: procedure.defaut_groupe_instructeur_for_new_dossier,
user: current_user,
state: Dossier.states.fetch(:brouillon)
)
@ -542,6 +541,7 @@ module Users
def update_dossier_and_compute_errors
errors = []
@dossier.assign_attributes(champs_public_params)
if @dossier.champs_public_all.any?(&:changed_for_autosave?)
@dossier.last_champ_updated_at = Time.zone.now
@ -559,7 +559,6 @@ module Users
@dossier.valid?(**submit_validation_options)
errors += format_errors(errors: @dossier.errors)
errors += format_errors(errors: @dossier.check_mandatory_and_visible_champs)
errors
end

View file

@ -6,7 +6,7 @@ class Users::SessionsController < Devise::SessionsController
layout 'login', only: [:new, :create]
before_action :restore_procedure_context, only: [:new, :create]
skip_before_action :redirect_if_untrusted, only: [:reset_link_sent]
# POST /resource/sign_in
def create
user = User.find_by(email: params[:user][:email])
@ -18,6 +18,13 @@ class Users::SessionsController < Devise::SessionsController
super
end
def reset_link_sent
if send_login_token_or_bufferize(current_instructeur)
flash[:notice] = "Nous venons de vous renvoyer un nouveau lien de connexion sécurisée à #{APPLICATION_NAME}"
end
redirect_to link_sent_path(email: current_instructeur.email)
end
def link_sent
if Devise.email_regexp.match?(params[:email])
@email = params[:email]

View file

@ -1,4 +0,0 @@
require "administrate/base_dashboard"
class DemandeDashboard < Administrate::BaseDashboard
end

View file

@ -13,6 +13,8 @@ class UserDashboard < Administrate::BaseDashboard
confirmed?: Field::Boolean,
created_at: Field::DateTime,
updated_at: Field::DateTime,
blocked_at: Field::DateTime,
blocked_reason: Field::String,
current_sign_in_at: Field::DateTime,
dossiers: Field::HasMany
}.freeze
@ -36,7 +38,9 @@ class UserDashboard < Administrate::BaseDashboard
:email,
:confirmed?,
:current_sign_in_at,
:created_at
:created_at,
:blocked_at,
:blocked_reason
].freeze
# FORM_ATTRIBUTES

View file

@ -59,6 +59,7 @@ class API::V2::Context < GraphQL::Query::Context
{
graphql_query: query.query_string,
graphql_variables: query.provided_variables&.to_json,
graphql_mutation: mutation?,
graphql_null_error: errors.any? { _1.is_a? GraphQL::InvalidNullError }.presence,
graphql_timeout_error: errors.any? { _1.is_a? GraphQL::Schema::Timeout::TimeoutError }.presence
}.compact
@ -66,6 +67,12 @@ class API::V2::Context < GraphQL::Query::Context
private
def mutation?
query.lookahead.selections.any? { _1.field.type.respond_to?(:mutation) }.presence
rescue
false
end
def compute_demarche_authorization(demarche)
# procedure_ids and token are passed from graphql controller
if self[:procedure_ids].present?
@ -73,6 +80,7 @@ class API::V2::Context < GraphQL::Query::Context
elsif self[:token].present?
token = APIToken.find_and_verify(self[:token], demarche.administrateurs)
if token.present?
token.touch(:last_v2_authenticated_at)
Current.user = token.administrateur.user
true
else

View file

@ -138,7 +138,7 @@ class API::V2::Schema < GraphQL::Schema
end
end
use Timeout, max_seconds: 10
use Timeout, max_seconds: 30
use GraphQL::Batch
use GraphQL::Backtrace

View file

@ -43,6 +43,7 @@ class API::V2::StoredQuery
$includeInstructeurs: Boolean = true
$includeAvis: Boolean = false
$includeMessages: Boolean = false
$includeCorrections: Boolean = false
$includeGeometry: Boolean = false
) {
demarche(number: $demarcheNumber) {
@ -135,6 +136,7 @@ class API::V2::StoredQuery
$includeInstructeurs: Boolean = true
$includeAvis: Boolean = false
$includeMessages: Boolean = false
$includeCorrections: Boolean = false
$includeGeometry: Boolean = false
) {
groupeInstructeur(number: $groupeInstructeurNumber) {
@ -201,6 +203,7 @@ class API::V2::StoredQuery
$includeInstructeurs: Boolean = true
$includeAvis: Boolean = false
$includeMessages: Boolean = false
$includeCorrections: Boolean = false
$includeGeometry: Boolean = false
) {
dossier(number: $dossierNumber) {
@ -239,6 +242,7 @@ class API::V2::StoredQuery
}
fragment DossierFragment on Dossier {
__typename
id
number
archived
@ -250,6 +254,7 @@ class API::V2::StoredQuery
dateTraitement
dateExpiration
dateSuppressionParUsager
dateDerniereCorrectionEnAttente @include(if: $includeCorrections)
motivation
motivationAttachment {
...FileFragment
@ -318,8 +323,8 @@ class API::V2::StoredQuery
dateFermeture
notice { url }
deliberation { url }
demarcheUrl
cadreJuridiqueUrl
demarcheURL
cadreJuridiqueURL
service @include(if: $includeService) {
...ServiceFragment
}
@ -409,6 +414,10 @@ class API::V2::StoredQuery
attachments {
...FileFragment
}
correction @include(if: $includeCorrections) {
reason
dateResolution
}
}
fragment GeoAreaFragment on GeoArea {
@ -455,6 +464,7 @@ class API::V2::StoredQuery
__typename
label
stringValue
updatedAt
... on DateChamp {
date
}
@ -584,11 +594,13 @@ class API::V2::StoredQuery
fragment FileFragment on File {
__typename
filename
contentType
checksum
byteSize: byteSizeBigInt
url
createdAt
}
fragment AddressFragment on Address {
@ -635,6 +647,7 @@ class API::V2::StoredQuery
fragment PageInfoFragment on PageInfo {
hasPreviousPage
hasNextPage
startCursor
endCursor
}
GRAPHQL

View file

@ -35,7 +35,7 @@ module Extensions
# is a lazy value (e.g., a Promise like in our case)
def after_resolve(value:, **_rest)
if value.respond_to?(:map)
attachments = value.map { after_resolve_attachment(_1) }
attachments = value.map { after_resolve_attachment(_1) }.compact
if options[:as] == :single
attachments.first

View file

@ -1066,7 +1066,8 @@ type DemarcheDescriptor {
"""
URL du cadre juridique qui justifie le droit de collecter les données demandées dans la démarche
"""
cadreJuridiqueUrl: String
cadreJuridiqueURL: String
cadreJuridiqueUrl: String @deprecated(reason: "Utilisez le champ `cadreJuridiqueURL` à la place.")
"""
Date de la création.
@ -1106,7 +1107,8 @@ type DemarcheDescriptor {
"""
URL pour commencer la démarche
"""
demarcheUrl: URL
demarcheURL: URL
demarcheUrl: URL @deprecated(reason: "Utilisez le champ `demarcheURL` à la place.")
"""
Description de la démarche.
@ -1116,7 +1118,8 @@ type DemarcheDescriptor {
"""
URL ou email pour contacter le Délégué à la Protection des Données (DPO)
"""
dpoUrl: String
dpoURL: String
dpoUrl: String @deprecated(reason: "Utilisez le champ `dpoURL` à la place.")
"""
Durée de conservation des dossiers en mois.
@ -1129,7 +1132,8 @@ type DemarcheDescriptor {
notice explicative de la démarche
"""
notice: File
noticeUrl: URL
noticeURL: URL
noticeUrl: URL @deprecated(reason: "Utilisez le champ `noticeURL` à la place.")
"""
Numero de la démarche.
@ -1142,7 +1146,8 @@ type DemarcheDescriptor {
"""
URL les usagers trouvent le lien vers la démarche
"""
siteWebUrl: String
siteWebURL: String
siteWebUrl: String @deprecated(reason: "Utilisez le champ `siteWebURL` à la place.")
"""
État de la démarche.

View file

@ -25,6 +25,12 @@ Cela évite laccès récursif aux dossiers."
field :duree_conservation_dossiers, Int, "Durée de conservation des dossiers en mois.", null: false
field :demarcheUrl, Types::URL, camelize: false, null: true, deprecation_reason: 'Utilisez le champ `demarcheURL` à la place.'
field :siteWebUrl, String, camelize: false, null: true, deprecation_reason: 'Utilisez le champ `siteWebURL` à la place.'
field :dpoUrl, String, camelize: false, null: true, deprecation_reason: 'Utilisez le champ `dpoURL` à la place.'
field :noticeUrl, Types::URL, camelize: false, null: true, deprecation_reason: 'Utilisez le champ `noticeURL` à la place.'
field :cadreJuridiqueUrl, String, camelize: false, null: true, deprecation_reason: 'Utilisez le champ `cadreJuridiqueURL` à la place.'
field :demarche_url, Types::URL, "URL pour commencer la démarche", null: true
field :site_web_url, String, "URL où les usagers trouvent le lien vers la démarche", null: true
field :dpo_url, String, "URL ou email pour contacter le Délégué à la Protection des Données (DPO)", null: true
@ -77,22 +83,27 @@ Cela évite laccès récursif aux dossiers."
def demarche_url
Rails.application.routes.url_helpers.commencer_url(path: procedure.path)
end
alias demarcheUrl demarche_url
def dpo_url
procedure.lien_dpo
end
alias dpoUrl dpo_url
def notice_url
procedure.lien_notice
end
alias noticeUrl notice_url
def cadre_juridique_url
procedure.cadre_juridique
end
alias cadreJuridiqueUrl cadre_juridique_url
def site_web_url
procedure.lien_site_web
end
alias siteWebUrl site_web_url
def number
procedure.id

View file

@ -1,21 +0,0 @@
module DemandeHelper
def nb_of_procedures_options
{
'je ne sais pas' => Pipedrive::DealAdapter::PIPEDRIVE_NB_OF_PROCEDURES_DO_NOT_KNOW_VALUE,
'1' => Pipedrive::DealAdapter::PIPEDRIVE_NB_OF_PROCEDURES_1_VALUE,
'1 à 10' => Pipedrive::DealAdapter::PIPEDRIVE_NB_OF_PROCEDURES_1_TO_10_VALUE,
'10 à 100 ' => Pipedrive::DealAdapter::PIPEDRIVE_NB_OF_PROCEDURES_10_TO_100_VALUE,
'plus de 100' => Pipedrive::DealAdapter::PIPEDRIVE_NB_OF_PROCEDURES_ABOVE_100_VALUE
}
end
def deadline_options
{
'le plus vite possible' => Pipedrive::DealAdapter::PIPEDRIVE_DEADLINE_ASAP_VALUE,
'dans les 3 prochains mois' => Pipedrive::DealAdapter::PIPEDRIVE_DEADLINE_NEXT_3_MONTHS_VALUE,
'dans les 6 prochains mois' => Pipedrive::DealAdapter::PIPEDRIVE_DEADLINE_NEXT_6_MONTHS_VALUE,
'dans les 12 prochains mois' => Pipedrive::DealAdapter::PIPEDRIVE_DEADLINE_NEXT_12_MONTHS_VALUE,
'pas de date' => Pipedrive::DealAdapter::PIPEDRIVE_DEADLINE_NO_DATE_VALUE
}
end
end

View file

@ -39,10 +39,10 @@ module ProcedureHelper
end
def can_send_groupe_message?(procedure)
procedure.dossiers
.state_brouillon
.includes(:groupe_instructeur)
.exists?(groupe_instructeur: current_instructeur.groupe_instructeurs)
groupe_instructeur_on_procedure_ids = procedure.groupe_instructeurs.active.ids.sort
groupe_instructeur_on_instructeur_ids = current_instructeur.groupe_instructeurs.active.where(procedure: procedure).ids.sort
groupe_instructeur_on_procedure_ids == groupe_instructeur_on_instructeur_ids
end
def url_or_email_to_lien_dpo(procedure)

View file

@ -1,5 +0,0 @@
class PipedriveAcceptsDealsJob < ApplicationJob
def perform(person_id, administration_id, stage_id)
PipedriveService.accept_demande_from_person(person_id, administration_id, stage_id)
end
end

View file

@ -1,5 +0,0 @@
class PipedriveRefusesDealsJob < ApplicationJob
def perform(person_id, administration_id)
PipedriveService.refuse_demande_from_person(person_id, administration_id)
end
end

View file

@ -5,8 +5,4 @@ module BizDev
def self.full_name(administration_id)
NAME
end
def self.pipedrive_id(administration_id)
PIPEDRIVE_ID
end
end

View file

@ -1,82 +0,0 @@
class Pipedrive::API
PIPEDRIVE_ALL_NOT_DELETED_DEALS = 'all_not_deleted'
PIPEDRIVE_DEALS_URL = [PIPEDRIVE_API_URL, 'deals'].join("/")
PIPEDRIVE_PEOPLE_URL = [PIPEDRIVE_API_URL, 'persons'].join("/")
PIPEDRIVE_ORGANIZATIONS_URL = [PIPEDRIVE_API_URL, 'organizations'].join("/")
def self.get_persons_owned_by_user(user_id)
url = PIPEDRIVE_PEOPLE_URL
params = { user_id: user_id }
self.get(url, params)
end
def self.get_deals_for_person(person_id)
url = [PIPEDRIVE_PEOPLE_URL, person_id, "deals"].join('/')
params = { status: PIPEDRIVE_ALL_NOT_DELETED_DEALS }
self.get(url, params)
end
def self.put_deal(deal_id, params)
url = [PIPEDRIVE_DEALS_URL, deal_id].join("/")
self.put(url, params)
end
def self.post_deal(params)
self.post(PIPEDRIVE_DEALS_URL, params)
end
def self.put_person(person_id, params)
url = [PIPEDRIVE_PEOPLE_URL, person_id].join("/")
self.put(url, params)
end
def self.post_person(params)
self.post(PIPEDRIVE_PEOPLE_URL, params)
end
def self.post_organization(params)
self.post(PIPEDRIVE_ORGANIZATIONS_URL, params)
end
private
def self.get(url, params)
params.merge!({
start: 0,
limit: 500,
api_token: token
})
response = Typhoeus.get(url, params: params)
if response.success?
JSON.parse(response.body)['data']
end
end
def self.put(url, params)
Typhoeus.put(
url,
params: { api_token: token },
body: params.to_json,
headers: { 'content-type' => 'application/json' }
)
end
def self.post(url, params)
Typhoeus.post(
url,
params: { api_token: token },
body: params.to_json,
headers: { 'content-type' => 'application/json' }
)
end
def self.token
Rails.application.secrets.pipedrive[:key]
end
end

View file

@ -1,63 +0,0 @@
class Pipedrive::DealAdapter
PIPEDRIVE_ADMIN_CENTRAL_STOCK_STAGE_ID = 35
PIPEDRIVE_SERVICE_DECO_REGIONAL_STOCK_STAGE_ID = 24
PIPEDRIVE_SERVICE_DECO_DEPARTEMENTAL_STOCK_STAGE_ID = 20
PIPEDRIVE_COLLECTIVITE_DEP_OU_REG_STOCK_STAGE_ID = 30
PIPEDRIVE_COLLECTIVITE_LOCALE_STOCK_STAGE_ID = 40
PIPEDRIVE_ORGANISMES_STOCK_STAGE_ID = 1
PIPEDRIVE_ORGANISMES_REFUSES_STOCK_STAGE_ID = 45
PIPEDRIVE_SUSPECTS_COMPTE_CREE_STAGE_ID = 48
PIPEDRIVE_LOST_STATUS = "lost"
PIPEDRIVE_LOST_REASON = "refusé depuis DS"
PIPEDRIVE_NB_OF_PROCEDURES_ATTRIBUTE_ID = "b22f8710352a7fb548623c062bf82ed6d1b6b704"
PIPEDRIVE_NB_OF_PROCEDURES_DO_NOT_KNOW_VALUE = "Je ne sais pas"
PIPEDRIVE_NB_OF_PROCEDURES_1_VALUE = "juste 1"
PIPEDRIVE_NB_OF_PROCEDURES_1_TO_10_VALUE = "de 1 a 10"
PIPEDRIVE_NB_OF_PROCEDURES_10_TO_100_VALUE = "de 10 a 100"
PIPEDRIVE_NB_OF_PROCEDURES_ABOVE_100_VALUE = "Plus de 100"
PIPEDRIVE_DEADLINE_ATTRIBUTE_ID = "36a72c82af9d9f0d476b041ede8876844a249bf2"
PIPEDRIVE_DEADLINE_ASAP_VALUE = "Le plus vite possible"
PIPEDRIVE_DEADLINE_NEXT_3_MONTHS_VALUE = "Dans les 3 prochain mois"
PIPEDRIVE_DEADLINE_NEXT_6_MONTHS_VALUE = "Dans les 6 prochain mois"
PIPEDRIVE_DEADLINE_NEXT_12_MONTHS_VALUE = "Dans les 12 prochain mois"
PIPEDRIVE_DEADLINE_NO_DATE_VALUE = "Pas de date"
def self.refuse_deal(deal_id, owner_id)
params = {
user_id: owner_id,
stage_id: PIPEDRIVE_ORGANISMES_REFUSES_STOCK_STAGE_ID,
status: PIPEDRIVE_LOST_STATUS,
lost_reason: PIPEDRIVE_LOST_REASON
}
Pipedrive::API.put_deal(deal_id, params)
end
def self.get_deals_ids_for_person(person_id)
deals = Pipedrive::API.get_deals_for_person(person_id) || []
deals.map { |datum| datum['id'] }
end
def self.update_deal_owner_and_stage(deal_id, owner_id, stage_id)
params = { user_id: owner_id, stage_id: stage_id }
Pipedrive::API.put_deal(deal_id, params)
end
def self.add_deal(organisation_id, person_id, title, nb_of_procedures, nb_of_dossiers, deadline)
params = {
org_id: organisation_id,
person_id: person_id,
title: title,
user_id: Pipedrive::PersonAdapter::PIPEDRIVE_ROBOT_ID,
"#{PIPEDRIVE_NB_OF_PROCEDURES_ATTRIBUTE_ID}": nb_of_procedures,
value: nb_of_dossiers,
"#{PIPEDRIVE_DEADLINE_ATTRIBUTE_ID}": deadline
}
Pipedrive::API.post_deal(params)
end
end

View file

@ -1,13 +0,0 @@
class Pipedrive::OrganizationAdapter
def self.add_organization(name, address)
params = {
name: name,
owner_id: Pipedrive::PersonAdapter::PIPEDRIVE_ROBOT_ID,
address: address
}
response = Pipedrive::API.post_organization(params)
JSON.parse(response.body)['data']['id']
end
end

View file

@ -1,52 +0,0 @@
class Pipedrive::PersonAdapter
PIPEDRIVE_POSTE_ATTRIBUTE_ID = '33a790746f1713d712fe97bcce9ac1ca6374a4d6'
PIPEDRIVE_SOURCE_ATTRIBUTE_ID = '2fa7864f467ffa97721cbcd08df5a3d591b15f50'
PIPEDRIVE_NB_DOSSIERS_ATTRIBUTE_ID = '2734a3ff19f4b88bd0d7b4cf02c47c7545617207'
PIPEDRIVE_DEADLINE_ATTRIBUTE_ID = 'ef766dd14de7da246fb5fc1704f45d1f1830f6c9'
PIPEDRIVE_ROBOT_ID = '11381160'
def self.get_demandes_from_persons_owned_by_robot
demandes = Pipedrive::API.get_persons_owned_by_user(PIPEDRIVE_ROBOT_ID)
if demandes.present?
demandes.map do |datum|
{
person_id: datum['id'],
nom: datum['name'],
poste: datum[PIPEDRIVE_POSTE_ATTRIBUTE_ID],
email: datum.dig('email', 0, 'value'),
tel: datum.dig('phone', 0, 'value'),
organisation: datum['org_name'],
nb_dossiers: datum[PIPEDRIVE_NB_DOSSIERS_ATTRIBUTE_ID],
deadline: datum[PIPEDRIVE_DEADLINE_ATTRIBUTE_ID]
}
end
else
[]
end
end
def self.update_person_owner(person_id, owner_id)
params = { owner_id: owner_id }
Pipedrive::API.put_person(person_id, params)
end
def self.add_person(email, phone, name, organization_id, poste, source, nb_of_dossiers, deadline)
params = {
email: email,
phone: phone,
name: name,
org_id: organization_id,
owner_id: PIPEDRIVE_ROBOT_ID,
"#{PIPEDRIVE_POSTE_ATTRIBUTE_ID}": poste,
"#{PIPEDRIVE_SOURCE_ATTRIBUTE_ID}": source,
"#{PIPEDRIVE_NB_DOSSIERS_ATTRIBUTE_ID}": nb_of_dossiers,
"#{PIPEDRIVE_DEADLINE_ATTRIBUTE_ID}": deadline
}
response = Pipedrive::API.post_person(params)
JSON.parse(response.body)['data']['id']
end
end

View file

@ -8,18 +8,4 @@ class ApplicationMailer < ActionMailer::Base
layout 'mailer'
before_action -> { Sentry.set_tags(mailer: mailer_name, action: action_name) }
# Attach the procedure logo to the email (if any).
# Returns the attachment url.
def attach_logo(procedure)
if procedure.logo.attached?
logo_filename = procedure.logo.filename.to_s
attachments.inline[logo_filename] = procedure.logo.download
attachments[logo_filename].url
end
rescue StandardError => e
# A problem occured when reading logo, maybe the logo is missing and we should clean the procedure to remove logo reference ?
Sentry.capture_exception(e, extra: { procedure_id: procedure.id })
nil
end
end

View file

@ -12,7 +12,7 @@ class DossierMailer < ApplicationMailer
@dossier = params[:dossier]
I18n.with_locale(@dossier.user_locale) do
@service = @dossier.procedure.service
@logo_url = attach_logo(@dossier.procedure)
@logo_url = procedure_logo_url(@dossier.procedure)
@subject = default_i18n_subject(libelle_demarche: @dossier.procedure.libelle)
mail(to: @dossier.user_email_for(:notification), subject: @subject) do |format|
@ -27,7 +27,7 @@ class DossierMailer < ApplicationMailer
I18n.with_locale(dossier.user_locale) do
@dossier = dossier
@service = dossier.procedure.service
@logo_url = attach_logo(dossier.procedure)
@logo_url = procedure_logo_url(@dossier.procedure)
@body = commentaire.body
@subject = default_i18n_subject(dossier_id: dossier.id, libelle_demarche: dossier.procedure.libelle)
@ -52,7 +52,7 @@ class DossierMailer < ApplicationMailer
I18n.with_locale(dossier.user_locale) do
@dossier = dossier
@service = dossier.procedure.service
@logo_url = attach_logo(dossier.procedure)
@logo_url = procedure_logo_url(@dossier.procedure)
@correction = commentaire.dossier_correction
@subject = default_i18n_subject(dossier_id: dossier.id, libelle_demarche: dossier.procedure.libelle)
@ -85,7 +85,7 @@ class DossierMailer < ApplicationMailer
I18n.with_locale(dossier.user_locale) do
@dossier = dossier
@service = dossier.procedure.service
@logo_url = attach_logo(dossier.procedure)
@logo_url = procedure_logo_url(@dossier.procedure)
@subject = default_i18n_subject(dossier_id: dossier.id, libelle_demarche: dossier.procedure.libelle)
mail(to: dossier.user_email_for(:notification), subject: @subject) do |format|

View file

@ -17,7 +17,7 @@ class NotificationMailer < ApplicationMailer
def send_notification
@service = @dossier.procedure.service
@logo_url = attach_logo(@dossier.procedure)
@logo_url = procedure_logo_url(@dossier.procedure)
attachments[@attachment[:filename]] = @attachment[:content] if @attachment.present?
I18n.with_locale(@dossier.user_locale) do
mail(subject: @subject, to: @email, template_name: 'send_notification')

View file

@ -1,12 +1,3 @@
# == Schema Information
#
# Table name: administrateurs
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
# user_id :bigint not null
#
class Administrateur < ApplicationRecord
UNUSED_ADMIN_THRESHOLD = ENV.fetch('UNUSED_ADMIN_THRESHOLD') { 6 }.to_i.months
@ -29,7 +20,10 @@ class Administrateur < ApplicationRecord
.where.missing(:services)
.left_outer_joins(:administrateurs_procedures) # needed to bypass procedure hidden default scope
.where(administrateurs_procedures: { procedure_id: nil })
.where("users.last_sign_in_at < ? ", UNUSED_ADMIN_THRESHOLD.ago)
.includes(:api_tokens)
.where(users: { last_sign_in_at: ..UNUSED_ADMIN_THRESHOLD.ago })
.merge(APIToken.where(last_v1_authenticated_at: nil).or(APIToken.where(last_v1_authenticated_at: ..UNUSED_ADMIN_THRESHOLD.ago)))
.merge(APIToken.where(last_v2_authenticated_at: nil).or(APIToken.where(last_v2_authenticated_at: ..UNUSED_ADMIN_THRESHOLD.ago)))
end
def self.by_email(email)

View file

@ -1,12 +1,3 @@
# == Schema Information
#
# Table name: administrateurs_instructeurs
#
# created_at :datetime
# updated_at :datetime
# administrateur_id :integer not null
# instructeur_id :integer not null
#
class AdministrateursInstructeur < ApplicationRecord
belongs_to :administrateur
belongs_to :instructeur

View file

@ -1,13 +1,3 @@
# == Schema Information
#
# Table name: administrateurs_procedures
#
# manager :boolean
# created_at :datetime not null
# updated_at :datetime not null
# administrateur_id :bigint not null
# procedure_id :bigint not null
#
class AdministrateursProcedure < ApplicationRecord
belongs_to :administrateur
belongs_to :procedure

View file

@ -1,17 +1,3 @@
# == Schema Information
#
# Table name: api_tokens
#
# id :uuid not null, primary key
# allowed_procedure_ids :bigint is an Array
# encrypted_token :string not null
# name :string not null
# write_access :boolean default(TRUE), not null
# version :integer default(3), not null
# created_at :datetime not null
# updated_at :datetime not null
# administrateur_id :bigint not null
#
class APIToken < ApplicationRecord
include ActiveRecord::SecureToken

View file

@ -1,15 +1,4 @@
# == Schema Information
#
# Table name: archives
#
# id :bigint not null, primary key
# job_status :string not null
# key :text not null
# month :date
# time_span_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
#
class Archive < ApplicationRecord
include TransientModelsWithPurgeableJobConcern

View file

@ -1,19 +1,3 @@
# == Schema Information
#
# Table name: assign_tos
#
# id :integer not null, primary key
# daily_email_notifications_enabled :boolean default(FALSE), not null
# instant_email_dossier_notifications_enabled :boolean default(FALSE), not null
# instant_email_message_notifications_enabled :boolean default(FALSE), not null
# instant_expert_avis_email_notifications_enabled :boolean default(FALSE)
# manager :boolean default(FALSE)
# weekly_email_notifications_enabled :boolean default(TRUE), not null
# created_at :datetime
# updated_at :datetime
# groupe_instructeur_id :bigint
# instructeur_id :integer
#
class AssignTo < ApplicationRecord
belongs_to :instructeur, optional: false
belongs_to :groupe_instructeur, optional: false

View file

@ -1,13 +1,3 @@
# == Schema Information
#
# Table name: attestations
#
# id :integer not null, primary key
# title :string
# created_at :datetime not null
# updated_at :datetime not null
# dossier_id :integer not null
#
class Attestation < ApplicationRecord
belongs_to :dossier, optional: false

View file

@ -1,16 +1,3 @@
# == Schema Information
#
# Table name: attestation_templates
#
# id :integer not null, primary key
# activated :boolean
# body :text
# footer :text
# title :text
# created_at :datetime not null
# updated_at :datetime not null
# procedure_id :integer
#
class AttestationTemplate < ApplicationRecord
include ActionView::Helpers::NumberHelper
include TagsSubstitutionConcern

View file

@ -1,23 +1,3 @@
# == Schema Information
#
# Table name: avis
#
# id :integer not null, primary key
# answer :text
# claimant_type :string
# confidentiel :boolean default(FALSE), not null
# email :string
# introduction :text
# question_answer :boolean
# question_label :string
# reminded_at :datetime
# revoked_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
# claimant_id :integer not null
# dossier_id :integer
# experts_procedure_id :bigint
#
class Avis < ApplicationRecord
include EmailSanitizableConcern

View file

@ -1,20 +1,3 @@
# == Schema Information
#
# Table name: batch_operations
#
# id :bigint not null, primary key
# failed_dossier_ids :bigint default([]), not null, is an Array
# finished_at :datetime
# operation :string not null
# payload :jsonb not null
# run_at :datetime
# seen_at :datetime
# success_dossier_ids :bigint default([]), not null, is an Array
# created_at :datetime not null
# updated_at :datetime not null
# instructeur_id :bigint not null
#
class BatchOperation < ApplicationRecord
enum operation: {
accepter: 'accepter',

View file

@ -1,12 +1,3 @@
# == Schema Information
#
# Table name: bill_signatures
#
# id :bigint not null, primary key
# digest :string
# created_at :datetime not null
# updated_at :datetime not null
#
class BillSignature < ApplicationRecord
has_many :dossier_operation_logs

View file

@ -1,18 +1,4 @@
# == Schema Information
#
# Table name: bulk_messages
#
# id :bigint not null, primary key
# body :text not null
# dossier_count :integer
# dossier_state :string
# sent_at :datetime not null
# created_at :datetime not null
# updated_at :datetime not null
# instructeur_id :bigint not null
#
class BulkMessage < ApplicationRecord
belongs_to :instructeur
has_and_belongs_to_many :groupe_instructeurs, -> { order(:label) }
has_one_attached :piece_jointe
end

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champ < ApplicationRecord
include ChampConditionalConcern

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::AddressChamp < Champs::TextChamp
def full_address?
data.present?

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::AnnuaireEducationChamp < Champs::TextChamp
def fetch_external_data?
true

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::BooleanChamp < Champ
TRUE_VALUE = 'true'
FALSE_VALUE = 'false'

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::CarteChamp < Champ
# Default map location. Center of the World, ahm, France...
DEFAULT_LON = 2.428462

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::CheckboxChamp < Champs::BooleanChamp
def for_export
true? ? 'on' : 'off'

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::CiviliteChamp < Champ
validates :value, inclusion: ["M.", "Mme"], allow_nil: true, allow_blank: false

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::CnafChamp < Champs::TextChamp
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/cnaf-input-validation.middleware.ts
validates :numero_allocataire, format: { with: /\A\d{1,7}\z/ }, if: -> { code_postal.present? && validation_context != :brouillon }

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::CommuneChamp < Champs::TextChamp
store_accessor :value_json, :code_departement, :code_postal
before_validation :on_code_postal_change

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DateChamp < Champ
before_validation :convert_to_iso8601, unless: -> { validation_context == :prefill }
validate :iso_8601

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DatetimeChamp < Champ
before_validation :convert_to_iso8601, unless: -> { validation_context == :prefill }
validate :iso_8601
@ -66,6 +44,6 @@ class Champs::DatetimeChamp < Champ
end
def valid_iso8601?
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}\+\d{2}:\d{2})?$/.match?(value)
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}[\+\-]\d{2}:\d{2})?$/.match?(value)
end
end

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DecimalNumberChamp < Champ
validates :value, numericality: {
allow_nil: true,

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DepartementChamp < Champs::TextChamp
validate :value_in_departement_names, unless: -> { value.nil? }
validate :external_id_in_departement_codes, unless: -> { external_id.nil? }

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DgfipChamp < Champs::TextChamp
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/dgfip-input-validation.middleware.ts
validates :numero_fiscal, format: { with: /\A\w{13,14}\z/ }, if: -> { reference_avis.present? && validation_context != :brouillon }

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DossierLinkChamp < Champ
validate :value_integerable, if: -> { value.present? }, on: :prefill

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::DropDownListChamp < Champ
store_accessor :value_json, :other
THRESHOLD_NB_OPTIONS_AS_RADIO = 5

View file

@ -1,24 +1,2 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::EmailChamp < Champs::TextChamp
end

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::EpciChamp < Champs::TextChamp
store_accessor :value_json, :code_departement
before_validation :on_departement_change

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::ExplicationChamp < Champs::TextChamp
def search_terms
# The user cannot enter any information here so it doesnt make much sense to search

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::HeaderSectionChamp < Champ
def level
if parent.present?

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::IbanChamp < Champ
validates_with IbanValidator, if: -> { validation_context != :brouillon }
after_validation :format_iban

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::IntegerNumberChamp < Champ
validates :value, numericality: {
only_integer: true,

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::LinkedDropDownListChamp < Champ
delegate :primary_options, :secondary_options, to: 'type_de_champ.dynamic_type'

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::MesriChamp < Champs::TextChamp
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/mesri-input-validation.middleware.ts
store_accessor :value_json, :ine

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::MultipleDropDownListChamp < Champ
validate :values_are_in_options, if: -> { value.present? }

View file

@ -1,24 +1,2 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::NumberChamp < Champ
end

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::PaysChamp < Champs::TextChamp
validates :value, inclusion: APIGeoService.countries.pluck(:name), allow_nil: true, allow_blank: false
validates :external_id, inclusion: APIGeoService.countries.pluck(:code), allow_nil: true, allow_blank: false

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::PhoneChamp < Champs::TextChamp
# We want to allow:
# * international (e164) phone numbers

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::PieceJustificativeChamp < Champ
FILE_MAX_SIZE = 200.megabytes

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::PoleEmploiChamp < Champs::TextChamp
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/pole-emploi-input-validation.middleware.ts
store_accessor :value_json, :identifiant

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::RegionChamp < Champs::TextChamp
validate :value_in_region_names, unless: -> { value.nil? }
validate :external_id_in_region_codes, unless: -> { external_id.nil? }

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::RepetitionChamp < Champ
accepts_nested_attributes_for :champs
delegate :libelle_for_export, to: :type_de_champ

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::RNAChamp < Champ
include RNAChampAssociationFetchableConcern

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::SiretChamp < Champ
include SiretChampEtablissementFetchableConcern

View file

@ -1,24 +1,2 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::TextChamp < Champ
end

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::TextareaChamp < Champs::TextChamp
def for_export
value.present? ? ActionView::Base.full_sanitizer.sanitize(value) : nil

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::TitreIdentiteChamp < Champ
FILE_MAX_SIZE = 20.megabytes
ACCEPTED_FORMATS = ['image/png', 'image/jpeg']

View file

@ -1,25 +1,3 @@
# == Schema Information
#
# Table name: champs
#
# id :integer not null, primary key
# data :jsonb
# fetch_external_data_exceptions :string is an Array
# prefilled :boolean default(FALSE)
# private :boolean default(FALSE), not null
# rebased_at :datetime
# type :string
# value :string
# value_json :jsonb
# created_at :datetime
# updated_at :datetime
# dossier_id :integer
# etablissement_id :integer
# external_id :string
# parent_id :bigint
# row_id :string
# type_de_champ_id :integer
#
class Champs::YesNoChamp < Champs::BooleanChamp
def yes_input_id
"#{input_id}-yes"

View file

@ -1,22 +1,6 @@
# == Schema Information
#
# Table name: commentaires
#
# id :integer not null, primary key
# body :string
# discarded_at :datetime
# email :string
# created_at :datetime not null
# updated_at :datetime not null
# dossier_id :integer
# expert_id :bigint
# instructeur_id :bigint
#
class Commentaire < ApplicationRecord
include Discard::Model
belongs_to :dossier, inverse_of: :commentaires, touch: true, optional: false
belongs_to :instructeur, inverse_of: :commentaires, optional: true
belongs_to :expert, inverse_of: :commentaires, optional: true
has_one :dossier_correction, inverse_of: :commentaire, dependent: :nullify

View file

@ -76,7 +76,8 @@ module DossierCloneConcern
end
def clone(user: nil, fork: false)
dossier_attributes = [:autorisation_donnees, :revision_id, :groupe_instructeur_id]
dossier_attributes = [:autorisation_donnees, :revision_id]
dossier_attributes += [:groupe_instructeur_id] if fork
relationships = [:individual, :etablissement]
cloned_champs = champs
@ -95,7 +96,6 @@ module DossierCloneConcern
kopy.user = user || original.user
kopy.state = Dossier.states.fetch(:brouillon)
kopy.champs = cloned_champs.values.map do |(_, champ)|
champ.dossier = kopy
champ.parent = cloned_champs[champ.parent_id].second if champ.child?

Some files were not shown because too many files have changed in this diff Show more