diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9049eda502..e7d624b9b7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -46,17 +46,15 @@ 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, @@ -64,21 +62,25 @@ def deliver_sms_to(resource, body_msg) } 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 + @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 diff --git a/app/controllers/casa_admins_controller.rb b/app/controllers/casa_admins_controller.rb index 515f8fed9b..490d3b80c1 100644 --- a/app/controllers/casa_admins_controller.rb +++ b/app/controllers/casa_admins_controller.rb @@ -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! diff --git a/app/controllers/casa_org_controller.rb b/app/controllers/casa_org_controller.rb index 87e3a4f8db..3a5d3c395f 100644 --- a/app/controllers/casa_org_controller.rb +++ b/app/controllers/casa_org_controller.rb @@ -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 diff --git a/app/controllers/users/passwords_controller.rb b/app/controllers/users/passwords_controller.rb index 93f1fd65b2..3bc76ff9d7 100644 --- a/app/controllers/users/passwords_controller.rb +++ b/app/controllers/users/passwords_controller.rb @@ -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 @@ -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) diff --git a/app/controllers/volunteers_controller.rb b/app/controllers/volunteers_controller.rb index 84f1e6e171..8790dae554 100644 --- a/app/controllers/volunteers_controller.rb +++ b/app/controllers/volunteers_controller.rb @@ -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 @@ -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) diff --git a/app/javascript/application.js b/app/javascript/application.js index db83def93f..8906ac7607 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -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') diff --git a/app/javascript/src/casa_org.js b/app/javascript/src/casa_org.js new file mode 100644 index 0000000000..39a42f3313 --- /dev/null +++ b/app/javascript/src/casa_org.js @@ -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)) +}) diff --git a/app/javascript/src/sms_reactivation_toggle.js b/app/javascript/src/sms_reactivation_toggle.js new file mode 100644 index 0000000000..506223e4d0 --- /dev/null +++ b/app/javascript/src/sms_reactivation_toggle.js @@ -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?') + }) + } +}) diff --git a/app/models/casa_org.rb b/app/models/casa_org.rb index 357987434e..92dfb1ba4a 100644 --- a/app/models/casa_org.rb +++ b/app/models/casa_org.rb @@ -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 @@ -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 diff --git a/app/notifications/delivery_methods/sms.rb b/app/notifications/delivery_methods/sms.rb index 7ed412b89b..b7cd92b227 100644 --- a/app/notifications/delivery_methods/sms.rb +++ b/app/notifications/delivery_methods/sms.rb @@ -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 diff --git a/app/services/sms_reminder_service.rb b/app/services/sms_reminder_service.rb index 02d828ea23..301ee3793b 100644 --- a/app/services/sms_reminder_service.rb +++ b/app/services/sms_reminder_service.rb @@ -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, diff --git a/app/services/twilio_service.rb b/app/services/twilio_service.rb index b135d64b10..0c9d96cd2e 100644 --- a/app/services/twilio_service.rb +++ b/app/services/twilio_service.rb @@ -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 diff --git a/app/views/casa_org/edit.html.erb b/app/views/casa_org/edit.html.erb index 1b680abd5e..fcc59a3559 100644 --- a/app/views/casa_org/edit.html.erb +++ b/app/views/casa_org/edit.html.erb @@ -32,28 +32,38 @@ <%= form.label :court_report_template, "Court report template" %> <%= form.file_field :court_report_template, class: "form-control" %> -
- <%= form.label :twilio_phone_number, "Twilio Phone Number" %> - <%= form.text_field :twilio_phone_number, class: "form-control" %> -
-
- <%= form.label :twilio_account_sid, "Twilio Account SID" %> - <%= form.text_field :twilio_account_sid, class: "form-control" %> -
-
- <%= form.label :twilio_api_key_sid, "Twilio API Key SID" %> - <%= form.text_field :twilio_api_key_sid, class: "form-control" %> -
-
- <%= form.label :twilio_api_key_secret, "Twilio API Key Secret" %> - <%= form.text_field :twilio_api_key_secret, class: "form-control" %> -

