Skip to content

Commit

Permalink
Merge pull request #117 from esimonov/integrate_routemobile_sms_provider
Browse files Browse the repository at this point in the history
Support RouteMobile SMS service
  • Loading branch information
esimonov authored Feb 7, 2020
2 parents 7913199 + 5e734aa commit 8211176
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 6 deletions.
68 changes: 68 additions & 0 deletions external_services/sms/routemobile/sms_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package routemobile

import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"

"github.com/madappgang/identifo/model"
)

const baseURLuae = "https://sms.rmlconnect.net%s"

// SMSService sends SMS via RouteMobile service.
type SMSService struct {
username string
password string
source string
baseURL string
httpClient *http.Client
}

// NewSMSService creates, inits and returns RouteMobile-backed SMS service.
func NewSMSService(settings model.SMSServiceSettings) (*SMSService, error) {
s := &SMSService{
username: settings.Username,
password: settings.Password,
source: settings.Source,
httpClient: &http.Client{
Timeout: 60 * time.Second,
},
}
switch {
case settings.Region == model.RouteMobileRegionUAE:
s.baseURL = baseURLuae
default:
return nil, fmt.Errorf("Unknown RouteMobile region %s", settings.Region)
}
return s, nil
}

// SendSMS sends SMS messages using RouteMobile service.
func (ss *SMSService) SendSMS(recipient, message string) error {
queryParams := fmt.Sprintf("username=%s&password=%s&type=0&dlr=0&destination=%s&source=%s&message=%s", ss.username, ss.password, strings.TrimPrefix(recipient, "+"), url.QueryEscape(ss.source), url.QueryEscape(message))
url := fmt.Sprintf(ss.baseURL, fmt.Sprintf("/bulksms/bulksms?%s", queryParams))

resp, err := ss.httpClient.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()

respBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
respString := string(respBytes)

if resp.StatusCode >= 400 {
return fmt.Errorf("%s. %d", respString, resp.StatusCode)
}
if !strings.HasPrefix(respString, "1701") {
return fmt.Errorf("Error from RouteMobile API: '%s'. Please refer to the RouteMobile documentation", respString)
}
return nil
}
11 changes: 9 additions & 2 deletions model/server_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,18 @@ type EmailServiceSettings struct {
// SMSServiceSettings holds together settings for SMS service.
type SMSServiceSettings struct {
Type SMSServiceType `yaml:"type,omitempty" json:"type,omitempty"`
// Twilio related config
// Twilio related config.
AccountSid string `yaml:"accountSid,omitempty" json:"account_sid,omitempty"`
AuthToken string `yaml:"authToken,omitempty" json:"auth_token,omitempty"`
ServiceSid string `yaml:"serviceSid,omitempty" json:"service_sid,omitempty"`
// Nexmo related config
// Nexmo related config.
APIKey string `yaml:"apiKey,omitempty" json:"api_key,omitempty"`
APISecret string `yaml:"apiSecret,omitempty" json:"api_secret,omitempty"`
// RouteMobile related config.
Username string `yaml:"username,omitempty" json:"username,omitempty"`
Password string `yaml:"password,omitempty" json:"password,omitempty"`
Source string `yaml:"source,omitempty" json:"source,omitempty"`
Region string `yaml:"region,omitempty" json:"region,omitempty"`
}

// SMSServiceType - service for sending sms messages.
Expand All @@ -197,6 +202,8 @@ const (
SMSServiceTwilio SMSServiceType = "twilio"
// SMSServiceNexmo is a Nexmo SMS service.
SMSServiceNexmo SMSServiceType = "nexmo"
// SMSServiceRouteMobile is a RouteMobile SMS service.
SMSServiceRouteMobile SMSServiceType = "routemobile"
// SMSServiceMock is an SMS service mock.
SMSServiceMock SMSServiceType = "mock"
)
Expand Down
15 changes: 13 additions & 2 deletions model/server_settings_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ func (ess *ExternalServicesSettings) Validate() error {
return nil
}

// RouteMobileRegionUAE is a regional UAE RouteMobileR platform.
const RouteMobileRegionUAE = "uae"

// Validate validates SMS service settings.
func (sss *SMSServiceSettings) Validate() error {
subject := "SMSServiceSettings"
Expand All @@ -285,15 +288,23 @@ func (sss *SMSServiceSettings) Validate() error {
case SMSServiceMock:
return nil
case SMSServiceNexmo:
if len(sss.APIKey)*len(sss.APISecret) == 0 {
if len(sss.APIKey) == 0 || len(sss.APISecret) == 0 {
return fmt.Errorf("%s. Error creating Nexmo SMS service, missing at least one of the parameters:"+
"\n apiKey : %v\n apiSecret : %v\n", subject, sss.APIKey, sss.APISecret)
}
case SMSServiceTwilio:
if len(sss.AccountSid)*len(sss.AuthToken)*len(sss.ServiceSid) == 0 {
if len(sss.AccountSid) == 0 || len(sss.AuthToken) == 0 || len(sss.ServiceSid) == 0 {
return fmt.Errorf("%s. Error creating Twilio SMS service, missing at least one of the parameters:"+
"\n sidKey : %v\n tokenKey : %v\n ServiceSidKey : %v\n", subject, sss.AccountSid, sss.AuthToken, sss.ServiceSid)
}
case SMSServiceRouteMobile:
if len(sss.Username) == 0 || len(sss.Password) == 0 || len(sss.Source) == 0 {
return fmt.Errorf("%s. Error creating RouteMobile SMS service, missing at least one of the parameters:"+
"\n username : %v\n password : %v\n", subject, sss.Username, sss.Password)
}
if sss.Region != RouteMobileRegionUAE {
return fmt.Errorf("%s. Error creating RouteMobile SMS service, region %s is not supported", subject, sss.Region)
}
default:
return fmt.Errorf("%s. Unknown type", subject)
}
Expand Down
8 changes: 6 additions & 2 deletions server-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,13 @@ externalServices:
sender: # Sender of the emails. If "MAILGUN_SENDER" or "AWS_SES_SENDER" env variable is set, it overrides (depending on the email service type) the value specified here.
region: # AWS SES-related setting. If "AWS_SES_REGION" env variable is set, it overrides the value specified here.
smsService: # SMS service settings.
type: mock # Supported values are: "twilio", "mock".
type: mock # Supported values are: "twilio", "nexmo", "routemobile", "mock".
accountSid: # Twilio-related setting.
authToken: # Twilio-related setting.
serviceSid: # Twilio-related setting.
apiKey: # Nexmo-related setting.
apiSecret: # Nexmo-related setting.
apiSecret: # Nexmo-related setting.
username: # RouteMobile-related setting.
password: # RouteMobile-related setting.
source: # RouteMobile-related setting.
region: # RouteMobile-related setting. Supported values are: uae.
3 changes: 3 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/madappgang/identifo/external_services/mail/ses"
smsMock "github.com/madappgang/identifo/external_services/sms/mock"
"github.com/madappgang/identifo/external_services/sms/nexmo"
"github.com/madappgang/identifo/external_services/sms/routemobile"
"github.com/madappgang/identifo/external_services/sms/twilio"
ijwt "github.com/madappgang/identifo/jwt"
jwtService "github.com/madappgang/identifo/jwt/service"
Expand Down Expand Up @@ -271,6 +272,8 @@ func initSMSService(settings model.SMSServiceSettings) (model.SMSService, error)
return twilio.NewSMSService(settings)
case model.SMSServiceNexmo:
return nexmo.NewSMSService(settings)
case model.SMSServiceRouteMobile:
return routemobile.NewSMSService(settings)
case model.SMSServiceMock:
return smsMock.NewSMSService()
}
Expand Down

0 comments on commit 8211176

Please sign in to comment.