Skip to content

Commit c4df212

Browse files
committed
feat: Implement weekly email report
Fixes #80
1 parent 5401144 commit c4df212

30 files changed

+600
-38
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ gem 'validate_url'
7575

7676
# Background job processing
7777
gem 'sidekiq', '< 6'
78+
gem 'sidekiq-cron', '~> 1.1'
7879

7980
# Misc support gems
8081
gem 'rails-settings-cached', '~> 0.7.2'

Gemfile.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ GEM
141141
errbase (0.1.1)
142142
erubi (1.8.0)
143143
erubis (2.7.0)
144+
et-orbi (1.2.1)
145+
tzinfo
144146
excon (0.64.0)
145147
execjs (2.7.0)
146148
factory_bot (5.0.2)
@@ -157,6 +159,9 @@ GEM
157159
font-awesome-rails (4.7.0.5)
158160
railties (>= 3.2, < 6.1)
159161
formatador (0.2.5)
162+
fugit (1.2.1)
163+
et-orbi (~> 1.1, >= 1.1.8)
164+
raabro (~> 1.1)
160165
globalid (0.4.2)
161166
activesupport (>= 4.2.0)
162167
groupdate (4.1.1)
@@ -274,6 +279,7 @@ GEM
274279
method_source (~> 0.9.0)
275280
public_suffix (3.0.3)
276281
puma (3.12.1)
282+
raabro (1.1.6)
277283
rack (2.0.7)
278284
rack-protection (2.0.5)
279285
rack
@@ -377,6 +383,9 @@ GEM
377383
rack (>= 1.5.0)
378384
rack-protection (>= 1.5.0)
379385
redis (>= 3.3.5, < 5)
386+
sidekiq-cron (1.1.0)
387+
fugit (~> 1.1)
388+
sidekiq (>= 4.2.1)
380389
simple_form (4.1.0)
381390
actionpack (>= 5.0)
382391
activemodel (>= 5.0)
@@ -496,6 +505,7 @@ DEPENDENCIES
496505
shoulda (~> 3.5)
497506
shoulda-matchers (~> 2.0)
498507
sidekiq (< 6)
508+
sidekiq-cron (~> 1.1)
499509
simple_form
500510
simple_spark
501511
simplecov

app/assets/javascripts/manage/lib/setupDataTables.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var setupDataTables = function() {
3939
{ orderable: true, data: "email" },
4040
{ orderable: true, data: "role" },
4141
{ orderable: true, data: "active" },
42+
{ orderable: true, data: "receive_weekly_report" },
4243
{ orderable: true, data: "created_at" }
4344
]
4445
});

app/controllers/manage/admins_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def destroy
4646

4747
def user_params
4848
params.require(:user).permit(
49-
:email, :password, :password_confirmation, :remember_me, :role, :is_active
49+
:email, :password, :password_confirmation, :remember_me, :role, :is_active, :receive_weekly_report
5050
)
5151
end
5252

app/datatables/admin_datatable.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def view_columns
77
email: { source: "User.email" },
88
role: { source: "User.role", searchable: false },
99
active: { source: "User.is_active", searchable: false },
10+
receive_weekly_report: { source: "User.receive_weekly_report", searchable: false },
1011
created_at: { source: "User.created_at", searchable: false },
1112
}
1213
end
@@ -20,6 +21,7 @@ def data
2021
email: link_to(bold(record.email), manage_admin_path(record)),
2122
role: record.role.titleize,
2223
active: record.is_active ? '<span class="badge badge-secondary">Active</span>'.html_safe : '<span class="badge badge-danger">Inactive<span>'.html_safe,
24+
receive_weekly_report: record.receive_weekly_report ? '<span class="badge badge-success">Yes</span>'.html_safe : '<span class="badge badge-secondary">No<span>'.html_safe,
2325
created_at: display_datetime(record.created_at),
2426
}
2527
end

app/jobs/admin_weekly_report_job.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class AdminWeeklyReportJob < ApplicationJob
2+
queue_as :default
3+
4+
def perform
5+
# Queue all eligible users and let the is_active (or other) logic determine if they should really receive it
6+
users = User.where(receive_weekly_report: true)
7+
users.each do |user|
8+
AdminMailer.weekly_report(user.id).deliver_later
9+
end
10+
end
11+
end

