Compare commits

...

15 commits

Author SHA1 Message Date
Paul Chavard
c20da3378e
Merge pull request #8921 from demarches-simplifiees/8827-user-path-translations-fix
ETQ usager, je veux que mon interface soit traduite en anglais
2023-04-26 17:17:35 +00:00
Paul Chavard
9a22c25c1c
Merge pull request #8899 from demarches-simplifiees/8738-validate-adresse-electronique
ETQ usager, je veux que les champs de type adresse électronique soit validé
2023-04-26 16:52:02 +00:00
Paul Chavard
0e03ab653a
Merge pull request #8968 from demarches-simplifiees/fix_defaut_groupe_instructeur_again
Correctif: definit le groupe instructeur par defaut pour certaines procedure clonées
2023-04-26 16:51:40 +00:00
simon lehericey
0934a672fe fix: defaut_groupe_instructeur for a cloned procedure from another admin without a group with default label 2023-04-26 10:52:31 +02:00
simon lehericey
dce2bf3209 spec: move procedure.clone in subject, to enable future before 2023-04-26 10:47:51 +02:00
Julie Salha
e6004d83f3
Merge branch 'main' into 8827-user-path-translations-fix 2023-04-25 09:36:05 +02:00
krichtof
c2461f230c validate value for email champ 2023-04-20 18:27:02 +02:00
Colin Darie
e5df31fd66 fix(yaml): yes & no are reserved keywords in yaml, so they have to be quoted 2023-04-19 18:26:40 +02:00
Julie Salha
f80cccba93 reset component yes no structure 2023-04-18 14:54:01 +02:00
Julie Salha
f4ffbbf042 add missing translations 2023-04-18 14:21:09 +02:00
Julie Salha
f039b6687a add translations account confirmation page 2023-04-18 14:11:58 +02:00
Julie Salha
b1dfc83c17 add translations upload group notice 2023-04-18 14:04:32 +02:00
Julie Salha
be16cb6f5e add missing translations footer email change password 2023-04-18 13:56:50 +02:00
Julie Salha
c37a54b65b add translations profile identification tokens 2023-04-18 13:51:41 +02:00
Julie Salha
93c5c52e19 add translations for yes-no radios form and update dsfr styles 2023-04-18 13:43:11 +02:00
23 changed files with 161 additions and 32 deletions

View file

@ -0,0 +1,4 @@
en:
"yes": "Yes"
"no": "No"
legend: "Yes/No"

View file

@ -0,0 +1,4 @@
fr:
"yes": "Oui"
"no": "Non"
legend: "Oui/Non"

View file

@ -1,8 +1,11 @@
%fieldset.radios
%fieldset.fr-fieldset
%legend.fr-fieldset__legend.visually-hidden
= t(".legend")
%label{ for: @champ.yes_input_id }
= @form.radio_button :value, true, id: @champ.yes_input_id
Oui
= t(".yes")
%label{ for: @champ.no_input_id }
= @form.radio_button :value, false, id: @champ.no_input_id
Non
= t(".no")

View file

@ -0,0 +1,5 @@
en:
tokens_title: API identification tokens
first_paragraph: These tokens are needed to make calls to the
second_paragraph: If you already have applications that use a token and you revoke it, access to the API will be blocked for those applications.
action: Create and display a new token

View file

@ -0,0 +1,5 @@
fr:
tokens_title: Jetons didentification de lAPI (token)
first_paragraph: Ces jetons sont nécessaire pour effectuer des appels vers lAPI de
second_paragraph: Si vous avez déjà des applications qui utilisent un jeton et vous le révoquez, laccès à lAPI sera bloqué pour ces applications.
action: Créer et afficher un nouveau jeton

View file

@ -1,7 +1,11 @@
.card.no-list{ 'data-turbo': 'true', id: dom_id(current_administrateur, :profil_api_token) }
.card-title Jetons didentification de lAPI (token)
%p Ces jetons sont nécessaire pour effectuer des appels vers lAPI de #{APPLICATION_NAME}.
%p Si vous avez déjà des applications qui utilisent un jeton et vous le révoquez, laccès à lAPI sera bloqué pour ces applications.
.card-title
= t('.tokens_title')
%p
= t('.first_paragraph')
#{APPLICATION_NAME}.
%p
= t('.second_paragraph')
= render Dsfr::ListComponent.new do |list|
- api_and_packed_tokens.each do |(api_token, packed_token)|
@ -11,5 +15,4 @@
.fr-card__content
= render Profile::APITokenComponent.new(api_token:, packed_token:)
%br
= button_to "Créer et afficher un nouveau jeton", api_tokens_path, method: :post, class: "fr-btn fr-btn--secondary"
= button_to t('.action'), api_tokens_path, method: :post, class: "fr-btn fr-btn--secondary"

