Class: AccountDailyActivityReport

Inherits:
Object
  • Object
show all
Defined in:
app/services/account_daily_activity_report.rb

Overview

Reporting window for the sysadmin email:

  • Production default: previous calendar day in America/Chicago.
  • Optional local/test: set ACCOUNT_ACTIVITY_REPORT_LOOKBACK_HOURS=48 for a rolling window
    ending at “now” in Chicago (e.g. dev DB snapshot testing).

Constant Summary collapse

TZ =

Tz.

'America/Chicago'
ENV_LOOKBACK_HOURS =

Env lookback hours.

'ACCOUNT_ACTIVITY_REPORT_LOOKBACK_HOURS'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(date: nil, range: nil, rolling_hours: nil) ⇒ AccountDailyActivityReport

Returns a new instance of AccountDailyActivityReport.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'app/services/account_daily_activity_report.rb', line 15

def initialize(date: nil, range: nil, rolling_hours: nil)
  tz = ActiveSupport::TimeZone[TZ]
  if range
    @window_start = range.begin.in_time_zone(tz)
    @window_end = range.end.in_time_zone(tz)
    @date = @window_start.to_date
    @rolling_hours = rolling_hours
  elsif date
    @date = date
    @window_start = tz.local(date.year, date.month, date.day).beginning_of_day
    @window_end = @window_start.end_of_day
    @rolling_hours = nil
  else
    raise ArgumentError, 'Provide date: or range:'
  end
end

Instance Attribute Details

#dateObject (readonly)

Returns the value of attribute date.



13
14
15
# File 'app/services/account_daily_activity_report.rb', line 13

def date
  @date
end

#rolling_hoursObject (readonly)

Returns the value of attribute rolling_hours.



13
14
15
# File 'app/services/account_daily_activity_report.rb', line 13

def rolling_hours
  @rolling_hours
end

#window_endObject (readonly)

Returns the value of attribute window_end.



13
14
15
# File 'app/services/account_daily_activity_report.rb', line 13

def window_end
  @window_end
end

#window_startObject (readonly)

Returns the value of attribute window_start.



13
14
15
# File 'app/services/account_daily_activity_report.rb', line 13

def window_start
  @window_start
end

Class Method Details

.calendar_yesterdayObject



47
48
49
50
# File 'app/services/account_daily_activity_report.rb', line 47

def self.calendar_yesterday
  tz = ActiveSupport::TimeZone[TZ]
  new(date: tz.now.to_date - 1)
end

.for_scheduled_runObject



32
33
34
35
36
37
38
39
# File 'app/services/account_daily_activity_report.rb', line 32

def self.for_scheduled_run
  hours = lookback_hours_from_env
  if hours&.positive?
    rolling_hours(hours)
  else
    calendar_yesterday
  end
end

.lookback_hours_from_envObject



52
53
54
55
56
57
58
59
# File 'app/services/account_daily_activity_report.rb', line 52

def self.lookback_hours_from_env
  v = ENV[ENV_LOOKBACK_HOURS].to_s.strip
  return nil if v.blank?

  Integer(v)
rescue ArgumentError, TypeError
  nil
end

.rolling_hours(hours) ⇒ Object



41
42
43
44
45
# File 'app/services/account_daily_activity_report.rb', line 41

def self.rolling_hours(hours)
  tz = ActiveSupport::TimeZone[TZ]
  now = tz.now
  new(range: (now - hours.hours)..now, rolling_hours: hours)
end

Instance Method Details

#accounts_createdObject



61
62
63
# File 'app/services/account_daily_activity_report.rb', line 61

def accounts_created
  Account.includes(:party).where(created_at: window_start..window_end).order(:id)
end

#accounts_created_by_groupObject

Split: WWW = customer site (Customer party), CRM = employee app (Employee party).



73
74
75
# File 'app/services/account_daily_activity_report.rb', line 73

def accounts_created_by_group
  split_by_www_crm(accounts_created)
end

#login_eventsObject

Per-event sign-in attempts (success + failure) recorded by AuthTrail
in login_activities. Replaces the previous Devise current_sign_in_at
snapshot, which collapsed multi-login days into a single row per account.



68
69
70
# File 'app/services/account_daily_activity_report.rb', line 68

def 
  LoginActivity.where(created_at: window_start..window_end).order(:created_at)
end

#login_events_by_groupObject

Bucket every LoginActivity row in the window by audience and outcome:

{
www: { success: [...], failure: [...] },
crm: { success: [...], failure: [...] },
other: { success: [...], failure: [...] }, # Account exists but party is neither Customer nor Employee
unmatched: { success: [...], failure: [...] }, # No Account row matched (typical for failed attempts)
}

Each event also carries a memoised :account (or nil) and :party
(or nil) on the row's instance_variable_get(:@report_*) shims so the
mailer view can render them without re-querying.



89
90
91
92
93
# File 'app/services/account_daily_activity_report.rb', line 89

def 
  events = .to_a
  grouped = bucket_events(events, preload_accounts(events))
  ensure_all_buckets(grouped)
end