Skip to content

Commit 785ceca

Browse files
committed
Add Sendrid back
1 parent 6529586 commit 785ceca

6 files changed

Lines changed: 170 additions & 4 deletions

File tree

api/cmd/experiments/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ func main() {
2727
logger := container.Logger()
2828

2929
logger.Info("Starting experiments")
30-
loadTest()
30+
31+
sendgrid := container.MarketingService()
32+
err = sendgrid.ClearList(context.Background())
33+
if err != nil {
34+
logger.Fatal(err)
35+
}
3136
}
3237

3338
func text3CX() {

api/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ require (
3535
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5
3636
github.com/redis/go-redis/v9 v9.3.0
3737
github.com/rs/zerolog v1.31.0
38+
github.com/sendgrid/sendgrid-go v3.13.0+incompatible
3839
github.com/stretchr/testify v1.8.4
3940
github.com/swaggo/swag v1.16.2
4041
github.com/thedevsaddam/govalidator v1.9.10
@@ -117,6 +118,7 @@ require (
117118
github.com/richardlehane/msoleps v1.0.3 // indirect
118119
github.com/rivo/uniseg v0.4.4 // indirect
119120
github.com/russross/blackfriday/v2 v2.1.0 // indirect
121+
github.com/sendgrid/rest v2.6.9+incompatible // indirect
120122
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
121123
github.com/swaggo/files/v2 v2.0.0 // indirect
122124
github.com/valyala/bytebufferpool v1.0.0 // indirect

api/go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWR
302302
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
303303
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
304304
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
305+
github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0=
306+
github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
307+
github.com/sendgrid/sendgrid-go v3.13.0+incompatible h1:HZrzc06/QfBGesY9o3n1lvBrRONA+57rbDRKet7plos=
308+
github.com/sendgrid/sendgrid-go v3.13.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
305309
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
306310
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
307311
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=

api/pkg/di/container.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,18 @@ func (container *Container) PhoneService() (service *services.PhoneService) {
831831
)
832832
}
833833

834+
// MarketingService creates a new instance of services.MarketingService
835+
func (container *Container) MarketingService() (service *services.MarketingService) {
836+
container.logger.Debug(fmt.Sprintf("creating %T", service))
837+
return services.NewMarketingService(
838+
container.Logger(),
839+
container.Tracer(),
840+
container.FirebaseAuthClient(),
841+
os.Getenv("SENDGRID_API_KEY"),
842+
os.Getenv("SENDGRID_LIST_ID"),
843+
)
844+
}
845+
834846
// UserService creates a new instance of services.UserService
835847
func (container *Container) UserService() (service *services.UserService) {
836848
container.logger.Debug(fmt.Sprintf("creating %T", service))
@@ -840,6 +852,7 @@ func (container *Container) UserService() (service *services.UserService) {
840852
container.UserRepository(),
841853
container.Mailer(),
842854
container.UserEmailFactory(),
855+
container.MarketingService(),
843856
container.LemonsqueezyClient(),
844857
)
845858
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package services
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"log"
8+
"strings"
9+
10+
"github.com/sendgrid/sendgrid-go"
11+
12+
"firebase.google.com/go/auth"
13+
"github.com/NdoleStudio/httpsms/pkg/entities"
14+
"github.com/NdoleStudio/httpsms/pkg/telemetry"
15+
"github.com/davecgh/go-spew/spew"
16+
"github.com/palantir/stacktrace"
17+
)
18+
19+
// MarketingService is handles marketing requests
20+
type MarketingService struct {
21+
logger telemetry.Logger
22+
tracer telemetry.Tracer
23+
authClient *auth.Client
24+
sendgridAPIKey string
25+
sendgridListID string
26+
}
27+
28+
type sendgridContact struct {
29+
FirstName string `json:"first_name"`
30+
LastName string `json:"last_name"`
31+
Email string `json:"email"`
32+
}
33+
34+
type sendgridContactRequest struct {
35+
ListIDs []string `json:"list_ids"`
36+
Contacts []sendgridContact `json:"contacts"`
37+
}
38+
39+
// NewMarketingService creates a new instance of the MarketingService
40+
func NewMarketingService(
41+
logger telemetry.Logger,
42+
tracer telemetry.Tracer,
43+
authClient *auth.Client,
44+
sendgridAPIKey string,
45+
sendgridListID string,
46+
) *MarketingService {
47+
return &MarketingService{
48+
logger: logger.WithService(fmt.Sprintf("%T", &MarketingService{})),
49+
tracer: tracer,
50+
authClient: authClient,
51+
sendgridAPIKey: sendgridAPIKey,
52+
sendgridListID: sendgridListID,
53+
}
54+
}
55+
56+
// AddToList adds a new user on the onboarding automation.
57+
func (service *MarketingService) AddToList(ctx context.Context, user *entities.User) {
58+
ctx, span, ctxLogger := service.tracer.StartWithLogger(ctx, service.logger)
59+
defer span.End()
60+
61+
userRecord, err := service.authClient.GetUser(ctx, string(user.ID))
62+
if err != nil {
63+
msg := fmt.Sprintf("cannot get auth user with id [%s]", user.ID)
64+
ctxLogger.Error(stacktrace.Propagate(err, msg))
65+
return
66+
}
67+
68+
id, err := service.addContact(sendgridContactRequest{
69+
ListIDs: []string{service.sendgridListID},
70+
Contacts: []sendgridContact{service.toSendgridContact(userRecord)},
71+
})
72+
if err != nil {
73+
msg := fmt.Sprintf("cannot add user with id [%s] to list [%s]", user.ID, service.sendgridListID)
74+
ctxLogger.Error(stacktrace.Propagate(err, msg))
75+
return
76+
}
77+
78+
ctxLogger.Info(fmt.Sprintf("user [%s] added to list [%s] with job [%s]", user.ID, service.sendgridListID, id))
79+
}
80+
81+
// ClearList removes all new contacts from the sendgrid list.
82+
func (service *MarketingService) ClearList(ctx context.Context) error {
83+
ctx, span, ctxLogger := service.tracer.StartWithLogger(ctx, service.logger)
84+
defer span.End()
85+
86+
request := sendgrid.GetRequest(service.sendgridAPIKey, fmt.Sprintf("/v3/contactdb/lists/%s/recipients", service.sendgridListID), "https://api.sendgrid.com")
87+
request.Method = "GET"
88+
89+
response, err := sendgrid.API(request)
90+
if err != nil {
91+
return stacktrace.Propagate(err, fmt.Sprintf("cannot get all contacts in a sendgrid list [%s]", service.sendgridListID))
92+
}
93+
94+
ctxLogger.Info(spew.Sdump(response.Body))
95+
return nil
96+
}
97+
98+
func (service *MarketingService) toSendgridContact(user *auth.UserRecord) sendgridContact {
99+
name := strings.TrimSpace(user.DisplayName)
100+
if name == "" {
101+
return sendgridContact{
102+
FirstName: "",
103+
LastName: "",
104+
Email: user.Email,
105+
}
106+
}
107+
108+
parts := strings.Split(name, " ")
109+
if len(parts) == 1 {
110+
return sendgridContact{
111+
FirstName: name,
112+
LastName: "",
113+
Email: user.Email,
114+
}
115+
}
116+
117+
return sendgridContact{
118+
FirstName: strings.Join(parts[0:len(parts)-1], " "),
119+
LastName: parts[len(parts)-1],
120+
Email: user.Email,
121+
}
122+
}
123+
124+
func (service *MarketingService) addContact(contactRequest sendgridContactRequest) (string, error) {
125+
request := sendgrid.GetRequest(service.sendgridAPIKey, "/v3/marketing/contacts", "https://api.sendgrid.com")
126+
request.Method = "PUT"
127+
128+
body, err := json.Marshal(contactRequest)
129+
if err != nil {
130+
log.Fatal(stacktrace.Propagate(err, fmt.Sprintf("cannot marshal [%s]", spew.Sdump(contactRequest))))
131+
}
132+
133+
request.Body = body
134+
response, err := sendgrid.API(request)
135+
if err != nil {
136+
return "", stacktrace.Propagate(err, fmt.Sprintf("cannot add contact to sendgrid list [%s]", spew.Sdump(contactRequest)))
137+
}
138+
return response.Body, nil
139+
}

api/pkg/services/user_service.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type UserService struct {
2626
emailFactory emails.UserEmailFactory
2727
mailer emails.Mailer
2828
repository repositories.UserRepository
29+
marketingService *MarketingService
2930
lemonsqueezyClient *lemonsqueezy.Client
3031
}
3132

@@ -36,12 +37,14 @@ func NewUserService(
3637
repository repositories.UserRepository,
3738
mailer emails.Mailer,
3839
emailFactory emails.UserEmailFactory,
40+
marketingService *MarketingService,
3941
lemonsqueezyClient *lemonsqueezy.Client,
4042
) (s *UserService) {
4143
return &UserService{
4244
logger: logger.WithService(fmt.Sprintf("%T", s)),
4345
tracer: tracer,
4446
mailer: mailer,
47+
marketingService: marketingService,
4548
emailFactory: emailFactory,
4649
repository: repository,
4750
lemonsqueezyClient: lemonsqueezyClient,
@@ -50,7 +53,7 @@ func NewUserService(
5053

5154
// Get fetches or creates an entities.User
5255
func (service *UserService) Get(ctx context.Context, authUser entities.AuthUser) (*entities.User, error) {
53-
ctx, span, ctxLogger := service.tracer.StartWithLogger(ctx, service.logger)
56+
ctx, span := service.tracer.Start(ctx)
5457
defer span.End()
5558

5659
user, isNew, err := service.repository.LoadOrStore(ctx, authUser)
@@ -60,7 +63,7 @@ func (service *UserService) Get(ctx context.Context, authUser entities.AuthUser)
6063
}
6164

6265
if isNew {
63-
ctxLogger.Info(fmt.Sprintf("created a new user with ID [%s]", user.ID))
66+
service.marketingService.AddToList(ctx, user)
6467
}
6568

6669
return user, nil
@@ -100,7 +103,7 @@ func (service *UserService) Update(ctx context.Context, authUser entities.AuthUs
100103
}
101104

102105
if isNew {
103-
ctxLogger.Info(fmt.Sprintf("created a new user with ID [%s]", user.ID))
106+
service.marketingService.AddToList(ctx, user)
104107
}
105108

106109
user.Timezone = params.Timezone.String()

0 commit comments

Comments
 (0)