View file

@ -0,0 +1,16 @@
en:
allowed_full_access_html: This token has access to <strong>all</strong> the procedures attached to your administrator account
allowed_procedures_html:
zero: This token has no access to <strong>any</strong> process.
one: This token has access to a selected process
other: This token has access to %{count} selected steps
security_one: For security reasons, it will not be re-posted, please note.
security_two: For security reasons, we can only show it to you when it is created.
action_all: Allow access to all procedures
action_choice: Allow access only to selected steps
add: Add
delete: Delete
token_procedures: This token has access to the procedures
revoke_token: Revoke token
reading_writing: Reading and writing
reading: Read only

View file

@ -4,3 +4,13 @@ fr:
zero: Ce jeton na accès à <strong>aucune</strong> démarche
one: Ce jeton a accès a une démarche sélectionnée
other: Ce jeton a accès a %{count} démarches sélectionnées
security_one: Pour des raisons de sécurité, il ne sera plus ré-affiché, notez-le bien.
security_two: Pour des raisons de sécurité, nous ne pouvons vous lafficher que lors de sa création.
action_all: Autoriser laccès a toutes les démarches
action_choice: Autoriser laccès seulement a des démarches choisies
add: Ajouter
delete: Supprimer
token_procedures: Ce jeton a accès aux démarches
revoke_token: Révoquer le jeton
reading_writing: En lecture et écriture
reading: En lecture seule

View file

@ -13,10 +13,12 @@
- button = render Dsfr::CopyButtonComponent.new(text: @packed_token, title: "Copier le jeton dans le presse-papier", success: "Le jeton a été copié dans le presse-papier")
= "#{@packed_token} #{button}"
%p Pour des raisons de sécurité, il ne sera plus ré-affiché, notez-le bien.
%p
= t('.security_one')
- else
%p Pour des raisons de sécurité, nous ne pouvons vous lafficher que lors de sa création.
%p
= t('.security_two')
- if @api_token.full_access?
%p.fr-text--lg
@ -26,33 +28,35 @@
= t('.allowed_procedures_html', count: @api_token.allowed_procedures.size)
- if @api_token.allowed_procedures.empty?
= button_to "Autoriser laccès a toutes les démarches", @api_token, method: :patch, params: { api_token: { disallow_procedure_id: '0' } }, class: "fr-btn fr-btn--secondary"
= button_to t('.action_all'), @api_token, method: :patch, params: { api_token: { disallow_procedure_id: '0' } }, class: "fr-btn fr-btn--secondary"
- else
%ul
- @api_token.allowed_procedures.each do |procedure|
%li.flex.justify-between.align-center
.truncate-80
= "#{procedure.id} #{procedure.libelle}"
= button_to "Supprimer", @api_token, method: :patch, params: { api_token: { disallow_procedure_id: procedure.id } }, class: "fr-btn fr-btn--secondary"
= button_to t('.delete'), @api_token, method: :patch, params: { api_token: { disallow_procedure_id: procedure.id } }, class: "fr-btn fr-btn--secondary"
.fr-card__end
= form_for @api_token, namespace: dom_id(@api_token, :allowed_procedures), html: { class: 'form form-ds-fr-white mb-3', data: { turbo: true } } do |f|
= f.label :allowed_procedure_ids do
Autoriser laccès seulement a des démarches choisies
= t('.action_choice')
- @api_token.allowed_procedures.each do |procedure|
= f.hidden_field :allowed_procedure_ids, value: procedure.id, multiple: true, id: dom_id(procedure, :allowed_procedure)
.flex.justify-between.align-center{ 'data-turbo-force': true }
= f.select :allowed_procedure_ids, procedures_to_allow_options, procedures_to_allow_select_options, { class: 'no-margin width-66 small', name: "api_token[allowed_procedure_ids][]" }
= f.button type: :submit, class: "fr-btn fr-btn--secondary" do
Ajouter
= t('.add')
= form_for @api_token, namespace: dom_id(@api_token, :write_access), html: { class: 'form form-ds-fr-white mb-3', data: { turbo: true, controller: 'autosubmit' } } do |f|
= f.label :write_access do
Ce jeton a accès aux démarches
= t('.token_procedures')
%label.toggle-switch.no-margin
= f.check_box :write_access, class: 'toggle-switch-checkbox'
%span.toggle-switch-control.round
%span.toggle-switch-label.on En lecture et écriture
%span.toggle-switch-label.off En lecture seule
%span.toggle-switch-label.on
= t('.reading_writing')
%span.toggle-switch-label.off
= t('.reading')
= button_to "Révoquer le jeton", api_token_path(@api_token), method: :delete, class: "fr-btn fr-btn--secondary", data: { turbo_confirm: "Confirmez-vous la révocation de ce jeton ? Les applications qui lutilisent actuellement seront bloquées." }
= button_to t('.revoke_token'), api_token_path(@api_token), method: :delete, class: "fr-btn fr-btn--secondary", data: { turbo_confirm: "Confirmez-vous la révocation de ce jeton ? Les applications qui lutilisent actuellement seront bloquées." }

