Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
306b9ad
LG-7832: Transliterate name, address, and city for USPS API (w/ FF)
NavaTim Mar 6, 2023
bbb6bd8
LG-7832: Preserve State ID and Address form data on invalid submissions
NavaTim Mar 6, 2023
7e43196
Merge branch 'tbradley/lg-7832-transliterate-usps-api-fix-forms' into…
NavaTim Mar 6, 2023
d2f5e4c
LG-7832: Validate State ID and Address are transliterable to a valid …
NavaTim Mar 6, 2023
7dd52e4
LG-7832: Fix address test
NavaTim Mar 7, 2023
e3c5080
Merge branch 'tbradley/lg-7832-transliterate-usps-api-fix-forms' into…
NavaTim Mar 7, 2023
0f5103b
LG-7832: Remove bad auto-merged configs
NavaTim Mar 7, 2023
73e3fa6
Merge branch 'tbradley/lg-7832-transliterate-usps-api-integration' in…
NavaTim Mar 7, 2023
3b1bb95
LG-7832: Move TransliterationResult to location expected by Rails aut…
NavaTim Mar 7, 2023
3d683fb
LG-7832: Fix state ID step test
NavaTim Mar 7, 2023
acf503a
Merge branch 'tbradley/lg-7832-transliterate-usps-api-fix-forms' into…
NavaTim Mar 7, 2023
ce32726
Update Makefile
NavaTim Mar 7, 2023
06ea563
Merge branch 'tbradley/lg-7832-transliterate-usps-api-integration' in…
NavaTim Mar 7, 2023
923e77b
Update app/services/usps_in_person_proofing/transliterator.rb
NavaTim Mar 7, 2023
36c5cab
Update app/services/usps_in_person_proofing/transliterator.rb
NavaTim Mar 7, 2023
05b579c
LG-7832: Make test updates based on PR feedback
NavaTim Mar 7, 2023
2b42b45
Merge branch 'tbradley/lg-7832-transliterate-usps-api-integration' of…
NavaTim Mar 7, 2023
e15cb28
LG-7832: Lint fix
NavaTim Mar 7, 2023
63df395
Update spec/services/usps_in_person_proofing/enrollment_helper_spec.rb
NavaTim Mar 7, 2023
cad7a75
Update app/services/usps_in_person_proofing/enrollment_helper.rb
NavaTim Mar 7, 2023
8bbf6bd
LG-7832: Remove incorrect usage of .class
NavaTim Mar 7, 2023
8bda24e
LG-7832: Feature should only be enabled by default in dev environments
NavaTim Mar 7, 2023
0a85a50
Update app/services/idv/steps/in_person/address_step.rb
NavaTim Mar 7, 2023
d76ccba
Update app/services/idv/steps/in_person/state_id_step.rb
NavaTim Mar 7, 2023
fc48a3e
Merge branch 'main' of https://github.com/18F/identity-idp into tbrad…
NavaTim Mar 7, 2023
969c2f4
Merge branch 'main' of https://github.com/18F/identity-idp into tbrad…
NavaTim Mar 7, 2023
0fc657c
Merge branch 'main' of https://github.com/18F/identity-idp into tbrad…
NavaTim Mar 7, 2023
22ba566
Merge branch 'tbradley/lg-7832-transliterate-usps-api-fix-forms' of h…
NavaTim Mar 7, 2023
959b264
Merge branch 'tbradley/lg-7832-transliterate-usps-api-integration' in…
NavaTim Mar 7, 2023
94c54b7
Merge branch 'tbradley/lg-7832-transliterate-usps-api-fix-forms' into…
NavaTim Mar 7, 2023
d2b2390
Merge branch 'main' of https://github.com/18F/identity-idp into tbrad…
NavaTim Mar 7, 2023
eb4fee3
Merge branch 'main' of https://github.com/18F/identity-idp into tbrad…
NavaTim Mar 7, 2023
f8daae1
LG-7832: Use case no longer requires support for HashWithIndifferentA…
NavaTim Mar 7, 2023
2d9d5d6
LG-7832: Clean up translation usage
NavaTim Mar 7, 2023
966e7ac
LG-7832: Update test
NavaTim Mar 7, 2023
66cbf42
LG-7832: Update test
NavaTim Mar 7, 2023
79e09fc
LG-7832: Simplify unsupported character extraction from transliterate…
NavaTim Mar 8, 2023
b772dc5
LG-7832: Clarify transliteration result documentation
NavaTim Mar 8, 2023
7b49ac3
LG-7832: Refactor helper logic into validator classes
NavaTim Mar 9, 2023
5b20738
Switch to ->() lambda syntax to remove extra parens
zachmargolis Mar 9, 2023
0841878
Change one more proc syntax to "stabby lambda"
zachmargolis Mar 9, 2023
9a8522e
un-stub the TransliterableValidator spec as much as possible
zachmargolis Mar 9, 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
7 changes: 6 additions & 1 deletion app/forms/idv/in_person/address_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ def self.model_name
def submit(params)
consume_params(params)

