Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
76f3f4e
Twilio Accordion HTML/CSS
ShamiTomita May 17, 2023
8a63717
add twilio_enabled boolean to casa_orgs table
ShamiTomita May 17, 2023
bdb406a
WIP JS file
ShamiTomita May 17, 2023
fd528a7
WIP frontend
ShamiTomita May 17, 2023
878952e
WIP, next step working with persisted data
ShamiTomita May 17, 2023
81a1ee4
form works?
ShamiTomita May 19, 2023
a7c423d
adding twilio_enabled bool to CasaOrg model#validate_twilio_credentials
ShamiTomita May 19, 2023
770ae54
twilio checks, code comments, twilio flash notices
ShamiTomita May 22, 2023
84f2adf
lint and casa_org factory add twilio_enabled
ShamiTomita May 22, 2023
06d82c9
clean up on aisle casa_org.js
ShamiTomita May 23, 2023
96ef969
Twilio redo
ShamiTomita May 26, 2023
f916f1b
lint
ShamiTomita May 26, 2023
2622620
removed empty method
ShamiTomita May 26, 2023
8f91448
yarn lint
ShamiTomita May 26, 2023
8b62b53
removing debugger
ShamiTomita May 26, 2023
9eb48ad
clean up
ShamiTomita May 26, 2023
c809fb9
sms button.js
ShamiTomita May 26, 2023
56fa057
casa_org js
ShamiTomita May 26, 2023
13e83cf
updates
ShamiTomita May 26, 2023
81b0c23
lint
ShamiTomita May 26, 2023
0462da3
Update sms.rb
ShamiTomita May 29, 2023
3d514a0
spec updates
ShamiTomita May 30, 2023
93f4c85
error updates
ShamiTomita May 30, 2023
e91f683
removing twilio check
ShamiTomita May 30, 2023
c4a423e
Merge branch 'main' into st/4815/AddSMStoOrganizationFeaturesSection
ShamiTomita May 30, 2023
912c9f4
updates
ShamiTomita May 30, 2023
be2aab6
changes so far
ShamiTomita May 30, 2023
dc6cb7d
Merge branch 'st/4815/AddSMStoOrganizationFeaturesSection' of https:/…
ShamiTomita May 30, 2023
28fb15b
changes
ShamiTomita May 31, 2023
635fc04
changes
ShamiTomita May 31, 2023
3247152
Merge branch 'st/4815/AddSMStoOrganizationFeaturesSection' of https:/…
ShamiTomita May 31, 2023
0652fce
added back the return value
ShamiTomita May 31, 2023
3dfeab6
lint and app controller spec
ShamiTomita May 31, 2023
6857a3f
TwilioService resource to current_user
ShamiTomita May 31, 2023
e7b9336
remove unecessary code, refactor
ShamiTomita May 31, 2023
4ac3e32
lint
ShamiTomita May 31, 2023
85064d8
removing unnecessary complexity
ShamiTomita May 31, 2023
eff49f9
rename for sms_reactivation js file
ShamiTomita May 31, 2023
6a52f91
password spec
ShamiTomita May 31, 2023
609c812
lint
ShamiTomita May 31, 2023
8d545a1
twilio service spec move
ShamiTomita May 31, 2023
3daa15e
lint
ShamiTomita May 31, 2023
77db3a0
remove comment
ShamiTomita May 31, 2023
e5abd7b
Delete Gemfile.lock
ShamiTomita May 31, 2023
e10cf21
remove comment
ShamiTomita May 31, 2023
a7905e5
revert to old gem file
ShamiTomita May 31, 2023
97a1639
Merge branch 'st/4815/AddSMStoOrganizationFeaturesSection' of https:/…
ShamiTomita May 31, 2023
2d7acc0
actual revert
ShamiTomita May 31, 2023
3ae7afe
lint
ShamiTomita May 31, 2023
403425e
Update Gemfile.lock
ShamiTomita May 31, 2023
866db00
revert to old gem file
ShamiTomita May 31, 2023
3f986d5
Merge branch 'st/4815/AddSMStoOrganizationFeaturesSection' of https:/…
ShamiTomita May 31, 2023
dfc0c7f
updates
ShamiTomita May 30, 2023
df73072
Do not use blank padding for hour display
littleforest May 17, 2023
67c2fcf
build(deps): bump bootstrap-datepicker from 1.9.0 to 1.10.0 (#4826)
dependabot[bot] May 26, 2023
7e51d0a
Add casa cases section without court dates to admin home page (#4798)
tonyaraujop May 26, 2023
70cedae
Pr2 for Issue #2698 - Adds a task to backfill user preference sets. …
GALTdea May 26, 2023
3041d23
add patch note diagrams
FireLemons May 28, 2023
31e9a97
remove unused image
FireLemons May 28, 2023
a831c29
parent 31e9a97a2708f44731ef126845c5877cad57fba8
ShamiTomita May 31, 2023
4bf1f91
Merge branch 'st/4815/AddSMStoOrganizationFeaturesSection' of https:/…
ShamiTomita May 31, 2023
faaf18e
Update Gemfile.lock
ShamiTomita May 31, 2023
e92b47b
Update Gemfile.lock
ShamiTomita May 31, 2023
0e66032
flaky email export test
ShamiTomita Jun 1, 2023
17f92a7
lint
ShamiTomita Jun 1, 2023
59d6034
Merge branch 'main' into st/4815/AddSMStoOrganizationFeaturesSection
ShamiTomita Jun 5, 2023
6023166
remove comment
ShamiTomita Jun 5, 2023
95eed1a
Merge branch 'st/4815/AddSMStoOrganizationFeaturesSection' of https:/…
ShamiTomita Jun 5, 2023
e008b7c
notes
ShamiTomita Jun 9, 2023
b6ad45a
spec updates
ShamiTomita Jun 15, 2023
dcef4d1
controller updates
ShamiTomita Jun 15, 2023
7a5e4f3
services updates
ShamiTomita Jun 15, 2023
a8949f0
view update
ShamiTomita Jun 15, 2023
8400eb1
lint
ShamiTomita Jun 15, 2023
b934138
lint
ShamiTomita Jun 15, 2023
877f6b5
lint
ShamiTomita Jun 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,39 +46,41 @@ def handle_short_url(url_list)
# volunteer/supervisor/casa_admin controller uses to send SMS
# returns appropriate flash notice for SMS
def deliver_sms_to(resource, body_msg)
if resource.phone_number.blank?
if resource.phone_number.blank? || !resource.casa_org.twilio_enabled?
return "blank"
end
acc_sid = current_user.casa_org.twilio_account_sid
api_key = current_user.casa_org.twilio_api_key_sid
api_secret = current_user.casa_org.twilio_api_key_secret

body = body_msg
to = resource.phone_number
from = current_user.casa_org.twilio_phone_number

twilio = TwilioService.new(api_key, api_secret, acc_sid)
@twilio = TwilioService.new(current_user.casa_org)
req_params = {
From: from,
Body: body,
To: to
}

begin
twilio_res = twilio.send_sms(req_params)
twilio_res = @twilio.send_sms(req_params)
twilio_res.error_code.nil? ? "sent" : "error"
rescue Twilio::REST::RestError
rescue Twilio::REST::RestError => error
@error = error
"error"
rescue # unverfied error isnt picked up by Twilio::Rest::RestError
# https://www.twilio.com/docs/errors/21608
Comment thread
ShamiTomita marked this conversation as resolved.
@error = "Phone number is unverifiied"
"error"
end
end

def sms_acct_creation_notice(resource_name, sms_status)
if sms_status === "blank"
return "New #{resource_name} created successfully."
end
if sms_status === "error"
return "New #{resource_name} created successfully. SMS not sent due to error."
end
if sms_status === "sent"
case sms_status
when "blank"
"New #{resource_name} created successfully."
when "error"
"New #{resource_name} created successfully. SMS not sent. Error: #{@error}."
when "sent"
"New #{resource_name} created successfully. SMS has been sent!"
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/casa_admins_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def create
service = ::CreateCasaAdminService.new(current_organization, params, current_user)
@casa_admin = service.build
authorize @casa_admin
sms_status = "blank"
sms_status = "blank" # shami: why hard code here if deliver_sms_to takes care of this?

begin
casa_admin = service.create!
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/casa_org_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def casa_org_update_params
:twilio_account_sid,
:twilio_phone_number,
:twilio_api_key_sid,
:twilio_api_key_secret
:twilio_api_key_secret,
:twilio_enabled
)
end

Expand Down
20 changes: 11 additions & 9 deletions app/controllers/users/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class Users::PasswordsController < Devise::PasswordsController
def create
@email, @phone_number = [params[resource_name][:email], params[resource_name][:phone_number]]
@resource = @email.blank? ? User.find_by(phone_number: @phone_number) : User.find_by(email: @email)

valid_params?(@email, @phone_number) ? send_password : render_error
return if @errors

Expand All @@ -33,15 +32,18 @@ def send_password_reset_sms
# for case where user enters ONLY a phone number, generate a new reset token to use;
# otherwise, use the same reset token as sent by devise mailer
@reset_token ||= @resource.generate_password_reset_token

create_short_url
twilio_service = TwilioService.new(@resource.casa_org.twilio_api_key_sid, @resource.casa_org.twilio_api_key_secret, @resource.casa_org.twilio_account_sid)
sms_params = {
From: @resource.casa_org.twilio_phone_number,
Body: password_reset_msg(@resource.display_name, @short_io_service.short_url),
To: @phone_number
}
twilio_service.send_sms(sms_params)
begin
twilio_service = TwilioService.new(@resource.casa_org)
sms_params = {
From: @resource.casa_org.twilio_phone_number,
Body: password_reset_msg(@resource.display_name, @short_io_service.short_url),
To: @phone_number
}
twilio_service.send_sms(sms_params)
rescue => e
Rails.logger.error("send SMS failed: #{e}")
end
end

def valid_params?(email, phone_number)
Expand Down
12 changes: 7 additions & 5 deletions app/controllers/volunteers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ def resend_invitation
def send_reactivation_alert
authorize @volunteer
if @volunteer.save
send_sms_to(volunteers_phone_number, "Hello #{@volunteer.display_name}, \n \n Your CASA/Prince George’s County volunteer console account has been reactivated. You can login using the credentials you were already using. \n \n If you have any questions, please contact your most recent Case Supervisor for assistance. \n \n CASA/Prince George’s County")
redirect_to edit_volunteer_path(@volunteer), notice: "Volunteer reactivation alert sent"
else
redirect_to edit_volunteer_path(@volunteer), alert: "Volunteer reactivation alert failed"
begin
send_sms_to(volunteers_phone_number, "Hello #{@volunteer.display_name}, \n \n Your CASA/Prince George’s County volunteer console account has been reactivated. You can login using the credentials you were already using. \n \n If you have any questions, please contact your most recent Case Supervisor for assistance. \n \n CASA/Prince George’s County")
redirect_to edit_volunteer_path(@volunteer), notice: "Volunteer reactivation alert sent"
rescue
redirect_to edit_volunteer_path(@volunteer), notice: "Volunteer reactivation alert not sent. Twilio is disabled for #{@volunteer.casa_org.name}."
end
end
end

Expand Down Expand Up @@ -162,7 +164,7 @@ def volunteers_phone_number
end

def send_sms_to(phone_number, body)
twilio = TwilioService.new(current_user.casa_org.twilio_api_key_sid, current_user.casa_org.twilio_api_key_secret, current_user.casa_org.twilio_account_sid)
twilio = TwilioService.new(current_user.casa_org)
req_params = {From: current_user.casa_org.twilio_phone_number, Body: body, To: phone_number}
twilio_res = twilio.send_sms(req_params)

Expand Down
2 changes: 2 additions & 0 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ require('./src/select')
require('./src/sidebar')
require('./src/tooltip')
require('./src/session_timeout_poller.js')
require('./src/casa_org')
require('./src/sms_reactivation_toggle')
require('./src/display_app_metric.js')
46 changes: 46 additions & 0 deletions app/javascript/src/casa_org.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function twilioToggle () {
const phoneNumber = $('#casa_org_twilio_phone_number')
const accSid = $('#casa_org_twilio_account_sid')
const keySid = $('#casa_org_twilio_api_key_sid')
const secret = $('#casa_org_twilio_api_key_secret')

if ($('.accordionTwilio').is(':checked')) {
addCheckedAttr(phoneNumber)
addCheckedAttr(accSid)
addCheckedAttr(keySid)
addCheckedAttr(secret)
} else {
removeCheckedAttr(phoneNumber)
removeCheckedAttr(accSid)
removeCheckedAttr(keySid)
removeCheckedAttr(secret)
}
}

function addCheckedAttr (el) {
el.attr('required', true)
el.setAttribute('aria-disabled', false)
el.setAttribute('aria-required', true)
el.removeAttr('disabled')
}

function removeCheckedAttr (el) {
el.removeAttr('required')
el.setAttribute('aria-required', false)
el.setAttribute('aria-disabled', true)
el.attr('disabled', true)
}

$('document').ready(() => {
$('.accordionTwilio').attr('data-bs-toggle', 'collapse')
$('.accordionTwilio').attr('data-bs-target', '#collapseTwilio')
$('.accordionTwilio').attr('aria-expanded', 'false')

if ($('.accordionTwilio').is(':checked')) {
$('.accordionTwilio').attr('aria_expanded')
$('.accordionTwilio').removeClass('collapsed')
$('#collapseTwilio').addClass('show')
}

($('.accordionTwilio').on('click', twilioToggle))
})
16 changes: 16 additions & 0 deletions app/javascript/src/sms_reactivation_toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

$('document').ready(() => {
if ($('#twilio_disabled').length) {
$('#twilio_disabled').removeClass('main-btn danger-btn-outline btn-hover btn-sm my-1')
$('#twilio_disabled').addClass('main-btn deactive-btn btn-sm my-1')
$('#twilio_tooltip').attr('data-bs-toggle', 'tooltip')
$('#twilio_tooltip').attr('data-bs-placement', 'bottom')
$('#twilio_tooltip').attr('data-turbo', 'false')
$('#twilio_tooltip').attr('title', "Twilio is not enabled for this user's CASA org")

$('#twilio_disabled').on('click', function (event) {
event.preventDefault()
console.log('tooltip?')
})
}
})
3 changes: 2 additions & 1 deletion app/models/casa_org.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class CasaOrg < ApplicationRecord

validates :name, presence: true, uniqueness: true
validates_with CasaOrgValidator
validate :validate_twilio_credentials, if: -> { twilio_account_sid.present? || twilio_api_key_sid.present? || twilio_api_key_secret.present? }, on: :update
validate :validate_twilio_credentials, if: -> { twilio_enabled || twilio_account_sid.present? || twilio_api_key_sid.present? || twilio_api_key_secret.present? }, on: :update

has_many :users, dependent: :destroy
has_many :casa_cases, dependent: :destroy
Expand Down Expand Up @@ -128,6 +128,7 @@ def normalize_phone_number
# twilio_account_sid :string
# twilio_api_key_secret :string
# twilio_api_key_sid :string
# twilio_enabled :boolean default(FALSE)
# twilio_phone_number :string
# created_at :datetime not null
# updated_at :datetime not null
Expand Down
2 changes: 1 addition & 1 deletion app/notifications/delivery_methods/sms.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def deliver
short_io_api = ShortUrlService.new
short_io_api.create_short_url(case_contact_url)
shortened_url = short_io_api.short_url
twilio_api = TwilioService.new(sender.casa_org.twilio_api_key_sid, sender.casa_org.twilio_api_key_secret, sender.casa_org.twilio_account_sid)
twilio_api = TwilioService.new(sender.casa_org)
twilio_api.send_sms({From: sender.casa_org.twilio_phone_number, Body: case_contact_flagged_msg(sender.display_name, shortened_url), To: recipient.phone_number})
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/services/sms_reminder_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ module SmsReminderService

BASE_URL = Rails.application.credentials[:BASE_URL]
def send_reminder(user, message)
return if !user[:receive_sms_notifications] || user[:phone_number].blank?
return if !user[:receive_sms_notifications] || user[:phone_number].blank? || !user.casa_org.twilio_enabled?

user_casa_org = user.casa_org
twilio_service = TwilioService.new(user_casa_org.twilio_api_key_sid, user_casa_org.twilio_api_key_secret, user_casa_org.twilio_account_sid)
twilio_service = TwilioService.new(user_casa_org)
sms_params = {
From: user_casa_org.twilio_phone_number,
Body: message,
Expand Down
34 changes: 25 additions & 9 deletions app/services/twilio_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,48 @@
require "twilio-ruby"

class TwilioService
attr_writer :api_key, :api_secret, :acc_sid
class TwilioCasaOrgError < StandardError; end
attr_writer :api_key, :api_secret, :acc_sid, :casa_org

def initialize(api_key, api_secret, acc_sid)
@api_key = api_key
@api_secret = api_secret
@acc_sid = acc_sid
@client = Twilio::REST::Client.new(api_key, api_secret, acc_sid)
def initialize(casa_org)
@api_key = casa_org.twilio_api_key_sid
@api_secret = casa_org.twilio_api_key_secret
@acc_sid = casa_org.twilio_account_sid
@enabled = casa_org.twilio_enabled
end

def client # lazy create client only if twilio enabled
@client = Twilio::REST::Client.new(@api_key, @api_secret, @acc_sid)
end

def enabled?
@enabled
end

# this method takes in a hash
# required keys are: From:, To:, Body:
# to send a short url, set URL: key in hash
def send_sms(params)
# return unless casa_org twilio enabled
# add check here, Twilio client
if !enabled?
return nil
end
from = params[:From]
body = params.key?(:URL) ? params[:Body] + params[:URL] : params[:Body]
to = params[:To]
# returns a twilio API message object
# refer to docs: https://www.twilio.com/docs/sms/api/message-resource#message-properties
begin
@client.messages.create(
client
client.messages.create(
from: from,
body: body,
to: to
)
rescue => e
Rails.logger.error("send SMS failed: #{e}")
rescue => error
Rails.logger.error("send SMS failed: #{error}") # help a person know whats going on, these messages can be inspected (Twilio)
error
end
end
end
42 changes: 26 additions & 16 deletions app/views/casa_org/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,38 @@
<%= form.label :court_report_template, "Court report template" %>
<%= form.file_field :court_report_template, class: "form-control" %>
</div>
<div class="input-style-1">
<%= form.label :twilio_phone_number, "Twilio Phone Number" %>
<%= form.text_field :twilio_phone_number, class: "form-control" %>
</div>
<div class="input-style-1">
<%= form.label :twilio_account_sid, "Twilio Account SID" %>
<%= form.text_field :twilio_account_sid, class: "form-control" %>
</div>
<div class="input-style-1">
<%= form.label :twilio_api_key_sid, "Twilio API Key SID" %>
<%= form.text_field :twilio_api_key_sid, class: "form-control" %>
</div>
<div class="input-style-1">
<%= form.label :twilio_api_key_secret, "Twilio API Key Secret" %>
<%= form.text_field :twilio_api_key_secret, class: "form-control" %>
</div>
<hr>
<h3 class="mb-2">Organization Features</h3>
<div class="form-check checkbox-style mb-20">
<%= form.check_box :show_driving_reimbursement, class: 'form-check-input' %>
<%= form.label :show_driving_reimbursement, "Show driving reimbursement", class: 'form-check-label mb-2' %>
</div>
<div>
<div class="form-check checkbox-style mb-20">
<%= form.check_box :twilio_enabled, class: 'form-check-input accordionTwilio' %>
<%= form.label :twilio_enabled, "Enable Twilio", class: 'form-check-label mb-2' %>
</div>
<div class="accordionGroup">
<div id="collapseTwilio" class="collapse" aria-labelledby="headingOne" data-bs-parent="#accordionTwilio">
<div class="input-style-1">
<%= form.label :twilio_phone_number, "Twilio Phone Number" %>
<%= form.text_field :twilio_phone_number, class: "form-control", autocomplete: :on %>
</div>
<div class="input-style-1">
<%= form.label :twilio_account_sid, "Twilio Account SID" %>
<%= form.text_field :twilio_account_sid, class: "form-control", autocomplete: :on %>
</div>
<div class="input-style-1">
<%= form.label :twilio_api_key_sid, "Twilio API Key SID" %>
<%= form.text_field :twilio_api_key_sid, class: "form-control", autocomplete: :on %>
</div>
<div class="input-style-1">
<%= form.label :twilio_api_key_secret, "Twilio API Key Secret" %>
<%= form.text_field :twilio_api_key_secret, class: "form-control", autocomplete: :on %>
</div>
</div>
</div>
</div>
<div class="actions mb-10">
<%= button_tag(
type: "submit",
Expand Down
Loading