View file

@ -21,4 +21,11 @@
# type_de_champ_id :integer
#
class Champs::EmailChamp < Champs::TextChamp
validates :value,
format: {
with: Devise.email_regexp,
message: I18n.t('invalid', scope: 'activerecord.errors.models.email_champ.attributes.value')
},
allow_nil: true,
if: -> { validation_context != :brouillon }
end

View file

@ -580,7 +580,8 @@ class Procedure < ApplicationRecord
procedure.draft_revision.types_de_champ_public.each { |tdc| tdc.options&.delete(:old_pj) }
end
new_defaut_groupe = procedure.groupe_instructeurs.find_by(label: defaut_groupe_instructeur.label)
new_defaut_groupe = procedure.groupe_instructeurs
.find_by(label: defaut_groupe_instructeur.label) || procedure.groupe_instructeurs.first
procedure.update!(defaut_groupe_instructeur: new_defaut_groupe)
procedure

View file

@ -5,4 +5,5 @@
= service.nom
- else
-# The WORD JOINER unicode entity (&#8288;) prevents email clients from auto-linking the signature
Léquipe #{APPLICATION_NAME.gsub(".","&#8288;.").html_safe}
= t('.team')
#{APPLICATION_NAME.gsub(".","&#8288;.").html_safe}

View file

@ -61,7 +61,8 @@
.fr-upload-group
= label_tag :piece_jointe, class: 'fr-label' do
= t('pj', scope: [:utils])
%span.fr-hint-text Taille maximale : 200 Mo. Formats supportés : jpg, png, pdf.
%span.fr-hint-text
= t('.notice_upload_group')
%p.notice.hidden{ data: { 'contact-type-only': Helpscout::FormAdapter::TYPE_AMELIORATION } }
= t('.notice_pj_product')

View file

@ -31,8 +31,10 @@
- else
.blank-tab
%h2.empty-text Aucun dossier.
%h2.empty-text
= t("views.users.dossiers.account_creation.empty")
%p.empty-text-details
Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche.
%br
Celui ci doit ressembler à #{APPLICATION_BASE_URL}/commencer/xxx.
= t("views.users.dossiers.account_creation.detail_one")
%p.empty-text-details
= t("views.users.dossiers.account_creation.detail_two")
#{APPLICATION_BASE_URL}/commencer/xxx.

View file

@ -35,8 +35,10 @@
- else
.blank-tab
%h2.empty-text Aucun dossier.
%h2.empty-text
= t("views.users.dossiers.account_creation.empty")
%p.empty-text-details
Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche.
%br
Celui ci doit ressembler à #{APPLICATION_BASE_URL}/commencer/xxx.
= t("views.users.dossiers.account_creation.detail_one")
%p.empty-text-details
= t("views.users.dossiers.account_creation.detail_two")
#{APPLICATION_BASE_URL}/commencer/xxx.

View file