cleaned_errors = errors.deep_dup
cleaned_errors.delete(:city, :nontransliterable_field)
cleaned_errors.delete(:address1, :nontransliterable_field)
cleaned_errors.delete(:address2, :nontransliterable_field)

FormResponse.new(
success: valid?,
errors: errors,
errors: cleaned_errors,
)
end

Expand Down
6 changes: 5 additions & 1 deletion app/forms/idv/state_id_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ def initialize(pii)
def submit(params)
consume_params(params)

cleaned_errors = errors.deep_dup
cleaned_errors.delete(:first_name, :nontransliterable_field)
cleaned_errors.delete(:last_name, :nontransliterable_field)

FormResponse.new(
success: valid?,
errors: errors,
errors: cleaned_errors,
)
end

Expand Down
91 changes: 91 additions & 0 deletions app/services/usps_in_person_proofing/transliterable_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
module UspsInPersonProofing
# Validator that can be attached to a form or other model
# to verify that specific supported fields are transliterable
# and conform to additional character requirements
#
# == Example
#
# validates_with UspsInPersonProofing::TransliterableValidator,
# fields: [:first_name, :last_name],
# reject_chars: /[^A-Za-z\-' ]/,
# message: ->(invalid_chars)
# "Rejected chars: #{invalid_chars.join(', ')}"
# end
#
class TransliterableValidator < ActiveModel::Validator
# Initialize the validator with the given fields configured
# for transliteration validation
#
# @param [Hash] options
# @option options [Array<Symbol>] fields Fields for which to validate transliterability
# @option options [Regexp] reject_chars Regex of chars to reject post-transliteration
# @option options [String,#call] message Error message or message generator
def initialize(options)
super
@fields = options[:fields]
@reject_chars = options[:reject_chars]
@message = options[:message]
end

# Check if the configured values on the record are transliterable
#
# @param [ActiveModel::Validations] record
def validate(record)
return unless IdentityConfig.store.usps_ipp_transliteration_enabled

@fields.each do |field|
next unless record.respond_to?(field)

value = record.send(field)
next unless value.respond_to?(:to_s)

invalid_chars = get_invalid_chars(value)
next unless invalid_chars.present?

record.errors.add(
field,
:nontransliterable_field,
message: get_error_message(invalid_chars),
)
end
end

def transliterator
@transliterator ||= Transliterator.new
end

private

# Use unsupported character list to generate error message
def get_error_message(unsupported_chars)
return unless unsupported_chars.present?
if @message.respond_to?(:call)
@message.call(unsupported_chars)
else
@message
end
end

def get_invalid_chars(value)
# Get transliterated value
result = transliterator.transliterate(value)
transliterated = result.transliterated

# Remove question marks corresponding with unsupported chars
# for transliteration
unless transliterated.count(Transliterator::REPLACEMENT) > result.unsupported_chars.length
transliterated = transliterated.gsub(Transliterator::REPLACEMENT, '')
end

# Scan for unsupported chars for the field
if @reject_chars.is_a?(Regexp)
additional_chars = transliterated.scan(@reject_chars)
else
additional_chars = []
end

# Create sorted list of unique unsupported characters
(result.unsupported_chars + additional_chars).sort.uniq
end
end
end
3 changes: 2 additions & 1 deletion app/services/usps_in_person_proofing/transliterator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class Transliterator
:original,
# Transliterated value
:transliterated,
# Characters from the original that could not be transliterated
# Characters from the original that could not be transliterated,
# in the same order and quantity as in the original string
:unsupported_chars,
keyword_init: true,
)
Expand Down
10 changes: 10 additions & 0 deletions app/validators/idv/form_state_id_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ module FormStateIdValidator
:state_id_jurisdiction,
:state_id_number,
presence: true

