Merge pull request #9418 from adullact/feature-ouidou/admin_creation_delegation

FEAT: init admins group
This commit is contained in:
Paul Chavard 2023-10-03 12:08:19 +00:00 committed by GitHub
commit 4dd9d4b2b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 630 additions and 3 deletions

View file

@ -21,7 +21,8 @@ class ApplicationController < ActionController::Base
around_action :switch_locale
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur, :current_expert, :expert_signed_in?,
:administrateur_signed_in?, :current_administrateur, :current_account, :localization_enabled?, :set_locale, :current_expert_not_instructeur?
:administrateur_signed_in?, :current_administrateur, :current_account, :localization_enabled?, :set_locale, :current_expert_not_instructeur?,
:gestionnaire_signed_in?, :current_gestionnaire
before_action do
Current.request_id = request.uuid
@ -37,9 +38,12 @@ class ApplicationController < ActionController::Base
def multiple_devise_profile_connect?
user_signed_in? && instructeur_signed_in? ||
instructeur_signed_in? && administrateur_signed_in? ||
instructeur_signed_in? && gestionnaire_signed_in? ||
instructeur_signed_in? && expert_signed_in? ||
user_signed_in? && administrateur_signed_in? ||
user_signed_in? && expert_signed_in?
user_signed_in? && gestionnaire_signed_in? ||
user_signed_in? && expert_signed_in? ||
administrateur_signed_in? && gestionnaire_signed_in?
end
def current_instructeur
@ -58,6 +62,14 @@ class ApplicationController < ActionController::Base
current_administrateur.present?
end
def current_gestionnaire
current_user&.gestionnaire
end
def gestionnaire_signed_in?
current_gestionnaire.present?
end
def current_expert
current_user&.expert
end
@ -72,6 +84,7 @@ class ApplicationController < ActionController::Base
def current_account
{
gestionnaire: current_gestionnaire,
administrateur: current_administrateur,
instructeur: current_instructeur,
user: current_user
@ -115,6 +128,8 @@ class ApplicationController < ActionController::Base
authenticate_expert!
elsif administrateur_signed_in?
authenticate_administrateur!
elsif gestionnaire_signed_in?
authenticate_gestionnaire!
else
authenticate_user!
end
@ -144,6 +159,12 @@ class ApplicationController < ActionController::Base
end
end
def authenticate_gestionnaire!
if !gestionnaire_signed_in?
redirect_to new_user_session_path
end
end
def after_sign_out_path_for(_resource_or_scope)
stored_location_for(:user) || super
end
@ -178,6 +199,7 @@ class ApplicationController < ActionController::Base
current_user,
current_instructeur,
current_administrateur,
current_gestionnaire,
current_super_admin
].compact.map { |role| role.class.name }

View file

@ -0,0 +1,9 @@
module Gestionnaires
class GestionnaireController < ApplicationController
before_action :authenticate_gestionnaire!
def nav_bar_profile
:gestionnaire
end
end
end

View file

@ -0,0 +1,14 @@
module Gestionnaires
class GroupeGestionnairesController < GestionnaireController
def index
@groupe_gestionnaires = groupe_gestionnaires
end
private
def groupe_gestionnaires
groupe_gestionnaire_ids = current_gestionnaire.groupe_gestionnaire_ids
GroupeGestionnaire.where(id: groupe_gestionnaire_ids.compact.uniq)
end
end
end

View file

@ -0,0 +1,4 @@
module Manager
class GestionnairesController < Manager::ApplicationController
end
end

View file

@ -0,0 +1,32 @@
module Manager
class GroupeGestionnairesController < Manager::ApplicationController
def add_gestionnaire
emails = (params['emails'].presence || '').split(',').to_json
emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) }
gestionnaires, invalid_emails = groupe_gestionnaire.add_gestionnaires(emails:)
if invalid_emails.present?
flash[:alert] = t('.wrong_address',
count: invalid_emails.size,
emails: invalid_emails)
end
if gestionnaires.present?
flash[:notice] = "Les gestionnaires ont bien été affectés au groupe d'administrateurs"
GroupeGestionnaireMailer
.notify_added_gestionnaires(groupe_gestionnaire, gestionnaires, current_super_admin.email)
.deliver_later
end
redirect_to manager_groupe_gestionnaires_path(groupe_gestionnaire)
end
private
def groupe_gestionnaire
@groupe_gestionnaire ||= GroupeGestionnaire.find(params[:id])
end
end
end

View file

@ -0,0 +1,57 @@
require "administrate/base_dashboard"
class GestionnaireDashboard < Administrate::BaseDashboard
# ATTRIBUTE_TYPES
# a hash that describes the type of each of the model's fields.
#
# Each different type represents an Administrate::Field object,
# which determines how the attribute is displayed
# on pages throughout the dashboard.
ATTRIBUTE_TYPES = {
id: Field::Number,
user: Field::HasOne.with_options(searchable: true, searchable_field: 'email'),
created_at: Field::DateTime,
updated_at: Field::DateTime,
groupe_gestionnaires: Field::HasMany.with_options(limit: 20),
registration_state: Field::String.with_options(searchable: false),
email: Field::Email.with_options(searchable: false)
}.freeze
# COLLECTION_ATTRIBUTES
# an array of attributes that will be displayed on the model's index page.
#
# By default, it's limited to four items to reduce clutter on index pages.
# Feel free to add, remove, or rearrange items.
COLLECTION_ATTRIBUTES = [
:id,
:user,
:created_at,
:groupe_gestionnaires,
:registration_state
].freeze
# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = [
:id,
:user,
:created_at,
:updated_at,
:registration_state,
:groupe_gestionnaires
].freeze
# FORM_ATTRIBUTES
# an array of attributes that will be displayed
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = [
:email
].freeze
# Overwrite this method to customize how users are displayed
# across all pages of the admin dashboard.
#
def display_resource(gestionnaire)
gestionnaire.email
end
end

View file

@ -0,0 +1,54 @@
require "administrate/base_dashboard"
class GroupeGestionnaireDashboard < Administrate::BaseDashboard
# ATTRIBUTE_TYPES
# a hash that describes the type of each of the model's fields.
#
# Each different type represents an Administrate::Field object,
# which determines how the attribute is displayed
# on pages throughout the dashboard.
ATTRIBUTE_TYPES = {
id: Field::Number,
name: Field::String,
created_at: Field::DateTime,
updated_at: Field::DateTime,
gestionnaires: Field::HasMany,
administrateurs: Field::HasMany
}.freeze
# COLLECTION_ATTRIBUTES
# an array of attributes that will be displayed on the model's index page.
#
# By default, it's limited to four items to reduce clutter on index pages.
# Feel free to add, remove, or rearrange items.
COLLECTION_ATTRIBUTES = [
:id,
:created_at,
:name,
:gestionnaires,
:administrateurs
].freeze
# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = [
:gestionnaires,
:administrateurs,
:id,
:created_at
].freeze
# FORM_ATTRIBUTES
# an array of attributes that will be displayed
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = [
:name
].freeze
# Overwrite this method to customize how users are displayed
# across all pages of the admin dashboard.
#
def display_resource(groupe_gestionnaire)
groupe_gestionnaire.name
end
end

View file

@ -47,7 +47,8 @@ module ApplicationHelper
def current_email
current_user&.email ||
current_instructeur&.email ||
current_administrateur&.email
current_administrateur&.email ||
current_gestionnaire&.email
end
def staging?
@ -77,6 +78,8 @@ module ApplicationHelper
case nav_bar_profile
when :administrateur
[admin_procedures_path, t("admin", scope: "layouts.root_path_link_title")]
when :gestionnaire
[gestionnaire_groupe_gestionnaires_path, t("gestionnaire", scope: "layouts.root_path_link_title")]
when :instructeur
[instructeur_procedures_path, t("instructeur", scope: "layouts.root_path_link_title")]
when :user

View file

@ -0,0 +1,13 @@
class GroupeGestionnaireMailer < ApplicationMailer
layout 'mailers/layout'
def notify_added_gestionnaires(groupe_gestionnaire, added_gestionnaires, current_super_admin_email)
added_gestionnaire_emails = added_gestionnaires.map(&:email)
@groupe_gestionnaire = groupe_gestionnaire
@current_super_admin_email = current_super_admin_email
subject = "Vous avez été ajouté(e) en tant que gestionnaire du groupe gestionnaire \"#{groupe_gestionnaire.name}\""
mail(bcc: added_gestionnaire_emails, subject: subject)
end
end

View file

@ -38,6 +38,17 @@ class UserMailer < ApplicationMailer
reply_to: CONTACT_EMAIL)
end
def invite_gestionnaire(user, reset_password_token, groupe_gestionnaire)
@reset_password_token = reset_password_token
@user = user
@groupe_gestionnaire = groupe_gestionnaire
subject = "Activez votre compte gestionnaire"
mail(to: user.email,
subject: subject,
reply_to: CONTACT_EMAIL)
end
def send_archive(administrateur_or_instructeur, procedure, archive)
@archive = archive
@procedure = procedure

View file

@ -9,6 +9,7 @@ class Administrateur < ApplicationRecord
has_and_belongs_to_many :default_zones, class_name: 'Zone', join_table: 'default_zones_administrateurs'
belongs_to :user
belongs_to :groupe_gestionnaire, optional: true
default_scope { eager_load(:user) }

View file

@ -0,0 +1,41 @@
class Gestionnaire < ApplicationRecord
has_and_belongs_to_many :groupe_gestionnaires
belongs_to :user
delegate :email, to: :user
default_scope { eager_load(:user) }
def self.by_email(email)
find_by(users: { email: email })
end
def self.find_all_by_identifier(ids: [], emails: [])
find_all_by_identifier_with_emails(ids:, emails:).first
end
def self.find_all_by_identifier_with_emails(ids: [], emails: [])
valid_emails, invalid_emails = emails.partition { URI::MailTo::EMAIL_REGEXP.match?(_1) }
[
where(id: ids).or(where(users: { email: valid_emails })).distinct(:id),
valid_emails,
invalid_emails
]
end
def can_be_deleted?
!(root_groupe_gestionnaire = groupe_gestionnaires.where(groupe_gestionnaire: nil).first) || root_groupe_gestionnaire.gestionnaires.size > 1
end
def registration_state
if user.active?
'Actif'
elsif user.reset_password_period_valid?
'En attente'
else
'Expiré'
end
end
end

View file

@ -0,0 +1,30 @@
class GroupeGestionnaire < ApplicationRecord
belongs_to :groupe_gestionnaire, optional: true # parent
has_many :children, class_name: "GroupeGestionnaire", inverse_of: :groupe_gestionnaire
has_many :administrateurs
has_and_belongs_to_many :gestionnaires
def add(gestionnaire)
gestionnaires << gestionnaire
end
def add_gestionnaires(ids: [], emails: [])
gestionnaires_to_add, valid_emails, invalid_emails = Gestionnaire.find_all_by_identifier_with_emails(ids:, emails:)
not_found_emails = valid_emails - gestionnaires_to_add.map(&:email)
# Send invitations to users without account
if not_found_emails.present?
gestionnaires_to_add += not_found_emails.map do |email|
user = User.create_or_promote_to_gestionnaire(email, SecureRandom.hex)
user.invite_gestionnaire!(self)
user.gestionnaire
end
end
# We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it
gestionnaires_to_add -= gestionnaires
gestionnaires_to_add.each { add(_1) }
[gestionnaires_to_add, invalid_emails]
end
end

View file

@ -26,6 +26,7 @@ class User < ApplicationRecord
has_one :france_connect_information, dependent: :destroy
has_one :instructeur, dependent: :destroy
has_one :administrateur, dependent: :destroy
has_one :gestionnaire, dependent: :destroy
has_one :expert, dependent: :destroy
belongs_to :requested_merge_into, class_name: 'User', optional: true
@ -76,6 +77,10 @@ class User < ApplicationRecord
UserMailer.invite_instructeur(self, set_reset_password_token).deliver_later
end
def invite_gestionnaire!(groupe_gestionnaire)
UserMailer.invite_gestionnaire(self, set_reset_password_token, groupe_gestionnaire).deliver_later
end
def invite_administrateur!(administration_id)
AdministrationMailer.invite_admin(self, set_reset_password_token, administration_id).deliver_later
end
@ -103,6 +108,16 @@ class User < ApplicationRecord
user
end
def self.create_or_promote_to_gestionnaire(email, password)
user = User.create_or_promote_to_administrateur(email, password)
if user.valid? && user.gestionnaire.nil?
user.create_gestionnaire!
end
user
end
def self.create_or_promote_to_administrateur(email, password)
user = User.create_or_promote_to_instructeur(email, password)
@ -145,6 +160,10 @@ class User < ApplicationRecord
instructeur.present?
end
def gestionnaire?
gestionnaire.present?
end
def expert?
expert.present?
end

View file

@ -0,0 +1,6 @@
%p= t(:hello, scope: [:views, :shared, :greetings])
%p
= t(".email_body", groupe_gestionnaire_name: @groupe_gestionnaire.name, email: @current_super_admin_email, application_name: APPLICATION_NAME)
= render partial: "layouts/mailers/signature"

View file

@ -30,6 +30,11 @@
= link_to admin_procedures_path, class: "fr-nav__link" do
%span.fr-icon-refresh-line.fr-icon--sm
= t('go_admin', scope: [:layouts])
- if gestionnaire_signed_in? && nav_bar_profile != :gestionnaire
%li
= link_to gestionnaire_groupe_gestionnaires_path, class: "fr-nav__link" do
%span.fr-icon-refresh-line.fr-icon--sm
= t('go_gestionnaire', scope: [:layouts])
- if super_admin_signed_in?
%li

View file

@ -0,0 +1,13 @@
- content_for(:title, 'Activation de votre compte gestionnaire')
%p
Bonjour,
%p
Vous venez dêtre nommé gestionnaire du groupe gestionnaire #{@groupe_gestionnaire.name} sur #{APPLICATION_NAME}.
%p
Votre compte a été créé pour l'adresse email #{@user.email}. Pour lactiver, nous vous invitons à cliquer sur le lien suivant : 
= link_to(users_activate_url(token: @reset_password_token), users_activate_url(token: @reset_password_token))
= render partial: "layouts/mailers/signature"

View file

@ -226,3 +226,7 @@ REDIS_CACHE_SSL_VERIFY_NONE="enabled"
# Setup log level, info if nil
# can be debug, info, warn, error, fatal, and unknown
DS_LOG_LEVEL='info'
# Admins group usage (gestionnaire de groupes d'administrateurs)
# can be removed if needed when EVERY PARTS of the feature will be merged / only used in routes.rb
ADMINS_GROUP_ENABLED="disabled"

View file

@ -101,6 +101,7 @@ en:
user: 'Go to files list'
instructeur: 'Go to procedures list'
admin: 'Go to administration panel'
gestionnaire: "Go to admins group panel"
views:
legal_notice:
title: "Legal Notices"

View file

@ -92,6 +92,7 @@ fr:
user: 'Aller à la liste des dossiers'
instructeur: 'Aller à la liste des démarches'
admin: "Aller au panneau dadministration"
gestionnaire: "Aller au panneau de gestionnaire"
views:
legal_notice:
title: "Mentions légales"

View file

@ -0,0 +1,9 @@
fr:
activerecord:
attributes:
gestionnaire:
groupe_gestionnaires: Groupes
models:
gestionnaire:
one: Gestionnaire
other: Gestionnaires

View file

@ -0,0 +1,4 @@
en:
groupe_gestionnaire_mailer:
notify_added_gestionnaires:
email_body: "You were assigned as manager on the admins group %{groupe_gestionnaire_name} on %{application_name} by « %{email} »"

View file

@ -0,0 +1,4 @@
fr:
groupe_gestionnaire_mailer:
notify_added_gestionnaires:
email_body: "Vous venez dêtre nommé gestionnaire du groupe gestionnaire %{groupe_gestionnaire_name} sur %{application_name} par « %{email} »."

View file

@ -8,12 +8,14 @@ en:
go_instructor: "Switch to instructor"
go_expert: "Switch to expert"
go_admin: "Switch to administrator"
go_gestionnaire: "Switch to admins group manager"
profile: "See my profile"
logout: "Log out"
my_account: "My account"
connected_as: "connected as %{profile}"
instructeur: instructor
administrateur: admin
gestionnaire: admins group manager
expert: expert
user: user
guest: guest

View file

@ -8,12 +8,14 @@ fr:
go_instructor: "Passer en instructeur"
go_expert: "Passer en expert"
go_admin: "Passer en administrateur"
go_gestionnaire: "Passer en gestionnaire"
profile: "Voir mon profil"
logout: "Se déconnecter"
my_account: "Mon compte"
connected_as: "connecté en tant qu%{profile}"
instructeur: instructeur
administrateur: administrateur
gestionnaire: gestionnaire
expert: expert
user: usager
guest: invité

View file

@ -0,0 +1,7 @@
fr:
manager:
groupe_gestionnaires:
add_gestionnaire:
wrong_address:
one: "%{emails} nest pas une adresse email valide"
other: "%{emails} ne sont pas des adresses emails valides"

View file

@ -56,6 +56,14 @@ Rails.application.routes.draw do
delete 'delete', on: :member
end
if ENV['ADMINS_GROUP_ENABLED'] == 'enabled' # can be removed if needed when EVERY PARTS of the feature will be merged / from env.example.optional
resources :gestionnaires, only: [:index, :show, :edit, :update]
resources :groupe_gestionnaires, path: 'groupe_administrateurs', only: [:index, :show, :new, :create, :edit, :update] do
post 'add_gestionnaire', on: :member
end
end
resources :dossiers, only: [:show]
resources :bill_signatures, only: [:index]
@ -465,6 +473,17 @@ Rails.application.routes.draw do
end
end
if ENV['ADMINS_GROUP_ENABLED'] == 'enabled' # can be removed if needed when EVERY PARTS of the feature will be merged / from env.example.optional
#
# Gestionnaire
#
scope module: 'gestionnaires', as: 'gestionnaire' do
resources :groupe_gestionnaires, path: 'groupe_administrateurs', only: [:index, :create]
end
end
#
# Administrateur
#

View file

@ -0,0 +1,9 @@
class CreateGestionnaires < ActiveRecord::Migration[7.0]
def change
create_table "gestionnaires" do |t|
t.bigint :user_id, null: false
t.index [:user_id], name: :index_gestionnaires_on_user_id
t.timestamps
end
end
end

View file

@ -0,0 +1,15 @@
class CreateGroupeGestionnaires < ActiveRecord::Migration[7.0]
def change
create_table "groupe_gestionnaires" do |t|
t.string :name, null: false
t.references :groupe_gestionnaire
t.index [:name], name: :index_groupe_gestionnaires_on_name
t.timestamps
end
create_join_table :groupe_gestionnaires, :gestionnaires do |t|
t.index [:groupe_gestionnaire_id, :gestionnaire_id], name: :index_on_groupe_gestionnaire_and_gestionnaire
t.index [:gestionnaire_id, :groupe_gestionnaire_id], name: :index_on_gestionnaire_and_groupe_gestionnaire
end
end
end

View file

@ -0,0 +1,7 @@
class AddGroupeGestionnaireToAdministrateurs < ActiveRecord::Migration[7.0]
disable_ddl_transaction!
def change
add_reference :administrateurs, :groupe_gestionnaire, index: { algorithm: :concurrently }, null: true
end
end

View file

@ -0,0 +1,5 @@
class AddForeignKeyGroupeGestionnaireToAdministrateurs < ActiveRecord::Migration[7.0]
def change
add_foreign_key :administrateurs, :groupe_gestionnaires, validate: false
end
end

View file

@ -0,0 +1,5 @@
class ValidateForeignKeyGroupeGestionnaireToAdministrateurs < ActiveRecord::Migration[7.0]
def change
validate_foreign_key :administrateurs, :groupe_gestionnaires
end
end

View file

