Skip to content

Commit

Permalink
Merge branch 'production' into frf/remove-users-notes
Browse files Browse the repository at this point in the history
  • Loading branch information
francois-ferrandis authored Mar 4, 2025
2 parents e7b4ecf + 3a38fa6 commit 2a94005
Show file tree
Hide file tree
Showing 43 changed files with 355 additions and 138 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,14 @@ jobs:
path: node_modules
- name: Install JS dependencies
run: yarn install
- name: Cache precompiled assets
id: cache-precompiled-assets
uses: actions/cache@v4
with:
key: assets-${{ hashFiles('yarn.lock', 'app/javascript/**') }}
path: app/assets/builds
- name: Precompile assets
if: steps.cache-precompiled-assets.outputs.cache-hit != 'true' # Skip if cache was restored
run: yarn run build
- name: Prepare runtime log cache key
run: ls spec/**/*.rb > tmp/spec_files.txt
Expand Down Expand Up @@ -202,7 +209,14 @@ jobs:
path: node_modules
- name: Install JS dependencies
run: yarn install
- name: Cache precompiled assets
id: cache-precompiled-assets
uses: actions/cache@v4
with:
key: assets-${{ hashFiles('yarn.lock', 'app/javascript/**') }}
path: app/assets/builds
- name: Precompile assets
if: steps.cache-precompiled-assets.outputs.cache-hit != 'true' # Skip if cache was restored
run: yarn run build
- name: Prepare runtime log cache key
run: "ls spec/features/${{ matrix.dirname }}/**/*.rb > tmp/feature_spec_${{ matrix.dirname }}_files.txt"
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ GEM
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uniform_notifier (1.16.0)
uri (0.13.0)
uri (1.0.3)
validate_email (0.1.6)
activemodel (>= 3.0)
mail (>= 2.2.5)
Expand Down
8 changes: 0 additions & 8 deletions app/controllers/admin/organisations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ class Admin::OrganisationsController < AgentAuthController
respond_to :html, :json

before_action :set_organisation, except: :index
before_action :follow_unique, only: :index

def index
@organisations_by_territory = policy_scope(current_agent.organisations, policy_scope_class: Agent::OrganisationPolicy::Scope)
Expand Down Expand Up @@ -73,11 +72,4 @@ def organisation_params
def new_organisation_params
params.require(:organisation).permit(:name, :territory_id)
end

def follow_unique
accessible_organisations = policy_scope(Organisation, policy_scope_class: Agent::OrganisationPolicy::Scope)
return if params[:follow_unique].blank? || accessible_organisations.count != 1

redirect_to admin_organisation_agent_agenda_path(accessible_organisations.first, current_agent)
end
end
6 changes: 5 additions & 1 deletion app/controllers/agent_connect_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def auth
redirect_to auth_client.redirect_url(agent_connect_callback_url), allow_other_host: true
end

def callback
def callback # rubocop:disable Metrics/PerceivedComplexity
callback_client = AgentConnectOpenIdClient::Callback.new(
session_state: session.delete(:agent_connect_state),
params_state: params[:state],
Expand All @@ -33,6 +33,10 @@ def callback
# voir https://github.com/numerique-gouv/agentconnect-documentation/blob/main/doc_fs/donnees_fournies.md#le-champ-sub
agent = Agent.active.find_by(email: callback_client.user_email)

if current_domain.allow_agent_creation_with_agent_connect
agent ||= Agent.new(email: callback_client.user_email, password: SecureRandom.base64(32))
end

if agent
agent.update!(
connected_with_agent_connect: true,
Expand Down
23 changes: 23 additions & 0 deletions app/controllers/agents/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Agents::PagesController < AgentAuthController
layout "application"

CONTACT_TEAM_URL = "https://cal.com/forms/937585aa-48a4-4efd-a642-961fad79c9c5".freeze

def home
skip_authorization

accessible_organisations = policy_scope(Organisation, policy_scope_class: Agent::OrganisationPolicy::Scope)

if accessible_organisations.count == 1
redirect_to admin_organisation_agent_agenda_path(accessible_organisations.first, current_agent)
elsif accessible_organisations.count > 1
redirect_to admin_organisations_path
end
end

private

def pundit_user
AgentContext.new(current_agent)
end
end
11 changes: 10 additions & 1 deletion app/controllers/super_admins/comptes_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
module SuperAdmins
class ComptesController < SuperAdmins::ApplicationController
def new
@agent = Agent.find_by(id: params[:agent_id])
if @agent
authorize_resource(@agent)
end

super
end

def create
compte_params[:agent][:invited_by] = current_super_admin
compte = Compte.new(compte_params, current_domain)
Expand All @@ -24,7 +33,7 @@ def compte_params
territory: %i[name departement_number],
organisation: %i[name ants_connectable],
lieu: %i[address latitude longitude],
agent: %i[first_name last_name email service_ids]
agent: %i[id first_name last_name email service_ids]
)
end
end
Expand Down
22 changes: 18 additions & 4 deletions app/form_models/compte.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ def save!
organisation.save!
lieu.save!

self.agent = Agent.invite!(@attributes[:agent].merge(
password: SecureRandom.base64(32),
roles_attributes: [{ organisation: organisation, access_level: AgentRole::ACCESS_LEVEL_ADMIN }]
))
self.agent = find_or_invite_agent(organisation)

agent.services.each do |service|
TerritoryService.create!(service: service, territory: territory)
Expand Down Expand Up @@ -65,6 +62,23 @@ def to_s

private

def find_or_invite_agent(organisation)
if @attributes.dig(:agent, :id)
Agent.find(@attributes.dig(:agent, :id)).tap do |agent|
agent.update(
@attributes[:agent].merge(
roles_attributes: [{ organisation: organisation, access_level: AgentRole::ACCESS_LEVEL_ADMIN }]
)
)
end
else
Agent.invite!(@attributes[:agent].merge(
roles_attributes: [{ organisation: organisation, access_level: AgentRole::ACCESS_LEVEL_ADMIN }],
password: SecureRandom.base64(32)
))
end
end

def create_mairie_motifs!
service = Service.find_by(name: Service::MAIRIE)

Expand Down
7 changes: 5 additions & 2 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,12 @@ def boolean_attribute_tag(object, attribute_name)
boolean_tag(value) { object.class.human_attribute_value(attribute_name, value) }
end

def object_attribute_tag(object, attribute_name, value = nil)
def object_attribute_tag(object, attribute_name, value = :delegate_to_object)
name = object.class.human_attribute_name(attribute_name)
value ||= object.human_attribute_value(attribute_name)

if value == :delegate_to_object
value = object.human_attribute_value(attribute_name)
end

tag.strong(tag.span(name) + tag.span(" : ")) +
tag.span(value.presence || "Non renseigné", class: class_names("text-muted": value.blank?))
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/stylesheets/administrate/base/_forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,7 @@ select {
outline-offset: $focus-outline-offset;
}
}

