Skip to content

Commit 633fef1

Browse files
DrewProebstelDrewProebstelCfaarinchoi03
authored
Fyst 2142 implement pya sms contact validation (#61)
* add i18n and styling for landing page * rubocop * pr comments * remove unused flash messages styles * git ignore * restore DS store * rubocop * client menu component * wip dropdown menu' * rubocop * use unless prod for environemntal warning * wip * wip * wip * add specs * rubocop * clean up some unneeded changes * wip * Re-render show to show the error message but with error_status * Pin necessary modules and include "application" since thats the entrypoint - without this importmap will load without executing application.js * Fix rubocop * Use the already available activestorage * fix changed variable in honeycrisp * try precomplie in app.json * try fixing some css * remove asset precompile * add email address page * rubocop * i18n * wip * implement knockout page * update path in is intake locked * wip * wip * wip * wip * add sms functionality * merge main * contact preference controller redirects * touch up * new migration * update contact preference case * contact preference form no longer saves anything * restore some development artificats * wip * contact preference is not a form * remove unneeded files * remove devise migration * annotate * make enum * rubocop * add turbo false to phone number --------- Co-authored-by: Drew Proebstel <dproebstel@codeforamerica.org> Co-authored-by: Arin Choi <achoi@codeforamerica.org>
1 parent d69fdee commit 633fef1

27 files changed

Lines changed: 492 additions & 75 deletions

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ gem "propshaft"
77
gem "pg"
88
gem "rails-i18n"
99
gem "valid_email2", "~> 4.0.6"
10+
gem "phony"
11+
gem "auto_strip_attributes"
1012

1113
# Use the Puma web server [https://github.com/puma/puma]
1214
gem "puma", ">= 5.0"

Gemfile.lock

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ GEM
9090
activerecord (>= 6.0.0)
9191
activesupport (>= 6.0.0)
9292
ast (2.4.3)
93+
auto_strip_attributes (2.6.0)
94+
activerecord (>= 4.0)
9395
autoprefixer-rails (10.4.21.0)
9496
execjs (~> 2)
9597
aws-eventstream (1.4.0)
96-
aws-partitions (1.1124.0)
97-
aws-sdk-core (3.226.2)
98+
aws-partitions (1.1130.0)
99+
aws-sdk-core (3.226.3)
98100
aws-eventstream (~> 1, >= 1.3.0)
99101
aws-partitions (~> 1, >= 1.992.0)
100102
aws-sigv4 (~> 1.9)
@@ -104,7 +106,7 @@ GEM
104106
aws-sdk-kms (1.106.0)
105107
aws-sdk-core (~> 3, >= 3.225.0)
106108
aws-sigv4 (~> 1.5)
107-
aws-sdk-s3 (1.192.0)
109+
aws-sdk-s3 (1.193.0)
108110
aws-sdk-core (~> 3, >= 3.225.0)
109111
aws-sdk-kms (~> 1)
110112
aws-sigv4 (~> 1.5)
@@ -145,16 +147,16 @@ GEM
145147
diff-lcs (1.6.2)
146148
dotenv (3.1.8)
147149
drb (2.2.3)
148-
erb (5.0.1)
150+
erb (5.0.2)
149151
erubi (1.13.1)
150152
et-orbi (1.2.11)
151153
tzinfo
152154
execjs (2.10.0)
153-
factory_bot (6.5.1)
155+
factory_bot (6.5.4)
154156
activesupport (>= 6.1.0)
155-
factory_bot_rails (6.4.4)
157+
factory_bot_rails (6.5.0)
156158
factory_bot (~> 6.5)
157-
railties (>= 5.0.0)
159+
railties (>= 6.1.0)
158160
ffi (1.17.2-aarch64-linux-gnu)
159161
ffi (1.17.2-aarch64-linux-musl)
160162
ffi (1.17.2-arm-linux-gnu)
@@ -168,25 +170,25 @@ GEM
168170
raabro (~> 1.4)
169171
globalid (1.2.1)
170172
activesupport (>= 6.1)
171-
google-protobuf (4.31.0)
173+
google-protobuf (4.31.1)
172174
bigdecimal
173175
rake (>= 13)
174-
google-protobuf (4.31.0-aarch64-linux-gnu)
176+
google-protobuf (4.31.1-aarch64-linux-gnu)
175177
bigdecimal
176178
rake (>= 13)
177-
google-protobuf (4.31.0-aarch64-linux-musl)
179+
google-protobuf (4.31.1-aarch64-linux-musl)
178180
bigdecimal
179181
rake (>= 13)
180-
google-protobuf (4.31.0-arm64-darwin)
182+
google-protobuf (4.31.1-arm64-darwin)
181183
bigdecimal
182184
rake (>= 13)
183-
google-protobuf (4.31.0-x86_64-darwin)
185+
google-protobuf (4.31.1-x86_64-darwin)
184186
bigdecimal
185187
rake (>= 13)
186-
google-protobuf (4.31.0-x86_64-linux-gnu)
188+
google-protobuf (4.31.1-x86_64-linux-gnu)
187189
bigdecimal
188190
rake (>= 13)
189-
google-protobuf (4.31.0-x86_64-linux-musl)
191+
google-protobuf (4.31.1-x86_64-linux-musl)
190192
bigdecimal
191193
rake (>= 13)
192194
http_accept_language (2.1.1)
@@ -196,7 +198,7 @@ GEM
196198
actionpack (>= 6.0.0)
197199
activesupport (>= 6.0.0)
198200
railties (>= 6.0.0)
199-
io-console (0.8.0)
201+
io-console (0.8.1)
200202
irb (1.15.2)
201203
pp (>= 0.6.0)
202204
rdoc (>= 4.0.0)
@@ -209,7 +211,7 @@ GEM
209211
rails-dom-testing (>= 1, < 3)
210212
railties (>= 4.2.0)
211213
thor (>= 0.14, < 2.0)
212-
json (2.12.0)
214+
json (2.13.0)
213215
language_server-protocol (3.17.0.5)
214216
lint_roller (1.1.0)
215217
logger (1.7.0)
@@ -222,12 +224,12 @@ GEM
222224
net-pop
223225
net-smtp
224226
marcel (1.0.4)
225-
matrix (0.4.2)
227+
matrix (0.4.3)
226228
method_source (1.1.0)
227229
mini_mime (1.1.5)
228230
minitest (5.25.5)
229231
msgpack (1.8.0)
230-
net-imap (0.5.8)
232+
net-imap (0.5.9)
231233
date
232234
net-protocol
233235
net-pop (0.1.2)
@@ -258,15 +260,15 @@ GEM
258260
ast (~> 2.4.1)
259261
racc
260262
pg (1.5.9)
263+
phony (2.22.3)
261264
pp (0.6.2)
262265
prettyprint
263266
prettyprint (0.2.0)
264267
prism (1.4.0)
265-
propshaft (1.1.0)
268+
propshaft (1.2.0)
266269
actionpack (>= 7.0.0)
267270
activesupport (>= 7.0.0)
268271
rack
269-
railties (>= 7.0.0)
270272
pry (0.15.2)
271273
coderay (~> 1.1)
272274
method_source (~> 1.0)
@@ -330,14 +332,14 @@ GEM
330332
rb-fsevent (0.11.2)
331333
rb-inotify (0.11.1)
332334
ffi (~> 1.0)
333-
rdoc (6.14.1)
335+
rdoc (6.14.2)
334336
erb
335337
psych (>= 4.0.0)
336338
regexp_parser (2.10.0)
337339
reline (0.6.1)
338340
io-console (~> 0.5)
339341
rexml (3.4.1)
340-
rspec-core (3.13.4)
342+
rspec-core (3.13.5)
341343
rspec-support (~> 3.13.0)
342344
rspec-expectations (3.13.5)
343345
diff-lcs (>= 1.2.0, < 2.0)
@@ -354,18 +356,18 @@ GEM
354356
rspec-mocks (~> 3.13)
355357
rspec-support (~> 3.13)
356358
rspec-support (3.13.4)
357-
rubocop (1.75.7)
359+
rubocop (1.78.0)
358360
json (~> 2.3)
359361
language_server-protocol (~> 3.17.0.2)
360362
lint_roller (~> 1.1.0)
361363
parallel (~> 1.10)
362364
parser (>= 3.3.0.2)
363365
rainbow (>= 2.2.2, < 4.0)
364366
regexp_parser (>= 2.9.3, < 3.0)
365-
rubocop-ast (>= 1.44.0, < 2.0)
367+
rubocop-ast (>= 1.45.1, < 2.0)
366368
ruby-progressbar (~> 1.7)
367369
unicode-display_width (>= 2.4.0, < 4.0)
368-
rubocop-ast (1.44.1)
370+
rubocop-ast (1.46.0)
369371
parser (>= 3.3.7.2)
370372
prism (~> 1.4)
371373
rubocop-performance (1.25.0)
@@ -386,21 +388,21 @@ GEM
386388
rubyzip (2.4.1)
387389
sass (3.7.4)
388390
sass-listen (~> 4.0.0)
389-
sass-embedded (1.89.0-aarch64-linux-gnu)
391+
sass-embedded (1.89.2-aarch64-linux-gnu)
390392
google-protobuf (~> 4.31)
391-
sass-embedded (1.89.0-aarch64-linux-musl)
393+
sass-embedded (1.89.2-aarch64-linux-musl)
392394
google-protobuf (~> 4.31)
393-
sass-embedded (1.89.0-arm-linux-gnueabihf)
395+
sass-embedded (1.89.2-arm-linux-gnueabihf)
394396
google-protobuf (~> 4.31)
395-
sass-embedded (1.89.0-arm-linux-musleabihf)
397+
sass-embedded (1.89.2-arm-linux-musleabihf)
396398
google-protobuf (~> 4.31)
397-
sass-embedded (1.89.0-arm64-darwin)
399+
sass-embedded (1.89.2-arm64-darwin)
398400
google-protobuf (~> 4.31)
399-
sass-embedded (1.89.0-x86_64-darwin)
401+
sass-embedded (1.89.2-x86_64-darwin)
400402
google-protobuf (~> 4.31)
401-
sass-embedded (1.89.0-x86_64-linux-gnu)
403+
sass-embedded (1.89.2-x86_64-linux-gnu)
402404
google-protobuf (~> 4.31)
403-
sass-embedded (1.89.0-x86_64-linux-musl)
405+
sass-embedded (1.89.2-x86_64-linux-musl)
404406
google-protobuf (~> 4.31)
405407
sass-listen (4.0.0)
406408
rb-fsevent (~> 0.9, >= 0.9.4)
@@ -421,7 +423,7 @@ GEM
421423
activejob (>= 7.2)
422424
activerecord (>= 7.2)
423425
railties (>= 7.2)
424-
solid_queue (1.1.5)
426+
solid_queue (1.2.0)
425427
activejob (>= 7.1)
426428
activerecord (>= 7.1)
427429
concurrent-ruby (>= 1.3.1)
@@ -470,7 +472,9 @@ PLATFORMS
470472
aarch64-linux-gnu
471473
aarch64-linux-musl
472474
arm-linux-gnu
475+
arm-linux-gnueabihf
473476
arm-linux-musl
477+
arm-linux-musleabihf
474478
arm64-darwin
475479
x86_64-darwin
476480
x86_64-linux
@@ -479,6 +483,7 @@ PLATFORMS
479483

480484
DEPENDENCIES
481485
annotaterb
486+
auto_strip_attributes
482487
aws-sdk-s3
483488
bootsnap
484489
brakeman
@@ -492,6 +497,7 @@ DEPENDENCIES
492497
importmap-rails
493498
jbuilder
494499
pg
500+
phony
495501
propshaft
496502
pry-byebug
497503
puma (>= 5.0)
@@ -512,4 +518,4 @@ DEPENDENCIES
512518
web-console
513519

514520
BUNDLED WITH
515-
2.6.4
521+
2.6.7

app/controllers/base_controller.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
class BaseController < ApplicationController
2-
def current_archived_intake
3-
# If a user does not have an associated email, we still create an ArchivedIntake
4-
# so they can go through the flow. This prevents it from being obvious whether
5-
# an email is linked to an existing intake.
6-
#
7-
# These intakes are created without an IP address, meaning the user will not
8-
# be able to pass the identification number controller.
9-
return unless session[:email_address].present?
2+
def current_archived_intake
3+
# If a user does not have an associated email or phone, we still create an ArchivedIntake
4+
# so they can go through the flow. This prevents it from being obvious whether
5+
# an email or phone is linked to an existing intake.
6+
#
7+
# These intakes are created without an IP address, meaning the user will not
8+
# be able to pass the identification number controller.
109

10+
if session[:phone_number].present?
11+
phone = session[:phone_number]
12+
existing = StateFileArchivedIntake.find_by(phone_number: phone)
13+
existing || StateFileArchivedIntake.create(phone_number: phone, contact_preference: "text")
14+
elsif session[:email_address].present?
1115
email = session[:email_address].downcase
1216
existing = StateFileArchivedIntake.find_by("LOWER(email_address) = ?", email)
13-
existing || StateFileArchivedIntake.create(email_address: email)
17+
existing || StateFileArchivedIntake.create(email_address: email, contact_preference: "email")
1418
end
19+
end
1520
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class ContactPreferenceController < BaseController
2+
def show
3+
end
4+
end

app/controllers/email_address_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def update
1111
session[:mailing_verified] = false
1212
session[:code_verified] = false
1313
session[:email_address] = @form.email_address
14+
session[:phone_number] = nil
1415
current_archived_intake
1516
# TODO Add some kind of logging here
1617
# https://codeforamerica.atlassian.net/browse/FYST-2088
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class PhoneNumberController < BaseController
2+
def edit
3+
@form = PhoneNumberForm.new
4+
end
5+
6+
def update
7+
@form = PhoneNumberForm.new(phone_number_form_params)
8+
9+
if @form.valid?
10+
session[:ssn_verified] = false
11+
session[:mailing_verified] = false
12+
session[:code_verified] = false
13+
session[:phone_number] = @form.phone_number
14+
session[:email_address] = nil
15+
current_archived_intake
16+
# TODO Add some kind of logging here. https://codeforamerica.atlassian.net/browse/FYST-2088
17+
18+
redirect_to root_path
19+
else
20+
render :edit
21+
end
22+
end
23+
24+
private
25+
26+
def phone_number_form_params
27+
params.require(:phone_number_form).permit(:phone_number)
28+
end
29+
end

app/controllers/year_select_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def update
1212
redirect_to edit_email_address_path
1313
when "2024"
1414
session[:year_selected] = "2024"
15-
redirect_to edit_email_address_path
15+
redirect_to contact_preference_show_path
1616
else
1717
render :show
1818
end

app/forms/phone_number_form.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class PhoneNumberForm < Form
2+
attr_accessor :phone_number
3+
4+
before_validation :normalize_phone_number
5+
6+
validates :phone_number, e164_phone: true
7+
8+
def normalize_phone_number
9+
self.phone_number = PhoneParser.normalize(phone_number) if phone_number.present?
10+
end
11+
end

app/models/state_file_archived_intake.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Table name: state_file_archived_intakes
44
#
55
# id :bigint not null, primary key
6-
# contact_preference :string
6+
# contact_preference :integer default("unfilled"), not null
77
# email_address :string
88
# fake_address_1 :string
99
# fake_address_2 :string
@@ -24,6 +24,8 @@ class StateFileArchivedIntake < ApplicationRecord
2424
has_one_attached :submission_pdf
2525
has_many :state_file_archived_intake_access_logs, class_name: "StateFileArchivedIntakeAccessLog"
2626

27+
enum :contact_preference, { unfilled: 0, email: 1, text: 2 }, prefix: :contact_preference
28+
2729
def full_address
2830
address_parts = [ mailing_street, mailing_apartment, mailing_city, mailing_state, mailing_zip ]
2931
address_parts.compact_blank.join(", ")

app/services/phone_parser.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class PhoneParser
2+
def self.normalize(raw_phone_number)
3+
valid, phony_normalized = self.phony_normalize_or_error(raw_phone_number)
4+
valid ? self.e164(phony_normalized) : raw_phone_number&.to_s
5+
end
6+
7+
private
8+
9+
def self.phony_normalize_or_error(raw_phone_number)
10+
return [ false, nil ] if raw_phone_number.nil?
11+
return [ false, "" ] if raw_phone_number == ""
12+
13+
raw_phone_number = raw_phone_number.to_s
14+
15+
phony_normalized = Phony.normalize(raw_phone_number, cc: "1")
16+
if Phony.plausible?(phony_normalized)
17+
[ true, phony_normalized ]
18+
else
19+
[ false, raw_phone_number ]
20+
end
21+
end
22+
23+
def self.e164(phony_normalized)
24+
# Phony normalization results in a phone number with no punctuation and with a country calling code.
25+
"+#{phony_normalized}"
26+
end
27+
end

0 commit comments

Comments
 (0)