diff --git a/go.mod b/go.mod index de9ec15f7330b73b41780fd745bd326c43e24ba4..0b04d83613e282d1270a15687afc1cbd1e2855e3 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,14 @@ require ( github.com/aws/smithy-go v1.20.2 github.com/dimuska139/go-email-normalizer/v2 v2.0.0 github.com/dlsniper/debugger v0.6.0 + github.com/dongri/phonenumber v0.1.6 github.com/go-pg/pg/v10 v10.10.6 github.com/go-redis/redis/v8 v8.11.4 github.com/go-redis/redis_rate/v9 v9.1.2 github.com/go-resty/resty/v2 v2.7.0 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/uuid v1.6.0 + github.com/infobip/infobip-api-go-client/v3 v3.1.1 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 github.com/jinzhu/now v1.1.5 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 @@ -69,7 +71,6 @@ require ( github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dongri/phonenumber v0.1.6 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-errors/errors v1.4.1 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -119,5 +120,6 @@ require ( google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/validator.v2 v2.0.1 // indirect mellium.im/sasl v0.2.1 // indirect ) diff --git a/go.sum b/go.sum index fdef8661b544a331c5d515bfb3a941436fa3148e..c01dbd13c5a3d95034de4df5518b4e45bdd32085 100644 --- a/go.sum +++ b/go.sum @@ -184,6 +184,8 @@ github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible h1:zaX5fYT98jX5j4 github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/inconshreveable/log15/v3 v3.0.0-testing.5 h1:h4e0f3kjgg+RJBlKOabrohjHe47D3bbAB9BgMrc3DYA= github.com/inconshreveable/log15/v3 v3.0.0-testing.5/go.mod h1:3GQg1SVrLoWGfRv/kAZMsdyU5cp8eFc1P3cw+Wwku94= +github.com/infobip/infobip-api-go-client/v3 v3.1.1 h1:hgkvZiwgLzmk9BGumElRRCxDQNhv37DuIzrGraXTXlI= +github.com/infobip/infobip-api-go-client/v3 v3.1.1/go.mod h1:DuvEYDOank/s4FO4mQtmbOiZCTQFFr/vAWW41kZ5Wxc= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -482,6 +484,8 @@ gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= +gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/infobip_utils/infobip_utils.go b/infobip_utils/infobip_utils.go new file mode 100644 index 0000000000000000000000000000000000000000..567c6b1cc2e180aadc6275ad4472fa9731d6f955 --- /dev/null +++ b/infobip_utils/infobip_utils.go @@ -0,0 +1,179 @@ +package infobip_utils + +import ( + "github.com/infobip/infobip-api-go-client/v3/pkg/infobip/models/messagesapi" +) + +type InfobipFailover string + +const ( + FailoverTypeRCS InfobipFailover = "RCS" + FailoverTypeSMS InfobipFailover = "SMS" +) + +type MessageDetails struct { + From string + To string + MessageText string + CallbackData string + CallbackURL string + ValidityPeriodAmount int32 + ValidityPeriodTimeUnit string + Variables map[string]any + Failovers []InfobipFailover +} + +// ------------------------------------------------------------------------------------------------ +// Message builder functions +// ------------------------------------------------------------------------------------------------ + +func getDestinations(messageDetails MessageDetails) []messagesapi.MessageDestination { + whatsAppChannelDestination := messagesapi.NewChannelDestination(messagesapi.OUTBOUNDMESSAGECHANNEL_WHATSAPP, messageDetails.To) + rcsChannelDestination := messagesapi.NewChannelDestination(messagesapi.OUTBOUNDMESSAGECHANNEL_RCS, messageDetails.To) + smsChannelDestination := messagesapi.NewChannelDestination(messagesapi.OUTBOUNDMESSAGECHANNEL_SMS, messageDetails.To) + + destinations := messagesapi.NewChannelsDestination([]messagesapi.ChannelDestination{*whatsAppChannelDestination, *rcsChannelDestination, *smsChannelDestination}) + return []messagesapi.MessageDestination{{ChannelsDestination: destinations}} +} + +func getMessageContent(messageDetails MessageDetails) messagesapi.MessageContent { + content := messagesapi.NewMessageContent(messagesapi.MessageBody{ + MessageTextBody: messagesapi.NewMessageTextBody(messageDetails.MessageText), + }) + + return *content +} + +func getTemplate(templateName string) messagesapi.Template { + template := messagesapi.NewTemplate(templateName) + template.SetLanguage("en_GB") + return *template +} + +func getDefaultValidityPeriod(messageDetails MessageDetails) messagesapi.ValidityPeriod { + validityPeriod := messagesapi.NewValidityPeriod(messageDetails.ValidityPeriodAmount) + validityPeriod.SetTimeUnit(messagesapi.ValidityPeriodTimeUnit(messageDetails.ValidityPeriodTimeUnit)) + + return *validityPeriod +} + +func getMessageOptionsForValidityPeriod(validityPeriod messagesapi.ValidityPeriod) messagesapi.MessageOptions { + messageOptions := messagesapi.NewMessageOptions() + messageOptions.SetValidityPeriod(validityPeriod) + + return *messageOptions +} + +func getWebhookForCallbacks(messageDetails MessageDetails) *messagesapi.OttWebhooks { + deliveryReporting := messagesapi.NewMessageDeliveryReporting() + deliveryReporting.SetUrl(messageDetails.CallbackURL) + + webhooks := messagesapi.NewOttWebhooks() + webhooks.SetDelivery(*deliveryReporting) + webhooks.SetContentType("application/json") + webhooks.SetCallbackData(messageDetails.CallbackData) + + return webhooks +} + +func getRCSFailover(messageDetails MessageDetails) messagesapi.BaseFailover { + rcsFailover := messagesapi.NewFailover(messagesapi.OUTBOUNDMESSAGECHANNEL_RCS, messageDetails.From) + rcsFailover.SetValidityPeriod(getDefaultValidityPeriod(messageDetails)) + rcsFailover.SetContent(getMessageContent(messageDetails)) + + return messagesapi.BaseFailover{Failover: rcsFailover} +} + +func getSMSFailover(messageDetails MessageDetails) messagesapi.BaseFailover { + smsFailover := messagesapi.NewFailover(messagesapi.OUTBOUNDMESSAGECHANNEL_SMS, messageDetails.From) + smsFailover.SetValidityPeriod(getDefaultValidityPeriod(messageDetails)) + smsFailover.SetContent(getMessageContent(messageDetails)) + + return messagesapi.BaseFailover{Failover: smsFailover} +} + +func SetTemplateMessageValidityPeriod(message *messagesapi.TemplateMessage, messageDetails MessageDetails) { + validityPeriod := getDefaultValidityPeriod(messageDetails) + messageOptions := getMessageOptionsForValidityPeriod(validityPeriod) + message.SetOptions(messageOptions) +} + +func SetMessageValidityPeriod(message *messagesapi.Message, messageDetails MessageDetails) { + validityPeriod := getDefaultValidityPeriod(messageDetails) + messageOptions := getMessageOptionsForValidityPeriod(validityPeriod) + message.SetOptions(messageOptions) +} + +func SetTemplateMessageFailovers(message *messagesapi.TemplateMessage, messageDetails MessageDetails) { + var baseFailovers []messagesapi.BaseFailover + for _, failoverType := range messageDetails.Failovers { + switch failoverType { + case FailoverTypeRCS: + baseFailovers = append(baseFailovers, getRCSFailover(messageDetails)) + case FailoverTypeSMS: + baseFailovers = append(baseFailovers, getSMSFailover(messageDetails)) + } + } + message.SetFailover(baseFailovers) +} + +func SetMessageFailovers(message *messagesapi.Message, messageDetails MessageDetails) { + var baseFailovers []messagesapi.BaseFailover + for _, failoverType := range messageDetails.Failovers { + switch failoverType { + case FailoverTypeRCS: + baseFailovers = append(baseFailovers, getRCSFailover(messageDetails)) + case FailoverTypeSMS: + baseFailovers = append(baseFailovers, getSMSFailover(messageDetails)) + } + } + message.SetFailover(baseFailovers) +} + +func SetTemplateMessageWebhooksForCallbacks(message *messagesapi.TemplateMessage, messageDetails MessageDetails) { + webhooks := getWebhookForCallbacks(messageDetails) + message.SetWebhooks(*webhooks) +} + +func SetMessageWebhooksForCallbacks(message *messagesapi.Message, messageDetails MessageDetails) { + webhooks := getWebhookForCallbacks(messageDetails) + message.SetWebhooks(*webhooks) +} + +func CreateTemplateMessage(messageDetails MessageDetails, templateName string, fromAccountName string) *messagesapi.TemplateMessage { + destinations := getDestinations(messageDetails) + template := getTemplate(templateName) + + content := messagesapi.NewTemplateMessageContent() + textBody := messagesapi.NewTemplateTextBody() + textBody.AdditionalProperties = messageDetails.Variables + contentBody := messagesapi.TemplateTextBodyAsTemplateBody(textBody) + content.SetBody(contentBody) + + templateMessage := messagesapi.NewTemplateMessage(messagesapi.OUTBOUNDTEMPLATECHANNEL_WHATSAPP, fromAccountName, destinations, template) + templateMessage.SetContent(*content) + return templateMessage +} + +func CreateWhatsAppMessage(messageDetails MessageDetails, fromAccountName string) *messagesapi.Message { + destinations := getDestinations(messageDetails) + content := getMessageContent(messageDetails) + + return messagesapi.NewMessage(messagesapi.OUTBOUNDMESSAGECHANNEL_WHATSAPP, fromAccountName, destinations, content) +} + +func CreateRCSMessage(messageDetails MessageDetails, fromAccountName string) *messagesapi.Message { + destinations := getDestinations(messageDetails) + content := getMessageContent(messageDetails) + + return messagesapi.NewMessage(messagesapi.OUTBOUNDMESSAGECHANNEL_RCS, fromAccountName, destinations, content) +} + +func CreateSMSMessage(messageDetails MessageDetails, fromAccountName string) *messagesapi.Message { + destinations := getDestinations(messageDetails) + content := getMessageContent(messageDetails) + + return messagesapi.NewMessage(messagesapi.OUTBOUNDMESSAGECHANNEL_SMS, fromAccountName, destinations, content) +} + +// endregion