@ -385,6 +385,10 @@ en:
dossier_not_in_instructor_group: "File no. %{dossier_id} of the “%{procedure_libelle}” procedure corresponds to your search, but it is attached to the “%{groupe_instructeur_label}” instructor group."
users:
dossiers:
account_creation:
empty: "No file"
detail_one: "To complete a procedure, contact your administration and ask for the link to the procedure."
detail_two: "This one should look like"
archived_dossier: "Your file will be kept %{duree_conservation_dossiers_dans_ds} more months"
identite:
identity_data: Identity data
@ -561,6 +565,10 @@ en:
attributes:
email:
taken: ': Invitation already sent'
email_champ:
attributes:
value:
invalid: "is invalid. Fill in a valid email address, example: john.doe@example.fr"
user:
attributes: &error_attributes

View file

@ -386,6 +386,10 @@ fr:
dossier_not_in_instructor_group: "Le dossier n° %{dossier_id} de la procédure « %{procedure_libelle} » correspond à votre recherche mais il est rattaché au groupe dinstructeurs « %{groupe_instructeur_label} »."
users:
dossiers:
account_creation:
empty: "Aucun dossier"
detail_one: "Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche."
detail_two: "Celui ci doit ressembler à"
archived_dossier: "Votre dossier sera conservé %{duree_conservation_dossiers_dans_ds} mois supplémentaire"
identite:
identity_data: Données didentité
@ -562,6 +566,10 @@ fr:
attributes:
email:
taken: ': Invitation déjà envoyée'
email_champ:
attributes:
value:
invalid: "est invalide. Saisir une adresse éléctronique valide, exemple : john.doe@exemple.fr"
user:
attributes: &error_attributes
reset_password_token:

View file

@ -11,3 +11,5 @@ en:
by_email: "By email :"
by_phone: "By phone :"
schedule: "Schedule :"
signature:
team: "The team"

View file

@ -1,3 +1,4 @@
fr:
layouts:
mailers:
@ -11,3 +12,5 @@ fr:
by_email: "Par email :"
by_phone: "Par téléphone :"
schedule: "Horaires :"
signature:
team: "Léquipe"

View file

@ -8,6 +8,7 @@ en:
our_answer: 👉 Our answer
notice_pj_product: A screenshot can help us identify the element to improve.
notice_pj_other: A screenshot can help us identify the issue.
notice_upload_group: "Maximum size: 200 MB. Supported formats: jpg, png, pdf."
procedure_info:
question: I've encountered a problem while completing my application
answer_html: "<p>Are you sure that all the mandatory fields (<span class= mandatory> * </span>) are properly filled?

View file

@ -8,6 +8,7 @@ fr:
our_answer: 👉 Notre réponse
notice_pj_product: Une capture décran peut nous aider à identifier plus facilement lendroit à améliorer.
notice_pj_other: Une capture décran peut nous aider à identifier plus facilement le problème.
notice_upload_group: "Taille maximale : 200 Mo. Formats supportés : jpg, png, pdf."
procedure_info:
question: Jai un problème lors du remplissage de mon dossier
answer_html: "<p>Avez-vous bien vérifié que tous les champs obligatoires (<span class= mandatory> * </span>) sont remplis ?

View file

@ -0,0 +1,29 @@
describe Champs::EmailChamp do
subject { build(:champ_email, value: value).tap(&:valid?) }
describe '#valid?' do
context 'when the value is an email' do
let(:value) { 'jean@dupont.fr' }
it { is_expected.to be_valid }
end
context 'when the value is not an email' do
let(:value) { 'jean@' }
it { is_expected.to_not be_valid }
end
context 'when the value is blank' do
let(:value) { '' }
it { is_expected.to_not be_valid }
end
context 'when the value is nil' do
let(:value) { nil }
it { is_expected.to be_valid }
end
end
end

View file

@ -504,13 +504,12 @@ describe Procedure do
let!(:assign_to_1) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_1) }
let!(:assign_to_2) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_2) }
before do
subject do
@procedure = procedure.clone(administrateur, from_library)
@procedure.save
@procedure
end
subject { @procedure }
it { expect(subject.parent_procedure).to eq(procedure) }
describe "should keep groupe instructeurs " do
@ -623,6 +622,16 @@ describe Procedure do
let(:administrateur) { create(:administrateur) }
let(:opendata) { false }
context 'and the procedure does not have a groupe with the defaut label' do
before do
procedure.defaut_groupe_instructeur.update!(label: 'another label')
end
it "affects the first groupe as the defaut groupe" do
expect(subject.defaut_groupe_instructeur).to eq(subject.groupe_instructeurs.first)
end
end
it 'should not clone service' do
expect(subject.service).to eq(nil)
end