Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create service to resend emails #1345

Merged
merged 10 commits into from
Jan 24, 2025
17 changes: 6 additions & 11 deletions app/controllers/claims/sampling/claims_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ class Claims::Sampling::ClaimsController < Claims::ApplicationController
skip_before_action :authenticate_user!

before_action :skip_authorization
before_action :validate_token
before_action :set_provider_sampling
after_action :mark_as_downloaded, only: :download

Expand All @@ -13,17 +12,14 @@ def download

private

def validate_token
@provider_sampling_id = Rails.application.message_verifier(:sampling).verify(token_param)
rescue ActiveSupport::MessageVerifier::InvalidSignature
def set_provider_sampling
@provider_sampling = download_access_token.activity_record
rescue ActiveRecord::RecordNotFound, ActiveSupport::MessageVerifier::InvalidSignature
render "error"
end

def set_provider_sampling
@provider_sampling = Claims::ProviderSampling.find(@provider_sampling_id)
raise CSVPreviouslyDownloadedError if @provider_sampling.downloaded?
rescue ActiveRecord::RecordNotFound, CSVPreviouslyDownloadedError
render "error"
def download_access_token
@download_access_token = Claims::DownloadAccessToken.find_by_token_for!(:csv_download, token_param)
end

def token_param
Expand All @@ -32,7 +28,6 @@ def token_param

def mark_as_downloaded
@provider_sampling.update!(downloaded_at: Time.current)
download_access_token.update!(downloaded_at: Time.current)
end
end

class CSVPreviouslyDownloadedError < StandardError; end
23 changes: 19 additions & 4 deletions app/mailers/claims/provider_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
class Claims::ProviderMailer < Claims::ApplicationMailer
def sampling_checks_required(provider_sampling)
def sampling_checks_required(provider_sampling, email_address:)
@provider_sampling = provider_sampling
@email_address = email_address

notify_email to: @provider_sampling.provider_email_addresses,
notify_email to: email_address,
subject: t(".subject"),
body: t(
".body",
provider_name: @provider_sampling.provider_name,
download_csv_url: claims_sampling_claims_url(token:),
support_email:, service_name:, completion_date:, service_url: claims_root_url
)
end

def resend_sampling_checks_required(provider_sampling, email_address:)
@provider_sampling = provider_sampling
@email_address = email_address