validates_with UspsInPersonProofing::TransliterableValidator,
fields: [:first_name, :last_name],
reject_chars: /[^A-Za-z\-' ]/,
message: ->(invalid_chars) do
I18n.t(
'in_person_proofing.form.state_id.errors.unsupported_chars',
char_list: invalid_chars.join(', '),
)
end
end
end
end
20 changes: 20 additions & 0 deletions app/validators/idv/in_person/form_address_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ module FormAddressValidator
included do
validates :same_address_as_id,
presence: true

validates_with UspsInPersonProofing::TransliterableValidator,
fields: [:city],
reject_chars: /[^A-Za-z\-' ]/,
message: ->(invalid_chars) do
I18n.t(
'in_person_proofing.form.address.errors.unsupported_chars',
char_list: invalid_chars.join(', '),
)
end

validates_with UspsInPersonProofing::TransliterableValidator,
fields: [:address1, :address2],
reject_chars: /[^A-Za-z0-9\-' .\/#]/,
message: ->(invalid_chars) do
I18n.t(
'in_person_proofing.form.address.errors.unsupported_chars',
char_list: invalid_chars.join(', '),
)
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions config/locales/in_person_proofing/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ en:
ID in person.
form:
address:
errors:
unsupported_chars: 'Our system cannot read the following characters:
%{char_list}. Please try again using substitutes for those
characters.'
Comment on lines +93 to +95
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the copy is a little misleading, clearly the system can read the characters if we can render them back... but I'm guessing this copy already went through UX, and this is not the hill I die on

same_address: Is this address displayed on the state-issued ID that you are
bringing to the Post Office?
same_address_choice_no: I have a different address on my ID
Expand All @@ -101,6 +105,9 @@ en:
year: 'Example: 1986'
dob: Date of birth
dob_hint: 'Example: 4 28 1986'
errors:
unsupported_chars: 'Our system cannot read the following characters:
%{char_list}. Please try again using the characters on your ID.'
first_name: First name
last_name: Last name
memorable_date:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/in_person_proofing/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ es:
información para confirmar que coincide con su cédula en persona.
form:
address:
errors:
unsupported_chars: 'Los siguientes caracteres no pueden ser leídos por nuestro
sistema: %{char_list}. Inténtelo nuevamente usando sustitutos para
estos caracteres.'
same_address: '¿Aparece esta dirección en la cédula de identidad emitido por el
Estado que va a llevar a la oficina de Correos?'
same_address_choice_no: Tengo una dirección diferente en mi cédula de identidad
Expand All @@ -113,6 +117,10 @@ es:
year: 'Ejemplo: 1986'
dob: Fecha de nacimiento
dob_hint: 'Ejemplo: 4 28 1986'
errors:
unsupported_chars: 'Los siguientes caracteres no pueden ser leídos por nuestro
sistema: %{char_list}. Inténtelo nuevamente usando los caracteres de
su documento de identidad.'
first_name: Nombre
last_name: Apellido
memorable_date:
Expand Down
8 changes: 8 additions & 0 deletions config/locales/in_person_proofing/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ fr:
d’identité en personne.
form:
address:
errors:
unsupported_chars: 'Notre système ne parvient pas à lire les caractères suivants
: %{char_list}. Veuillez réessayer en utilisant d’autres caractères
alternatifs.'
same_address: Cette adresse figure-t-elle sur la pièce d’identité délivrée par
l’État que vous apportez au bureau de poste?
same_address_choice_no: J’ai une adresse différente sur mon document d’identité
Expand All @@ -115,6 +119,10 @@ fr:
year: 'Exemple: 1986'
dob: Date de naissance
dob_hint: 'Exemple: 4 28 1986'
errors:
unsupported_chars: 'Notre système ne parvient pas à lire les caractères suivants
: %{char_list}. Veuillez réessayer en utilisant les caractères de
votre carte d’identité.'
first_name: Prénom
last_name: Nom de famille
memorable_date:
Expand Down
72 changes: 72 additions & 0 deletions spec/features/idv/in_person_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -411,4 +411,76 @@
expect(page).to have_current_path(idv_doc_auth_welcome_step)
end
end

context 'transliteration' do
before(:each) do
allow(IdentityConfig.store).to receive(:usps_ipp_transliteration_enabled).
and_return(true)
end
it 'shows validation errors', allow_browser_log: true do
sign_in_and_2fa_user
begin_in_person_proofing
complete_location_step
complete_prepare_step
expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10)

fill_out_state_id_form_ok
fill_in t('in_person_proofing.form.state_id.first_name'), with: 'T0mmy "Lee"'
fill_in t('in_person_proofing.form.state_id.last_name'), with: 'Джейкоб'
click_idv_continue
expect(page).to have_content(
I18n.t(
'in_person_proofing.form.state_id.errors.unsupported_chars',
char_list: '", 0',
),
)

expect(page).to have_content(
I18n.t(
'in_person_proofing.form.state_id.errors.unsupported_chars',
char_list: 'Д, б, е, ж, й, к, о',
),
)

fill_in t('in_person_proofing.form.state_id.first_name'),
with: InPersonHelper::GOOD_FIRST_NAME
fill_in t('in_person_proofing.form.state_id.last_name'), with: InPersonHelper::GOOD_LAST_NAME
click_idv_continue

expect(page).to have_current_path(idv_in_person_step_path(step: :address), wait: 10)
fill_out_address_form_ok

fill_in t('idv.form.address1'), with: 'Джордж'
fill_in t('idv.form.address2_optional'), with: '(Nope) = %'
fill_in t('idv.form.city'), with: 'Елена'
click_idv_continue

expect(page).to have_content(
I18n.t(
'in_person_proofing.form.address.errors.unsupported_chars',
char_list: 'Д, д, ж, о, р',
),
)

expect(page).to have_content(
I18n.t(
'in_person_proofing.form.address.errors.unsupported_chars',
char_list: '%, (, ), =',
),
)

expect(page).to have_content(
I18n.t(
'in_person_proofing.form.address.errors.unsupported_chars',
char_list: 'Е, а, е, л, н',
),
)

fill_in t('idv.form.address1'), with: InPersonHelper::GOOD_ADDRESS1
fill_in t('idv.form.address2_optional'), with: InPersonHelper::GOOD_ADDRESS2
fill_in t('idv.form.city'), with: InPersonHelper::GOOD_CITY
click_idv_continue
expect(page).to have_current_path(idv_in_person_step_path(step: :ssn), wait: 10)
end
end
end
Loading