Compare commits

..

No commits in common. "7cf97b063b81b87ed4837c7c9a6dfa9de44c4e37" and "4f55a80dbedd32b62e233bc7267ad641351d7a54" have entirely different histories.

7 changed files with 63 additions and 267 deletions

View File

@ -40,8 +40,23 @@ powow:
# Clé d'API à utiliser par les clients Powow utilisant le mock # Clé d'API à utiliser par les clients Powow utilisant le mock
apiKey: powow apiKey: powow
# La création/mise à jour de modèles de SMS s'effectue via les méthodes TransactionalSMS.Create et TransactionalSMS.Update. # Modèles de SMS transactionnels
# Voir le fichier ./misc/powow.http pour un exemple de requête. # Voir https://powow4.iroquois.fr/user/docs/api/#create-transactional-sms
# et https://powow4.iroquois.fr/user/docs/api/#update-transactional-sms
#
# L'identifiant (SmsID) de chaque modèle est son index dans le tableau.
sms:
- name: Powow SMS
from: FakeSMS
# Modèle de contenu pour le SMS avec patrons d'insertion
# Voir https://powow4.iroquois.fr/user/docs/api/#send-transactional-sms, "About the CustomData parameter"
content: |
Bonjour %Subscriber:Firstname%,
Lorem ipsum dolor sit amet...
# Cet attribut n'est pas utilisé dans le cadre du mock
shortLink: false
``` ```
### Variables d'environnement ### Variables d'environnement

View File

@ -8,8 +8,6 @@ import (
"forge.cadoles.com/Cadoles/fake-sms/internal/command" "forge.cadoles.com/Cadoles/fake-sms/internal/command"
"forge.cadoles.com/Cadoles/fake-sms/internal/config" "forge.cadoles.com/Cadoles/fake-sms/internal/config"
"forge.cadoles.com/Cadoles/fake-sms/internal/model"
"forge.cadoles.com/Cadoles/fake-sms/internal/model/powow"
"forge.cadoles.com/Cadoles/fake-sms/internal/query" "forge.cadoles.com/Cadoles/fake-sms/internal/query"
"forge.cadoles.com/Cadoles/fake-sms/internal/storm" "forge.cadoles.com/Cadoles/fake-sms/internal/storm"
"gitlab.com/wpetit/goweb/cqrs" "gitlab.com/wpetit/goweb/cqrs"
@ -42,10 +40,6 @@ func getServiceContainer(conf *config.Config) (*service.Container, error) {
ctn.Provide(storm.ServiceName, storm.ServiceProvider( ctn.Provide(storm.ServiceName, storm.ServiceProvider(
storm.WithPath(conf.Data.Path), storm.WithPath(conf.Data.Path),
storm.WithObjects(
&model.SMS{},
&powow.SMSTemplate{},
),
)) ))
ctn.Provide(cqrs.ServiceName, cqrs.ServiceProvider()) ctn.Provide(cqrs.ServiceName, cqrs.ServiceProvider())

View File

@ -28,7 +28,8 @@ type DataConfig struct {
} }
type PowowConfig struct { type PowowConfig struct {
APIKey string `yaml:"apiKey" env:"FAKESMS_POWOW_API_KEY"` APIKey string `yaml:"apiKey" env:"FAKESMS_POWOW_API_KEY"`
SMS []PowowSMS `yaml:"sms"`
} }
type PowowSMS struct { type PowowSMS struct {
@ -79,6 +80,17 @@ func NewDefault() *Config {
}, },
Powow: PowowConfig{ Powow: PowowConfig{
APIKey: "powow", APIKey: "powow",
SMS: []PowowSMS{
{
Name: "Powow SMS",
From: "FakeSMS",
ShortLink: false,
Content: `Bonjour %Subscriber:Firstname%,
Lorem ipsum dolor sit amet...
`,
},
},
}, },
} }
} }

View File

@ -1,10 +0,0 @@
package powow
type SMSTemplate struct {
ID int `storm:"id,increment"`
SmsName string
FromName string
Content string
ShortLink int
Language string
}

View File