.form-group {
margin: 8px 0;
}
3 changes: 3 additions & 0 deletions app/jobs/create_crisp_ticket_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def perform(nickname:, email:, phone:, subject:, message:, role:, domain:)
domain,
],
subject:,
device: {
locales: ["fr"],
},
}
)
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def timeout_in = 14.days # Used by Devise's :timeoutable
# * it validates :email (the invite_key) specifically with Devise.email_regexp.
validates :first_name, presence: true, unless: -> { allow_blank_name || is_an_intervenant? }
validates :last_name, presence: true, unless: -> { allow_blank_name }
validates :agent_services, presence: true
validates :agent_services, presence: true, unless: -> { roles.none? }

# Hooks
before_destroy :prevent_destroy_if_rdvs
Expand Down
4 changes: 4 additions & 0 deletions app/models/domain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
:support_email,
:secretariat_email,
:verticale,
:allow_agent_creation_with_agent_connect,
keyword_init: true
)

Expand All @@ -36,6 +37,7 @@ class Domain
france_connect_enabled: true,
support_email: "[email protected]",
verticale: :rdv_solidarites,
allow_agent_creation_with_agent_connect: false,
secretariat_email: "[email protected]"
# secretariat_email est utilisé comme adresse de "Reply-To" pour les e-mails
# qui contiennent des ICS. Lorsque l'événement ICS est acceptée par le
Expand All @@ -58,6 +60,7 @@ class Domain
france_connect_enabled: false,
support_email: "[email protected]",
verticale: :rdv_aide_numerique,
allow_agent_creation_with_agent_connect: false,
secretariat_email: "[email protected]"
),

Expand All @@ -76,6 +79,7 @@ class Domain
france_connect_enabled: true,
support_email: "[email protected]",
verticale: :rdv_mairie,
allow_agent_creation_with_agent_connect: true,
secretariat_email: "[email protected]"
),
].freeze
Expand Down
3 changes: 3 additions & 0 deletions app/services/admin_creates_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ def call
@agent = find_agent

if @agent
if @agent.services.none?
@agent.update(service_ids: @agent_params[:service_ids])
end
add_agent_to_organisations
@warning_message = self.class.check_agent_service(@agent, @agent_params[:service_ids])
elsif @access_level == "intervenant"
Expand Down
11 changes: 3 additions & 8 deletions app/services/concerns/users/creneaux_wizard_concern.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
module Users::CreneauxWizardConcern
extend ActiveSupport::Concern

# *** Method that outputs the next step for the user to complete its rdv journey ***
# *** It is used in #to_partial_path to render the matching partial view ***
# *** Method that outputs the current step for the user to complete its rdv journey ***
def current_step
if departement.blank?
:address_selection
Expand All @@ -23,10 +22,6 @@ def start_date
query_params[:date]&.to_date || super
end

def to_partial_path
"search/#{current_step}"
end

