forked from NdoleStudio/httpsms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmessage_send_schedule.go
More file actions
90 lines (72 loc) · 2.82 KB
/
Copy pathmessage_send_schedule.go
File metadata and controls
90 lines (72 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package entities
import (
"time"
"github.com/google/uuid"
)
// EntityNameMessageSendSchedule is the entitlement entity name for message send schedules.
const EntityNameMessageSendSchedule = "MessageSendSchedule"
// MessageSendScheduleWindow represents a single availability window for a day of the week.
type MessageSendScheduleWindow struct {
DayOfWeek int `json:"day_of_week" example:"1"`
StartMinute int `json:"start_minute" example:"540"`
EndMinute int `json:"end_minute" example:"1020"`
}
// MessageSendSchedule controls when a phone is allowed to send outgoing SMS messages.
type MessageSendSchedule struct {
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
UserID UserID `json:"user_id" example:"WB7DRDWrJZRGbYrv2CKGkqbzvqdC"`
Name string `json:"name" example:"Business Hours"`
Timezone string `json:"timezone" example:"Europe/Tallinn"`
Windows []MessageSendScheduleWindow `json:"windows" gorm:"type:jsonb;serializer:json"`
CreatedAt time.Time `json:"created_at" example:"2022-06-05T14:26:02.302718+03:00"`
UpdatedAt time.Time `json:"updated_at" example:"2022-06-05T14:26:10.303278+03:00"`
}
// ResolveScheduledAt returns the next allowed send time based on the schedule.
// If the schedule is inactive, has no windows, or has an invalid timezone,
// the current time is returned in UTC. An active schedule with no windows
// is treated as inactive (messages are sent immediately).
func (schedule *MessageSendSchedule) ResolveScheduledAt(current time.Time) time.Time {
if schedule == nil || len(schedule.Windows) == 0 {
return current.UTC()
}
location, err := time.LoadLocation(schedule.Timezone)
if err != nil {
return current.UTC()
}
base := current.In(location)
var best time.Time
for dayOffset := 0; dayOffset <= 7; dayOffset++ {
day := base.AddDate(0, 0, dayOffset)
weekday := int(day.Weekday())
for _, window := range schedule.Windows {
if window.DayOfWeek != weekday {
continue
}
start := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, location).
Add(time.Duration(window.StartMinute) * time.Minute)
end := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, location).
Add(time.Duration(window.EndMinute) * time.Minute)
var candidate time.Time
switch {
case dayOffset == 0 && base.Before(start):
candidate = start
case dayOffset == 0 && (base.Equal(start) || (base.After(start) && base.Before(end))):
candidate = base
case dayOffset > 0:
candidate = start
default:
continue
}
if best.IsZero() || candidate.Before(best) {
best = candidate
}
}
if !best.IsZero() {
break
}
}
if best.IsZero() {
return current.UTC()
}
return best.UTC()
}