@ -10,8 +10,6 @@ import (
"forge.cadoles.com/Cadoles/fake-sms/internal/command" "forge.cadoles.com/Cadoles/fake-sms/internal/command"
"forge.cadoles.com/Cadoles/fake-sms/internal/config" "forge.cadoles.com/Cadoles/fake-sms/internal/config"
"forge.cadoles.com/Cadoles/fake-sms/internal/model/powow"
"forge.cadoles.com/Cadoles/fake-sms/internal/storm"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/cqrs" "gitlab.com/wpetit/goweb/cqrs"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
@ -22,32 +20,25 @@ import (
type ErrorCode int type ErrorCode int
const ( const (
ErrorCodeInvalidCommand ErrorCode = 99997 ErrorCodeInvalidCommand ErrorCode = 99997
ErrorCodeAuthenticationFailure ErrorCode = 99998 ErrorCodeAuthenticationFailure ErrorCode = 99998
ErrorCodeNotEnoughPrivileges ErrorCode = 99999 ErrorCodeNotEnoughPrivileges ErrorCode = 99999
ErrorCodeTransactionSMSSendMissingSMSID ErrorCode = 1 ErrorCodeMissingSMSID ErrorCode = 1
ErrorCodeTransactionSMSSendMissingMobilePhoneNumber ErrorCode = 2 ErrorCodeMissingMobilePhoneNumber ErrorCode = 2
ErrorCodeTransactionSMSSendInvalidSMSID ErrorCode = 3 ErrorCodeInvalidSMSID ErrorCode = 3
ErrorCodeTransactionSMSSendInvalidMobilePhoneNumber ErrorCode = 4 ErrorCodeInvalidMobilePhoneNumber ErrorCode = 4
ErrorCodeTransactionSMSSendInvalidCustomData ErrorCode = 5 ErrorCodeInvalidCustomData ErrorCode = 5
ErrorCodeTransactionSMSSendInvalidTimeToSend ErrorCode = 6 ErrorCodeInvalidTimeToSend ErrorCode = 6
ErrorCodeTransactionSMSSendAccountSubscribersLimitExceeded ErrorCode = 7 ErrorCodeAccountSubscribersLimitExceeded ErrorCode = 7
ErrorCodeTransactionSMSSendMobilePhoneNumberCannotBeSaved ErrorCode = 7 ErrorCodeMobilePhoneNumberCannotBeSaved ErrorCode = 7
ErrorCodeTransactionSMSSendTransactionalIDCannotBeCreated ErrorCode = 9 ErrorCodeTransactionalIDCannotBeCreated ErrorCode = 9
ErrorCodeTransactionSMSSendSMSSentLimitExceeded ErrorCode = 10 ErrorCodeSMSSentLimitExceeded ErrorCode = 10
ErrorCodeTransactionSMSUpdateMissingSMSID ErrorCode = 1
ErrorCodeTransactionSMSUpdateInvalidSMSID ErrorCode = 3
ErrorCodeTransactionSMSUpdateInvalidFromName ErrorCode = 4
ErrorCodeTransactionSMSUpdateInvalidLanguage ErrorCode = 7
) )
type Command string type Command string
const ( const (
CommandTransactionalSMSSend = "TransactionalSms.Send" CommandTransactionalSMSSend = "TransactionalSms.Send"
CommandTransactionalSMSCreate = "TransactionalSms.Create"
CommandTransactionalSMSUpdate = "TransactionalSms.Update"
) )
type PowowRequest struct { type PowowRequest struct {
@ -112,14 +103,6 @@ func handlePowowEntrypoint(w http.ResponseWriter, r *http.Request) {
case CommandTransactionalSMSSend: case CommandTransactionalSMSSend:
handleTransactionalSMSSend(ctx, ctn, w, pr) handleTransactionalSMSSend(ctx, ctn, w, pr)
return
case CommandTransactionalSMSCreate:
handleTransactionalSMSCreate(ctx, ctn, w, pr)
return
case CommandTransactionalSMSUpdate:
handleTransactionalSMSUpdate(ctx, ctn, w, pr)
return return
default: default:
res := &PowowResponse{ res := &PowowResponse{
@ -136,52 +119,45 @@ func handlePowowEntrypoint(w http.ResponseWriter, r *http.Request) {
// Mock https://powow4.iroquois.fr/user/docs/api/#send-transactional-sms // Mock https://powow4.iroquois.fr/user/docs/api/#send-transactional-sms
func handleTransactionalSMSSend(ctx context.Context, ctn *service.Container, w http.ResponseWriter, req *PowowRequest) { func handleTransactionalSMSSend(ctx context.Context, ctn *service.Container, w http.ResponseWriter, req *PowowRequest) {
bus := cqrs.Must(ctn) bus := cqrs.Must(ctn)
db := storm.Must(ctn) conf := config.Must(ctn)
smsID, exists, valid := getPowowSMSID(req) rawSMSID, exists := req.Payload["SmsID"]
if !exists { if !exists {
sendPowowResponse(w, &PowowResponse{ sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSSendMissingSMSID, ErrorCode: ErrorCodeMissingSMSID,
Success: false, Success: false,
}) })
return return
} }
if !valid { smsID, ok := rawSMSID.(float64)
if !ok {
sendPowowResponse(w, &PowowResponse{ sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSSendInvalidSMSID, ErrorCode: ErrorCodeInvalidSMSID,
Success: false, Success: false,
}) })
return return
} }
smsTmpl := &powow.SMSTemplate{} if smsID < 0 || int(smsID) > len(conf.Powow.SMS)-1 {
sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeInvalidSMSID,
Success: false,
})
if err := db.One("ID", smsID, smsTmpl); err != nil { return
if errors.Is(err, storm.ErrNotFound) {
sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSSendInvalidSMSID,
Success: false,
})
return
}
panic(errors.Wrap(err, "could not retrieve sms template"))
} }
customData := make(map[string]interface{}) customData := make(map[string]interface{})
var ok bool
rawCustomData, exists := req.Payload["CustomData"] rawCustomData, exists := req.Payload["CustomData"]
if exists { if exists {
customData, ok = rawCustomData.(map[string]interface{}) customData, ok = rawCustomData.(map[string]interface{})
if !ok { if !ok {
sendPowowResponse(w, &PowowResponse{ sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSSendInvalidCustomData, ErrorCode: ErrorCodeInvalidCustomData,
Success: false, Success: false,
}) })
@ -189,15 +165,17 @@ func handleTransactionalSMSSend(ctx context.Context, ctn *service.Container, w h
} }
} }
body, err := createSMSBody(smsTmpl.Content, customData) sms := conf.Powow.SMS[int(smsID)]
body, err := createSMSBody(sms.Content, customData)
if err != nil { if err != nil {
panic(errors.Wrap(err, "could not generate sms body")) panic(errors.Wrap(err, "could not generate sms body"))
} }
req.Payload["_Template"] = smsTmpl req.Payload["_Template"] = sms
storeSMS := &command.StoreSMSRequest{ storeSMS := &command.StoreSMSRequest{
From: smsTmpl.FromName, From: sms.From,
Body: body, Body: body,
Recipient: req.Payload["MobilePhoneNumber"].(string), Recipient: req.Payload["MobilePhoneNumber"].(string),
Metadata: req.Payload, Metadata: req.Payload,
@ -239,143 +217,6 @@ func createSMSBody(template string, customData map[string]interface{}) (string,
return content, nil return content, nil
} }
// Mock https://powow4.iroquois.fr/user/docs/api/#create-transactional-sms
func handleTransactionalSMSCreate(ctx context.Context, ctn *service.Container, w http.ResponseWriter, req *PowowRequest) {
db := storm.Must(ctn)
smsTemplate := &powow.SMSTemplate{}
if err := db.Save(smsTemplate); err != nil {
panic(errors.Wrap(err, "could not save sms template"))
}
res := &struct {
PowowResponse
SmsID int
}{
PowowResponse: PowowResponse{
Success: true,
ErrorCode: 0,
},
SmsID: smsTemplate.ID,
}
sendPowowResponse(w, res)
}
// Mock https://powow4.iroquois.fr/user/docs/api/#update-transactional-sms
func handleTransactionalSMSUpdate(ctx context.Context, ctn *service.Container, w http.ResponseWriter, req *PowowRequest) {
smsID, exists, valid := getPowowSMSID(req)
if !exists {
sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSUpdateMissingSMSID,
Success: false,
})
return
}
if !valid {
sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSUpdateInvalidSMSID,
Success: false,
})
return
}
db := storm.Must(ctn)
smsTmpl := &powow.SMSTemplate{}
if err := db.One("ID", smsID, smsTmpl); err != nil {
if errors.Is(err, storm.ErrNotFound) {
sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSUpdateInvalidSMSID,
Success: false,
})
return
}
panic(errors.Wrap(err, "could not retrieve sms template"))
}
rawContent, exists := req.Payload["Content"]
if exists {
content, ok := rawContent.(string)
if ok {
smsTmpl.Content = content
}
}
rawLanguage, exists := req.Payload["Language"]
if exists {
language, ok := rawLanguage.(string)
if ok {
if !contains(language, "en", "fr", "it", "es", "de", "pt", "pl", "zh") {
sendPowowResponse(w, &PowowResponse{
ErrorCode: ErrorCodeTransactionSMSUpdateInvalidLanguage,
Success: false,
})
return
}
smsTmpl.Language = language
}
}
rawFromName, exists := req.Payload["FromName"]
if exists {
fromName, ok := rawFromName.(string)
if ok {
smsTmpl.FromName = fromName
}
}
rawShortLink, exists := req.Payload["ShortLink"]
if exists {
shortLink, ok := rawShortLink.(float64)
if ok {
if shortLink == 1.0 {
smsTmpl.ShortLink = 1
} else {
smsTmpl.ShortLink = 0
}
}
}
rawSMSName, exists := req.Payload["SmsName"]
if exists {
smsName, ok := rawSMSName.(string)
if ok {
smsTmpl.SmsName = smsName
}
}
rawShortLink, exists = req.Payload["ShortLink"]
if exists {
shortLink, ok := rawShortLink.(float64)
if ok {
if shortLink == 1.0 {
smsTmpl.ShortLink = 1
} else {
smsTmpl.ShortLink = 0
}
}
}
if err := db.Save(smsTmpl); err != nil {
panic(errors.Wrap(err, "could not save sms template"))
}
sendPowowResponse(w, &PowowResponse{
ErrorCode: 0,
Success: true,
})
}
func sendPowowResponse(w http.ResponseWriter, res interface{}) { func sendPowowResponse(w http.ResponseWriter, res interface{}) {
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
@ -386,17 +227,3 @@ func sendPowowResponse(w http.ResponseWriter, res interface{}) {
panic(errors.WithStack(err)) panic(errors.WithStack(err))
} }
} }
func getPowowSMSID(req *PowowRequest) (smsID int, exists bool, valid bool) {
rawSMSID, exists := req.Payload["SmsID"]
if !exists {
return -1, false, false
}
smsIDFloat, ok := rawSMSID.(float64)
if !ok {
return -1, true, false
}
return int(smsIDFloat), true, true
}