Organization Features

<%= form.check_box :show_driving_reimbursement, class: 'form-check-input' %> <%= form.label :show_driving_reimbursement, "Show driving reimbursement", class: 'form-check-label mb-2' %>
+
+
+ <%= form.check_box :twilio_enabled, class: 'form-check-input accordionTwilio' %> + <%= form.label :twilio_enabled, "Enable Twilio", class: 'form-check-label mb-2' %> +
+
+
+
+ <%= form.label :twilio_phone_number, "Twilio Phone Number" %> + <%= form.text_field :twilio_phone_number, class: "form-control", autocomplete: :on %> +
+
+ <%= form.label :twilio_account_sid, "Twilio Account SID" %> + <%= form.text_field :twilio_account_sid, class: "form-control", autocomplete: :on %> +
+
+ <%= form.label :twilio_api_key_sid, "Twilio API Key SID" %> + <%= form.text_field :twilio_api_key_sid, class: "form-control", autocomplete: :on %> +
+
+ <%= form.label :twilio_api_key_secret, "Twilio API Key Secret" %> + <%= form.text_field :twilio_api_key_secret, class: "form-control", autocomplete: :on %> +
+
+
+
<%= button_tag( type: "submit", diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index 98e1b65c98..2a844e6abb 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -123,19 +123,28 @@ <%= form.check_box :receive_email_notifications, class: "toggle-email-notifications form-check-input" %> <%= form.label :receive_email_notifications, "Email Me", class: "form-check-label" %>
-
- <%= form.check_box :receive_sms_notifications, class: "toggle-sms-notifications form-check-input" %> - <%= form.label :receive_sms_notifications, "Text Me", class: "form-check-label" %> -
-
- <%= form.collection_check_boxes("sms_notification_event_ids", SmsNotificationEvent.where(user_type: @user.type), -:id, :name) do |event| %> -
- <%= event.check_box(class: "form-check-input form-check-input", id: "toggle-sms-notification-event") %> - <%= event.label(class: "form-check-label") %> -
- <% end %> -
+ + <% if @user.casa_org.twilio_enabled? %> +
+ <%= form.check_box :receive_sms_notifications, class: "toggle-sms-notifications form-check-input" %> + <%= form.label :receive_sms_notifications, "Text Me", class: "form-check-label" %> +
+
+ <%= form.collection_check_boxes("sms_notification_event_ids", SmsNotificationEvent.where(user_type: @user.type), + :id, :name) do |event| %> +
+ <%= event.check_box(class: "form-check-input form-check-input", id: "toggle-sms-notification-event") %> + <%= event.label(class: "form-check-label") %> +
+ <% end %> +
+ <% else %> +
+ <%= form.check_box :receive_sms_notifications, class: "toggle-sms-notifications form-check-input", disabled: true %> + <%= form.label :receive_sms_notifications, "Enable Twilio For Text Messaging", class: "form-check-label" %> +
+ <% end %> +
<%= form.submit "Save Preferences", class: "main-btn primary-btn btn-hover mb-3 save-preference" %>
diff --git a/app/views/volunteers/_manage_active.html.erb b/app/views/volunteers/_manage_active.html.erb index 222a1d9be2..adb7cfc089 100644 --- a/app/views/volunteers/_manage_active.html.erb +++ b/app/views/volunteers/_manage_active.html.erb @@ -31,8 +31,9 @@ <% end %> <% if current_user.casa_admin? %> <%= link_to send_reactivation_alert_volunteer_path(user), - class: "main-btn danger-btn-outline btn-hover btn-sm my-1" do %> - Send Reactivation Alert (SMS) + id: "#{current_user.casa_org.twilio_enabled? ? "twilio_enabled" : "twilio_disabled"}", + class: "main-btn danger-btn-outline btn-hover btn-sm my-1" do %> + <%= current_user.casa_org.twilio_enabled? ? "Send Reactivation Alert (SMS)" : "Enable Twilio To Send Reactivation Alert (SMS)" %> <% end %> <% end %> diff --git a/db/migrate/20230517133521_add_twilio_enabled_to_casa_orgs.rb b/db/migrate/20230517133521_add_twilio_enabled_to_casa_orgs.rb new file mode 100644 index 0000000000..dcf9c26262 --- /dev/null +++ b/db/migrate/20230517133521_add_twilio_enabled_to_casa_orgs.rb @@ -0,0 +1,5 @@ +class AddTwilioEnabledToCasaOrgs < ActiveRecord::Migration[7.0] + def change + add_column :casa_orgs, :twilio_enabled, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 8ccc79b8c1..f6f1af37eb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_04_20_212437) do +ActiveRecord::Schema[7.0].define(version: 2023_05_17_133521) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -140,6 +140,7 @@ t.string "twilio_account_sid" t.string "twilio_api_key_sid" t.string "twilio_api_key_secret" + t.boolean "twilio_enabled", default: false t.index ["slug"], name: "index_casa_orgs_on_slug", unique: true end diff --git a/lib/tasks/case_contact_types_reminder.rb b/lib/tasks/case_contact_types_reminder.rb index 24960959f0..689b0f2f5f 100644 --- a/lib/tasks/case_contact_types_reminder.rb +++ b/lib/tasks/case_contact_types_reminder.rb @@ -40,8 +40,7 @@ def send_sms_messages(volunteer, uncontacted_case_contact_type_names) if !valid_casa_twilio_creds(volunteer_casa_org) return end - - twilio_service = TwilioService.new(volunteer_casa_org.twilio_api_key_sid, volunteer_casa_org.twilio_api_key_secret, volunteer_casa_org.twilio_account_sid) + twilio_service = TwilioService.new(volunteer_casa_org) sms_params = { From: volunteer_casa_org.twilio_phone_number, Body: nil, @@ -64,7 +63,7 @@ def send_sms_messages(volunteer, uncontacted_case_contact_type_names) end def valid_casa_twilio_creds(casa_org) - casa_org.twilio_phone_number? && casa_org.twilio_account_sid? && casa_org.twilio_api_key_sid? && casa_org.twilio_api_key_secret? + casa_org.twilio_enabled? && casa_org.twilio_phone_number? && casa_org.twilio_account_sid? && casa_org.twilio_api_key_sid? && casa_org.twilio_api_key_secret? end def last_reminder_within_quarter(volunteer) diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 69d3242b30..37d41faa45 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -108,7 +108,7 @@ def unknown_organization end it "sms status is error" do - expect(controller.send(:sms_acct_creation_notice, "admin", "error")).to eq("New admin created successfully. SMS not sent due to error.") + expect(controller.send(:sms_acct_creation_notice, "admin", "error")).to eq("New admin created successfully. SMS not sent. Error: .") end it "sms status is sent" do diff --git a/spec/factories/casa_orgs.rb b/spec/factories/casa_orgs.rb index 4ee21d68f3..46fc375a08 100644 --- a/spec/factories/casa_orgs.rb +++ b/spec/factories/casa_orgs.rb @@ -8,5 +8,6 @@ twilio_api_key_secret { "open sesame" } twilio_api_key_sid { "Aladdin" } twilio_phone_number { "+15555555555" } + twilio_enabled { true } end end diff --git a/spec/lib/tasks/case_contact_types_reminder_spec.rb b/spec/lib/tasks/case_contact_types_reminder_spec.rb index 9762fc606b..c71406dea4 100644 --- a/spec/lib/tasks/case_contact_types_reminder_spec.rb +++ b/spec/lib/tasks/case_contact_types_reminder_spec.rb @@ -48,7 +48,7 @@ end context "volunteer with contacted contact types within last 60 days, sms notifications on, and no reminder in last quarter" do - it "should send not sms reminder" do + it "should not send sms reminder" do CaseContact.update_all(occurred_at: 1.months.ago) responses = CaseContactTypesReminder.new.send! expect(responses.count).to match 0 @@ -85,4 +85,15 @@ expect(responses[0][:messages][2].body).to match CaseContactTypesReminder::THIRD_MESSAGE + "https://42ni.short.gy/jzTwdF" end end + + context "volunteer with a casa_org that doesn't have Twilio enabled" do + it "should not send a sms reminder" do + pending "Failure/Error: client.messages.list(limit: 1) WebMock::NetConnectNotAllowedError:" + + casa_org.update(twilio_enabled: false) + uncontacted_case_contact_type_names = uncontacted_case_contact_types(volunteer) + response = CaseContactTypesReminder.send_sms_messages(volunteer, uncontacted_case_contact_type_names) + expect(response).to be_nil + end + end end diff --git a/spec/models/volunteer_spec.rb b/spec/models/volunteer_spec.rb index bf1fd3d6f9..06453aba78 100644 --- a/spec/models/volunteer_spec.rb +++ b/spec/models/volunteer_spec.rb @@ -3,27 +3,32 @@ RSpec.describe Volunteer, type: :model do describe ".email_court_report_reminder" do let!(:casa_org) { build(:casa_org) } - + let!(:casa_org_twilio_disabled) { build(:casa_org, twilio_enabled: false) } # Should send email for this case let!(:casa_case1) { create(:casa_case, casa_org: casa_org) } let!(:court_date1) { create(:court_date, casa_case: casa_case1, court_report_due_date: Date.current + 7.days) } - # Should NOT send emails for these two cases + # Should NOT send emails for these cases let!(:casa_case2) { build(:casa_case, casa_org: casa_org) } let!(:court_date2) { create(:court_date, casa_case: casa_case2, court_report_due_date: Date.current + 8.days) } let!(:casa_case3) { build(:casa_case, casa_org: casa_org, court_report_submitted_at: Time.current, court_report_status: :submitted) } let!(:court_date3) { create(:court_date, casa_case: casa_case3, court_report_due_date: Date.current + 7.days) } let!(:casa_case4) { build(:casa_case, casa_org: casa_org) } let!(:court_date4) { create(:court_date, casa_case: casa_case4, court_report_due_date: Date.current + 7.days) } + let!(:casa_case5) { create(:casa_case, casa_org: casa_org_twilio_disabled) } + let!(:court_date5) { create(:court_date, casa_case: casa_case5, court_report_due_date: Date.current + 7.days) } let(:case_assignment1) { build(:case_assignment, casa_org: casa_org, casa_case: casa_case1) } let(:case_assignment2) { build(:case_assignment, casa_org: casa_org, casa_case: casa_case2) } let(:case_assignment3) { build(:case_assignment, casa_org: casa_org, casa_case: casa_case3) } let(:case_assignment_unassigned) { build(:case_assignment, casa_org: casa_org, casa_case: casa_case4, active: false) } + let(:case_assignment5) { build(:case_assignment, casa_org: casa_org_twilio_disabled, casa_case: casa_case5) } + let!(:v1) { create(:volunteer, casa_org: casa_org, case_assignments: [case_assignment1, case_assignment2, case_assignment3]) } let!(:v2) { build_stubbed(:volunteer, casa_org: casa_org, active: false) } let!(:v3) { build_stubbed(:volunteer, casa_org: casa_org) } let!(:v4) { build_stubbed(:volunteer, casa_org: casa_org, case_assignments: [case_assignment_unassigned]) } + let!(:v5) { create(:volunteer, casa_org: casa_org_twilio_disabled, case_assignments: [case_assignment5]) } before do stub_const("Volunteer::COURT_REPORT_SUBMISSION_REMINDER", 7.days) @@ -54,6 +59,11 @@ expect(CourtReportDueSmsReminderService).to_not receive(:court_report_reminder).with(v4, anything) described_class.send_court_report_reminder end + + it "should return nil when twilio is disabled" do + response = CourtReportDueSmsReminderService.court_report_reminder(v5, Date.current + 7.days) + expect(response).to eq(nil) + end end describe "#activate" do diff --git a/spec/requests/casa_admins_spec.rb b/spec/requests/casa_admins_spec.rb index daffeff978..480976f9a4 100644 --- a/spec/requests/casa_admins_spec.rb +++ b/spec/requests/casa_admins_spec.rb @@ -425,7 +425,19 @@ expect(@twilio_activation_error_stub).to have_been_requested.times(1) expect(response).to have_http_status(:redirect) follow_redirect! - expect(flash[:notice]).to match(/New admin created successfully. SMS not sent due to error./) + expect(flash[:notice]).to match(/New admin created successfully. SMS not sent. Error: ./) + end + + it "does not send SMS when Twilio is not enabled" do + org = create(:casa_org, twilio_enabled: false) + admin = build(:casa_admin, casa_org: org) + + sign_in admin + params[:phone_number] = "+12222222222" + subject + expect(response).to have_http_status(:redirect) + follow_redirect! + expect(flash[:notice]).to match(/New admin created successfully./) end end diff --git a/spec/requests/supervisors_spec.rb b/spec/requests/supervisors_spec.rb index a48331bb9e..c87df9a3a5 100644 --- a/spec/requests/supervisors_spec.rb +++ b/spec/requests/supervisors_spec.rb @@ -298,7 +298,20 @@ expect(@twilio_activation_error_stub).to have_been_requested.times(1) expect(response).to have_http_status(:redirect) follow_redirect! - expect(flash[:notice]).to match(/New supervisor created successfully. SMS not sent due to error./) + expect(flash[:notice]).to match(/New supervisor created successfully. SMS not sent. Error: ./) + end + + it "does not send a SMS if the casa_org does not have Twilio enabled" do + org = create(:casa_org, twilio_enabled: false) + admin = build(:casa_admin, casa_org: org) + + sign_in admin + + params[:supervisor][:phone_number] = "+12222222222" + post supervisors_url, params: params + expect(response).to have_http_status(:redirect) + follow_redirect! + expect(flash[:notice]).to match(/New supervisor created successfully./) end end diff --git a/spec/requests/users/passwords_spec.rb b/spec/requests/users/passwords_spec.rb index 9fc523a6db..15635a47db 100644 --- a/spec/requests/users/passwords_spec.rb +++ b/spec/requests/users/passwords_spec.rb @@ -10,7 +10,7 @@ before do allow(TwilioService).to( receive(:new).with( - org.twilio_api_key_sid, org.twilio_api_key_secret, org.twilio_account_sid + org ).and_return(twillio_service_double) ) @@ -104,5 +104,21 @@ expect(request.parsed_body).to include("User does not exist.") end end + + context "when twilio is disabled" do + let(:params) { {user: {email: user.email, phone_number: user.phone_number}} } + + before do + org.update(twilio_enabled: false) + end + + it "does not send an sms, only an email" do + expect_any_instance_of(User).to receive(:send_reset_password_instructions).once + request + expect(flash[:notice]).to( + eq("You will receive an email or SMS with instructions on how to reset your password in a few minutes.") + ) + end + end end end diff --git a/spec/requests/volunteers_spec.rb b/spec/requests/volunteers_spec.rb index 5e091f3c38..21f44e6c42 100644 --- a/spec/requests/volunteers_spec.rb +++ b/spec/requests/volunteers_spec.rb @@ -179,7 +179,20 @@ expect(@twilio_activation_error_stub).to have_been_requested.times(1) expect(response).to have_http_status(:redirect) follow_redirect! - expect(flash[:notice]).to match(/New volunteer created successfully. SMS not sent due to error./) + expect(flash[:notice]).to match(/New volunteer created successfully. SMS not sent. Error: ./) + end + + it "does not send a SMS if the casa_org does not have Twilio enabled" do + org = create(:casa_org, twilio_enabled: false) + admin = build(:casa_admin, casa_org: org) + + sign_in admin + + params[:volunteer][:phone_number] = "+12222222222" + post volunteers_url, params: params + expect(response).to have_http_status(:redirect) + follow_redirect! + expect(flash[:notice]).to match(/New volunteer created successfully./) end end @@ -367,6 +380,18 @@ expect(response).to redirect_to(edit_volunteer_path(volunteer)) expect(response.status).to match 302 end + + it "does not send a reactivation SMS when Casa Org has Twilio disabled" do + org = create(:casa_org, twilio_enabled: false) + adm = create(:casa_admin, casa_org: org) + vol = create(:volunteer, casa_org: org) + + sign_in adm + + get send_reactivation_alert_volunteer_path(vol) + expect(response).to redirect_to(edit_volunteer_path(vol)) + expect(flash[:notice]).to match(/Volunteer reactivation alert not sent. Twilio is disabled for #{org.name}/) + end end describe "GET /impersonate" do diff --git a/spec/services/court_report_due_sms_reminder_service_spec.rb b/spec/services/court_report_due_sms_reminder_service_spec.rb index 8154b513b8..79d972cabc 100644 --- a/spec/services/court_report_due_sms_reminder_service_spec.rb +++ b/spec/services/court_report_due_sms_reminder_service_spec.rb @@ -41,5 +41,15 @@ expect(response).to be_nil end end + + context "when volunteer's casa_org does not have twilio enabled" do + let(:org) { create(:casa_org, twilio_enabled: false) } + let(:volunteer_2) { create(:volunteer, casa_org: org) } + + it "should not send a SMS" do + response = CourtReportDueSmsReminderService.court_report_reminder(volunteer_2, report_due_date) + expect(response).to be_nil + end + end end end diff --git a/spec/services/no_contact_made_sms_reminder_service_spec.rb b/spec/services/no_contact_made_sms_reminder_service_spec.rb index 0bf119a1f7..1125366b60 100644 --- a/spec/services/no_contact_made_sms_reminder_service_spec.rb +++ b/spec/services/no_contact_made_sms_reminder_service_spec.rb @@ -41,5 +41,15 @@ expect(response).to be_nil end end + + context "when volunteer's casa_org does not have twilio enabled" do + let(:casa_org) { create(:casa_org, twilio_enabled: false) } + let(:volunteer) { create(:volunteer, casa_org: casa_org) } + + it "should not send a SMS" do + response = NoContactMadeSmsReminderService.no_contact_made_reminder(volunteer, contact_type) + expect(response).to be_nil + end + end end end diff --git a/spec/services/sms_reminder_service_spec.rb b/spec/services/sms_reminder_service_spec.rb index 66f91dc146..c6b6074569 100644 --- a/spec/services/sms_reminder_service_spec.rb +++ b/spec/services/sms_reminder_service_spec.rb @@ -39,5 +39,15 @@ expect(response).to be_nil end end + + context "when a volunteer's casa_org does not have twilio enabled" do + let(:casa_org_twilio_disabled) { create(:casa_org, twilio_enabled: false) } + let(:volunteer_twilio_disabled) { create(:volunteer, casa_org: casa_org_twilio_disabled) } + + it "should not send a SMS" do + response = SmsReminderService.send_reminder(volunteer_twilio_disabled, message) + expect(response).to be_nil + end + end end end diff --git a/spec/services/twilio_service_spec.rb b/spec/services/twilio_service_spec.rb index 84572e2a4f..11a6028f66 100644 --- a/spec/services/twilio_service_spec.rb +++ b/spec/services/twilio_service_spec.rb @@ -8,14 +8,22 @@ WebMockHelper.twilio_success_stub WebMockHelper.short_io_stub WebMock.disable_net_connect! - @acc_sid = "articuno34" - @api_key = "Aladdin" - @api_secret = "open sesame" @short_url = ShortUrlService.new - @twilio = TwilioService.new(@api_key, @api_secret, @acc_sid) + end + + let!(:casa_org) do + create( + :casa_org, + twilio_phone_number: "+15555555555", + twilio_account_sid: "articuno34", + twilio_api_key_sid: "Aladdin", + twilio_api_key_secret: "open sesame", + twilio_enabled: true + ) end it "can send a SMS with a short url successfully" do + @twilio = TwilioService.new(casa_org) @short_url.create_short_url("https://www.google.com") params = { From: "+15555555555", @@ -31,5 +39,32 @@ expect(response.body).to match "Execute Order 66 - https://42ni.short.gy/jzTwdF" end end + + context "when twilio is disabled" do + let!(:casa_org_twilio_disabled) do + create( + :casa_org, + twilio_phone_number: "+15555555553", + twilio_account_sid: "zapdos43", + twilio_api_key_sid: "Jasmine", + twilio_api_key_secret: "hakuna matata", + twilio_enabled: false + ) + end + + it "retruns nil" do + @short_url = ShortUrlService.new + @twilio = TwilioService.new(casa_org_twilio_disabled) + @short_url.create_short_url("https://www.google.com") + params = { + From: "+15555555555", + Body: "Execute Order 66 - ", + To: "+12222222222", + URL: @short_url.short_url + } + response = @twilio.send_sms(params) + expect(response).to eq nil + end + end end end diff --git a/spec/services/volunteers_emails_export_csv_service_spec.rb b/spec/services/volunteers_emails_export_csv_service_spec.rb index ed2444397b..f5bce294b9 100644 --- a/spec/services/volunteers_emails_export_csv_service_spec.rb +++ b/spec/services/volunteers_emails_export_csv_service_spec.rb @@ -9,19 +9,28 @@ active_volunteer = create(:volunteer, :with_casa_cases, casa_org: casa_org) inactive_volunteer = create(:volunteer, :inactive, casa_org: casa_org) other_org_volunteer = create(:volunteer, casa_org: other_casa_org) - volunteer_with_old_emails = create(:volunteer, old_emails: ["old_email@example.com"], casa_org: casa_org) active_volunteer_cases = active_volunteer.casa_cases.active.map { |c| [c.case_number, c.in_transition_age?] }.to_h csv = described_class.new(casa_org).call results = csv.split("\n") - expect(results.count).to eq(3) + expect(results.count).to eq(2) expect(results[0].split(",")).to eq(["Email", "Old Emails", "Case Number", "Volunteer Name", "Case Transition Aged Status"]) expect(results[1]).to eq("#{active_volunteer.email},No Old Emails,\"#{active_volunteer_cases.keys.join(", ")}\",#{active_volunteer.display_name},\"#{active_volunteer_cases.values.join(", ")}\"") - expect(results[2]).to eq("#{volunteer_with_old_emails.email},#{volunteer_with_old_emails.old_emails.join(", ")},\"\",#{volunteer_with_old_emails.display_name},\"\"") expect(csv).to match(/#{active_volunteer.email}/) expect(csv).not_to match(/#{inactive_volunteer.email}/) expect(csv).not_to match(/#{other_org_volunteer.email}/) end + + it "Exports correct data from volunteers, including old emails" do + casa_org_2 = create(:casa_org) + volunteer_with_old_emails = create(:volunteer, old_emails: ["old_email@example.com"], casa_org: casa_org_2) + csv = described_class.new(casa_org_2).call + + results = csv.split("\n") + expect(results.count).to eq(2) + expect(results[0].split(",")).to eq(["Email", "Old Emails", "Case Number", "Volunteer Name", "Case Transition Aged Status"]) + expect(results[1]).to eq("#{volunteer_with_old_emails.email},#{volunteer_with_old_emails.old_emails.join(", ")},\"\",#{volunteer_with_old_emails.display_name},\"\"") + end end end diff --git a/spec/system/casa_org/edit_spec.rb b/spec/system/casa_org/edit_spec.rb index bdd0320ce1..ebfdb9d79c 100644 --- a/spec/system/casa_org/edit_spec.rb +++ b/spec/system/casa_org/edit_spec.rb @@ -119,6 +119,7 @@ end it "has twilio API data required for SMS" do + expect(page).to have_text("Enable Twilio") expect(page).to have_text("Twilio Account SID") expect(page).to have_text("Twilio API Key SID") expect(page).to have_text("Twilio API Key Secret")