Skip to content

Commit

Permalink
refactor: phone number validation
Browse files Browse the repository at this point in the history
  • Loading branch information
sundowndev committed Jul 31, 2022
1 parent 29d2593 commit d61a5e8
Show file tree
Hide file tree
Showing 17 changed files with 803 additions and 69 deletions.
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ require (
github.com/fatih/color v1.10.0
github.com/gin-gonic/gin v1.6.3
github.com/nyaruka/phonenumbers v1.0.66
github.com/onlinecity/go-phone-iso3166 v0.0.1
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0
github.com/sundowndev/dorkgen v1.2.0
github.com/swaggo/swag v1.7.0
github.com/tchap/go-patricia v2.3.0+incompatible
gopkg.in/h2non/gock.v1 v1.0.16
)

Expand All @@ -31,8 +31,6 @@ require (
github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/golang/protobuf v1.3.4 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
Expand Down
9 changes: 2 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,16 @@ github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyN
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc=
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
Expand Down Expand Up @@ -184,8 +179,6 @@ github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uY
github.com/nyaruka/phonenumbers v1.0.66 h1:OVFSLMXhNR7CS3yq6ekm2uggokeggwJVO31h7OgB3OU=
github.com/nyaruka/phonenumbers v1.0.66/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onlinecity/go-phone-iso3166 v0.0.1 h1:srN6o8NjxBWIrlK6Z+zD9wGMSGYi4itWA/fRyaxetqs=
github.com/onlinecity/go-phone-iso3166 v0.0.1/go.mod h1:n8+yIOCu9O63MH3WVwlWq1YVF6ZuAG5xlZ4mZ5ZzKF8=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -238,6 +231,8 @@ github.com/sundowndev/dorkgen v1.2.0 h1:dnB3tyV0n0IJ60KkaID35zoHRDvCbtJLcX9pLudQ
github.com/sundowndev/dorkgen v1.2.0/go.mod h1:7CCMM/9plw5FEpuUgdqO+shHhKon1+T3TzcKGaDKyqk=
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
Expand Down
13 changes: 10 additions & 3 deletions lib/number/number.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package number

import (
"errors"
"fmt"
"github.com/nyaruka/phonenumbers"
"github.com/sundowndev/phoneinfoga/v2/lib/phonegeocode"
)

// Number is a phone number
Expand All @@ -16,10 +19,14 @@ type Number struct {
}

func NewNumber(number string) (res *Number, err error) {
n := "+" + FormatNumber(number)
country := ParseCountryCode(n)
n := fmt.Sprintf("+%s", FormatNumber(number))

num, err := phonenumbers.Parse(n, country)
country, err := phonegeocode.Country(number)
if err != nil {
return nil, errors.New("country code not recognized")
}

num, err := phonenumbers.Parse(n, "")
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion lib/number/number_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestNumber(t *testing.T) {
E164: "+15552221212",
International: "15552221212",
CountryCode: 1,
Country: "",
Country: "US",
Carrier: "",
},
},
Expand Down
17 changes: 2 additions & 15 deletions lib/number/utils.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
package number

import (
_ "embed"
"regexp"
"strconv"

phoneiso3166 "github.com/onlinecity/go-phone-iso3166"
)

// FormatNumber formats a phone number to remove
// unnecessary chars and avoid dealing with unwanted input.
func FormatNumber(n string) string {
re := regexp.MustCompile(`[_\W]+`)
number := re.ReplaceAllString(n, "")

return number
}

// ParseCountryCode parses a phone number and returns ISO country code.
// This is required in order to use the phonenumbers library.
func ParseCountryCode(n string) string {
var number uint64
number, _ = strconv.ParseUint(FormatNumber(n), 10, 64)

return phoneiso3166.E164.Lookup(number)
return re.ReplaceAllString(n, "")
}

// IsValid indicate if a phone number has a valid format.
Expand Down
20 changes: 0 additions & 20 deletions lib/number/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,6 @@ func TestUtils(t *testing.T) {
})
})

t.Run("ParseCountryCode", func(t *testing.T) {
t.Run("should parse country code correctly", func(t *testing.T) {
result := ParseCountryCode("+33 679368229")

assert.Equal(t, result, "FR", "they should be equal")
})

t.Run("should parse country code correctly", func(t *testing.T) {
result := ParseCountryCode("+1 315-284-1580")

assert.Equal(t, result, "US", "they should be equal")
})

t.Run("should parse country code correctly", func(t *testing.T) {
result := ParseCountryCode("4566118311")

assert.Equal(t, result, "DK", "they should be equal")
})
})

t.Run("IsValid", func(t *testing.T) {
t.Run("should validate phone number", func(t *testing.T) {
result := IsValid("+1 315-284-1580")
Expand Down
59 changes: 59 additions & 0 deletions lib/phonegeocode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Phone Geocode

**This package was copied from [github.com/davegardnerisme/phonegeocode](https://github.com/davegardnerisme/phonegeocode) then modified.**

----

Internationalised phone number geocoding by country for Go.

I built this because I needed to turn phone numbers into countries, and that's
really _all_ I needed. If [libphonenumber](https://code.google.com/p/libphonenumber/)
existed for Go, I would probably just use that. AFAIK it doesn't.

This is based on work in [github.com/relops/prefixes](https://github.com/relops/prefixes),
however it has a different implementation, using a [Trie](http://en.wikipedia.org/wiki/Trie)
data structure - specifically [github.com/tchap/go-patricia](https://github.com/tchap/go-patricia).

The way it works is that we have a list of prefixes that identify a country, and
we simply match the _most specific prefix_ to find the country code. This deals
with Canada where the country code is `+1` and shared with US.

All the data lives in a CSV and can be used via codegen to create our Trie.

```
go run data/codegen.go > ./data.go && go fmt
```

## Usage

```
// cc = GB, err = nil
cc, err := phonegeocode.Country("+447999111222")
// cc = "", err = phonegeocode.ErrCountryNotFound
cc, err := phonegeocode.Country("+999999999998")
```

## License

The MIT License (MIT)

Copyright (c) 2016 Dave Gardner

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading

0 comments on commit d61a5e8

Please sign in to comment.