@ -62,8 +62,10 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_28_083809) do
create_table "administrateurs", id: :serial, force: :cascade do |t|
t.datetime "created_at", precision: 6
t.bigint "groupe_gestionnaire_id"
t.datetime "updated_at", precision: 6
t.bigint "user_id", null: false
t.index ["groupe_gestionnaire_id"], name: "index_administrateurs_on_groupe_gestionnaire_id"
t.index ["user_id"], name: "index_administrateurs_on_user_id"
end
@ -625,6 +627,29 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_28_083809) do
t.index ["groupe_instructeur_id"], name: "index_contact_informations_on_groupe_instructeur_id"
end
create_table "gestionnaires", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "user_id", null: false
t.index ["user_id"], name: "index_gestionnaires_on_user_id"
end
create_table "gestionnaires_groupe_gestionnaires", id: false, force: :cascade do |t|
t.bigint "gestionnaire_id", null: false
t.bigint "groupe_gestionnaire_id", null: false
t.index ["gestionnaire_id", "groupe_gestionnaire_id"], name: "index_on_gestionnaire_and_groupe_gestionnaire"
t.index ["groupe_gestionnaire_id", "gestionnaire_id"], name: "index_on_groupe_gestionnaire_and_gestionnaire"
end
create_table "groupe_gestionnaires", force: :cascade do |t|
t.datetime "created_at", null: false
t.bigint "groupe_gestionnaire_id"
t.string "name", null: false
t.datetime "updated_at", null: false
t.index ["groupe_gestionnaire_id"], name: "index_groupe_gestionnaires_on_groupe_gestionnaire_id"
t.index ["name"], name: "index_groupe_gestionnaires_on_name"
end
create_table "groupe_instructeurs", force: :cascade do |t|
t.boolean "closed", default: false
t.datetime "created_at", precision: 6, null: false
@ -1034,6 +1059,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_28_083809) do
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "administrateurs", "groupe_gestionnaires"
add_foreign_key "administrateurs", "users"
add_foreign_key "administrateurs_instructeurs", "administrateurs"
add_foreign_key "administrateurs_instructeurs", "instructeurs"

View file

@ -0,0 +1,12 @@
FactoryBot.define do
sequence(:gestionnaire_email) { |n| "gestionnaire#{n}@demarches-simplifiees.fr" }
factory :gestionnaire do
user { association :user, email: email, password: password }
transient do
email { generate(:gestionnaire_email) }
password { 'somethingverycomplated!' }
end
end
end

View file

@ -0,0 +1,5 @@
FactoryBot.define do
factory :groupe_gestionnaire do
sequence(:name) { |n| "Group #{n}" }
end
end

View file

@ -0,0 +1,16 @@
RSpec.describe GroupeGestionnaireMailer, type: :mailer do
describe '#notify_added_gestionnaires' do
let(:groupe_gestionnaire) { create(:groupe_gestionnaire) }
let(:gestionnaires_to_add) { [create(:gestionnaire, email: 'int3@g'), create(:gestionnaire, email: 'int4@g')] }
let(:current_super_admin_email) { 'toto@email.com' }
subject { described_class.notify_added_gestionnaires(groupe_gestionnaire, gestionnaires_to_add, current_super_admin_email) }
before { gestionnaires_to_add.each { groupe_gestionnaire.add(_1) } }
it { expect(subject.body).to include('Vous venez dêtre nommé gestionnaire du groupe gestionnaire') }
it { expect(subject.bcc).to match_array(['int3@g', 'int4@g']) }
end
end

View file

@ -0,0 +1,14 @@
class GroupeGestionnaireMailerPreview < ActionMailer::Preview
def notify_added_gestionnaires
groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe d\'admin')
current_super_admin_email = 'admin@dgfip.com'
gestionnaires = [Gestionnaire.new(user: user)]
GroupeGestionnaireMailer.notify_added_gestionnaires(groupe_gestionnaire, gestionnaires, current_super_admin_email)
end
private
def user
User.new(id: 10, email: 'test@exemple.fr')
end
end

View file

@ -24,6 +24,11 @@ class UserMailerPreview < ActionMailer::Preview
UserMailer.invite_instructeur(user, 'aedfa0d0')
end
def invite_gestionnaire
groupe_gestionnaire = GroupeGestionnaire.new(name: 'Root admins group')
UserMailer.invite_gestionnaire(user, 'aedfa0d0', groupe_gestionnaire)
end
private
def user

View file