notify_email to: email_address,
subject: t(".subject"),
body: t(
".body",
Expand All @@ -14,10 +29,10 @@ def sampling_checks_required(provider_sampling)

private

attr_reader :provider_sampling
attr_reader :provider_sampling, :email_address

def token
Rails.application.message_verifier(:sampling).generate(provider_sampling.id, expires_in: 7.days)
Claims::DownloadAccessToken.create!(activity_record: provider_sampling, email_address:).generate_token_for(:csv_download)
end

def completion_date
Expand Down
26 changes: 26 additions & 0 deletions app/models/claims/download_access_token.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# == Schema Information
#
# Table name: download_access_tokens
#
# id :uuid not null, primary key
# activity_record_type :string not null
# downloaded_at :datetime
# email_address :string not null
# created_at :datetime not null
# updated_at :datetime not null
# activity_record_id :uuid not null
#
# Indexes
#
# index_download_access_tokens_on_activity_record (activity_record_type,activity_record_id)
#
class Claims::DownloadAccessToken < ApplicationRecord
generates_token_for :csv_download, expires_in: 7.days do
downloaded_at
end

belongs_to :activity_record, polymorphic: true

validates :email_address, presence: true
validates :activity_record, presence: true
end
1 change: 1 addition & 0 deletions app/models/claims/provider_sampling.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Claims::ProviderSampling < ApplicationRecord

has_many :provider_sampling_claims
has_many :claims, through: :provider_sampling_claims
has_many :download_access_tokens, as: :activity_record, dependent: :destroy

has_one_attached :csv_file

Expand Down
4 changes: 3 additions & 1 deletion app/services/claims/sampling/create_and_deliver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ def call
provider_sampling = Claims::ProviderSampling.create!(provider:, claims: provider_claims, sampling:, csv_file: File.open(csv_for_provider(provider_claims, provider.name).to_io))

transaction.after_commit do
Claims::ProviderMailer.sampling_checks_required(provider_sampling).deliver_later
provider.email_addresses.each do |email_address|
Claims::ProviderMailer.sampling_checks_required(provider_sampling, email_address:).deliver_later
end
end
end
end
Expand Down
27 changes: 27 additions & 0 deletions app/services/claims/sampling/resend_emails.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Claims::Sampling::ResendEmails < ApplicationService
def initialize(provider_sampling:, email_addresses: provider_sampling.provider_email_addresses)
@provider_sampling = provider_sampling
@email_addresses = email_addresses
end

def call
validate_email_addresses
provider_sampling.transaction do
provider_sampling.download_access_tokens.where(email_address: email_addresses).destroy_all

email_addresses.each do |email_address|
Claims::ProviderMailer.resend_sampling_checks_required(provider_sampling, email_address:).deliver_later
end
end
end

private

attr_reader :provider_sampling, :email_addresses

def validate_email_addresses
raise InvalidEmailAddressesError unless (email_addresses - provider_sampling.provider_email_addresses).empty?
end

class InvalidEmailAddressesError < StandardError; end
end
8 changes: 8 additions & 0 deletions config/analytics_blocklist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ shared:
- record_id
- blob_id
- created_at
:download_access_tokens:
- id
- email_address
- activity_record_type
- activity_record_id
- created_at
- updated_at
- downloaded_at
:good_job_settings:
- id
- created_at
Expand Down
74 changes: 73 additions & 1 deletion config/locales/en/claims/provider_mailer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,79 @@ en:

# What you need to do

Use the CSV file to check the accuracy of the claims associated with you and record your answers in the file. It is in a spreadsheet format for you to fill out.
Use the CSV file to check the accuracy of the claims associated with you and record your answers in the file. It is in a spreadsheet format for you to fill out.

Visit the GOV.UK claim funding for mentor training website to download the file:

[%{download_csv_url}](%{download_csv_url})

This link will expire in 7 days due to data security. To request a new link, reply to this email.

To complete the CSV, you must:

- fill in ‘yes’ or no’ in the ‘claim_accepted’ column
- for any ‘no’ answers, give us a reason for rejection validated by the school in the ‘rejection_reason’ column
- reply to this email and attach the updated file by %{completion_date}

## If the claims are accurate
If the mentors, hours and number of claims are correct, mark the claims as ‘yes’ in the ‘claim_accepted’ column of the CSV file.

## If you disagree with a claim
If you disagree with the information a school submitted to us, contact the school to discuss it. They may have additional evidence or a reason.

## If the school gives you valid evidence after speaking to them
If you accept the evidence the placement school provides, mark the claim as ‘yes’ in the ‘claim_accepted’ column.

## If the school does not give you valid evidence after speaking to them
If the school cannot provide any additional information or cannot provide information that you accept, mark the claim as ‘no’ in the ‘claim_accepted’ column.

You must give a reason why a claim is incorrect. Write this in the ‘rejection_reason’ column.

Some reasons may include that a mentor is:

- on the Early Career Framework (ECF), rather than ITT
- claiming too many hours
- claiming too few hours
- not known to you
- not employed at the school

--------

## After you complete quality assurance

For any rejected claims, we will contact schools to confirm they agree. Make sure you speak to the school about rejected claims before you submit your answers to us. This will avoid any confusion about their eligibility for funding.

--------

## Contact us

If you need any help with completing the quality assurance, contact the team at [%{support_email}](mailto:%{support_email})

Learn more about [funding for mentor training on GOV.UK](%{service_url})


Claim funding for mentor training team

resend_sampling_checks_required:
subject: ITT mentor claims need to be quality assured
body: |
%{provider_name},

^ We are resending this email due to an internal issue. Please disregard any previous emails you may have received.

You are required by Department for Education (DfE) to complete quality assurance on funding claims associated with %{provider_name}.

One or more schools submitted funding requests to DfE due to you providing training for their staff to become initial teacher training (ITT) mentors.

# You must complete quality assurance by %{completion_date}

If you do not check these claims by 11:59pm on %{completion_date}, we may escalate the assurance process. This can include removing funding from schools you worked with.

------------

# What you need to do

Use the CSV file to check the accuracy of the claims associated with you and record your answers in the file. It is in a spreadsheet format for you to fill out.

Visit the GOV.UK claim funding for mentor training website to download the file:

Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20250124105642_create_download_access_tokens.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateDownloadAccessTokens < ActiveRecord::Migration[7.2]
def change
create_table :download_access_tokens, id: :uuid do |t|
t.references :activity_record, polymorphic: true, null: false, type: :uuid
t.string :email_address, null: false
t.datetime :downloaded_at
t.timestamps
end
end
end
12 changes: 11 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2025_01_16_091921) do
ActiveRecord::Schema[7.2].define(version: 2025_01_24_105642) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
enable_extension "plpgsql"
Expand Down Expand Up @@ -147,6 +147,16 @@
t.datetime "downloaded_at"
end

create_table "download_access_tokens", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "activity_record_type", null: false
t.uuid "activity_record_id", null: false
t.string "email_address", null: false
t.datetime "downloaded_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["activity_record_type", "activity_record_id"], name: "index_download_access_tokens_on_activity_record"
end

create_table "flipflop_features", force: :cascade do |t|
t.string "key", null: false
t.boolean "enabled", default: false, null: false
Expand Down
23 changes: 23 additions & 0 deletions spec/factories/claims/download_access_tokens.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# == Schema Information
#
# Table name: download_access_tokens
#
# id :uuid not null, primary key
# activity_record_type :string not null
# downloaded_at :datetime
# email_address :string not null
# created_at :datetime not null
# updated_at :datetime not null
# activity_record_id :uuid not null
#
# Indexes
#
# index_download_access_tokens_on_activity_record (activity_record_type,activity_record_id)
#
FactoryBot.define do
factory :download_access_token, class: "Claims::DownloadAccessToken" do
email_address { "[email protected]" }

association :activity_record, factory: :provider_sampling
end
end
Loading