Skip to content

Commit 4ad6490

Browse files
committed
Fix owner
1 parent 83d1c91 commit 4ad6490

9 files changed

Lines changed: 720 additions & 22 deletions

File tree

api/go.mod

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/gofiber/swagger v0.0.1
1313
github.com/google/uuid v1.3.0
1414
github.com/joho/godotenv v1.4.0
15+
github.com/mark-ignacio/zerolog-gcp v0.4.0
1516
github.com/palantir/stacktrace v0.0.0-20161112013806-78658fd2d177
1617
github.com/rs/zerolog v1.26.1
1718
github.com/swaggo/swag v1.8.2
@@ -24,6 +25,9 @@ require (
2425
)
2526

2627
require (
28+
cloud.google.com/go v0.100.2 // indirect
29+
cloud.google.com/go/compute v0.1.0 // indirect
30+
cloud.google.com/go/logging v1.4.2 // indirect
2731
github.com/KyleBanks/depth v1.2.1 // indirect
2832
github.com/VividCortex/ewma v1.1.1 // indirect
2933
github.com/andybalholm/brotli v1.0.4 // indirect
@@ -33,6 +37,10 @@ require (
3337
github.com/go-openapi/spec v0.20.6 // indirect
3438
github.com/go-openapi/swag v0.21.1 // indirect
3539
github.com/go-sql-driver/mysql v1.6.0 // indirect
40+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
41+
github.com/golang/protobuf v1.5.2 // indirect
42+
github.com/google/go-cmp v0.5.7 // indirect
43+
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
3644
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
3745
github.com/jackc/pgconn v1.12.1 // indirect
3846
github.com/jackc/pgio v1.0.0 // indirect
@@ -57,15 +65,23 @@ require (
5765
github.com/valyala/bytebufferpool v1.0.0 // indirect
5866
github.com/valyala/fasthttp v1.37.0 // indirect
5967
github.com/valyala/tcplisten v1.0.0 // indirect
68+
go.opencensus.io v0.23.0 // indirect
6069
go.uber.org/atomic v1.6.0 // indirect
6170
go.uber.org/multierr v1.5.0 // indirect
6271
go.uber.org/zap v1.13.0 // indirect
6372
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167 // indirect
64-
golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect
73+
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
6574
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 // indirect
75+
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
76+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
6677
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
6778
golang.org/x/text v0.3.7 // indirect
6879
golang.org/x/tools v0.1.10 // indirect
80+
google.golang.org/api v0.65.0 // indirect
81+
google.golang.org/appengine v1.6.7 // indirect
82+
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998 // indirect
83+
google.golang.org/grpc v1.43.0 // indirect
84+
google.golang.org/protobuf v1.27.1 // indirect
6985
gopkg.in/yaml.v2 v2.4.0 // indirect
7086
gorm.io/driver/mysql v1.3.2 // indirect
7187
)

api/go.sum

Lines changed: 526 additions & 2 deletions
Large diffs are not rendered by default.

api/pkg/di/container.go

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package di
22

33
import (
4+
"context"
45
"fmt"
6+
"io"
57
"log"
68
"os"
79
"time"
@@ -21,6 +23,7 @@ import (
2123
"github.com/NdoleStudio/http-sms-manager/pkg/handlers"
2224
"github.com/NdoleStudio/http-sms-manager/pkg/telemetry"
2325
"github.com/NdoleStudio/http-sms-manager/pkg/validators"
26+
zlg "github.com/mark-ignacio/zerolog-gcp"
2427
"github.com/rs/zerolog"
2528
"gorm.io/driver/postgres"
2629
gormLogger "gorm.io/gorm/logger"
@@ -48,6 +51,10 @@ func NewContainer(projectID string) (container *Container) {
4851
container.RegisterMessageThreadRoutes()
4952
container.RegisterMessageThreadListeners()
5053

54+
container.RegisterHeartbeatRoutes()
55+
container.RegisterHeartbeatListeners()
56+
57+
// this has to be last since it registers the /* route
5158
container.RegisterSwaggerRoutes()
5259

5360
return container
@@ -139,6 +146,26 @@ func (container *Container) MessageHandlerValidator() (validator *validators.Mes
139146
)
140147
}
141148

149+
// HeartbeatHandler creates a new instance of handlers.HeartbeatHandler
150+
func (container *Container) HeartbeatHandler() (h *handlers.HeartbeatHandler) {
151+
container.logger.Debug(fmt.Sprintf("creating %T", h))
152+
return handlers.NewHeartbeatHandler(
153+
container.Logger(),
154+
container.Tracer(),
155+
container.HeartbeatHandlerValidator(),
156+
container.HeartbeatService(),
157+
)
158+
}
159+
160+
// HeartbeatHandlerValidator creates a new instance of validators.HeartbeatHandlerValidator
161+
func (container *Container) HeartbeatHandlerValidator() (validator *validators.HeartbeatHandlerValidator) {
162+
container.logger.Debug(fmt.Sprintf("creating %T", validator))
163+
return validators.NewHeartbeatHandlerValidator(
164+
container.Logger(),
165+
container.Tracer(),
166+
)
167+
}
168+
142169
// MessageThreadHandler creates a new instance of handlers.MessageThreadHandler
143170
func (container *Container) MessageThreadHandler() (h *handlers.MessageThreadHandler) {
144171
container.logger.Debug(fmt.Sprintf("creating %T", h))
@@ -216,6 +243,16 @@ func (container *Container) EventListenerLogRepository() (repository repositorie
216243
)
217244
}
218245

246+
// HeartbeatService creates a new instance of services.HeartbeatService
247+
func (container *Container) HeartbeatService() (service *services.HeartbeatService) {
248+
container.logger.Debug(fmt.Sprintf("creating %T", service))
249+
return services.NewHeartbeatService(
250+
container.Logger(),
251+
container.Tracer(),
252+
container.HeartbeatRepository(),
253+
)
254+
}
255+
219256
// MessageThreadService creates a new instance of services.MessageService
220257
func (container *Container) MessageThreadService() (service *services.MessageThreadService) {
221258
container.logger.Debug(fmt.Sprintf("creating %T", service))
@@ -267,6 +304,20 @@ func (container *Container) RegisterMessageThreadListeners() {
267304
}
268305
}
269306

307+
// RegisterHeartbeatListeners registers event listeners for listeners.HeartbeatListener
308+
func (container *Container) RegisterHeartbeatListeners() {
309+
container.logger.Debug(fmt.Sprintf("registering listners for %T", listeners.HeartbeatListener{}))
310+
_, routes := listeners.NewHeartbeatListener(
311+
container.Logger(),
312+
container.Tracer(),
313+
container.HeartbeatService(),
314+
)
315+
316+
for event, handler := range routes {
317+
container.EventDispatcher().Subscribe(event, handler)
318+
}
319+
}
320+
270321
// MessageService creates a new instance of services.MessageService
271322
func (container *Container) MessageService() (service *services.MessageService) {
272323
container.logger.Debug(fmt.Sprintf("creating %T", service))
@@ -290,23 +341,52 @@ func (container *Container) RegisterMessageThreadRoutes() {
290341
container.MessageThreadHandler().RegisterRoutes(container.App().Group("v1"))
291342
}
292343

344+
// RegisterHeartbeatRoutes registers routes for the /heartbeats prefix
345+
func (container *Container) RegisterHeartbeatRoutes() {
346+
container.logger.Debug(fmt.Sprintf("registering %T routes", &handlers.HeartbeatHandler{}))
347+
container.HeartbeatHandler().RegisterRoutes(container.App().Group("v1"))
348+
}
349+
293350
// RegisterSwaggerRoutes registers routes for swagger
294351
func (container *Container) RegisterSwaggerRoutes() {
295352
container.logger.Debug(fmt.Sprintf("registering %T routes", &handlers.MessageHandler{}))
296353
container.App().Get("/*", swagger.HandlerDefault)
297354
}
298355

356+
// HeartbeatRepository registers a new instance of repositories.HeartbeatRepository
357+
func (container *Container) HeartbeatRepository() repositories.HeartbeatRepository {
358+
container.logger.Debug("creating GORM repositories.HeartbeatRepository")
359+
return repositories.NewGormHeartbeatRepository(
360+
container.Logger(),
361+
container.Tracer(),
362+
container.DB(),
363+
)
364+
}
365+
299366
func logger() telemetry.Logger {
300367
hostname, _ := os.Hostname()
301368
fields := fiber.Map{
302369
"pid": os.Getpid(),
303370
"hostname": hostname,
304371
}
305-
return telemetry.NewZerologLogger(
306-
zerolog.New(
307-
zerolog.ConsoleWriter{
308-
Out: os.Stderr,
309-
},
310-
).With().Fields(fields).Timestamp().CallerWithSkipFrameCount(3),
311-
)
372+
373+
var writer io.Writer = zerolog.ConsoleWriter{Out: os.Stderr}
374+
if !isLocal() {
375+
gcpWriter, err := zlg.NewCloudLoggingWriter(
376+
context.Background(),
377+
os.Getenv("GCP_PROJECT_ID"),
378+
fmt.Sprintf("projects/%s/logs/run.googleapis.com%%2Fstderr", os.Getenv("GCP_PROJECT_ID")),
379+
zlg.CloudLoggingOptions{},
380+
)
381+
if err != nil {
382+
log.Fatal("could not create a CloudLoggingWriter")
383+
}
384+
writer = gcpWriter
385+
}
386+
387+
return telemetry.NewZerologLogger(zerolog.New(writer).With().Fields(fields).Timestamp().CallerWithSkipFrameCount(3))
388+
}
389+
390+
func isLocal() bool {
391+
return os.Getenv("ENV") == "local"
312392
}

api/pkg/handlers/message_handler.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package handlers
22

33
import (
44
"fmt"
5+
"time"
56

67
"github.com/NdoleStudio/http-sms-manager/pkg/repositories"
78
"github.com/google/uuid"
@@ -95,16 +96,18 @@ func (h *MessageHandler) PostSend(c *fiber.Ctx) error {
9596
// @Tags Messages
9697
// @Accept json
9798
// @Produce json
98-
// @Param limit query int false "Number of outstanding messages to return" minimum(1) maximum(10)
99-
// @Success 200 {object} responses.MessagesResponse
100-
// @Failure 400 {object} responses.BadRequest
101-
// @Failure 422 {object} responses.UnprocessableEntity
102-
// @Failure 500 {object} responses.InternalServerError
99+
// @Param owner query string true "The owner's phone number" default(+18005550199)
100+
// @Param limit query int false "Number of outstanding messages to fetch" minimum(1) maximum(10)
101+
// @Success 200 {object} responses.MessagesResponse
102+
// @Failure 400 {object} responses.BadRequest
103+
// @Failure 422 {object} responses.UnprocessableEntity
104+
// @Failure 500 {object} responses.InternalServerError
103105
// @Router /messages/outstanding [get]
104106
func (h *MessageHandler) GetOutstanding(c *fiber.Ctx) error {
105107
ctx, span := h.tracer.StartFromFiberCtx(c)
106108
defer span.End()
107109

110+
timestamp := time.Now().UTC()
108111
ctxLogger := h.tracer.CtxLogger(h.logger, span)
109112

110113
var request requests.MessageOutstanding
@@ -120,7 +123,7 @@ func (h *MessageHandler) GetOutstanding(c *fiber.Ctx) error {
120123
return h.responseUnprocessableEntity(c, errors, "validation errors while fetching outstanding messages")
121124
}
122125

123-
messages, err := h.service.GetOutstanding(ctx, request.ToGetOutstandingParams(c.OriginalURL()))
126+
messages, err := h.service.GetOutstanding(ctx, request.ToGetOutstandingParams(c.OriginalURL(), timestamp))
124127
if err != nil {
125128
msg := fmt.Sprintf("cannot get messgaes with URL [%s]", c.OriginalURL())
126129
ctxLogger.Error(stacktrace.Propagate(err, msg))
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package repositories
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/NdoleStudio/http-sms-manager/pkg/entities"
8+
"github.com/NdoleStudio/http-sms-manager/pkg/telemetry"
9+
"github.com/palantir/stacktrace"
10+
"gorm.io/gorm"
11+
)
12+
13+
// gormHeartbeatRepository is responsible for persisting entities.Heartbeat
14+
type gormHeartbeatRepository struct {
15+
logger telemetry.Logger
16+
tracer telemetry.Tracer
17+
db *gorm.DB
18+
}
19+
20+
// NewGormHeartbeatRepository creates the GORM version of the HeartbeatRepository
21+
func NewGormHeartbeatRepository(
22+
logger telemetry.Logger,
23+
tracer telemetry.Tracer,
24+
db *gorm.DB,
25+
) HeartbeatRepository {
26+
return &gormHeartbeatRepository{
27+
logger: logger.WithService(fmt.Sprintf("%T", &gormHeartbeatRepository{})),
28+
tracer: tracer,
29+
db: db,
30+
}
31+
}
32+
33+
// Index entities.Message between 2 parties
34+
func (repository *gormHeartbeatRepository) Index(ctx context.Context, owner string, params IndexParams) (*[]entities.Heartbeat, error) {
35+
ctx, span := repository.tracer.Start(ctx)
36+
defer span.End()
37+
38+
query := repository.db.Where("owner = ?", owner)
39+
if len(params.Query) > 0 {
40+
queryPattern := "%" + params.Query + "%"
41+
query.Where("quantity ILIKE ?", queryPattern)
42+
}
43+
44+
heartbeats := new([]entities.Heartbeat)
45+
if err := query.Order("timestamp DESC").Limit(params.Limit).Offset(params.Skip).Find(&heartbeats).Error; err != nil {
46+
msg := fmt.Sprintf("cannot fetch heartbeats with owner [%s] and params [%+#v]", owner, params)
47+
return nil, repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
48+
}
49+
50+
return heartbeats, nil
51+
}
52+
53+
// Store a new entities.Message
54+
func (repository *gormHeartbeatRepository) Store(ctx context.Context, heartbeat *entities.Heartbeat) error {
55+
ctx, span := repository.tracer.Start(ctx)
56+
defer span.End()
57+
58+
if err := repository.db.Create(heartbeat).Error; err != nil {
59+
msg := fmt.Sprintf("cannot save heartbeat with ID [%s]", heartbeat.ID)
60+
return repository.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
61+
}
62+
63+
return nil
64+
}

api/pkg/repositories/gorm_message_repository.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (repository *gormMessageRepository) Update(ctx context.Context, message *en
102102
}
103103

104104
// GetOutstanding fetches messages that still to be sent to the phone
105-
func (repository *gormMessageRepository) GetOutstanding(ctx context.Context, take int) (*[]entities.Message, error) {
105+
func (repository *gormMessageRepository) GetOutstanding(ctx context.Context, owner string, take int) (*[]entities.Message, error) {
106106
ctx, span := repository.tracer.Start(ctx)
107107
defer span.End()
108108

@@ -114,6 +114,7 @@ func (repository *gormMessageRepository) GetOutstanding(ctx context.Context, tak
114114
Where(
115115
"id IN (?)",
116116
tx.Model(&entities.Message{}).
117+
Where("owner = ?", owner).
117118
Where("status = ?", entities.MessageStatusPending).
118119
Order("request_received_at ASC").
119120
Select("id").

api/pkg/repositories/message_repository.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ type MessageRepository interface {
2222
Index(ctx context.Context, owner string, contact string, params IndexParams) (*[]entities.Message, error)
2323

2424
// GetOutstanding fetches list of outstanding []entities.Message
25-
GetOutstanding(ctx context.Context, limit int) (*[]entities.Message, error)
25+
GetOutstanding(ctx context.Context, owner string, limit int) (*[]entities.Message, error)
2626
}

api/pkg/requests/message_outstanding_request.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package requests
33
import (
44
"strconv"
55
"strings"
6+
"time"
67

78
"github.com/NdoleStudio/http-sms-manager/pkg/services"
89
)
910

1011
// MessageOutstanding is the payload fetching outstanding entities.Message
1112
type MessageOutstanding struct {
13+
request
14+
Owner string `json:"owner" query:"owner"`
1215
Limit string `json:"limit" query:"limit"`
1316
}
1417

@@ -18,6 +21,11 @@ func (input *MessageOutstanding) Sanitize() MessageOutstanding {
1821
input.Limit = "1"
1922
}
2023

24+
input.Owner = input.sanitizeAddress(input.Owner)
25+
if input.Owner == "" {
26+
input.Owner = "+37259139660"
27+
}
28+
2129
if input.Limit != "1" {
2230
input.Limit = "2"
2331
}
@@ -26,10 +34,12 @@ func (input *MessageOutstanding) Sanitize() MessageOutstanding {
2634
}
2735

2836
// ToGetOutstandingParams converts request to services.MessageGetOutstandingParams
29-
func (input *MessageOutstanding) ToGetOutstandingParams(source string) services.MessageGetOutstandingParams {
37+
func (input *MessageOutstanding) ToGetOutstandingParams(source string, timestamp time.Time) services.MessageGetOutstandingParams {
3038
return services.MessageGetOutstandingParams{
31-
Source: source,
32-
Limit: input.getLimit(),
39+
Source: source,
40+
Owner: input.Owner,
41+
Timestamp: timestamp,
42+
Limit: input.getLimit(),
3343
}
3444
}
3545

api/pkg/services/message_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (service *MessageService) GetOutstanding(ctx context.Context, params Messag
5454

5555
ctxLogger := service.tracer.CtxLogger(service.logger, span)
5656

57-
messages, err := service.repository.GetOutstanding(ctx, params.Limit)
57+
messages, err := service.repository.GetOutstanding(ctx, params.Owner, params.Limit)
5858
if err != nil {
5959
msg := fmt.Sprintf("could not fetch [%d] outstanding messages", params.Limit)
6060
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))

0 commit comments

Comments
 (0)