View File

@ -1,11 +0,0 @@
package route
func contains(search string, items ...string) bool {
for _, item := range items {
if item == search {
return true
}
}
return false
}

View File

@ -1,34 +1,3 @@
### Create transactional SMS template
# @name createSms
POST http://localhost:3000/api/v1/mock/powow
Content-Type: application/json
{
"APIKey": "powow",
"Command": "TransactionalSms.Create"
}
### Update transactional SMS template
@SmsID = {{createSms.response.body.$.SmsID}}
POST http://localhost:3000/api/v1/mock/powow
Content-Type: application/json
{
"APIKey": "powow",
"Command": "TransactionalSms.Update",
"SmsID": {{SmsID}},
"SmsName": "Defaut SMS",
"FromName": "FakeSMS",
"Content": "Bonjour %Subscriber:Firstname%,\nLorem ipsum dolor sit amet...",
"ShortLink": 0,
"Language": "fr"
}
### Send transactional SMS
POST http://localhost:3000/api/v1/mock/powow POST http://localhost:3000/api/v1/mock/powow
Content-Type: application/json Content-Type: application/json
@ -36,7 +5,7 @@ Content-Type: application/json
"APIKey": "powow", "APIKey": "powow",
"Command": "TransactionalSms.Send", "Command": "TransactionalSms.Send",
"ResponseFormat": "JSON", "ResponseFormat": "JSON",
"SmsID": {{SmsID}}, "SmsID": 0,
"MobilePhoneNumber": "+33699999999", "MobilePhoneNumber": "+33699999999",
"TimeToSend": "2017-01-01 10:00:00", "TimeToSend": "2017-01-01 10:00:00",
"CustomData": { "CustomData": {