Skip to content

Commit

Permalink
[CP] Add Mandrill Email Handling
Browse files Browse the repository at this point in the history
  • Loading branch information
CapCap authored and aptos-bot committed May 13, 2022
1 parent 1814ecd commit e2954b4
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def create
log @it1_profile, 'created'
validate_node(v, do_location: true)
if @it1_profile.validator_verified?
current_user.maybe_send_ait1_registration_complete_email
redirect_to it1_path, notice: 'AIT1 application completed successfully: your node is verified!' and return
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ class OnboardingController < ApplicationController

layout 'it1'

def email; end
def email
redirect_to it1_path if current_user.confirmed?
end

def kyc_redirect
if current_user.kyc_exempt?
Expand Down Expand Up @@ -41,7 +43,7 @@ def kyc_callback
reference_id = kyc_params.require(:'reference-id')
if current_user.external_id != reference_id
redirect_to onboarding_kyc_redirect_path,
status: :unprocessable_entity and return
status: :unprocessable_entity, error: 'Persona was started with a different user' and return
end

inquiry_id = kyc_params.require(:'inquiry-id')
Expand All @@ -56,12 +58,14 @@ def kyc_callback
end

def email_update
return redirect_to overview_index_path if current_user.confirmed?
redirect_to it1_path and return if current_user.confirmed?
render :email, status: :unprocessable_entity and return unless verify_recaptcha(model: current_user)

email_params = params.require(:user).permit(:email, :username)
if verify_recaptcha(model: current_user) && current_user.update(email_params)
if current_user.update(email_params.merge(confirmation_token: Devise.friendly_token))
log current_user, 'email updated'
current_user.send_confirmation_instructions
url = confirmation_url(current_user, confirmation_token: current_user.confirmation_token)
SendConfirmEmailJob.perform_now({ user_id: current_user.id, template_vars: { CONFIRM_LINK: url } })
redirect_to onboarding_email_path, notice: "Verification email sent to #{email_params[:email]}"
else
render :email, status: :unprocessable_entity
Expand Down
1 change: 1 addition & 0 deletions ecosystem/platform/server/app/jobs/application_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ApplicationJob < ActiveJob::Base
Sentry.configure_scope do |scope|
scope.set_context(:job_args, job.arguments.first)
scope.set_tags(job_name: job.class.name)
scope.set_user(id: job.arguments.first[:user_id]) if job.arguments.first.try(:include?, :user_id)
job.sentry_scope = scope
block.call
end
Expand Down
6 changes: 3 additions & 3 deletions ecosystem/platform/server/app/jobs/kyc_complete_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
# Copyright (c) Aptos
# SPDX-License-Identifier: Apache-2.0

class KYCCompleteJobError < StandardError
end
class KYCCompleteJobError < StandardError; end

class KYCCompleteJob < ApplicationJob
# Ex args: { user_id: 32, inquiry_id=inq_syMMVRdEz7fswAa2hi }
def perform(args)
user = User.find(args[:user_id])
sentry_scope.set_user(id: user.id)

inquiry_id = args[:inquiry_id]
sentry_scope.set_context(:inquiry_id, inquiry_id)

client = PersonaHelper::PersonaClient.new

Expand All @@ -29,5 +28,6 @@ def perform(args)
raise KYCCompleteJobError, "Inquiry was not complete! Status: '#{status}'" unless status == 'completed'

user.update(completed_persona_inquiry_id: inquiry_id, kyc_status: 'completed')
user.maybe_send_ait1_registration_complete_email
end
end
6 changes: 2 additions & 4 deletions ecosystem/platform/server/app/jobs/location_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
# Copyright (c) Aptos
# SPDX-License-Identifier: Apache-2.0

class LocationFetchError < StandardError
end
class LocationFetchError < StandardError; end

class LocationJob < ApplicationJob
# Ex args: { it1_profile_id: 32 }
def perform(args)
it1_profile = It1Profile.find(args[:it1_profile_id])
sentry_scope.set_user(id: it1_profile.user_id)
sentry_scope.set_context(:it1_profile_id, it1_profile.id)
sentry_scope.set_context(:validator_address, it1_profile.validator_address)
sentry_scope.set_context(:job_info, { validator_address: it1_profile.validator_address })

