commit
a6ab0f01fa
29 changed files with 409 additions and 92 deletions
|
@ -83,3 +83,11 @@
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-hidden-by-user {
|
||||||
|
background-color: rgba(242, 137, 0, 0.6);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(242, 137, 0, 0.6) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -556,3 +556,9 @@
|
||||||
[data-reach-combobox-popover] {
|
[data-reach-combobox-popover] {
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fconnect-form {
|
||||||
|
input[type=password] {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class FranceConnect::ParticulierController < ApplicationController
|
class FranceConnect::ParticulierController < ApplicationController
|
||||||
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
||||||
before_action :securely_retrieve_fci, only: [:merge, :merge_with_existing_account, :merge_with_new_account]
|
before_action :securely_retrieve_fci, only: [:merge, :merge_with_existing_account, :merge_with_new_account, :mail_merge_with_existing_account, :resend_and_renew_merge_confirmation]
|
||||||
|
|
||||||
def login
|
def login
|
||||||
if FranceConnectService.enabled?
|
if FranceConnectService.enabled?
|
||||||
|
@ -19,8 +19,12 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
if preexisting_unlinked_user.nil?
|
if preexisting_unlinked_user.nil?
|
||||||
fci.associate_user!(fci.email_france_connect)
|
fci.associate_user!(fci.email_france_connect)
|
||||||
connect_france_connect_particulier(fci.user)
|
connect_france_connect_particulier(fci.user)
|
||||||
|
elsif !preexisting_unlinked_user.can_france_connect?
|
||||||
|
fci.destroy
|
||||||
|
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
||||||
else
|
else
|
||||||
redirect_to france_connect_particulier_merge_path(fci.create_merge_token!)
|
merge_token = fci.create_merge_token!
|
||||||
|
redirect_to france_connect_particulier_merge_path(merge_token)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
user = fci.user
|
user = fci.user
|
||||||
|
@ -28,7 +32,7 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
if user.can_france_connect?
|
if user.can_france_connect?
|
||||||
fci.update(updated_at: Time.zone.now)
|
fci.update(updated_at: Time.zone.now)
|
||||||
connect_france_connect_particulier(user)
|
connect_france_connect_particulier(user)
|
||||||
else
|
else # same behaviour as redirect nicely with message when instructeur/administrateur
|
||||||
fci.destroy
|
fci.destroy
|
||||||
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
||||||
end
|
end
|
||||||
|
@ -47,23 +51,37 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
|
|
||||||
if user.present? && user.valid_for_authentication? { user.valid_password?(password_params) }
|
if user.present? && user.valid_for_authentication? { user.valid_password?(password_params) }
|
||||||
if !user.can_france_connect?
|
if !user.can_france_connect?
|
||||||
flash.alert = "#{user.email} ne peut utiliser FranceConnect"
|
flash.alert = t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
||||||
|
|
||||||
render js: ajax_redirect(root_path)
|
render js: ajax_redirect(root_path)
|
||||||
else
|
else
|
||||||
@fci.update(user: user)
|
@fci.update(user: user)
|
||||||
@fci.delete_merge_token!
|
@fci.delete_merge_token!
|
||||||
|
|
||||||
flash.notice = "Les comptes FranceConnect et #{APPLICATION_NAME} sont à présent fusionnés"
|
flash.notice = t('france_connect.particulier.flash.connection_done', application_name: APPLICATION_NAME)
|
||||||
connect_france_connect_particulier(user)
|
connect_france_connect_particulier(user)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
flash.alert = 'Mauvais mot de passe'
|
flash.alert = t('france_connect.particulier.flash.invalid_password')
|
||||||
|
|
||||||
render js: helpers.render_flash
|
render js: helpers.render_flash
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mail_merge_with_existing_account
|
||||||
|
user = User.find_by(email: @fci.email_france_connect.downcase)
|
||||||
|
if user.can_france_connect?
|
||||||
|
@fci.update(user: user)
|
||||||
|
@fci.delete_merge_token!
|
||||||
|
|
||||||
|
flash.notice = t('france_connect.particulier.flash.connection_done', application_name: APPLICATION_NAME)
|
||||||
|
connect_france_connect_particulier(user)
|
||||||
|
else # same behaviour as redirect nicely with message when instructeur/administrateur
|
||||||
|
@fci.destroy
|
||||||
|
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def merge_with_new_account
|
def merge_with_new_account
|
||||||
user = User.find_by(email: sanitized_email_params)
|
user = User.find_by(email: sanitized_email_params)
|
||||||
|
|
||||||
|
@ -71,7 +89,7 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
@fci.associate_user!(sanitized_email_params)
|
@fci.associate_user!(sanitized_email_params)
|
||||||
@fci.delete_merge_token!
|
@fci.delete_merge_token!
|
||||||
|
|
||||||
flash.notice = "Les comptes FranceConnect et #{APPLICATION_NAME} sont à présent fusionnés"
|
flash.notice = t('france_connect.particulier.flash.connection_done', application_name: APPLICATION_NAME)
|
||||||
connect_france_connect_particulier(@fci.user)
|
connect_france_connect_particulier(@fci.user)
|
||||||
else
|
else
|
||||||
@email = sanitized_email_params
|
@email = sanitized_email_params
|
||||||
|
@ -79,13 +97,20 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resend_and_renew_merge_confirmation
|
||||||
|
merge_token = @fci.create_merge_token!
|
||||||
|
UserMailer.france_connect_merge_confirmation(@fci.email_france_connect, merge_token, @fci.merge_token_created_at).deliver_later
|
||||||
|
redirect_to france_connect_particulier_merge_path(merge_token),
|
||||||
|
notice: t('france_connect.particulier.flash.confirmation_mail_sent')
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def securely_retrieve_fci
|
def securely_retrieve_fci
|
||||||
@fci = FranceConnectInformation.find_by(merge_token: merge_token_params)
|
@fci = FranceConnectInformation.find_by(merge_token: merge_token_params)
|
||||||
|
|
||||||
if @fci.nil? || !@fci.valid_for_merge?
|
if @fci.nil? || !@fci.valid_for_merge?
|
||||||
flash.alert = 'Votre compte FranceConnect a expiré, veuillez recommencer.'
|
flash.alert = t('france_connect.particulier.flash.merger_token_expired', application_name: APPLICATION_NAME)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to root_path }
|
format.html { redirect_to root_path }
|
||||||
|
|
|
@ -16,7 +16,8 @@ module Users
|
||||||
before_action :store_user_location!, only: :new
|
before_action :store_user_location!, only: :new
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@user_dossiers = current_user.dossiers.includes(:procedure).order_by_updated_at.page(page)
|
@user_dossiers = current_user.dossiers.includes(:procedure).not_termine.order_by_updated_at.page(page)
|
||||||
|
@dossiers_traites = current_user.dossiers.includes(:procedure).termine.not_hidden_by_user.order_by_updated_at.page(page)
|
||||||
@dossiers_invites = current_user.dossiers_invites.includes(:procedure).order_by_updated_at.page(page)
|
@dossiers_invites = current_user.dossiers_invites.includes(:procedure).order_by_updated_at.page(page)
|
||||||
@dossiers_supprimes = current_user.deleted_dossiers.order_by_updated_at.page(page)
|
@dossiers_supprimes = current_user.deleted_dossiers.order_by_updated_at.page(page)
|
||||||
@dossier_transfers = DossierTransfer
|
@dossier_transfers = DossierTransfer
|
||||||
|
@ -25,7 +26,7 @@ module Users
|
||||||
.where(email: current_user.email)
|
.where(email: current_user.email)
|
||||||
.page(page)
|
.page(page)
|
||||||
@dossiers_close_to_expiration = current_user.dossiers.close_to_expiration.page(page)
|
@dossiers_close_to_expiration = current_user.dossiers.close_to_expiration.page(page)
|
||||||
@statut = statut(@user_dossiers, @dossiers_invites, @dossiers_supprimes, @dossier_transfers, @dossiers_close_to_expiration, params[:statut])
|
@statut = statut(@user_dossiers, @dossiers_traites, @dossiers_invites, @dossiers_supprimes, @dossier_transfers, @dossiers_close_to_expiration, params[:statut])
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -287,14 +288,22 @@ module Users
|
||||||
@transfer = DossierTransfer.new(dossiers: current_user.dossiers)
|
@transfer = DossierTransfer.new(dossiers: current_user.dossiers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hide_dossier
|
||||||
|
dossier = current_user.dossiers.includes(:user, procedure: :administrateurs).find(params[:id])
|
||||||
|
dossier.update(hidden_by_user_at: Time.zone.now)
|
||||||
|
flash.notice = t('users.dossiers.ask_deletion.deleted_dossier')
|
||||||
|
redirect_to dossiers_path
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# if the status tab is filled, then this tab
|
# if the status tab is filled, then this tab
|
||||||
# else first filled tab
|
# else first filled tab
|
||||||
# else mes-dossiers
|
# else en-cours
|
||||||
def statut(mes_dossiers, dossiers_invites, dossiers_supprimes, dossier_transfers, dossiers_close_to_expiration, params_statut)
|
def statut(mes_dossiers, dossiers_traites, dossiers_invites, dossiers_supprimes, dossier_transfers, dossiers_close_to_expiration, params_statut)
|
||||||
tabs = {
|
tabs = {
|
||||||
'mes-dossiers' => mes_dossiers.present?,
|
'en-cours' => mes_dossiers.present?,
|
||||||
|
'traites' => dossiers_traites.present?,
|
||||||
'dossiers-invites' => dossiers_invites.present?,
|
'dossiers-invites' => dossiers_invites.present?,
|
||||||
'dossiers-supprimes' => dossiers_supprimes.present?,
|
'dossiers-supprimes' => dossiers_supprimes.present?,
|
||||||
'dossiers-transferes' => dossier_transfers.present?,
|
'dossiers-transferes' => dossier_transfers.present?,
|
||||||
|
@ -306,7 +315,7 @@ module Users
|
||||||
tabs
|
tabs
|
||||||
.filter { |_tab, filled| filled }
|
.filter { |_tab, filled| filled }
|
||||||
.map { |tab, _| tab }
|
.map { |tab, _| tab }
|
||||||
.first || 'mes-dossiers'
|
.first || 'en-cours'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ function ComboCommunesSearch(params) {
|
||||||
inputId={!departementCode ? inputId : null}
|
inputId={!departementCode ? inputId : null}
|
||||||
aria-describedby={departementDescribedBy}
|
aria-describedby={departementDescribedBy}
|
||||||
placeholder={placeholderDepartement}
|
placeholder={placeholderDepartement}
|
||||||
|
addForeignDepartement={false}
|
||||||
required={params.mandatory}
|
required={params.mandatory}
|
||||||
onChange={(value, result) => {
|
onChange={(value, result) => {
|
||||||
setDepartementCode(result?.code);
|
setDepartementCode(result?.code);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { QueryClientProvider } from 'react-query';
|
import { QueryClientProvider } from 'react-query';
|
||||||
import { matchSorter } from 'match-sorter';
|
import { matchSorter } from 'match-sorter';
|
||||||
|
|
||||||
|
@ -16,14 +17,19 @@ function expandResultsWithForeignDepartement(term, results) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ComboDepartementsSearch(params) {
|
export function ComboDepartementsSearch({
|
||||||
|
addForeignDepartement = true,
|
||||||
|
...params
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<ComboSearch
|
<ComboSearch
|
||||||
{...params}
|
{...params}
|
||||||
scope="departements"
|
scope="departements"
|
||||||
minimumInputLength={1}
|
minimumInputLength={1}
|
||||||
transformResult={({ code, nom }) => [code, `${code} - ${nom}`]}
|
transformResult={({ code, nom }) => [code, `${code} - ${nom}`]}
|
||||||
transformResults={expandResultsWithForeignDepartement}
|
transformResults={
|
||||||
|
addForeignDepartement ? expandResultsWithForeignDepartement : undefined
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,4 +45,9 @@ function ComboDepartementsSearchDefault(params) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComboDepartementsSearch.propTypes = {
|
||||||
|
...ComboSearch.propTypes,
|
||||||
|
addForeignDepartement: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
export default ComboDepartementsSearchDefault;
|
export default ComboDepartementsSearchDefault;
|
||||||
|
|
|
@ -20,6 +20,14 @@ class UserMailer < ApplicationMailer
|
||||||
mail(to: requested_email, subject: @subject)
|
mail(to: requested_email, subject: @subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def france_connect_merge_confirmation(email, merge_token, merge_token_created_at)
|
||||||
|
@merge_token = merge_token
|
||||||
|
@merge_token_created_at = merge_token_created_at
|
||||||
|
@subject = "Veuillez confirmer la fusion de compte"
|
||||||
|
|
||||||
|
mail(to: email, subject: @subject)
|
||||||
|
end
|
||||||
|
|
||||||
def invite_instructeur(user, reset_password_token)
|
def invite_instructeur(user, reset_password_token)
|
||||||
@reset_password_token = reset_password_token
|
@reset_password_token = reset_password_token
|
||||||
@user = user
|
@user = user
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
# en_instruction_at :datetime
|
# en_instruction_at :datetime
|
||||||
# groupe_instructeur_updated_at :datetime
|
# groupe_instructeur_updated_at :datetime
|
||||||
# hidden_at :datetime
|
# hidden_at :datetime
|
||||||
|
# hidden_by_user_at :datetime
|
||||||
# identity_updated_at :datetime
|
# identity_updated_at :datetime
|
||||||
# last_avis_updated_at :datetime
|
# last_avis_updated_at :datetime
|
||||||
# last_champ_private_updated_at :datetime
|
# last_champ_private_updated_at :datetime
|
||||||
|
@ -206,9 +207,11 @@ class Dossier < ApplicationRecord
|
||||||
scope :state_en_construction_ou_instruction, -> { where(state: EN_CONSTRUCTION_OU_INSTRUCTION) }
|
scope :state_en_construction_ou_instruction, -> { where(state: EN_CONSTRUCTION_OU_INSTRUCTION) }
|
||||||
scope :state_instruction_commencee, -> { where(state: INSTRUCTION_COMMENCEE) }
|
scope :state_instruction_commencee, -> { where(state: INSTRUCTION_COMMENCEE) }
|
||||||
scope :state_termine, -> { where(state: TERMINE) }
|
scope :state_termine, -> { where(state: TERMINE) }
|
||||||
|
scope :state_not_termine, -> { where.not(state: TERMINE) }
|
||||||
|
|
||||||
scope :archived, -> { where(archived: true) }
|
scope :archived, -> { where(archived: true) }
|
||||||
scope :not_archived, -> { where(archived: false) }
|
scope :not_archived, -> { where(archived: false) }
|
||||||
|
scope :not_hidden_by_user, -> { where(hidden_by_user_at: nil) }
|
||||||
|
|
||||||
scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) }
|
scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) }
|
||||||
scope :order_by_created_at, -> (order = :asc) { order(en_construction_at: order, created_at: order, id: order) }
|
scope :order_by_created_at, -> (order = :asc) { order(en_construction_at: order, created_at: order, id: order) }
|
||||||
|
@ -229,6 +232,7 @@ class Dossier < ApplicationRecord
|
||||||
scope :en_construction, -> { not_archived.state_en_construction }
|
scope :en_construction, -> { not_archived.state_en_construction }
|
||||||
scope :en_instruction, -> { not_archived.state_en_instruction }
|
scope :en_instruction, -> { not_archived.state_en_instruction }
|
||||||
scope :termine, -> { not_archived.state_termine }
|
scope :termine, -> { not_archived.state_termine }
|
||||||
|
scope :not_termine, -> { state_not_termine }
|
||||||
scope :processed_in_month, -> (month) do
|
scope :processed_in_month, -> (month) do
|
||||||
state_termine
|
state_termine
|
||||||
.joins(:traitements)
|
.joins(:traitements)
|
||||||
|
@ -1091,6 +1095,10 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hidden_by_user?
|
||||||
|
self.hidden_by_user_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_missing_traitemets
|
def create_missing_traitemets
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class DossierProjectionService
|
class DossierProjectionService
|
||||||
class DossierProjection < Struct.new(:dossier_id, :state, :archived, :columns)
|
class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :columns)
|
||||||
end
|
end
|
||||||
|
|
||||||
TABLE = 'table'
|
TABLE = 'table'
|
||||||
|
@ -20,8 +20,9 @@ class DossierProjectionService
|
||||||
def self.project(dossiers_ids, fields)
|
def self.project(dossiers_ids, fields)
|
||||||
state_field = { TABLE => 'self', COLUMN => 'state' }
|
state_field = { TABLE => 'self', COLUMN => 'state' }
|
||||||
archived_field = { TABLE => 'self', COLUMN => 'archived' }
|
archived_field = { TABLE => 'self', COLUMN => 'archived' }
|
||||||
|
hidden_by_user_at_field = { TABLE => 'self', COLUMN => 'hidden_by_user_at' }
|
||||||
|
|
||||||
([state_field, archived_field] + fields) # the view needs state and archived dossier attributes
|
([state_field, archived_field, hidden_by_user_at_field] + fields) # the view needs state and archived dossier attributes
|
||||||
.each { |f| f[:id_value_h] = {} }
|
.each { |f| f[:id_value_h] = {} }
|
||||||
.group_by { |f| f[TABLE] } # one query per table
|
.group_by { |f| f[TABLE] } # one query per table
|
||||||
.each do |table, fields|
|
.each do |table, fields|
|
||||||
|
@ -45,7 +46,7 @@ class DossierProjectionService
|
||||||
.pluck(:id, *fields.map { |f| f[COLUMN].to_sym })
|
.pluck(:id, *fields.map { |f| f[COLUMN].to_sym })
|
||||||
.each do |id, *columns|
|
.each do |id, *columns|
|
||||||
fields.zip(columns).each do |field, value|
|
fields.zip(columns).each do |field, value|
|
||||||
if [state_field, archived_field].include?(field)
|
if [state_field, archived_field, hidden_by_user_at_field].include?(field)
|
||||||
field[:id_value_h][id] = value
|
field[:id_value_h][id] = value
|
||||||
else
|
else
|
||||||
field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime
|
field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime
|
||||||
|
@ -98,6 +99,7 @@ class DossierProjectionService
|
||||||
dossier_id,
|
dossier_id,
|
||||||
state_field[:id_value_h][dossier_id],
|
state_field[:id_value_h][dossier_id],
|
||||||
archived_field[:id_value_h][dossier_id],
|
archived_field[:id_value_h][dossier_id],
|
||||||
|
hidden_by_user_at_field[:id_value_h][dossier_id],
|
||||||
fields.map { |f| f[:id_value_h][dossier_id] }
|
fields.map { |f| f[:id_value_h][dossier_id] }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
= link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path), class: ['button large expand']
|
= link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path), class: ['button large expand']
|
||||||
|
|
||||||
- else
|
- else
|
||||||
- dossiers = current_user.dossiers.where(revision: @revision.draft? ? @revision : @procedure.revisions.where.not(id: @procedure.draft_revision_id))
|
- dossiers = current_user.dossiers.where(hidden_by_user_at: nil, revision: @revision.draft? ? @revision : @procedure.revisions.where.not(id: @procedure.draft_revision_id))
|
||||||
- drafts = dossiers.merge(Dossier.state_brouillon)
|
- drafts = dossiers.merge(Dossier.state_brouillon)
|
||||||
- not_drafts = dossiers.merge(Dossier.state_not_brouillon)
|
- not_drafts = dossiers.merge(Dossier.state_not_brouillon)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
%p
|
%p
|
||||||
Le compte #{email} existe déjà sur #{APPLICATION_NAME}
|
= t('.already_exists', email: email, application_name: APPLICATION_NAME)
|
||||||
%br
|
%br
|
||||||
entrez votre mot de passe pour fusionner les comptes
|
= t('.fill_in_password')
|
||||||
|
|
||||||
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form' do
|
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form fconnect-form' do
|
||||||
= hidden_field_tag :merge_token, merge_token
|
= hidden_field_tag :merge_token, merge_token
|
||||||
= hidden_field_tag :email, email
|
= hidden_field_tag :email, email
|
||||||
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
= label_tag :password, t('views.registrations.new.password_label', min_length: 8)
|
||||||
= password_field_tag :password, nil, autocomplete: 'current-password', id: 'password-for-another-account'
|
= password_field_tag :password, nil, autocomplete: 'current-password', id: 'password-for-another-account'
|
||||||
= button_tag 'revenir en arrière', type: 'button', class: 'button secondary', onclick: 'DS.showNewAccount(event);'
|
.mb-2
|
||||||
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
= t('views.users.sessions.new.reset_password')
|
||||||
|
= link_to france_connect_particulier_resend_and_renew_merge_confirmation_path(merge_token: merge_token), method: :post do
|
||||||
|
= t('france_connect.particulier.merge.link_confirm_by_email')
|
||||||
|
= button_tag t('.back'), type: 'button', class: 'button secondary', onclick: 'DS.showNewAccount(event);'
|
||||||
|
= submit_tag t('france_connect.particulier.merge.button_merge'), class: 'button primary'
|
||||||
|
|
|
@ -1,44 +1,46 @@
|
||||||
= content_for :title, "Fusion des comptes FC et #{APPLICATION_NAME}"
|
= content_for :title, "Fusion des comptes FC et #{APPLICATION_NAME}"
|
||||||
|
|
||||||
.container
|
.container
|
||||||
%h1.page-title Fusion des comptes FranceConnect et #{APPLICATION_NAME}
|
%h1.page-title= t('.title', application_name: APPLICATION_NAME)
|
||||||
|
|
||||||
%p
|
%p= t('.subtitle', email: sanitize(@fci.email_france_connect), application_name: APPLICATION_NAME).html_safe
|
||||||
Bonjour,
|
|
||||||
%br
|
|
||||||
%br
|
|
||||||
Votre compte FranceConnect utilise <b class='bold'>#{@fci.email_france_connect}</b> comme email de contact.
|
|
||||||
%br
|
|
||||||
Or il existe un compte sur #{APPLICATION_NAME} avec cet email.
|
|
||||||
|
|
||||||
.form.mt-2
|
.form.mt-2
|
||||||
%label Ce compte #{@fci.email_france_connect} vous appartient-il ?
|
%label= t('.label_select_merge_flow', email: @fci.email_france_connect)
|
||||||
%fieldset.radios
|
%fieldset.radios
|
||||||
%label{ onclick: "DS.showFusion(event);" }
|
%label{ onclick: "DS.showFusion(event);" }
|
||||||
= radio_button_tag :value, true, false, autocomplete: "off", id: 'it-is-mine'
|
= radio_button_tag :value, true, false, autocomplete: "off", id: 'it-is-mine'
|
||||||
Oui
|
= t('utils.yes')
|
||||||
|
|
||||||
%label{ onclick: "DS.showNewAccount(event);" }
|
%label{ onclick: "DS.showNewAccount(event);" }
|
||||||
= radio_button_tag :value, false, false, autocomplete: "off", id: 'it-is-not-mine'
|
= radio_button_tag :value, false, false, autocomplete: "off", id: 'it-is-not-mine'
|
||||||
Non
|
= t('utils.no')
|
||||||
|
|
||||||
.fusion.hidden
|
.fusion.hidden
|
||||||
%p Pour les fusionner, entrez votre mot de passe
|
%p= t('.title_fill_in_password')
|
||||||
|
|
||||||
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form' do
|
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form fconnect-form' do
|
||||||
= hidden_field_tag :merge_token, @fci.merge_token
|
= hidden_field_tag :merge_token, @fci.merge_token
|
||||||
= hidden_field_tag :email, @fci.email_france_connect
|
= hidden_field_tag :email, @fci.email_france_connect
|
||||||
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
|
||||||
= password_field_tag :password, nil, autocomplete: 'current-password'
|
= label_tag :password, t('views.registrations.new.password_label', min_length: 8)
|
||||||
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
= password_field_tag :password, nil, autocomplete: 'current-password', class: 'mb-1'
|
||||||
|
.mb-2
|
||||||
|
= t('views.users.sessions.new.reset_password')
|
||||||
|
= link_to france_connect_particulier_resend_and_renew_merge_confirmation_path(merge_token: @fci.merge_token), method: :post do
|
||||||
|
= t('.link_confirm_by_email')
|
||||||
|
|
||||||
|
= submit_tag t('.button_merge'), class: 'button primary'
|
||||||
|
|
||||||
|
|
||||||
.new-account.hidden
|
.new-account.hidden
|
||||||
%p Donnez-nous alors le mail que #{APPLICATION_NAME} utilisera pour vous contacter
|
%p= t('.title_fill_in_email', application_name: APPLICATION_NAME)
|
||||||
|
|
||||||
= form_tag france_connect_particulier_merge_with_new_account_path, remote: true, class: 'mt-2 form' do
|
= form_tag france_connect_particulier_merge_with_new_account_path, remote: true, class: 'mt-2 form' do
|
||||||
= hidden_field_tag :merge_token, @fci.merge_token
|
= hidden_field_tag :merge_token, @fci.merge_token
|
||||||
= label_tag :email, 'Email (nom@site.com)'
|
= label_tag :email, t('views.registrations.new.email_label')
|
||||||
= email_field_tag :email
|
= email_field_tag :email, "", required: true
|
||||||
= submit_tag 'Utiliser ce mail', class: 'button primary'
|
= submit_tag t('.button_use_this_email'), class: 'button primary'
|
||||||
|
|
||||||
|
|
||||||
.new-account-password-confirmation.hidden
|
.new-account-password-confirmation.hidden
|
||||||
|
|
|
@ -100,8 +100,7 @@
|
||||||
%tbody
|
%tbody
|
||||||
- @projected_dossiers.each do |p|
|
- @projected_dossiers.each do |p|
|
||||||
- path = instructeur_dossier_path(@procedure, p.dossier_id)
|
- path = instructeur_dossier_path(@procedure, p.dossier_id)
|
||||||
|
%tr{ class: [p.hidden_by_user_at.present? && "file-hidden-by-user"] }
|
||||||
%tr
|
|
||||||
%td.folder-col
|
%td.folder-col
|
||||||
%a.cell-link{ href: path }
|
%a.cell-link{ href: path }
|
||||||
%span.icon.folder
|
%span.icon.folder
|
||||||
|
@ -113,7 +112,9 @@
|
||||||
|
|
||||||
- p.columns.each do |column|
|
- p.columns.each do |column|
|
||||||
%td
|
%td
|
||||||
%a.cell-link{ href: path }= column
|
%a.cell-link{ href: path }
|
||||||
|
= column
|
||||||
|
= "- #{t('views.instructeurs.dossiers.deleted_by_user')}" if p.hidden_by_user_at.present?
|
||||||
|
|
||||||
%td.status-col
|
%td.status-col
|
||||||
%a.cell-link{ href: path }= status_badge(p.state)
|
%a.cell-link{ href: path }= status_badge(p.state)
|
||||||
|
|
20
app/views/user_mailer/france_connect_merge_confirmation.haml
Normal file
20
app/views/user_mailer/france_connect_merge_confirmation.haml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
- content_for(:title, @subject)
|
||||||
|
|
||||||
|
%p
|
||||||
|
Bonjour,
|
||||||
|
|
||||||
|
%p
|
||||||
|
Pour confirmer la fusion de votre compte, veuillez cliquer sur le lien suivant :
|
||||||
|
= round_button 'Je confirme', france_connect_particulier_mail_merge_with_existing_account_url(merge_token: @merge_token), :primary
|
||||||
|
|
||||||
|
%p
|
||||||
|
Vous pouvez aussi visiter ce lien : #{link_to france_connect_particulier_mail_merge_with_existing_account_url(merge_token: @merge_token), france_connect_particulier_mail_merge_with_existing_account_url(merge_token: @merge_token)}
|
||||||
|
|
||||||
|
%p Ce lien est valide #{distance_of_time_in_words(FranceConnectInformation::MERGE_VALIDITY)}, jusqu'à #{@merge_token_created_at.strftime("%d-%m-%Y à %H:%M (%Z)")}
|
||||||
|
|
||||||
|
%p
|
||||||
|
Si vous n’êtes pas à l’origine de cette demande, vous pouvez ignorer ce message. Et si vous avez besoin d’assistance, n’hésitez pas à nous contacter à
|
||||||
|
= succeed '.' do
|
||||||
|
= mail_to CONTACT_EMAIL
|
||||||
|
|
||||||
|
= render partial: "layouts/mailers/signature"
|
|
@ -2,7 +2,8 @@
|
||||||
- has_delete_action = dossier.can_be_deleted_by_user?
|
- has_delete_action = dossier.can_be_deleted_by_user?
|
||||||
- has_new_dossier_action = dossier.procedure.accepts_new_dossiers?
|
- has_new_dossier_action = dossier.procedure.accepts_new_dossiers?
|
||||||
- has_transfer_action = dossier.user == current_user
|
- has_transfer_action = dossier.user == current_user
|
||||||
- has_actions = has_edit_action || has_delete_action || has_new_dossier_action || has_transfer_action
|
- has_hide_action = dossier.termine? && dossier.hidden_by_user_at.nil?
|
||||||
|
- has_actions = has_edit_action || has_delete_action || has_new_dossier_action || has_transfer_action || has_hide_action
|
||||||
|
|
||||||
- if has_actions
|
- if has_actions
|
||||||
.dropdown.user-dossier-actions
|
.dropdown.user-dossier-actions
|
||||||
|
@ -44,3 +45,10 @@
|
||||||
%span.icon.delete
|
%span.icon.delete
|
||||||
.dropdown-description
|
.dropdown-description
|
||||||
= t('views.users.dossiers.dossier_action.delete_dossier')
|
= t('views.users.dossiers.dossier_action.delete_dossier')
|
||||||
|
- if has_hide_action
|
||||||
|
%li
|
||||||
|
= link_to hide_dossier_dossier_path(dossier), method: :patch do
|
||||||
|
%span.icon.delete
|
||||||
|
.dropdown-description
|
||||||
|
= t('views.users.dossiers.dossier_action.hide_dossier')
|
||||||
|
|
||||||
|
|
|
@ -15,25 +15,31 @@
|
||||||
- else
|
- else
|
||||||
%h1.page-title= t('views.users.dossiers.index.dossiers')
|
%h1.page-title= t('views.users.dossiers.index.dossiers')
|
||||||
%ul.tabs
|
%ul.tabs
|
||||||
- if @user_dossiers.count > 0
|
- if @user_dossiers.present?
|
||||||
= tab_item(t('pluralize.mes_dossiers', count: @user_dossiers.count),
|
= tab_item(t('pluralize.en_cours', count: @user_dossiers.count),
|
||||||
dossiers_path(statut: 'mes-dossiers'),
|
dossiers_path(statut: 'en-cours'),
|
||||||
active: @statut == 'mes-dossiers',
|
active: @statut == 'en-cours',
|
||||||
badge: number_with_html_delimiter(@user_dossiers.count))
|
badge: number_with_html_delimiter(@user_dossiers.count))
|
||||||
|
|
||||||
- if @dossiers_invites.count > 0
|
- if @dossiers_traites.present?
|
||||||
|
= tab_item(t('pluralize.traites', count: @dossiers_traites.count),
|
||||||
|
dossiers_path(statut: 'traites'),
|
||||||
|
active: @statut == 'traites',
|
||||||
|
badge: number_with_html_delimiter(@dossiers_traites.count))
|
||||||
|
|
||||||
|
- if @dossiers_invites.present?
|
||||||
= tab_item(t('pluralize.dossiers_invites', count: @dossiers_invites.count),
|
= tab_item(t('pluralize.dossiers_invites', count: @dossiers_invites.count),
|
||||||
dossiers_path(statut: 'dossiers-invites'),
|
dossiers_path(statut: 'dossiers-invites'),
|
||||||
active: @statut == 'dossiers-invites',
|
active: @statut == 'dossiers-invites',
|
||||||
badge: number_with_html_delimiter(@dossiers_invites.count))
|
badge: number_with_html_delimiter(@dossiers_invites.count))
|
||||||
|
|
||||||
- if @dossiers_supprimes.count > 0
|
- if @dossiers_supprimes.present?
|
||||||
= tab_item(t('pluralize.dossiers_supprimes', count: @dossiers_supprimes.count),
|
= tab_item(t('pluralize.dossiers_supprimes', count: @dossiers_supprimes.count),
|
||||||
dossiers_path(statut: 'dossiers-supprimes'),
|
dossiers_path(statut: 'dossiers-supprimes'),
|
||||||
active: @statut == 'dossiers-supprimes',
|
active: @statut == 'dossiers-supprimes',
|
||||||
badge: number_with_html_delimiter(@dossiers_supprimes.count))
|
badge: number_with_html_delimiter(@dossiers_supprimes.count))
|
||||||
|
|
||||||
- if @dossier_transfers.count > 0
|
- if @dossier_transfers.present?
|
||||||
= tab_item(t('pluralize.dossiers_transferes', count: @dossier_transfers.count),
|
= tab_item(t('pluralize.dossiers_transferes', count: @dossier_transfers.count),
|
||||||
dossiers_path(statut: 'dossiers-transferes'),
|
dossiers_path(statut: 'dossiers-transferes'),
|
||||||
active: @statut == 'dossiers-transferes',
|
active: @statut == 'dossiers-transferes',
|
||||||
|
@ -46,9 +52,12 @@
|
||||||
badge: number_with_html_delimiter(@dossiers_close_to_expiration.count))
|
badge: number_with_html_delimiter(@dossiers_close_to_expiration.count))
|
||||||
|
|
||||||
.container
|
.container
|
||||||
- if @statut == "mes-dossiers"
|
- if @statut == "en-cours"
|
||||||
= render partial: "dossiers_list", locals: { dossiers: @user_dossiers }
|
= render partial: "dossiers_list", locals: { dossiers: @user_dossiers }
|
||||||
|
|
||||||
|
- if @statut == "traites"
|
||||||
|
= render partial: "dossiers_list", locals: { dossiers: @dossiers_traites }
|
||||||
|
|
||||||
- if @statut == "dossiers-invites"
|
- if @statut == "dossiers-invites"
|
||||||
= render partial: "dossiers_list", locals: { dossiers: @dossiers_invites }
|
= render partial: "dossiers_list", locals: { dossiers: @dossiers_invites }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,36 @@
|
||||||
{
|
{
|
||||||
"ignored_warnings": [
|
"ignored_warnings": [
|
||||||
|
{
|
||||||
|
"warning_type": "Cross-Site Scripting",
|
||||||
|
"warning_code": 2,
|
||||||
|
"fingerprint": "42099f4550a8377f455e830e8ab645cecd5806248481c5c646b4e17548c3cb07",
|
||||||
|
"check_name": "CrossSiteScripting",
|
||||||
|
"message": "Unescaped model attribute",
|
||||||
|
"file": "app/views/france_connect/particulier/merge.html.haml",
|
||||||
|
"line": 6,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
|
||||||
|
"code": "t(\".subtitle\", :email => sanitize(FranceConnectInformation.find_by(:merge_token => merge_token_params).email_france_connect), :application_name => (APPLICATION_NAME))",
|
||||||
|
"render_path": [
|
||||||
|
{
|
||||||
|
"type": "controller",
|
||||||
|
"class": "FranceConnect::ParticulierController",
|
||||||
|
"method": "merge",
|
||||||
|
"line": 48,
|
||||||
|
"file": "app/controllers/france_connect/particulier_controller.rb",
|
||||||
|
"rendered": {
|
||||||
|
"name": "france_connect/particulier/merge",
|
||||||
|
"file": "app/views/france_connect/particulier/merge.html.haml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": {
|
||||||
|
"type": "template",
|
||||||
|
"template": "france_connect/particulier/merge"
|
||||||
|
},
|
||||||
|
"user_input": "FranceConnectInformation.find_by(:merge_token => merge_token_params).email_france_connect",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"note": "explicitely sanitized even if we are using html_safe"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"warning_type": "Cross-Site Scripting",
|
"warning_type": "Cross-Site Scripting",
|
||||||
"warning_code": 2,
|
"warning_code": 2,
|
||||||
|
@ -15,7 +46,7 @@
|
||||||
"type": "controller",
|
"type": "controller",
|
||||||
"class": "Users::DossiersController",
|
"class": "Users::DossiersController",
|
||||||
"method": "merci",
|
"method": "merci",
|
||||||
"line": 188,
|
"line": 193,
|
||||||
"file": "app/controllers/users/dossiers_controller.rb",
|
"file": "app/controllers/users/dossiers_controller.rb",
|
||||||
"rendered": {
|
"rendered": {
|
||||||
"name": "users/dossiers/merci",
|
"name": "users/dossiers/merci",
|
||||||
|
@ -58,7 +89,7 @@
|
||||||
"check_name": "Redirect",
|
"check_name": "Redirect",
|
||||||
"message": "Possible unprotected redirect",
|
"message": "Possible unprotected redirect",
|
||||||
"file": "app/controllers/instructeurs/procedures_controller.rb",
|
"file": "app/controllers/instructeurs/procedures_controller.rb",
|
||||||
"line": 180,
|
"line": 190,
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
||||||
"code": "redirect_to(Export.find_or_create_export(params[:export_format], (params[:time_span_type] or \"everything\"), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url)",
|
"code": "redirect_to(Export.find_or_create_export(params[:export_format], (params[:time_span_type] or \"everything\"), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url)",
|
||||||
"render_path": null,
|
"render_path": null,
|
||||||
|
@ -72,6 +103,6 @@
|
||||||
"note": ""
|
"note": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updated": "2021-09-02 16:12:11 -0500",
|
"updated": "2021-11-23 14:09:21 +0100",
|
||||||
"brakeman_version": "5.1.1"
|
"brakeman_version": "5.1.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,9 @@ en:
|
||||||
form: "Form"
|
form: "Form"
|
||||||
edit_siret: "Edit SIRET"
|
edit_siret: "Edit SIRET"
|
||||||
edit_identity: "Edit identity data"
|
edit_identity: "Edit identity data"
|
||||||
|
instructeurs:
|
||||||
|
dossiers:
|
||||||
|
deleted_by_user: "File deleted by user"
|
||||||
users:
|
users:
|
||||||
dossiers:
|
dossiers:
|
||||||
autosave:
|
autosave:
|
||||||
|
@ -191,6 +194,7 @@ en:
|
||||||
edit_dossier: "Edit the file"
|
edit_dossier: "Edit the file"
|
||||||
start_other_dossier: "Start an other file"
|
start_other_dossier: "Start an other file"
|
||||||
delete_dossier: "Delete the file"
|
delete_dossier: "Delete the file"
|
||||||
|
hide_dossier: "Delete from your screen"
|
||||||
transfer_dossier: "Transfer the file"
|
transfer_dossier: "Transfer the file"
|
||||||
edit_draft: "Edit the draft"
|
edit_draft: "Edit the draft"
|
||||||
actions: "Actions"
|
actions: "Actions"
|
||||||
|
@ -326,10 +330,14 @@ en:
|
||||||
zero: archived
|
zero: archived
|
||||||
one: archived
|
one: archived
|
||||||
other: archived
|
other: archived
|
||||||
mes_dossiers:
|
en_cours:
|
||||||
zero: my file
|
zero: in progress
|
||||||
one: my file
|
one: in progress
|
||||||
other: my files
|
other: in progress
|
||||||
|
traites:
|
||||||
|
zero: finished
|
||||||
|
one: finished
|
||||||
|
other: finished
|
||||||
dossiers_invites:
|
dossiers_invites:
|
||||||
zero: guest file
|
zero: guest file
|
||||||
one: guest file
|
one: guest file
|
||||||
|
@ -382,3 +390,23 @@ en:
|
||||||
identity_saved: "Identity data is registred"
|
identity_saved: "Identity data is registred"
|
||||||
attestation:
|
attestation:
|
||||||
no_longer_available: "The certificate is no longer available on this file."
|
no_longer_available: "The certificate is no longer available on this file."
|
||||||
|
france_connect:
|
||||||
|
particulier:
|
||||||
|
password_confirmation:
|
||||||
|
back: 'back to previous step'
|
||||||
|
already_exists: An account with %{email} already existis on %{application_name}
|
||||||
|
fill_in_password: fill in your password to merge your accounts
|
||||||
|
merge:
|
||||||
|
title: "Merge your account FranceConnect and %{application_name}"
|
||||||
|
subtitle: "Hello,<br /><br />Your account FranceConnect uses <b class='bold'>%{email}</b> as contact email.<br />But there is an existing %{application_name} account using this email."
|
||||||
|
label_select_merge_flow: Is %{email} one of your email account ?
|
||||||
|
title_fill_in_password: To merge your accounts fill in your password
|
||||||
|
button_merge: Merge accounts
|
||||||
|
title_fill_in_email: Fill in the email that %{application_name} will use to contact you
|
||||||
|
button_use_this_email: Use this email
|
||||||
|
link_confirm_by_email: Confirm by receiving an email
|
||||||
|
flash:
|
||||||
|
confirmation_mail_sent: "An email with the confirmation link has been sent, please click on the link."
|
||||||
|
invalid_password: "The password is not correct."
|
||||||
|
connection_done: "The accounts for FranceConnect and %{application_name} are now merged."
|
||||||
|
merger_token_expired: "Le delay to merge your FranceConnect and %{application_name} accounts is expired. Please retry."
|
||||||
|
|
|
@ -128,6 +128,9 @@ fr:
|
||||||
form: "Formulaire"
|
form: "Formulaire"
|
||||||
edit_siret: "Modifier le SIRET"
|
edit_siret: "Modifier le SIRET"
|
||||||
edit_identity: "Modifier l’identité"
|
edit_identity: "Modifier l’identité"
|
||||||
|
instructeurs:
|
||||||
|
dossiers:
|
||||||
|
deleted_by_user: "Dossier supprimé par l'usager"
|
||||||
users:
|
users:
|
||||||
dossiers:
|
dossiers:
|
||||||
autosave:
|
autosave:
|
||||||
|
@ -187,6 +190,7 @@ fr:
|
||||||
edit_dossier: "Modifier le dossier"
|
edit_dossier: "Modifier le dossier"
|
||||||
start_other_dossier: "Commencer un autre dossier"
|
start_other_dossier: "Commencer un autre dossier"
|
||||||
delete_dossier: "Supprimer le dossier"
|
delete_dossier: "Supprimer le dossier"
|
||||||
|
hide_dossier: "Supprimer de votre interface"
|
||||||
transfer_dossier: "Transferer le dossier"
|
transfer_dossier: "Transferer le dossier"
|
||||||
edit_draft: "Modifier le brouillon"
|
edit_draft: "Modifier le brouillon"
|
||||||
actions: "Actions"
|
actions: "Actions"
|
||||||
|
@ -334,10 +338,14 @@ fr:
|
||||||
zero: archivé
|
zero: archivé
|
||||||
one: archivé
|
one: archivé
|
||||||
other: archivés
|
other: archivés
|
||||||
mes_dossiers:
|
en_cours:
|
||||||
zero: mon dossier
|
zero: en cours
|
||||||
one: mon dossier
|
one: en cours
|
||||||
other: mes dossiers
|
other: en cours
|
||||||
|
traites:
|
||||||
|
zero: traité
|
||||||
|
one: traité
|
||||||
|
other: traités
|
||||||
dossiers_invites:
|
dossiers_invites:
|
||||||
zero: dossier invité
|
zero: dossier invité
|
||||||
one: dossier invité
|
one: dossier invité
|
||||||
|
@ -421,3 +429,23 @@ fr:
|
||||||
ready: "Validé"
|
ready: "Validé"
|
||||||
needs_configuration: "À configurer"
|
needs_configuration: "À configurer"
|
||||||
configure_api_particulier_token: "Configurer le jeton API particulier"
|
configure_api_particulier_token: "Configurer le jeton API particulier"
|
||||||
|
france_connect:
|
||||||
|
particulier:
|
||||||
|
password_confirmation:
|
||||||
|
back: 'revenir en arrière'
|
||||||
|
already_exists: Le compte %{email} existe déjà sur %{application_name}
|
||||||
|
fill_in_password: entrez votre mot de passe pour fusionner les comptes
|
||||||
|
merge:
|
||||||
|
title: "Fusion des comptes FranceConnect et %{application_name}"
|
||||||
|
subtitle: "Bonjour,<br /><br />Votre compte FranceConnect utilise <b class='bold'>%{email}</b> comme email de contact.<br />Or il existe un compte sur %{application_name} avec cet email."
|
||||||
|
label_select_merge_flow: Ce compte %{email} vous appartient-il ?
|
||||||
|
title_fill_in_password: Pour les fusionner, entrez votre mot de passe
|
||||||
|
button_merge: Fusionner les comptes
|
||||||
|
title_fill_in_email: Donnez-nous alors le mail que %{application_name} utilisera pour vous contacter
|
||||||
|
button_use_this_email: Utiliser ce mail
|
||||||
|
link_confirm_by_email: Confirmer mon compte par email
|
||||||
|
flash:
|
||||||
|
confirmation_mail_sent: "Nous venons de vous envoyer le mail de confirmation, veuillez cliquer sur le lien contenu dans ce mail pour fusionner vos comptes"
|
||||||
|
invalid_password: "Mauvais mot de passe"
|
||||||
|
connection_done: "Les comptes FranceConnect et %{application_name} sont à présent fusionnés"
|
||||||
|
merger_token_expired: "Le délai pour fusionner les comptes FranceConnect et %{application_name} est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes."
|
||||||
|
|
|
@ -125,6 +125,8 @@ Rails.application.routes.draw do
|
||||||
get 'particulier' => 'particulier#login'
|
get 'particulier' => 'particulier#login'
|
||||||
get 'particulier/callback' => 'particulier#callback'
|
get 'particulier/callback' => 'particulier#callback'
|
||||||
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
||||||
|
get 'particulier/mail_merge_with_existing_account/:merge_token' => 'particulier#mail_merge_with_existing_account', as: :particulier_mail_merge_with_existing_account
|
||||||
|
post 'particulier/resend_and_renew_merge_confirmation' => 'particulier#resend_and_renew_merge_confirmation', as: :particulier_resend_and_renew_merge_confirmation
|
||||||
post 'particulier/merge_with_existing_account' => 'particulier#merge_with_existing_account'
|
post 'particulier/merge_with_existing_account' => 'particulier#merge_with_existing_account'
|
||||||
post 'particulier/merge_with_new_account' => 'particulier#merge_with_new_account'
|
post 'particulier/merge_with_new_account' => 'particulier#merge_with_new_account'
|
||||||
end
|
end
|
||||||
|
@ -266,6 +268,7 @@ Rails.application.routes.draw do
|
||||||
get 'messagerie'
|
get 'messagerie'
|
||||||
post 'commentaire' => 'dossiers#create_commentaire'
|
post 'commentaire' => 'dossiers#create_commentaire'
|
||||||
post 'ask_deletion'
|
post 'ask_deletion'
|
||||||
|
patch 'hide_dossier'
|
||||||
get 'attestation'
|
get 'attestation'
|
||||||
get 'transferer', to: 'dossiers#transferer'
|
get 'transferer', to: 'dossiers#transferer'
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddHideByUserAtOnDossiers < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :dossiers, :hidden_by_user_at, :datetime
|
||||||
|
end
|
||||||
|
end
|
|
@ -324,6 +324,7 @@ ActiveRecord::Schema.define(version: 2021_11_24_111429) do
|
||||||
t.bigint "dossier_transfer_id"
|
t.bigint "dossier_transfer_id"
|
||||||
t.datetime "identity_updated_at"
|
t.datetime "identity_updated_at"
|
||||||
t.datetime "depose_at"
|
t.datetime "depose_at"
|
||||||
|
t.datetime "hidden_by_user_at"
|
||||||
t.index ["archived"], name: "index_dossiers_on_archived"
|
t.index ["archived"], name: "index_dossiers_on_archived"
|
||||||
t.index ["dossier_transfer_id"], name: "index_dossiers_on_dossier_transfer_id"
|
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 ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
||||||
|
|
|
@ -106,6 +106,16 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
expect(response).to redirect_to(france_connect_particulier_merge_path(fci.reload.merge_token))
|
expect(response).to redirect_to(france_connect_particulier_merge_path(fci.reload.merge_token))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
context 'and an instructeur with the same email exists' do
|
||||||
|
let!(:preexisting_user) { create(:instructeur, email: email) }
|
||||||
|
|
||||||
|
it 'redirects to the merge process' do
|
||||||
|
expect { subject }.not_to change { User.count }
|
||||||
|
|
||||||
|
expect(response).to redirect_to(new_user_session_path)
|
||||||
|
expect(flash[:alert]).to eq(I18n.t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -150,7 +160,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
else
|
else
|
||||||
expect(subject).to redirect_to root_path
|
expect(subject).to redirect_to root_path
|
||||||
end
|
end
|
||||||
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
expect(flash.alert).to eq('Le délai pour fusionner les comptes FranceConnect et demarches-simplifiees.fr est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -173,7 +183,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(subject).to redirect_to root_path
|
expect(subject).to redirect_to root_path
|
||||||
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
expect(flash.alert).to eq("Le délai pour fusionner les comptes FranceConnect et demarches-simplifiees.fr est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -241,6 +251,55 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#mail_merge_with_existing_account' do
|
||||||
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
|
let!(:merge_token) { fci.create_merge_token! }
|
||||||
|
|
||||||
|
context 'when the merge_token is ok and the user is found' do
|
||||||
|
subject { post :mail_merge_with_existing_account, params: { merge_token: fci.merge_token } }
|
||||||
|
|
||||||
|
let!(:user) { create(:user, email: email, password: 'abcdefgh') }
|
||||||
|
|
||||||
|
it 'merges the account, signs in, and delete the merge token' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to eq(user)
|
||||||
|
expect(fci.merge_token).to be_nil
|
||||||
|
expect(controller.current_user).to eq(user)
|
||||||
|
expect(flash[:notice]).to eq("Les comptes FranceConnect et #{APPLICATION_NAME} sont à présent fusionnés")
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'but the targeted user is an instructeur' do
|
||||||
|
let!(:user) { create(:instructeur, email: email, password: 'abcdefgh').user }
|
||||||
|
|
||||||
|
it 'redirects to the new session' do
|
||||||
|
subject
|
||||||
|
expect(FranceConnectInformation.exists?(fci.id)).to be_falsey
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
expect(response).to redirect_to(new_user_session_path)
|
||||||
|
expect(flash[:alert]).to eq(I18n.t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the merge_token is not ok' do
|
||||||
|
subject { post :mail_merge_with_existing_account, params: { merge_token: 'ko' } }
|
||||||
|
|
||||||
|
let!(:user) { create(:user, email: email) }
|
||||||
|
|
||||||
|
it 'increases the failed attempts counter' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to be_nil
|
||||||
|
expect(fci.merge_token).not_to be_nil
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#merge_with_new_account' do
|
describe '#merge_with_new_account' do
|
||||||
let(:fci) { FranceConnectInformation.create!(user_info) }
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
let(:merge_token) { fci.create_merge_token! }
|
let(:merge_token) { fci.create_merge_token! }
|
||||||
|
@ -280,4 +339,13 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#resend_and_renew_merge_confirmation' do
|
||||||
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
|
let(:merge_token) { fci.create_merge_token! }
|
||||||
|
it 'renew token' do
|
||||||
|
expect { post :resend_and_renew_merge_confirmation, params: { merge_token: merge_token } }.to change { fci.reload.merge_token }
|
||||||
|
expect(response).to redirect_to(france_connect_particulier_merge_path(fci.reload.merge_token))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -793,14 +793,14 @@ describe Users::DossiersController, type: :controller do
|
||||||
context 'when the user does not have any dossiers' do
|
context 'when the user does not have any dossiers' do
|
||||||
before { get(:index) }
|
before { get(:index) }
|
||||||
|
|
||||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
it { expect(assigns(:statut)).to eq('en-cours') }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user only have its own dossiers' do
|
context 'when the user only have its own dossiers' do
|
||||||
let!(:own_dossier) { create(:dossier, user: user) }
|
let!(:own_dossier) { create(:dossier, user: user) }
|
||||||
|
|
||||||
before { get(:index) }
|
before { get(:index) }
|
||||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
it { expect(assigns(:statut)).to eq('en-cours') }
|
||||||
it { expect(assigns(:user_dossiers)).to match([own_dossier]) }
|
it { expect(assigns(:user_dossiers)).to match([own_dossier]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -813,14 +813,16 @@ describe Users::DossiersController, type: :controller do
|
||||||
it { expect(assigns(:dossiers_invites)).to match([invite.dossier]) }
|
it { expect(assigns(:dossiers_invites)).to match([invite.dossier]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user has both' do
|
context 'when the user has dossiers invites, own and traites' do
|
||||||
|
let!(:procedure) { create(:procedure, :published) }
|
||||||
let!(:own_dossier) { create(:dossier, user: user) }
|
let!(:own_dossier) { create(:dossier, user: user) }
|
||||||
|
let!(:own_dossier2) { create(:dossier, user: user, state: "accepte", procedure: procedure) }
|
||||||
let!(:invite) { create(:invite, dossier: create(:dossier), user: user) }
|
let!(:invite) { create(:invite, dossier: create(:dossier), user: user) }
|
||||||
|
|
||||||
context 'and there is no statut param' do
|
context 'and there is no statut param' do
|
||||||
before { get(:index) }
|
before { get(:index) }
|
||||||
|
|
||||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
it { expect(assigns(:statut)).to eq('en-cours') }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'and there is "dossiers-invites" param' do
|
context 'and there is "dossiers-invites" param' do
|
||||||
|
@ -829,10 +831,24 @@ describe Users::DossiersController, type: :controller do
|
||||||
it { expect(assigns(:statut)).to eq('dossiers-invites') }
|
it { expect(assigns(:statut)).to eq('dossiers-invites') }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'and there is "mes-dossiers" param' do
|
context 'and there is "en-cours" param' do
|
||||||
before { get(:index, params: { statut: 'mes-dossiers' }) }
|
before { get(:index, params: { statut: 'en-cours' }) }
|
||||||
|
|
||||||
it { expect(assigns(:statut)).to eq('mes-dossiers') }
|
it { expect(assigns(:statut)).to eq('en-cours') }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and there is "traites" param' do
|
||||||
|
before { get(:index, params: { statut: 'traites' }) }
|
||||||
|
|
||||||
|
it { expect(assigns(:statut)).to eq('traites') }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and the traité dossier has been hidden by user' do
|
||||||
|
before do
|
||||||
|
own_dossier2.update!(hidden_by_user_at: Time.zone.now)
|
||||||
|
get(:index, params: { statut: 'traites' })
|
||||||
|
end
|
||||||
|
it { expect(assigns(:statut)).to eq('en-cours') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ class UserMailerPreview < ActionMailer::Preview
|
||||||
UserMailer.ask_for_merge(user, 'dircab@territoires.gouv.fr')
|
UserMailer.ask_for_merge(user, 'dircab@territoires.gouv.fr')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def france_connect_merge_confirmation
|
||||||
|
UserMailer.france_connect_merge_confirmation('new.exemple.fr', '123456', 15.minutes.from_now)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def user
|
def user
|
||||||
|
|
|
@ -25,4 +25,14 @@ RSpec.describe UserMailer, type: :mailer do
|
||||||
it { expect(subject.to).to eq([requested_email]) }
|
it { expect(subject.to).to eq([requested_email]) }
|
||||||
it { expect(subject.body).to include(requested_email) }
|
it { expect(subject.body).to include(requested_email) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.france_connect_merge_confirmation' do
|
||||||
|
let(:email) { 'new.exemple.fr' }
|
||||||
|
let(:code) { '123456' }
|
||||||
|
|
||||||
|
subject { described_class.france_connect_merge_confirmation(email, code, 15.minutes.from_now) }
|
||||||
|
|
||||||
|
it { expect(subject.to).to eq([email]) }
|
||||||
|
it { expect(subject.body).to include(france_connect_particulier_mail_merge_with_existing_account_url(merge_token: code)) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,14 +18,4 @@ describe 'users/dossiers/dossier_actions.html.haml', type: :view do
|
||||||
let(:procedure) { create(:procedure, :closed) }
|
let(:procedure) { create(:procedure, :closed) }
|
||||||
it { is_expected.not_to have_link('Commencer un autre dossier') }
|
it { is_expected.not_to have_link('Commencer un autre dossier') }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when there are no actions to display' do
|
|
||||||
let(:procedure) { create(:procedure, :closed) }
|
|
||||||
let(:dossier) { create(:dossier, :accepte, procedure: procedure) }
|
|
||||||
let(:user) { create(:user) }
|
|
||||||
|
|
||||||
it 'doesn’t render the menu at all' do
|
|
||||||
expect(subject).not_to have_selector('.dropdown')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,9 +2,10 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:dossier_brouillon) { create(:dossier, state: Dossier.states.fetch(:brouillon), user: user) }
|
let(:dossier_brouillon) { create(:dossier, state: Dossier.states.fetch(:brouillon), user: user) }
|
||||||
let(:dossier_en_construction) { create(:dossier, state: Dossier.states.fetch(:en_construction), user: user) }
|
let(:dossier_en_construction) { create(:dossier, state: Dossier.states.fetch(:en_construction), user: user) }
|
||||||
let(:user_dossiers) { [dossier_brouillon, dossier_en_construction] }
|
let(:dossier_termine) { create(:dossier, state: Dossier.states.fetch(:accepte), user: user) }
|
||||||
|
let(:user_dossiers) { [dossier_brouillon, dossier_en_construction, dossier_termine] }
|
||||||
let(:dossiers_invites) { [] }
|
let(:dossiers_invites) { [] }
|
||||||
let(:statut) { 'mes-dossiers' }
|
let(:statut) { 'en-cours' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(view).to receive(:new_demarche_url).and_return('#')
|
allow(view).to receive(:new_demarche_url).and_return('#')
|
||||||
|
@ -12,6 +13,7 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
||||||
assign(:user_dossiers, Kaminari.paginate_array(user_dossiers).page(1))
|
assign(:user_dossiers, Kaminari.paginate_array(user_dossiers).page(1))
|
||||||
assign(:dossiers_invites, Kaminari.paginate_array(dossiers_invites).page(1))
|
assign(:dossiers_invites, Kaminari.paginate_array(dossiers_invites).page(1))
|
||||||
assign(:dossiers_supprimes, Kaminari.paginate_array(user_dossiers).page(1))
|
assign(:dossiers_supprimes, Kaminari.paginate_array(user_dossiers).page(1))
|
||||||
|
assign(:dossiers_traites, Kaminari.paginate_array(user_dossiers).page(1))
|
||||||
assign(:dossier_transfers, Kaminari.paginate_array([]).page(1))
|
assign(:dossier_transfers, Kaminari.paginate_array([]).page(1))
|
||||||
assign(:dossiers_close_to_expiration, Kaminari.paginate_array([]).page(1))
|
assign(:dossiers_close_to_expiration, Kaminari.paginate_array([]).page(1))
|
||||||
assign(:statut, statut)
|
assign(:statut, statut)
|
||||||
|
@ -19,7 +21,7 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'affiche la liste des dossiers' do
|
it 'affiche la liste des dossiers' do
|
||||||
expect(rendered).to have_selector('.dossiers-table tbody tr', count: 2)
|
expect(rendered).to have_selector('.dossiers-table tbody tr', count: 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'affiche les informations des dossiers' do
|
it 'affiche les informations des dossiers' do
|
||||||
|
@ -67,8 +69,16 @@ describe 'users/dossiers/index.html.haml', type: :view do
|
||||||
|
|
||||||
it 'affiche la barre d’onglets' do
|
it 'affiche la barre d’onglets' do
|
||||||
expect(rendered).to have_selector('ul.tabs')
|
expect(rendered).to have_selector('ul.tabs')
|
||||||
expect(rendered).to have_selector('ul.tabs li', count: 3)
|
expect(rendered).to have_selector('ul.tabs li', count: 4)
|
||||||
expect(rendered).to have_selector('ul.tabs li.active', count: 1)
|
expect(rendered).to have_selector('ul.tabs li.active', count: 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'where there is a traite dossier' do
|
||||||
|
let(:dossiers_traites) { create_list(:dossier, 1) }
|
||||||
|
|
||||||
|
it "displays the hide by user at button" do
|
||||||
|
expect(rendered).to have_text("Supprimer le dossier")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
1
vendor/assets/stylesheets/franceconnect.scss
vendored
1
vendor/assets/stylesheets/franceconnect.scss
vendored
|
@ -140,3 +140,4 @@
|
||||||
height: 500px;
|
height: 500px;
|
||||||
margin: 60px auto 0 auto;
|
margin: 60px auto 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue