Skip to content

Commit 16c6c39

Browse files
committed
Add ability to send SMS to short codes #172
1 parent 360ea7a commit 16c6c39

File tree

6 files changed

+36
-21
lines changed

6 files changed

+36
-21
lines changed

api/pkg/entities/message.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const (
7676
type Message struct {
7777
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
7878
Owner string `json:"owner" gorm:"index:idx_messages_user_id__owner__contact" example:"+18005550199"`
79-
UserID UserID `json:"user_id" gorm:"index:idx_messages_user_id__owner__contact" example:"WB7DRDWrJZRGbYrv2CKGkqbzvqdC"`
79+
UserID UserID `json:"user_id" gorm:"index:idx_messages__user_id" example:"WB7DRDWrJZRGbYrv2CKGkqbzvqdC"`
8080
Contact string `json:"contact" gorm:"index:idx_messages_user_id__owner__contact" example:"+18005550100"`
8181
Content string `json:"content" example:"This is a sample text message"`
8282
Type MessageType `json:"type" example:"mobile-terminated"`

api/pkg/requests/message_bulk_send_request.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,12 @@ func (input *MessageBulkSend) ToMessageSendParams(userID entities.UserID, source
4040
from, _ := phonenumbers.Parse(input.From, phonenumbers.UNKNOWN_REGION)
4141
var result []services.MessageSendParams
4242
for _, to := range input.To {
43-
toAddress, _ := phonenumbers.Parse(to, phonenumbers.UNKNOWN_REGION)
4443
result = append(result, services.MessageSendParams{
4544
Source: source,
4645
Owner: *from,
4746
UserID: userID,
4847
RequestReceivedAt: time.Now().UTC(),
49-
Contact: *toAddress,
48+
Contact: to,
5049
Content: input.Content,
5150
SIM: input.SIM,
5251
})

api/pkg/requests/message_send_request.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,12 @@ func (input *MessageSend) Sanitize() MessageSend {
3434
// ToMessageSendParams converts MessageSend to services.MessageSendParams
3535
func (input *MessageSend) ToMessageSendParams(userID entities.UserID, source string) services.MessageSendParams {
3636
from, _ := phonenumbers.Parse(input.From, phonenumbers.UNKNOWN_REGION)
37-
to, _ := phonenumbers.Parse(input.To, phonenumbers.UNKNOWN_REGION)
38-
3937
return services.MessageSendParams{
4038
Source: source,
4139
Owner: *from,
4240
UserID: userID,
4341
RequestReceivedAt: time.Now().UTC(),
44-
Contact: *to,
42+
Contact: input.sanitizeAddress(input.To),
4543
Content: input.Content,
4644
SIM: input.SIM,
4745
}

api/pkg/services/message_service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ func (service *MessageService) handleMessageFailedEvent(ctx context.Context, par
297297
// MessageSendParams parameters for sending a new message
298298
type MessageSendParams struct {
299299
Owner phonenumbers.PhoneNumber
300-
Contact phonenumbers.PhoneNumber
300+
Contact string
301301
Content string
302302
Source string
303303
SIM entities.SIM
@@ -317,7 +317,7 @@ func (service *MessageService) SendMessage(ctx context.Context, params MessageSe
317317
UserID: params.UserID,
318318
MaxSendAttempts: service.maxSendAttempts(ctx, params.UserID, phonenumbers.Format(&params.Owner, phonenumbers.E164)),
319319
Owner: phonenumbers.Format(&params.Owner, phonenumbers.E164),
320-
Contact: phonenumbers.Format(&params.Contact, phonenumbers.E164),
320+
Contact: params.Contact,
321321
RequestReceivedAt: params.RequestReceivedAt,
322322
Content: params.Content,
323323
SIM: params.SIM,

api/pkg/validators/message_handler_validator.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (validator MessageHandlerValidator) ValidateMessageSend(ctx context.Context
8181
Rules: govalidator.MapData{
8282
"to": []string{
8383
"required",
84+
contactPhoneNumberRule,
8485
},
8586
"from": []string{
8687
"required",
@@ -134,6 +135,7 @@ func (validator MessageHandlerValidator) ValidateMessageBulkSend(ctx context.Con
134135
"required",
135136
"max:50",
136137
"min:1",
138+
multipleContactPhoneNumberRule,
137139
},
138140
"from": []string{
139141
"required",

api/pkg/validators/validator.go

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net/url"
7+
"regexp"
78

89
"github.com/NdoleStudio/httpsms/pkg/events"
910

@@ -14,9 +15,10 @@ import (
1415
type validator struct{}
1516

1617
const (
17-
phoneNumberRule = "phoneNumber"
18-
multiplePhoneNumberRule = "multiplePhoneNumber"
19-
webhookEventsRule = "webhookEvents"
18+
phoneNumberRule = "phoneNumber"
19+
contactPhoneNumberRule = "contactPhoneNumber"
20+
multipleContactPhoneNumberRule = "multipleContactPhoneNumber"
21+
webhookEventsRule = "webhookEvents"
2022
)
2123

2224
func init() {
@@ -25,27 +27,41 @@ func init() {
2527
govalidator.AddCustomRule(phoneNumberRule, func(field string, rule string, message string, value interface{}) error {
2628
phoneNumber, ok := value.(string)
2729
if !ok {
28-
return fmt.Errorf("the %s field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164", field)
30+
return fmt.Errorf("The %s field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164", field)
2931
}
3032

3133
_, err := phonenumbers.Parse(phoneNumber, phonenumbers.UNKNOWN_REGION)
3234
if err != nil {
33-
return fmt.Errorf("the %s field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164", field)
35+
return fmt.Errorf("The %s field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164", field)
3436
}
3537

3638
return nil
3739
})
3840

39-
govalidator.AddCustomRule(multiplePhoneNumberRule, func(field string, rule string, message string, value interface{}) error {
41+
// custom rules to take fixed length word.
42+
// e.g: max_word:5 will throw error if the field contains more than 5 words
43+
govalidator.AddCustomRule(contactPhoneNumberRule, func(field string, rule string, message string, value interface{}) error {
44+
phoneNumber, ok := value.(string)
45+
if !ok {
46+
return fmt.Errorf("The %s field must contain only digits and must be less than 14 characters", field)
47+
}
48+
49+
if match, err := regexp.MatchString("^\\+?[0-9]\\d{1,14}$", phoneNumber); err != nil || !match {
50+
return fmt.Errorf("The %s field must contain only digits and must be less than 14 characters", field)
51+
}
52+
53+
return nil
54+
})
55+
56+
govalidator.AddCustomRule(multipleContactPhoneNumberRule, func(field string, rule string, message string, value interface{}) error {
4057
phoneNumbers, ok := value.([]string)
4158
if !ok {
42-
return fmt.Errorf("the %s field must be an array of a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164", field)
59+
return fmt.Errorf("The %s field must be an array of valid phone numbers", field)
4360
}
4461

4562
for index, number := range phoneNumbers {
46-
_, err := phonenumbers.Parse(number, phonenumbers.UNKNOWN_REGION)
47-
if err != nil {
48-
return fmt.Errorf("the %s value in index [%d] must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164", field, index)
63+
if match, err := regexp.MatchString("^\\+?[0-9]\\d{1,14}$", number); err != nil || !match {
64+
return fmt.Errorf("The %s field in index [%d] must contain only digits and must be less than 14 characters", field, index)
4965
}
5066
}
5167

@@ -55,11 +71,11 @@ func init() {
5571
govalidator.AddCustomRule(webhookEventsRule, func(field string, rule string, message string, value interface{}) error {
5672
input, ok := value.([]string)
5773
if !ok {
58-
return fmt.Errorf("the %s field must be a string array", field)
74+
return fmt.Errorf("The %s field must be a string array", field)
5975
}
6076

6177
if len(input) == 0 {
62-
return fmt.Errorf("the %s field is an empty array", field)
78+
return fmt.Errorf("The %s field is an empty array", field)
6379
}
6480

6581
validEvents := map[string]bool{
@@ -68,7 +84,7 @@ func init() {
6884

6985
for _, event := range input {
7086
if _, ok := validEvents[event]; !ok {
71-
return fmt.Errorf("the %s field has an invalid event with name [%s]", field, event)
87+
return fmt.Errorf("The %s field has an invalid event with name [%s]", field, event)
7288
}
7389
}
7490

0 commit comments

Comments
 (0)