Skip to content

Commit 5a64c08

Browse files
committed
Fix code
1 parent 2b9a45f commit 5a64c08

17 files changed

Lines changed: 195 additions & 248 deletions

api/pkg/di/container.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ func (container *Container) PhoneHandlerValidator() (validator *validators.Phone
663663
return validators.NewPhoneHandlerValidator(
664664
container.Logger(),
665665
container.Tracer(),
666+
container.MessageSendScheduleService(),
666667
)
667668
}
668669

@@ -1117,7 +1118,6 @@ func (container *Container) PhoneHandler() (handler *handlers.PhoneHandler) {
11171118
container.Logger(),
11181119
container.Tracer(),
11191120
container.PhoneService(),
1120-
container.MessageSendScheduleService(),
11211121
container.PhoneHandlerValidator(),
11221122
)
11231123
}

api/pkg/entities/message_send_schedule.go

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ type MessageSendSchedule struct {
1919
UserID UserID `json:"user_id" example:"WB7DRDWrJZRGbYrv2CKGkqbzvqdC"`
2020
Name string `json:"name" example:"Business Hours"`
2121
Timezone string `json:"timezone" example:"Europe/Tallinn"`
22-
IsActive bool `json:"is_active" gorm:"default:true" example:"true"`
2322
Windows []MessageSendScheduleWindow `json:"windows" gorm:"type:jsonb;serializer:json"`
2423
CreatedAt time.Time `json:"created_at" example:"2022-06-05T14:26:02.302718+03:00"`
2524
UpdatedAt time.Time `json:"updated_at" example:"2022-06-05T14:26:10.303278+03:00"`
@@ -30,11 +29,7 @@ type MessageSendSchedule struct {
3029
// the current time is returned in UTC. An active schedule with no windows
3130
// is treated as inactive (messages are sent immediately).
3231
func (schedule *MessageSendSchedule) ResolveScheduledAt(current time.Time) time.Time {
33-
if schedule == nil || !schedule.IsActive {
34-
return current.UTC()
35-
}
36-
37-
if len(schedule.Windows) == 0 {
32+
if schedule == nil || len(schedule.Windows) == 0 {
3833
return current.UTC()
3934
}
4035

@@ -55,27 +50,11 @@ func (schedule *MessageSendSchedule) ResolveScheduledAt(current time.Time) time.
5550
continue
5651
}
5752

58-
start := time.Date(
59-
day.Year(),
60-
day.Month(),
61-
day.Day(),
62-
0,
63-
0,
64-
0,
65-
0,
66-
location,
67-
).Add(time.Duration(window.StartMinute) * time.Minute)
68-
69-
end := time.Date(
70-
day.Year(),
71-
day.Month(),
72-
day.Day(),
73-
0,
74-
0,
75-
0,
76-
0,
77-
location,
78-
).Add(time.Duration(window.EndMinute) * time.Minute)
53+
start := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, location).
54+
Add(time.Duration(window.StartMinute) * time.Minute)
55+
56+
end := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, location).
57+
Add(time.Duration(window.EndMinute) * time.Minute)
7958

8059
var candidate time.Time
8160

api/pkg/entities/message_send_schedule_test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ func TestResolveScheduledAt_NilSchedule_ReturnsCurrentUTC(t *testing.T) {
1616

1717
func TestResolveScheduledAt_InactiveSchedule_ReturnsCurrentUTC(t *testing.T) {
1818
now := time.Now()
19-
schedule := &MessageSendSchedule{IsActive: false}
19+
schedule := &MessageSendSchedule{}
2020
result := schedule.ResolveScheduledAt(now)
2121
assert.Equal(t, now.UTC(), result)
2222
}
2323

2424
func TestResolveScheduledAt_NoWindows_ReturnsCurrentUTC(t *testing.T) {
2525
now := time.Now()
2626
schedule := &MessageSendSchedule{
27-
IsActive: true,
2827
Timezone: "UTC",
2928
Windows: []MessageSendScheduleWindow{},
3029
}
@@ -36,7 +35,6 @@ func TestResolveScheduledAt_WithinWindow_ReturnsCurrentUTC(t *testing.T) {
3635
// Wednesday at 10:00 UTC, window is Wed 9:00-17:00 (540-1020 minutes)
3736
now := time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC) // Wednesday
3837
schedule := &MessageSendSchedule{
39-
IsActive: true,
4038
Timezone: "UTC",
4139
Windows: []MessageSendScheduleWindow{
4240
{DayOfWeek: int(now.Weekday()), StartMinute: 540, EndMinute: 1020},
@@ -50,7 +48,6 @@ func TestResolveScheduledAt_BeforeWindow_ReturnsWindowStart(t *testing.T) {
5048
// Wednesday at 7:00 UTC, window is Wed 9:00-17:00
5149
now := time.Date(2025, 1, 1, 7, 0, 0, 0, time.UTC) // Wednesday
5250
schedule := &MessageSendSchedule{
53-
IsActive: true,
5451
Timezone: "UTC",
5552
Windows: []MessageSendScheduleWindow{
5653
{DayOfWeek: int(now.Weekday()), StartMinute: 540, EndMinute: 1020},

api/pkg/entities/phone.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import (
88

99
// Phone represents an android phone which has installed the http sms app
1010
type Phone struct {
11-
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
12-
UserID UserID `json:"user_id" example:"WB7DRDWrJZRGbYrv2CKGkqbzvqdC"`
13-
FcmToken *string `json:"fcm_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzd....." validate:"optional"`
14-
PhoneNumber string `json:"phone_number" example:"+18005550199"`
15-
MessagesPerMinute uint `json:"messages_per_minute" example:"1"`
16-
SIM SIM `json:"sim" gorm:"default:SIM1"`
17-
ScheduleID *uuid.UUID `json:"schedule_id" gorm:"type:uuid" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
18-
Schedule *MessageSendSchedule `json:"-" gorm:"foreignKey:ScheduleID;constraint:OnDelete:SET NULL"`
11+
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
12+
UserID UserID `json:"user_id" example:"WB7DRDWrJZRGbYrv2CKGkqbzvqdC"`
13+
FcmToken *string `json:"fcm_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzd....." validate:"optional"`
14+
PhoneNumber string `json:"phone_number" example:"+18005550199"`
15+
MessagesPerMinute uint `json:"messages_per_minute" example:"1"`
16+
SIM SIM `json:"sim" gorm:"default:SIM1"`
17+
MessageSendScheduleID *uuid.UUID `json:"message_send_schedule_id" gorm:"type:uuid" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
18+
1919
// MaxSendAttempts determines how many times to retry sending an SMS message
2020
MaxSendAttempts uint `json:"max_send_attempts" example:"2"`
2121

api/pkg/handlers/message_send_schedule_handler.go

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (h *MessageSendScheduleHandler) RegisterRoutes(router fiber.Router, middlew
5454
// @Summary List send schedules
5555
// @Description List all send schedules owned by the authenticated user.
5656
// @Security ApiKeyAuth
57-
// @Tags Send Schedules
57+
// @Tags SendSchedules
5858
// @Produce json
5959
// @Success 200 {object} responses.MessageSendSchedulesResponse
6060
// @Failure 401 {object} responses.Unauthorized
@@ -64,9 +64,11 @@ func (h *MessageSendScheduleHandler) Index(c *fiber.Ctx) error {
6464
ctx, span, ctxLogger := h.tracer.StartFromFiberCtxWithLogger(c, h.logger)
6565
defer span.End()
6666

67-
schedules, err := h.service.Index(ctx, h.userIDFomContext(c))
67+
userID := h.userIDFomContext(c)
68+
69+
schedules, err := h.service.Index(ctx, userID)
6870
if err != nil {
69-
ctxLogger.Error(stacktrace.Propagate(err, "cannot list send schedules"))
71+
ctxLogger.Error(stacktrace.Propagate(err, fmt.Sprintf("cannot list send schedules for user [%s]", userID)))
7072
return h.responseInternalServerError(c)
7173
}
7274

@@ -78,7 +80,7 @@ func (h *MessageSendScheduleHandler) Index(c *fiber.Ctx) error {
7880
// @Summary Create send schedule
7981
// @Description Create a new send schedule for the authenticated user.
8082
// @Security ApiKeyAuth
81-
// @Tags Send Schedules
83+
// @Tags SendSchedules
8284
// @Accept json
8385
// @Produce json
8486
// @Param payload body requests.MessageSendScheduleStore true "Payload of new send schedule."
@@ -95,23 +97,19 @@ func (h *MessageSendScheduleHandler) Store(c *fiber.Ctx) error {
9597

9698
userID := h.userIDFomContext(c)
9799

98-
count, err := h.service.CountByUser(ctx, userID)
100+
result, err := h.entitlementService.Check(ctx, userID, "MessageSendSchedule", func() (int, error) {
101+
return h.service.CountByUser(ctx, userID)
102+
})
99103
if err != nil {
100-
ctxLogger.Error(stacktrace.Propagate(err, "cannot count send schedules for entitlement check"))
101-
return h.responseInternalServerError(c)
102-
}
103-
104-
result, err := h.entitlementService.Check(ctx, userID, "MessageSendSchedule", count)
105-
if err != nil {
106-
ctxLogger.Error(stacktrace.Propagate(err, "cannot check entitlement for send schedules"))
104+
ctxLogger.Error(stacktrace.Propagate(err, fmt.Sprintf("cannot check entitlement for send schedules for user [%s]", userID)))
107105
return h.responseInternalServerError(c)
108106
}
109107
if !result.Allowed {
110108
return h.responsePaymentRequired(c, result.Message)
111109
}
112110

113111
var request requests.MessageSendScheduleStore
114-
if err := c.BodyParser(&request); err != nil {
112+
if err = c.BodyParser(&request); err != nil {
115113
return h.responseBadRequest(c, err)
116114
}
117115

@@ -127,7 +125,7 @@ func (h *MessageSendScheduleHandler) Store(c *fiber.Ctx) error {
127125

128126
schedule, err := h.service.Store(ctx, request.ToParams(h.userFromContext(c)))
129127
if err != nil {
130-
ctxLogger.Error(stacktrace.Propagate(err, "cannot create send schedule"))
128+
ctxLogger.Error(stacktrace.Propagate(err, fmt.Sprintf("cannot create send schedule for user [%s]", userID)))
131129
return h.responseInternalServerError(c)
132130
}
133131

@@ -139,7 +137,7 @@ func (h *MessageSendScheduleHandler) Store(c *fiber.Ctx) error {
139137
// @Summary Update send schedule
140138
// @Description Update a send schedule owned by the authenticated user.
141139
// @Security ApiKeyAuth
142-
// @Tags Send Schedules
140+
// @Tags SendSchedules
143141
// @Accept json
144142
// @Produce json
145143
// @Param scheduleID path string true "Schedule ID"
@@ -170,14 +168,11 @@ func (h *MessageSendScheduleHandler) Update(c *fiber.Ctx) error {
170168
return h.responseUnprocessableEntity(c, errors, "validation errors while updating send schedule")
171169
}
172170

173-
schedule, err := h.service.Update(
174-
ctx,
175-
h.userIDFomContext(c),
176-
scheduleID,
177-
request.ToParams(h.userFromContext(c)),
178-
)
171+
userID := h.userIDFomContext(c)
172+
173+
schedule, err := h.service.Update(ctx, userID, scheduleID, request.ToParams(h.userFromContext(c)))
179174
if err != nil {
180-
ctxLogger.Error(stacktrace.Propagate(err, "cannot update send schedule"))
175+
ctxLogger.Error(stacktrace.Propagate(err, fmt.Sprintf("cannot update send schedule for user [%s] and schedule [%s]", userID, scheduleID)))
181176
if stacktrace.GetCode(err) == repositories.ErrCodeNotFound {
182177
return h.responseNotFound(c, err.Error())
183178
}
@@ -192,7 +187,7 @@ func (h *MessageSendScheduleHandler) Update(c *fiber.Ctx) error {
192187
// @Summary Delete send schedule
193188
// @Description Delete a send schedule owned by the authenticated user.
194189
// @Security ApiKeyAuth
195-
// @Tags Send Schedules
190+
// @Tags SendSchedules
196191
// @Produce json
197192
// @Param scheduleID path string true "Schedule ID"
198193
// @Success 204
@@ -210,19 +205,18 @@ func (h *MessageSendScheduleHandler) Delete(c *fiber.Ctx) error {
210205
return h.responseBadRequest(c, err)
211206
}
212207

213-
if _, err = h.service.Load(ctx, h.userIDFomContext(c), scheduleID); err != nil {
214-
ctxLogger.Error(stacktrace.Propagate(err, "cannot load send schedule for deletion"))
208+
userID := h.userIDFomContext(c)
209+
210+
if _, err = h.service.Load(ctx, userID, scheduleID); err != nil {
211+
ctxLogger.Error(stacktrace.Propagate(err, fmt.Sprintf("cannot load send schedule for deletion for user [%s] and schedule [%s]", userID, scheduleID)))
215212
if stacktrace.GetCode(err) == repositories.ErrCodeNotFound {
216213
return h.responseNotFound(c, err.Error())
217214
}
218215
return h.responseInternalServerError(c)
219216
}
220217

221-
if err = h.service.Delete(ctx, h.userIDFomContext(c), scheduleID); err != nil {
222-
ctxLogger.Error(stacktrace.Propagate(err, "cannot delete send schedule"))
223-
if stacktrace.GetCode(err) == repositories.ErrCodeNotFound {
224-
return h.responseNotFound(c, err.Error())
225-
}
218+
if err = h.service.Delete(ctx, userID, scheduleID); err != nil {
219+
ctxLogger.Error(stacktrace.Propagate(err, fmt.Sprintf("cannot delete send schedule for user [%s] and schedule [%s]", userID, scheduleID)))
226220
return h.responseInternalServerError(c)
227221
}
228222

api/pkg/handlers/phone_handler.go

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ package handlers
22

33
import (
44
"fmt"
5-
"net/url"
6-
"strings"
75

86
"github.com/NdoleStudio/httpsms/pkg/requests"
97
"github.com/NdoleStudio/httpsms/pkg/validators"
108
"github.com/davecgh/go-spew/spew"
11-
"github.com/google/uuid"
129

1310
"github.com/NdoleStudio/httpsms/pkg/services"
1411
"github.com/NdoleStudio/httpsms/pkg/telemetry"
@@ -19,27 +16,24 @@ import (
1916
// PhoneHandler handles phone http requests.
2017
type PhoneHandler struct {
2118
handler
22-
logger telemetry.Logger
23-
tracer telemetry.Tracer
24-
service *services.PhoneService
25-
scheduleService *services.MessageSendScheduleService
26-
validator *validators.PhoneHandlerValidator
19+
logger telemetry.Logger
20+
tracer telemetry.Tracer
21+
service *services.PhoneService
22+
validator *validators.PhoneHandlerValidator
2723
}
2824

2925
// NewPhoneHandler creates a new PhoneHandler
3026
func NewPhoneHandler(
3127
logger telemetry.Logger,
3228
tracer telemetry.Tracer,
3329
service *services.PhoneService,
34-
scheduleService *services.MessageSendScheduleService,
3530
validator *validators.PhoneHandlerValidator,
3631
) (h *PhoneHandler) {
3732
return &PhoneHandler{
38-
logger: logger.WithService(fmt.Sprintf("%T", h)),
39-
tracer: tracer,
40-
validator: validator,
41-
service: service,
42-
scheduleService: scheduleService,
33+
logger: logger.WithService(fmt.Sprintf("%T", h)),
34+
tracer: tracer,
35+
validator: validator,
36+
service: service,
4337
}
4438
}
4539

@@ -127,22 +121,13 @@ func (h *PhoneHandler) Upsert(c *fiber.Ctx) error {
127121
return h.responseBadRequest(c, err)
128122
}
129123

130-
if errors := h.validator.ValidateUpsert(ctx, request.Sanitize()); len(errors) != 0 {
124+
if errors := h.validator.ValidateUpsert(ctx, h.userIDFomContext(c), request.Sanitize()); len(errors) != 0 {
131125
msg := fmt.Sprintf("validation errors [%s], while updating phones [%+#v]", spew.Sdump(errors), request)
132126
ctxLogger.Warn(stacktrace.NewError(msg))
133127
return h.responseUnprocessableEntity(c, errors, "validation errors while updating phones")
134128
}
135129

136-
if request.ScheduleID != nil && strings.TrimSpace(*request.ScheduleID) != "" {
137-
scheduleID, _ := uuid.Parse(strings.TrimSpace(*request.ScheduleID))
138-
if _, err := h.scheduleService.Load(ctx, h.userFromContext(c).ID, scheduleID); err != nil {
139-
validationErrors := url.Values{}
140-
validationErrors.Add("schedule_id", "schedule_id does not belong to the authenticated user or does not exist")
141-
return h.responseUnprocessableEntity(c, validationErrors, "validation errors while updating phones")
142-
}
143-
}
144-
145-
phone, err := h.service.Upsert(ctx, request.ToUpsertParams(h.userFromContext(c), c.OriginalURL()))
130+
phone, err := h.service.Upsert(ctx, request.ToUpsertParams(h.userFromContext(c), c.OriginalURL(), c.Body()))
146131
if err != nil {
147132
msg := fmt.Sprintf("cannot update phones with params [%+#v]", request)
148133
ctxLogger.Error(stacktrace.Propagate(err, msg))

api/pkg/listeners/message_send_schedule_listener.go

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,12 @@ func (listener *MessageSendScheduleListener) onUserAccountDeleted(
4545

4646
var payload events.UserAccountDeletedPayload
4747
if err := event.DataAs(&payload); err != nil {
48-
return listener.tracer.WrapErrorSpan(
49-
span,
50-
stacktrace.Propagate(
51-
err,
52-
"cannot decode [%s] into [%T]",
53-
event.Data(),
54-
payload,
55-
),
56-
)
48+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)))
5749
}
5850

5951
if err := listener.service.DeleteAllForUser(ctx, payload.UserID); err != nil {
60-
return listener.tracer.WrapErrorSpan(
61-
span,
62-
stacktrace.Propagate(
63-
err,
64-
"cannot delete [entities.MessageSendSchedule] for user [%s] on [%s] event with ID [%s]",
65-
payload.UserID,
66-
event.Type(),
67-
event.ID(),
68-
),
69-
)
52+
msg := fmt.Sprintf("cannot delete [entities.MessageSendSchedule] for user [%s] on [%s] event with ID [%s]", payload.UserID, event.Type(), event.ID())
53+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
7054
}
7155

7256
return nil

0 commit comments

Comments
 (0)