diff options
Diffstat (limited to 'perllib/FixMyStreet/SMS.pm')
-rw-r--r-- | perllib/FixMyStreet/SMS.pm | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/SMS.pm b/perllib/FixMyStreet/SMS.pm new file mode 100644 index 000000000..874108706 --- /dev/null +++ b/perllib/FixMyStreet/SMS.pm @@ -0,0 +1,118 @@ +package FixMyStreet::SMS; + +use strict; +use warnings; + +use JSON::MaybeXS; +use Moo; +use Number::Phone::Lib; +use WWW::Twilio::API; + +use FixMyStreet; +use mySociety::EmailUtil qw(is_valid_email); +use FixMyStreet::DB; + +has twilio => ( + is => 'lazy', + default => sub { + WWW::Twilio::API->new( + AccountSid => FixMyStreet->config('TWILIO_ACCOUNT_SID'), + AuthToken => FixMyStreet->config('TWILIO_AUTH_TOKEN'), + utf8 => 1, + ); + }, +); + +has from => ( + is => 'lazy', + default => sub { FixMyStreet->config('TWILIO_FROM_PARAMETER') }, +); + +has messaging_service => ( + is => 'lazy', + default => sub { FixMyStreet->config('TWILIO_MESSAGING_SERVICE_SID') }, +); + +sub send_token { + my ($class, $token_data, $token_scope, $to) = @_; + + # Random number between 10,000 and 75,535 + my $random = 10000 + unpack('n', mySociety::Random::random_bytes(2, 1)); + $token_data->{code} = $random; + my $token_obj = FixMyStreet::DB->resultset("Token")->create({ + scope => $token_scope, + data => $token_data, + }); + my $body = sprintf(_("Your verification code is %s"), $random); + + my $result = $class->new->send(to => $to, body => $body); + return { + random => $random, + token => $token_obj->token, + %$result, + }; +} + +sub send { + my ($self, %params) = @_; + my $output = $self->twilio->POST('Messages.json', + $self->from ? (From => $self->from) : (), + $self->messaging_service ? (MessagingServiceSid => $self->messaging_service) : (), + To => $params{to}, + Body => $params{body}, + ); + my $data = decode_json($output->{content}); + if ($output->{code} >= 400) { + return { error => "$data->{message} ($data->{code})" }; + } + return { success => $data->{sid} }; +} + +=head2 parse_username + +Given a string that might be an email address or a phone number, +return what we think it is, and if it's valid one of those. Or +undef if it's empty. + +=cut + +sub parse_username { + my ($class, $username) = @_; + + return { type => 'email', username => $username } unless $username; + + $username = lc $username; + $username =~ s/\s+//g; + + return { type => 'email', email => $username, username => $username } if is_valid_email($username); + + my $type = $username =~ /^[^a-z]+$/i ? 'phone' : 'email'; + my $phone = do { + if ($username =~ /^\+/) { + # If already in international format, use that + Number::Phone::Lib->new($username) + } else { + # Otherwise, assume it is country configured + my $country = FixMyStreet->config('PHONE_COUNTRY'); + Number::Phone::Lib->new($country, $username); + } + }; + + my $may_be_mobile = 0; + if ($phone) { + $type = 'phone'; + # Store phone without spaces + ($username = $phone->format) =~ s/\s+//g; + # Is this mobile definitely or possibly a mobile? (+1 numbers) + $may_be_mobile = 1 if $phone->is_mobile || (!defined $phone->is_mobile && $phone->is_geographic); + } + + return { + type => $type, + phone => $phone, + may_be_mobile => $may_be_mobile, + username => $username, + }; +} + +1; |