models: ensure DROM phone numbers are valid

They were accepted before, because they were 'possible' – but now
they are explicitely considered as valid.
This commit is contained in:
Pierre de La Morinerie 2022-03-01 16:42:46 +01:00 committed by Paul Chavard
parent cb5561978a
commit 5150e33212
3 changed files with 40 additions and 1 deletions

View file

@ -20,12 +20,33 @@
# type_de_champ_id :integer
#
class Champs::PhoneChamp < Champs::TextChamp
# We want to allow:
# * international (e164) phone numbers
# * “french format” (ten digits with a leading 0)
# * DROM numbers
#
# However, we need to special-case some ten-digit numbers,
# because the ARCEP assigns some blocks of "O6 XX XX XX XX" numbers to DROM operators.
# Guadeloupe | GP | +590 | 0690XXXXXX, 0691XXXXXX
# Guyane | GF | +594 | 0694XXXXXX
# Martinique | MQ | +596 | 0696XXXXXX, 0697XXXXXX
# Réunion | RE | +262 | 0692XXXXXX, 0693XXXXXX
# Mayotte | YT | +262 | 0692XXXXXX, 0693XXXXXX
# Nouvelle-Calédonie | NC | +687 |
# Polynésie française | PF | +689 | 40XXXXXX, 45XXXXXX, 87XXXXXX, 88XXXXXX, 89XXXXXX
#
# Cf: Plan national de numérotation téléphonique,
# https://www.arcep.fr/uploads/tx_gsavis/05-1085.pdf “Numéros mobiles à 10 chiffres”, page 6
#
# See issue #6996.
DEFAULT_COUNTRY_CODES = [:FR, :GP, :GF, :MQ, :RE, :YT, :NC, :PF].freeze
validates :value,
phone: {
possible: true,
allow_blank: true,
message: I18n.t(:not_a_phone, scope: 'activerecord.errors.messages')
}, unless: -> { Phonelib.valid_for_country?(value, :pf) }
}, unless: -> { Phonelib.valid_for_countries?(value, DEFAULT_COUNTRY_CODES) }
def to_s
value.present? ? Phonelib.parse(value).full_national : ''

14
lib/core_ext/phonelib.rb Normal file
View file

@ -0,0 +1,14 @@
# Class extensions to the Phonelib module, which allow parsing using several countries at once.
module Phonelib
# Variation of `.valid_for_country`, that can check several countries at once.
def self.valid_for_countries?(value, countries)
countries.any? { |country| valid_for_country?(value, country) }
end
# Variation of `Phonelib.parse`, which parses the given string using the first country
# for which the phone number is valid.
def self.parse_for_countries(value, passed_countries = [])
valid_country = passed_countries.find { |country| valid_for_country?(value, country) }
parse(value, valid_country)
end
end

View file

@ -22,6 +22,10 @@ describe Champs::PhoneChamp do
expect(champ_with_value("+1(0) - 123456789")).to be_valid
expect(champ_with_value("+49 2109 87654321")).to be_valid
expect(champ_with_value("012345678")).to be_valid
# DROM numbers should be valid
expect(champ_with_value("06 96 04 78 07")).to be_valid
expect(champ_with_value("05 94 22 31 31")).to be_valid
expect(champ_with_value("+594 5 94 22 31 31")).to be_valid
# polynesian numbers should not return errors in any way
## landline numbers start with 40 or 45
expect(champ_with_value("45187272")).to be_valid