initial commit
This commit is contained in:
143
internal/pkg/azure/communication/azcommunication.go
Normal file
143
internal/pkg/azure/communication/azcommunication.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package communication
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"base/config"
|
||||
"base/pkg/email"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
logger zerolog.Logger
|
||||
endpoint string
|
||||
accessKey string
|
||||
apiVersion string
|
||||
senderAddress string
|
||||
templates *template.Template
|
||||
}
|
||||
|
||||
func New(logger zerolog.Logger, config *config.AppConfig) email.Email {
|
||||
return &client{
|
||||
logger: logger,
|
||||
endpoint: config.AzureCommunicationConfig.Endpoint,
|
||||
accessKey: config.AzureCommunicationConfig.AccessKey,
|
||||
apiVersion: config.AzureCommunicationConfig.ApiVersion,
|
||||
senderAddress: config.AzureCommunicationConfig.SenderAddress,
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) Send(ctx context.Context, params email.Request) (*email.Response, error) {
|
||||
var tpl bytes.Buffer
|
||||
if err := c.templates.ExecuteTemplate(&tpl, generateTemplateName(params.Template.EmailTemplateName), params.Template.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
html := tpl.String()
|
||||
|
||||
request := &ApiRequest{
|
||||
SenderAddress: c.senderAddress,
|
||||
Content: ApiContentDto{
|
||||
Subject: params.Subject,
|
||||
Html: html,
|
||||
},
|
||||
Recipients: ApiRecipientDto{
|
||||
To: []ApiRecipientDetailDto{
|
||||
{
|
||||
Address: params.RecipientAddress,
|
||||
DisplayName: params.UserFullName,
|
||||
},
|
||||
},
|
||||
CC: make([]ApiRecipientDetailDto, 0),
|
||||
BCC: make([]ApiRecipientDetailDto, 0),
|
||||
},
|
||||
}
|
||||
byteBody, err := json.Marshal(&request)
|
||||
if err != nil {
|
||||
return nil, errors.New("marshaling error")
|
||||
}
|
||||
|
||||
method := "POST"
|
||||
endpoint := c.endpoint
|
||||
u, _ := url.Parse(endpoint)
|
||||
snedPathAndQuery := fmt.Sprintf(
|
||||
"/emails:send?api-version=%s",
|
||||
c.apiVersion,
|
||||
)
|
||||
date := time.Now().In(time.FixedZone("GMT", 0)).Format("Mon, 02 Jan 2006 15:04:05 GMT")
|
||||
host := u.Host
|
||||
|
||||
contentHash := computeContentHash(byteBody)
|
||||
|
||||
stringToSign := fmt.Sprintf("%s\n%s\n%s;%s;%s", method, snedPathAndQuery, date, host, contentHash)
|
||||
signature, err := computeSignature(stringToSign, c.accessKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authHeader := fmt.Sprintf("HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=%s", signature)
|
||||
fullURL := endpoint + snedPathAndQuery
|
||||
req, _ := http.NewRequest(method, fullURL, bytes.NewReader(byteBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("x-ms-date", date)
|
||||
req.Header.Set("x-ms-content-sha256", contentHash)
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Host", host)
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusAccepted {
|
||||
response := &ApiErrorResponse{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.logger.Info().Msgf("email sending failed. %v", response)
|
||||
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
c.logger.Info().Msgf("email sending done. %v", resp.Body)
|
||||
response := &email.Response{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func computeContentHash(body []byte) string {
|
||||
sum := sha256.Sum256(body)
|
||||
return base64.StdEncoding.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func computeSignature(stringToSign, base64AccessKey string) (string, error) {
|
||||
key, err := base64.StdEncoding.DecodeString(base64AccessKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
mac := hmac.New(sha256.New, key)
|
||||
_, err = mac.Write([]byte(stringToSign))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sig := mac.Sum(nil)
|
||||
return base64.StdEncoding.EncodeToString(sig), nil
|
||||
}
|
||||
|
||||
func generateTemplateName(emailTemplateName email.Template) string {
|
||||
return fmt.Sprintf("%s.html", emailTemplateName.String())
|
||||
}
|
||||
Reference in New Issue
Block a user