initial commit 2
This commit is contained in:
31
application/notificationservice/notificationservice.go
Normal file
31
application/notificationservice/notificationservice.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package notificationservice
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||
)
|
||||
|
||||
var (
|
||||
instance *Service
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// Service holds the domain service repositories
|
||||
type Service struct {
|
||||
Twilio *twilioService
|
||||
}
|
||||
|
||||
// New returns a new domain Service instance
|
||||
func New(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, cache contract.CacheManager) *Service {
|
||||
once.Do(func() {
|
||||
instance = &Service{
|
||||
Twilio: newTwilioService(svc, mapper, cfg, cache),
|
||||
}
|
||||
})
|
||||
|
||||
return instance
|
||||
}
|
||||
259
application/notificationservice/twilio.go
Normal file
259
application/notificationservice/twilio.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package notificationservice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
|
||||
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
|
||||
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||
)
|
||||
|
||||
const (
|
||||
twilioMessageURL = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"
|
||||
twilioNumbersURL = "https://api.twilio.com/2010-04-01/Accounts/%s/AvailablePhoneNumbers/US/Local.json"
|
||||
twiliActualNumbersURL = "https://api.twilio.com/2010-04-01/Accounts/%s/IncomingPhoneNumbers.json"
|
||||
)
|
||||
|
||||
// twilioService holds methods to twillio application service
|
||||
type twilioService struct {
|
||||
svc *service.Service
|
||||
mapEntity *entitymapping.Mapper
|
||||
cfg *config.Config
|
||||
urlMessage string
|
||||
urlNumber string
|
||||
urlActualNumber string
|
||||
cache contract.CacheManager
|
||||
}
|
||||
|
||||
// newTwilioService returns a twilioService instance
|
||||
func newTwilioService(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, cache contract.CacheManager) *twilioService {
|
||||
return &twilioService{
|
||||
svc: svc,
|
||||
mapEntity: mapper,
|
||||
cfg: cfg,
|
||||
urlMessage: fmt.Sprintf(twilioMessageURL, cfg.Twilio.Account),
|
||||
urlNumber: fmt.Sprintf(twilioNumbersURL, cfg.Twilio.Account),
|
||||
urlActualNumber: fmt.Sprintf(twiliActualNumbersURL, cfg.Twilio.Account),
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (s twilioService) GetProxyNumber(to string) (viewmodel.ProxyNumber, error) {
|
||||
key := "proxy" + to
|
||||
var number viewmodel.ProxyNumber
|
||||
err := s.cache.GetStruct(key, &number)
|
||||
if err != nil || err == domain.ErrCacheMiss {
|
||||
return number, err
|
||||
} else {
|
||||
return number, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s twilioService) GetAvaliableNumbers(to string) (viewmodel.ListNumbers, error) {
|
||||
if to != "" {
|
||||
if strings.Contains(to, "+1") {
|
||||
to = strings.Replace(to, "+1", "", -1)
|
||||
}
|
||||
|
||||
area := to[0:3]
|
||||
|
||||
msgData := url.Values{}
|
||||
msgData.Set("PhoneNumber", area)
|
||||
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("GET", s.urlActualNumber+"?"+msgData.Encode(), bytes.NewBuffer([]byte{}))
|
||||
|
||||
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error Twilio: ", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||
var data viewmodel.ListNumbers
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
err := decoder.Decode(&data)
|
||||
if err != nil {
|
||||
return viewmodel.ListNumbers{}, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
} else {
|
||||
return viewmodel.ListNumbers{}, errors.New(resp.Status)
|
||||
}
|
||||
}
|
||||
return viewmodel.ListNumbers{}, nil
|
||||
}
|
||||
|
||||
func (s twilioService) GetAvaliableNewNumbers(to string) (viewmodel.ListNumbers, error) {
|
||||
if to != "" {
|
||||
if strings.Contains(to, "+1") {
|
||||
to = strings.Replace(to, "+1", "", -1)
|
||||
}
|
||||
|
||||
area := to[0:3]
|
||||
|
||||
msgData := url.Values{}
|
||||
msgData.Set("AreaCode", area)
|
||||
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("GET", s.urlNumber+"?"+msgData.Encode(), bytes.NewBuffer([]byte{}))
|
||||
|
||||
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error Twilio: ", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||
var data viewmodel.ListNumbers
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
err := decoder.Decode(&data)
|
||||
if err != nil {
|
||||
return viewmodel.ListNumbers{}, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
} else {
|
||||
return viewmodel.ListNumbers{}, errors.New(resp.Status)
|
||||
}
|
||||
}
|
||||
return viewmodel.ListNumbers{}, nil
|
||||
}
|
||||
|
||||
func (s twilioService) SaveNewNumber(number viewmodel.Number) (viewmodel.Number, error) {
|
||||
phoneNumber := number.PhoneNumber
|
||||
if strings.Contains(phoneNumber, "+1") {
|
||||
phoneNumber = strings.Replace(phoneNumber, "+1", "", -1)
|
||||
}
|
||||
area := phoneNumber[0:3]
|
||||
|
||||
msgData := url.Values{}
|
||||
msgData.Set("PhoneNumber", number.PhoneNumber)
|
||||
msgData.Set("AreaCode", area)
|
||||
msgData.Set("FriendlyName", number.FriendlyName)
|
||||
msgData.Set("SmsApplicationSid", s.cfg.Twilio.TwiMLSID)
|
||||
msgDataReader := *strings.NewReader(msgData.Encode())
|
||||
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("POST", s.urlActualNumber, &msgDataReader)
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error Twilio: ", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
err := decoder.Decode(&number)
|
||||
if err != nil {
|
||||
return viewmodel.Number{}, err
|
||||
}
|
||||
|
||||
return number, nil
|
||||
} else {
|
||||
return viewmodel.Number{}, errors.New(resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func (s twilioService) GetValidNumber(from string, to string) (viewmodel.Number, error) {
|
||||
list, err := s.GetAvaliableNumbers(to)
|
||||
if err != nil {
|
||||
return viewmodel.Number{}, err
|
||||
}
|
||||
|
||||
if len(list.IncomingPhones) > 0 {
|
||||
return list.IncomingPhones[0], nil
|
||||
}
|
||||
|
||||
list, err = s.GetAvaliableNewNumbers(to)
|
||||
if err != nil {
|
||||
return viewmodel.Number{}, err
|
||||
}
|
||||
|
||||
if len(list.AvailableNumbers) > 0 {
|
||||
number, err := s.SaveNewNumber(list.AvailableNumbers[0])
|
||||
if err != nil {
|
||||
fmt.Println("Error on GetValidNumber: ", err.Error())
|
||||
return viewmodel.Number{}, err
|
||||
}
|
||||
|
||||
return number, nil
|
||||
} else {
|
||||
return viewmodel.Number{}, errors.New("No new number available")
|
||||
}
|
||||
}
|
||||
|
||||
func (s twilioService) GetNumber(from string, to string) (string, error) {
|
||||
number, err := s.GetValidNumber(from, to)
|
||||
if err != nil {
|
||||
return from, err
|
||||
}
|
||||
|
||||
return number.PhoneNumber, nil
|
||||
}
|
||||
|
||||
func (s twilioService) SendSMS(from string, to string, message string) error {
|
||||
if from == "" {
|
||||
return errors.New("TwilioService.SendSMS: from parameter is mandatory")
|
||||
}
|
||||
if to == "" {
|
||||
return errors.New("TwilioService.SendSMS: to parameter is mandatory")
|
||||
}
|
||||
if message == "" {
|
||||
return errors.New("TwilioService.SendSMS: message parameter is mandatory")
|
||||
}
|
||||
|
||||
senderNumber, err := s.GetNumber(from, to)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgData := url.Values{}
|
||||
msgData.Set("To", to)
|
||||
msgData.Set("From", senderNumber)
|
||||
msgData.Set("Body", message)
|
||||
|
||||
msgDataReader := *strings.NewReader(msgData.Encode())
|
||||
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("POST", s.urlMessage, &msgDataReader)
|
||||
|
||||
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error Twilio: ", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||
var data map[string]interface{}
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
err := decoder.Decode(&data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Error on Twilio Response: ", resp.Status)
|
||||
return errors.New(resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user