Skip to content

Commit d5f802d

Browse files
SamJamCulstephencdaly
authored andcommitted
Add a job to send a daily batch of submissions for a form
Add a job that will send an email containing CSV(s) of submissions for a given form on a given day for a given mode. This job is not scheduled by anything yet. Co-authored-by: Samuel Culley <samuel.culley@digital.cabinet-office.gov.uk>
1 parent 3c60a22 commit d5f802d

File tree

5 files changed

+140
-2
lines changed

5 files changed

+140
-2
lines changed

app/jobs/application_job.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,12 @@ def set_submission_logging_attributes(submission)
77
CurrentJobLoggingAttributes.submission_reference = submission.reference
88
CurrentJobLoggingAttributes.preview = submission.preview?
99
end
10+
11+
def set_submission_batch_logging_attributes(form:, mode:)
12+
CurrentJobLoggingAttributes.job_class = self.class.name
13+
CurrentJobLoggingAttributes.job_id = job_id
14+
CurrentJobLoggingAttributes.form_id = form.id
15+
CurrentJobLoggingAttributes.form_name = form.name
16+
CurrentJobLoggingAttributes.preview = mode.preview?
17+
end
1018
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
class SendSubmissionBatchJob < ApplicationJob
2+
queue_as :submissions
3+
4+
# this translates to approximately 4.5 hours of retrying in total
5+
TOTAL_ATTEMPTS = 10
6+
7+
retry_on Aws::SESV2::Errors::ServiceError, wait: :polynomially_longer, attempts: TOTAL_ATTEMPTS
8+
9+
def perform(form_id:, mode_string:, date:, delivery:)
10+
submissions = Submission.for_daily_batch(form_id, date, mode_string)
11+
12+
if submissions.empty?
13+
Rails.logger.info("No submissions to batch for form_id: #{form_id}, mode: #{mode_string}, date: #{date}")
14+
return
15+
end
16+
17+
form = submissions.first.form
18+
mode = Mode.new(mode_string)
19+
set_submission_batch_logging_attributes(form:, mode:)
20+
21+
message_id = AwsSesSubmissionBatchService.new(submissions:, form:, date:, mode:).send_batch
22+
23+
delivery.update!(
24+
delivery_reference: message_id,
25+
last_attempt_at: Time.zone.now,
26+
submissions: submissions,
27+
)
28+
29+
EventLogger.log_form_event("daily_batch_email_sent", {
30+
mode:,
31+
batch_date: date,
32+
number_of_submissions: submissions.count,
33+
})
34+
35+
submissions.each do |submission|
36+
EventLogger.log_form_event("included_in_daily_batch_email", {
37+
submission_reference: submission.reference,
38+
batch_date: date,
39+
})
40+
end
41+
end
42+
end

spec/factories/submissions.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
}
1616
end
17-
mode { is_preview ? "preview-live" : "live" }
17+
mode { is_preview ? "preview-live" : "form" }
1818
form_document { build :v2_form_document, form_id: }
1919
submission_locale { :en }
2020

spec/factories/v2_form_document.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
end
3333

3434
steps do
35-
Array.new(steps_count) { attributes_for(:v2_step) }
35+
Array.new(steps_count) { attributes_for(:v2_question_page_step) }
3636
end
3737

3838
question_section_completed { true }
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
require "rails_helper"
2+
3+
# rubocop:disable RSpec/InstanceVariable
4+
RSpec.describe SendSubmissionBatchJob, type: :job do
5+
include ActiveJob::TestHelper
6+
7+
let(:mode_string) { "form" }
8+
let(:date) { Date.new(2022, 12, 14) }
9+
let(:delivery) { create(:delivery, batch_frequency: "daily") }
10+
11+
let(:form_document) { create(:v2_form_document, :with_steps, name: "My Form", submission_email: "to@example.com") }
12+
let(:form_id) { form_document.form_id }
13+
let(:submissions) { [] }
14+
15+
before do
16+
submissions
17+
ActionMailer::Base.deliveries.clear
18+
end
19+
20+
context "when the job is processed" do
21+
before do
22+
described_class.perform_later(form_id:, mode_string:, date:, delivery:)
23+
travel 5.seconds do
24+
@job_ran_at = Time.zone.now
25+
perform_enqueued_jobs
26+
end
27+
end
28+
29+
context "when there are no submissions" do
30+
it "does not send an email" do
31+
expect(ActionMailer::Base.deliveries).to be_empty
32+
end
33+
34+
it "does not update the delivery" do
35+
expect(delivery.reload.last_attempt_at).to be_nil
36+
end
37+
end
38+
39+
context "when there are submissions" do
40+
let(:submissions_to_include) do
41+
create_list(
42+
:submission,
43+
3,
44+
form_document:,
45+
form_id:,
46+
mode: mode_string,
47+
created_at: date.beginning_of_day + 1.hour,
48+
)
49+
end
50+
let(:submission_not_on_date) do
51+
create(:submission, form_document:, form_id:, mode: mode_string, created_at: date.beginning_of_day - 1.day)
52+
end
53+
let(:preview_submission) do
54+
create(:submission, :preview, form_document:, form_id:, created_at: date.beginning_of_day + 1.hour)
55+
end
56+
let(:submissions) { [submissions_to_include, submission_not_on_date, preview_submission] }
57+
58+
it "sends an email" do
59+
expect(ActionMailer::Base.deliveries.count).to eq(1)
60+
61+
mail = ActionMailer::Base.deliveries.last
62+
expect(mail.to).to include(form_document.submission_email)
63+
end
64+
65+
it "updates the delivery" do
66+
mail = ActionMailer::Base.deliveries.last
67+
expect(delivery.reload.delivery_reference).to eq(mail.message_id)
68+
expect(delivery.reload.last_attempt_at).to be_within(1.second).of(@job_ran_at)
69+
end
70+
71+
it "attaches a csv with the expected filename" do
72+
mail = ActionMailer::Base.deliveries.last
73+
expect(mail.attachments).not_to be_empty
74+
75+
filenames = mail.attachments.map(&:filename)
76+
expect(filenames).to contain_exactly("govuk_forms_my_form_2022-12-14.csv")
77+
end
78+
79+
it "attaches a csv containing header plus one line per submission" do
80+
mail = ActionMailer::Base.deliveries.last
81+
82+
csv_content = mail.attachments.first.decoded
83+
expect(csv_content.lines.count).to eq(submissions_to_include.count + 1)
84+
end
85+
end
86+
end
87+
end
88+
# rubocop:enable RSpec/InstanceVariable

0 commit comments

Comments
 (0)