def wizard_after_creneau_selection_path(params)
url_helpers = Rails.application.routes.url_helpers
if @prescripteur
Expand All @@ -48,7 +43,7 @@ def unique_motifs_by_name_and_location_type
# Retourne une liste d'organisations et leur prochaine dispo, ordonnées par date de prochaine dispo
def next_availability_by_motifs_organisations
@next_availability_by_motifs_organisations ||= matching_motifs.to_h do |motif|
[motif.organisation, creneaux_search_for(nil, date_range, motif).next_availability]
[motif.organisation, creneaux_search_for(nil, motif).next_availability]
end.compact.sort_by(&:last).to_h
end

Expand All @@ -72,7 +67,7 @@ def next_availability_by_lieux
return @next_availability_by_lieux if @next_availability_by_lieux

next_availability_by_lieux = Lieu.with_open_slots_for_motifs(matching_motifs).includes(:organisation).to_h do |lieu|
next_availability = creneaux_search_for(lieu, date_range, matching_motifs.where(organisation: lieu.organisation).first).next_availability
next_availability = creneaux_search_for(lieu, matching_motifs.where(organisation: lieu.organisation).first).next_availability
[lieu, next_availability]
end.compact

Expand Down
16 changes: 0 additions & 16 deletions app/services/invitation_search_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,4 @@ def matching_motifs
Motif.available_for_booking.where(organisation_id: @organisation_ids).joins(:organisation)
)
end

def contactable_organisations
@contactable_organisations ||= Organisation.where(id: @organisation_ids).contactable
end

def organisations_emails
contactable_organisations.where.not(email: [nil, ""]).pluck(:email).join(",")
end

def motif_category_name
@motif_category_short_name.present? ? MotifCategory.find_by(short_name: @motif_category_short_name)&.name : nil
end

private

attr_reader :referent_ids, :lieu_id
end
4 changes: 2 additions & 2 deletions app/services/merge_users_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def merge_annotations
current_territory = @organisation.territory

annotation_to_merge = @user_to_merge.annotations.find_by(territory: current_territory)
@user_target.annotate!(annotation_to_merge.content, territory: current_territory)
annotation_to_merge.destroy!
@user_target.annotate!(annotation_to_merge&.content, territory: current_territory)
annotation_to_merge&.destroy!
end

def merge_user_attributes
Expand Down
12 changes: 3 additions & 9 deletions app/services/search_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def available_collective_rdvs
end

def creneaux_search
creneaux_search_for(lieu, date_range, first_matching_motif)
creneaux_search_for(lieu, first_matching_motif)
end

def first_matching_motif
Expand Down Expand Up @@ -54,9 +54,7 @@ def filter_motifs(available_motifs)

private

def referent_ids
raise NoMethodError
end
attr_reader :referent_ids, :lieu_id

def matching_motifs
raise NoMethodError
Expand All @@ -74,11 +72,7 @@ def street_ban_id
raise NoMethodError
end

def lieu_id
raise NoMethodError
end

def creneaux_search_for(lieu, date_range, motif)
def creneaux_search_for(lieu, motif)
CreneauxSearch::ForUser.new(
user: @user,
motif: motif,
Expand Down
18 changes: 18 additions & 0 deletions app/services/users/contactable_organisations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Users::ContactableOrganisations
def initialize(organisation_ids, motif_category_short_name)
@organisation_ids = organisation_ids
@motif_category_short_name = motif_category_short_name
end

def organisations
@organisations ||= Organisation.where(id: @organisation_ids).contactable
end

def organisations_emails
organisations.where.not(email: [nil, ""]).pluck(:email).join(",")
end

def motif_category_name
@motif_category_short_name.present? ? MotifCategory.find_by(short_name: @motif_category_short_name)&.name : nil
end
end
2 changes: 1 addition & 1 deletion app/services/web_invitation_search_context.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class WebInvitationSearchContext < InvitationSearchContext
include Users::CreneauxWizardConcern
attr_reader :errors, :query_params, :address, :latitude, :longitude
attr_reader :errors, :query_params, :address, :latitude, :longitude, :organisation_ids, :motif_category_short_name

def initialize(user:, query_params: {})
super
Expand Down
3 changes: 0 additions & 3 deletions app/services/web_search_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def initialize(user:, query_params: {})
@user_selected_organisation_id = query_params[:user_selected_organisation_id]
@external_organisation_ids = query_params[:external_organisation_ids]
@motif_id = query_params[:motif_id]
@motif_category_short_name = query_params[:motif_category_short_name]
@motif_name_with_location_type = query_params[:motif_name_with_location_type]
@service_id = query_params[:service_id]
@lieu_id = query_params[:lieu_id]
Expand Down Expand Up @@ -68,8 +67,6 @@ def motif_param_present?

private

attr_reader :referent_ids, :lieu_id

def matching_motifs
@matching_motifs ||= filter_motifs(geo_search.available_motifs)
end
Expand Down
Loading

0 comments on commit 2a94005

Please sign in to comment.