mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 03:54:08 +00:00
Add scheduled DemoFamilyRefreshJob to rebuild demo data daily (#1217)
* Add scheduled demo family refresh job Rebuild demo data daily at 5am UTC by anonymizing and enqueueing deletion of the existing demo family while immediately generating new sample data. Add super-admin email notifications with 24-hour session and signup metrics, plus tests for the new job and mailer. * Delete demo monitoring key before family refresh Ensure DemoFamilyRefreshJob removes ApiKey::DEMO_MONITORING_KEY from the old demo family before enqueueing async family destruction and generating replacement sample data. Adds a regression assertion that the key is gone before generator execution.
This commit is contained in:
80
app/jobs/demo_family_refresh_job.rb
Normal file
80
app/jobs/demo_family_refresh_job.rb
Normal file
@@ -0,0 +1,80 @@
|
||||
class DemoFamilyRefreshJob < ApplicationJob
|
||||
queue_as :scheduled
|
||||
|
||||
def perform
|
||||
period_end = Time.current
|
||||
period_start = period_end - 24.hours
|
||||
|
||||
demo_email = Rails.application.config_for(:demo).fetch("email")
|
||||
demo_user = User.find_by(email: demo_email)
|
||||
old_family = demo_user&.family
|
||||
|
||||
old_family_session_count = sessions_count_for(old_family, period_start:, period_end:)
|
||||
newly_created_families_count = Family.where(created_at: period_start...period_end).count
|
||||
|
||||
if old_family
|
||||
delete_old_family_monitoring_key!(old_family)
|
||||
anonymize_family_emails!(old_family)
|
||||
DestroyJob.perform_later(old_family)
|
||||
end
|
||||
|
||||
Demo::Generator.new.generate_default_data!(skip_clear: true, email: demo_email)
|
||||
|
||||
notify_super_admins!(
|
||||
old_family:,
|
||||
old_family_session_count:,
|
||||
newly_created_families_count:,
|
||||
period_start:,
|
||||
period_end:
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sessions_count_for(family, period_start:, period_end:)
|
||||
return 0 unless family
|
||||
|
||||
Session
|
||||
.joins(:user)
|
||||
.where(users: { family_id: family.id })
|
||||
.where(created_at: period_start...period_end)
|
||||
.distinct
|
||||
.count(:id)
|
||||
end
|
||||
|
||||
|
||||
def delete_old_family_monitoring_key!(family)
|
||||
ApiKey
|
||||
.where(user_id: family.users.select(:id), display_key: ApiKey::DEMO_MONITORING_KEY)
|
||||
.delete_all
|
||||
end
|
||||
|
||||
def anonymize_family_emails!(family)
|
||||
family.users.find_each do |user|
|
||||
user.update_columns(
|
||||
email: deleted_email_for(user),
|
||||
unconfirmed_email: nil,
|
||||
updated_at: Time.current
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def deleted_email_for(user)
|
||||
local_part, domain = user.email.split("@", 2)
|
||||
"#{local_part}+deleting-#{user.id}-#{SecureRandom.hex(4)}@#{domain}"
|
||||
end
|
||||
|
||||
def notify_super_admins!(old_family:, old_family_session_count:, newly_created_families_count:, period_start:, period_end:)
|
||||
User.super_admin.find_each do |super_admin|
|
||||
DemoFamilyRefreshMailer.with(
|
||||
super_admin:,
|
||||
old_family_id: old_family&.id,
|
||||
old_family_name: old_family&.name,
|
||||
old_family_session_count:,
|
||||
newly_created_families_count:,
|
||||
period_start:,
|
||||
period_end:
|
||||
).completed.deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
16
app/mailers/demo_family_refresh_mailer.rb
Normal file
16
app/mailers/demo_family_refresh_mailer.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
class DemoFamilyRefreshMailer < ApplicationMailer
|
||||
def completed
|
||||
@super_admin = params.fetch(:super_admin)
|
||||
@old_family_id = params[:old_family_id]
|
||||
@old_family_name = params[:old_family_name]
|
||||
@old_family_session_count = params.fetch(:old_family_session_count)
|
||||
@newly_created_families_count = params.fetch(:newly_created_families_count)
|
||||
@period_start = params.fetch(:period_start)
|
||||
@period_end = params.fetch(:period_end)
|
||||
|
||||
mail(
|
||||
to: @super_admin.email,
|
||||
subject: "Demo family refresh completed"
|
||||
)
|
||||
end
|
||||
end
|
||||
6
app/views/demo_family_refresh_mailer/completed.text.erb
Normal file
6
app/views/demo_family_refresh_mailer/completed.text.erb
Normal file
@@ -0,0 +1,6 @@
|
||||
Demo family refresh has completed.
|
||||
|
||||
Period (UTC): <%= @period_start.iso8601 %> to <%= @period_end.iso8601 %>
|
||||
Old demo family: <%= @old_family_name || "not found" %><% if @old_family_id %> (ID: <%= @old_family_id %>)<% end %>
|
||||
Unique login sessions for old demo family in period: <%= @old_family_session_count %>
|
||||
New family accounts created in period: <%= @newly_created_families_count %>
|
||||
@@ -36,3 +36,9 @@ clean_inactive_families:
|
||||
class: "InactiveFamilyCleanerJob"
|
||||
queue: "scheduled"
|
||||
description: "Archives and destroys families that expired their trial without subscribing (managed mode only)"
|
||||
|
||||
refresh_demo_family:
|
||||
cron: "0 5 * * *" # daily at 5:00 AM UTC
|
||||
class: "DemoFamilyRefreshJob"
|
||||
queue: "scheduled"
|
||||
description: "Refreshes demo family data and emails super admins with daily usage summary"
|
||||
|
||||
64
test/jobs/demo_family_refresh_job_test.rb
Normal file
64
test/jobs/demo_family_refresh_job_test.rb
Normal file
@@ -0,0 +1,64 @@
|
||||
require "test_helper"
|
||||
|
||||
class DemoFamilyRefreshJobTest < ActiveJob::TestCase
|
||||
setup do
|
||||
@demo_email = "demo-user@example.com"
|
||||
Rails.application.stubs(:config_for).with(:demo).returns({ "email" => @demo_email })
|
||||
|
||||
@demo_family = Family.create!(name: "Demo Family")
|
||||
@demo_user = @demo_family.users.create!(
|
||||
first_name: "Demo",
|
||||
last_name: "Admin",
|
||||
email: @demo_email,
|
||||
password: "password123",
|
||||
role: :admin,
|
||||
onboarded_at: Time.current,
|
||||
ai_enabled: true,
|
||||
show_sidebar: true,
|
||||
show_ai_sidebar: true,
|
||||
ui_layout: :dashboard
|
||||
)
|
||||
|
||||
@super_admin = families(:dylan_family).users.create!(
|
||||
first_name: "Super",
|
||||
last_name: "Admin",
|
||||
email: "super-admin@example.com",
|
||||
password: "password123",
|
||||
role: :super_admin,
|
||||
onboarded_at: Time.current,
|
||||
ai_enabled: true,
|
||||
show_sidebar: true,
|
||||
show_ai_sidebar: true,
|
||||
ui_layout: :dashboard
|
||||
)
|
||||
end
|
||||
|
||||
test "anonymizes old demo user email, enqueues deletion, regenerates data, and notifies super admins" do
|
||||
travel_to Time.utc(2026, 1, 1, 5, 0, 0) do
|
||||
Session.create!(user: @demo_user)
|
||||
Family.create!(name: "New Family Today", created_at: 6.hours.ago)
|
||||
Family.create!(name: "Old Family", created_at: 2.days.ago)
|
||||
@demo_user.api_keys.create!(
|
||||
name: "monitoring",
|
||||
key: ApiKey::DEMO_MONITORING_KEY,
|
||||
scopes: [ "read" ],
|
||||
source: "monitoring"
|
||||
)
|
||||
|
||||
generator = mock
|
||||
generator.expects(:generate_default_data!).with(skip_clear: true, email: @demo_email) do
|
||||
assert_nil ApiKey.find_by(display_key: ApiKey::DEMO_MONITORING_KEY)
|
||||
end
|
||||
Demo::Generator.expects(:new).returns(generator)
|
||||
|
||||
assert_enqueued_with(job: DestroyJob, args: [ @demo_family ]) do
|
||||
assert_enqueued_jobs 2, only: ActionMailer::MailDeliveryJob do
|
||||
DemoFamilyRefreshJob.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
assert_not_equal @demo_email, @demo_user.reload.email
|
||||
assert_match(/\+deleting-/, @demo_user.email)
|
||||
end
|
||||
end
|
||||
end
|
||||
23
test/mailers/demo_family_refresh_mailer_test.rb
Normal file
23
test/mailers/demo_family_refresh_mailer_test.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require "test_helper"
|
||||
|
||||
class DemoFamilyRefreshMailerTest < ActionMailer::TestCase
|
||||
test "completed email includes summary metrics" do
|
||||
period_start = Time.utc(2026, 1, 1, 5, 0, 0)
|
||||
period_end = period_start + 24.hours
|
||||
|
||||
email = DemoFamilyRefreshMailer.with(
|
||||
super_admin: users(:sure_support_staff),
|
||||
old_family_id: families(:empty).id,
|
||||
old_family_name: families(:empty).name,
|
||||
old_family_session_count: 12,
|
||||
newly_created_families_count: 4,
|
||||
period_start:,
|
||||
period_end:
|
||||
).completed
|
||||
|
||||
assert_equal [ "support@sure.am" ], email.to
|
||||
assert_equal "Demo family refresh completed", email.subject
|
||||
assert_includes email.body.to_s, "Unique login sessions for old demo family in period: 12"
|
||||
assert_includes email.body.to_s, "New family accounts created in period: 4"
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user