app/mailers/admin_mailer.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class AdminMailer < ApplicationMailer
2+
include Roadie::Rails::Automatic
3+
add_template_helper(HackathonManagerHelper)
4+
5+
layout "admin_mailer"
6+
7+
def weekly_report(user_id)
8+
# Don't send emails more than 7 days after event starts
9+
stop_date = Date.parse(HackathonConfig["event_start_date"]) + 7.days
10+
return if Date.today > stop_date
11+
12+
@user = User.find_by_id(user_id)
13+
14+
return unless @user.safe_receive_weekly_report
15+
16+
@period_start = 7.days.ago.at_beginning_of_day
17+
@period_end = 1.day.ago.at_end_of_day
18+
@period = @period_start..@period_end
19+
20+
@applications = report_metric(Questionnaire, :created_at)
21+
@rsvp_confirmed = report_metric(Questionnaire.where(acc_status: "rsvp_confirmed"), :acc_status_date)
22+
@rsvp_denied = report_metric(Questionnaire.where(acc_status: "rsvp_denied"), :acc_status_date)
23+
24+
@bus_metrics = BusList.all.map do |bus_list|
25+
{
26+
name: bus_list.name,
27+
total: bus_list.passengers.count,
28+
}
29+
end
30+
31+
@messages_sent = Message.bulk.where(delivered_at: @period).count
32+
33+
@new_admissions_metrics = [@applications, @rsvp_confirmed, @rsvp_denied].any? { |x| x[:new].positive? }
34+
@new_communication_metrics = @messages_sent.positive?
35+
36+
# Don't send email if no new activity
37+
return if !@new_admissions_metrics && !@new_bus_list_metrics && !@new_communication_metrics
38+
39+
mail(
40+
to: pretty_email(@user.full_name, @user.email),
41+
subject: "Your Weekly Report",
42+
)
43+
end
44+
45+
private
46+
47+
def report_metric(query_base, new_query_field)
48+
{
49+
new: query_base.where(new_query_field => @period).count,
50+
total: query_base.count,
51+
}
52+
end
53+
end

app/mailers/application_mailer.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
class ApplicationMailer < ActionMailer::Base
2-
default from: -> { HackathonConfig['email_from'] }
3-
layout 'mailer'
2+
default from: -> { HackathonConfig["email_from"] }
3+
layout "mailer"
4+
5+
def pretty_email(name, email)
6+
return email if name.blank?
7+
8+
"\"#{name}\" <#{email}>"
9+
end
410
end

app/mailers/mail_preview.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@ def bulk_message_email
44
message = Message.first
55
Mailer.bulk_message_email(message, User.first.id)
66
end
7+
8+
def admin_weekly_report
9+
AdminMailer.weekly_report(User.first.id)
10+
end
711
end
812
end

app/mailers/mailer.rb

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,29 @@ class Mailer < ApplicationMailer
22
include Roadie::Rails::Automatic
33
add_template_helper(HackathonManagerHelper)
44

5-
default from: -> { HackathonConfig['email_from'] }
6-
75
def bulk_message_email(message_id, user_id, message = nil, use_examples = false)
8-
@message = message || Message.find_by_id(message_id)
9-
@user = User.find_by_id(user_id)
6+
@message = message || Message.find_by_id(message_id)
7+
@user = User.find_by_id(user_id)
108
@use_examples = use_examples
119
return if @user.blank? || @message.blank?
1210

1311
mail(
1412
to: pretty_email(@user.full_name, @user.email),
15-
subject: @message.subject
13+
subject: @message.subject,
1614
)
1715
end
1816

1917
def incomplete_reminder_email(user_id)
2018
@user = User.find_by_id(user_id)
21-
return if @user.blank? || @user.admin? || @user.questionnaire || Time.now.to_date > Date.parse(HackathonConfig['last_day_to_apply'])
19+
return if @user.blank? || @user.admin? || @user.questionnaire || Time.now.to_date > Date.parse(HackathonConfig["last_day_to_apply"])
2220

2321
Message.queue_for_trigger("user.24hr_incomplete_application", @user.id)
2422
end
2523

2624
rescue_from SparkPostRails::DeliveryException do |e|
2725
error_codes_to_not_retry = [
28-
"1902" # Generation rejection
26+
"1902", # Generation rejection
2927
]
3028
raise e unless e.blank? || error_codes_to_not_retry.include?(e.service_code)
3129
end
32-
33-
private
34-
35-
def pretty_email(name, email)
36-
return email if name.blank?
37-
38-
"\"#{name}\" <#{email}>"
39-
end
4030
end

0 commit comments

Comments
 (0)