demarches-normaliennes/app/services/expired/users_deletion_service.rb
2024-08-22 09:26:48 +02:00

79 lines
2.7 KiB
Ruby

# frozen_string_literal: true
class Expired::UsersDeletionService < Expired::MailRateLimiter
def process_expired
# we are working on two dataset because we apply two incompatible join on the same query
# inner join on users not having dossier.en_instruction [so we do not destroy users with dossiers.en_instruction]
# outer join on users not having dossier at all [so we destroy users without dossiers]
[expired_users_without_dossiers, expired_users_with_dossiers].each do |expired_segment|
delete_notified_users(expired_segment)
send_inactive_close_to_expiration_notice(expired_segment)
end
end
private
# in case of perf downside :
# consider using perform_all_later
# consider changing notify_inactive_close_to_deletion method, taking a user_id, and updating inactive_close_to_expiration_notice_sent_at
def send_inactive_close_to_expiration_notice(users)
user_ids = to_notify_only(users).pluck(:id)
user_ids.each do |user_id|
send_with_delay(UserMailer.notify_inactive_close_to_deletion(User.find(user_id)))
end
User.where(id: user_ids).update_all(inactive_close_to_expiration_notice_sent_at: Time.zone.now.utc)
end
def delete_notified_users(users)
user_ids = only_notified(users).pluck(:id)
user_ids.each do |user_id|
user = User.find(user_id)
begin
user.delete_and_keep_track_dossiers_also_delete_user(nil, reason: :user_expired)
rescue => e
Sentry.capture_exception(e, extra: { user_id: user.id })
end
end
end
# rubocop:disable DS/Unscoped
def expired_users_with_dossiers
dossiers = Dossier.arel_table
users = User.arel_table
expired_users
.joins(
users.join(dossiers, Arel::Nodes::OuterJoin)
.on(users[:id].eq(dossiers[:user_id])
.and(dossiers[:state].eq(Dossier.states.fetch(:en_instruction))))
.join_sources
)
.where(dossiers[:id].eq(nil))
.group("users.id")
end
def expired_users_without_dossiers
expired_users.where.missing(:dossiers)
end
def expired_users
User.unscoped
.where.missing(:expert, :instructeur, :administrateur)
.where(last_sign_in_at: ..Expired::INACTIVE_USER_RETATION_IN_YEAR.years.ago)
end
# rubocop:enable DS/Unscoped
def to_notify_only(users)
users.where(inactive_close_to_expiration_notice_sent_at: nil)
.limit(daily_limit) # ensure to not send too much email
end
def only_notified(users)
users.where.not(inactive_close_to_expiration_notice_sent_at: Expired::REMAINING_WEEKS_BEFORE_EXPIRATION.weeks.ago..)
.limit(daily_limit) # event if we do not send email, avoid to destroy 800k user in one batch
end
def daily_limit
(ENV['EXPIRE_USER_DELETION_JOB_LIMIT'] || 10_000).to_i
end
end