@ -3,6 +3,7 @@ describe Administrateur, type: :model do
describe 'associations' do
it { is_expected.to have_and_belong_to_many(:instructeurs) }
it { is_expected.to belong_to(:groupe_gestionnaire).optional }
end
describe "#can_be_deleted?" do

View file

@ -0,0 +1,80 @@
describe Gestionnaire, type: :model do
describe 'associations' do
it { is_expected.to have_and_belong_to_many(:groupe_gestionnaires) }
end
describe "#can_be_deleted?" do
subject { gestionnaire.can_be_deleted? }
context "when there are several gestionnaires in the groupe gestionnaire" do
let!(:gestionnaire) { create(:gestionnaire) }
let!(:autre_gestionnaire) { create(:gestionnaire) }
let!(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire, autre_gestionnaire]) }
it { is_expected.to be true }
end
context "when only one gestionnaire in the groupe gestionnaire" do
let!(:gestionnaire) { create(:gestionnaire) }
let!(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire]) }
it { is_expected.to be false }
end
context "when the gestionnaire has no groupe gestionnaire" do
let!(:gestionnaire) { create(:gestionnaire) }
it { is_expected.to be true }
end
end
describe "#registration_state" do
subject { gestionnaire.registration_state }
context "when active" do
let!(:gestionnaire) { create(:gestionnaire) }
before { gestionnaire.user.update(last_sign_in_at: Time.zone.now) }
it { is_expected.to eq 'Actif' }
end
context "when pending" do
let!(:gestionnaire) { create(:gestionnaire) }
before { gestionnaire.user.update(reset_password_sent_at: Time.zone.now) }
it { is_expected.to eq 'En attente' }
end
context "when expired" do
let!(:gestionnaire) { create(:gestionnaire) }
it { is_expected.to eq 'Expiré' }
end
end
describe "#by_email" do
context "returns gestionnaire" do
let!(:gestionnaire) { create(:gestionnaire) }
it { expect(Gestionnaire.by_email(gestionnaire.email)).to eq gestionnaire }
end
end
describe "#find_all_by_identifier" do
context "find gestionnaire by email " do
subject { Gestionnaire.find_all_by_identifier(emails: [gestionnaire.email]) }
let!(:gestionnaire) { create(:gestionnaire) }
it { is_expected.to eq [gestionnaire] }
end
context "find gestionnaire by id " do
subject { Gestionnaire.find_all_by_identifier(ids: [gestionnaire.id]) }
let!(:gestionnaire) { create(:gestionnaire) }
it { is_expected.to eq [gestionnaire] }
end
end
end

View file

@ -0,0 +1,40 @@
describe GroupeGestionnaire, type: :model do
describe 'associations' do
it { is_expected.to belong_to(:groupe_gestionnaire).optional }
it { is_expected.to have_many(:children) }
it { is_expected.to have_many(:administrateurs) }
it { is_expected.to have_and_belong_to_many(:gestionnaires) }
end
describe "#add" do
let(:groupe_gestionnaire) { create(:groupe_gestionnaire) }
let(:gestionnaire) { create(:gestionnaire) }
subject { groupe_gestionnaire.add(gestionnaire) }
it 'adds the gestionnaire to the groupe gestionnaire' do
subject
expect(groupe_gestionnaire.reload.gestionnaires).to include(gestionnaire)
end
end
describe "#add_gestionnaires" do
let(:groupe_gestionnaire) { create(:groupe_gestionnaire) }
let(:gestionnaire) { create(:gestionnaire) }
it 'adds the gestionnaire by id' do
groupe_gestionnaire.add_gestionnaires(ids: [gestionnaire.id])
expect(groupe_gestionnaire.reload.gestionnaires).to include(gestionnaire)
end
it 'adds the existing gestionnaire by email' do
groupe_gestionnaire.add_gestionnaires(emails: [gestionnaire.email])
expect(groupe_gestionnaire.reload.gestionnaires).to include(gestionnaire)
end
it 'adds the new gestionnaire by email' do
groupe_gestionnaire.add_gestionnaires(emails: ['new_gestionnaire@ds.fr'])
expect(groupe_gestionnaire.reload.gestionnaires.last.email).to eq('new_gestionnaire@ds.fr')
end
end
end