# pass zeroes as a hack here: we only need the validator address
node_verifier = NodeHelper::NodeVerifier.new(it1_profile.validator_address, 0, 0)
Expand Down
14 changes: 14 additions & 0 deletions ecosystem/platform/server/app/jobs/send_confirm_email_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# Copyright (c) Aptos
# SPDX-License-Identifier: Apache-2.0

class SendConfirmEmailJob < SendEmailJob
# Ex args: { user_id: 32, template_vars: { CONFIRM_LINK: 'https://...' } }

private

def template_name
:confirm
end
end
86 changes: 86 additions & 0 deletions ecosystem/platform/server/app/jobs/send_email_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

# Copyright (c) Aptos
# SPDX-License-Identifier: Apache-2.0

require 'MailchimpTransactional'

class SendEmailJobError < StandardError; end

BAD_STATUSES = %w[rejected invalid].freeze

class SendEmailJob < ApplicationJob
# Ex args: { user_id: 32, template_name: 'some-template', template_vars: { SOME_MAILMERGE_KEY: 'My Value!' } }
def perform(args)
@args = args
@user = User.find(args[:user_id])
sentry_scope.set_user(id: @user.id)

sentry_scope.set_context(:job_args, { template_name: })
sentry_scope.set_context(:job_args, { template_vars: })

send_email
end

# https://mailchimp.com/developer/transactional/api/messages/send-using-message-template/
def send_email
client = MailchimpTransactional::Client.new(ENV.fetch('MAILCHIMP_API_KEY', nil))
body = email_body
sentry_scope.set_context(:email_body, body)
results = client.messages.send_template(body)
handle_results(results)
rescue StandardError => e
Sentry.capture_exception(e)
puts "Error: #{e}"
end

def email_body
{
template_name:,
template_content: [{}],
message:
}
end

private

def handle_results(results)
# [{"email"=>"[email protected]", "status"=>"sent", "_id"=>"some-id", "reject_reason"=>nil}, ...]
results.each do |res|
# the sending status of the recipient. Possible values: "sent", "queued", "rejected", or "invalid".
raise SendEmailJobError, "Could not send email: #{res['reject_reason']}" if BAD_STATUSES.include? res['status']
rescue StandardError => e
Rails.logger.warn e
Sentry.capture_exception(e)
end
end

# Override any of these to have much nicer email job classes!
def template_name
@args[:template_name]
end

def template_vars
@args[:template_vars] || {}
end

def message
{
global_merge_vars:,
from_email:,
to: to_emails.map { |em| { email: em } }
}
end

def to_emails
[@user.email]
end

def from_email
'[email protected]'
end

def global_merge_vars
template_vars.map { |k, v| { name: k, content: v } }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# Copyright (c) Aptos
# SPDX-License-Identifier: Apache-2.0

class SendRegistrationCompleteEmailJob < SendEmailJob
# Ex args: { user_id: 32 }

private

def template_name
:'registration-complete'
end
end
8 changes: 8 additions & 0 deletions ecosystem/platform/server/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ def self.create_new_user_from_oauth(auth)
# end
# end

def maybe_send_ait1_registration_complete_email
SendRegistrationCompleteEmailJob.perform_now({ user_id: id }) if ait1_registration_complete?
end

def ait1_registration_complete?
kyc_complete? && it1_profile&.validator_verified?
end

def kyc_complete?
kyc_exempt? || kyc_status == 'completed'
end
Expand Down
10 changes: 8 additions & 2 deletions ecosystem/platform/server/app/views/welcome/it1.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@
<p class="mb-8 font-light">
Register your node, and automatically verify that it is set up correctly.
</p>
<%= render(ButtonComponent.new(href: new_it1_profile_path, class: 'w-full mt-auto')) do %>
Register
<% if current_user&.it1_profile&.validator_verified? %>
<%= render(ButtonComponent.new(href: edit_it1_profile_path(current_user.it1_profile), class: 'w-full mt-auto')) do %>
Edit Registration
<% end %>
<% else %>
<%= render(ButtonComponent.new(href: new_it1_profile_path, class: 'w-full mt-auto')) do %>
Register
<% end %>
<% end %>
</div>
</div>
Expand Down

0 comments on commit e2954b4

Please sign in to comment.