-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschedules.go
More file actions
251 lines (225 loc) · 9.4 KB
/
schedules.go
File metadata and controls
251 lines (225 loc) · 9.4 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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package flashduty
import (
"context"
"fmt"
)
// ListSchedulesWithSlotsInput contains parameters for listing schedules with computed slots
type ListSchedulesWithSlotsInput struct {
Start int64 // Required: Unix seconds, start of time range for slot computation
End int64 // Required: Unix seconds, end of time range (max 45-day window)
TeamIDs []int64 // Optional: filter by teams
Query string // Optional: schedule name search keyword
IsMyTeam bool // Optional: only schedules in the current user's teams
IsMyManage bool // Optional: only schedules created by the current user inside their teams
Limit int // Max results (default 20)
Page int // Page number (default 1)
// Deprecated: use TeamIDs.
TeamID int64
}
// ScheduleMember represents a role and the people assigned under it.
type ScheduleMember struct {
RoleID int64 `json:"role_id"`
PersonIDs []int64 `json:"person_ids"`
}
// ScheduleGroup represents a rotating group inside a schedule layer.
type ScheduleGroup struct {
GroupName string `json:"group_name"`
Name string `json:"name"`
Members []ScheduleMember `json:"members"`
Start int64 `json:"start"`
End int64 `json:"end"`
}
// ScheduleLayer represents a configured layer in a schedule.
type ScheduleLayer struct {
AccountID int64 `json:"account_id"`
Name string `json:"name"`
ScheduleID int64 `json:"schedule_id"`
Hidden int `json:"hidden"`
Mode int `json:"mode"`
Weight int `json:"weight"`
Groups []ScheduleGroup `json:"groups"`
RotationDuration int64 `json:"rotation_duration"`
HandoffTime int64 `json:"handoff_time"`
EnableTime int64 `json:"enable_time"`
ExpireTime int64 `json:"expire_time"`
RestrictMode int `json:"restrict_mode"`
RestrictStart int64 `json:"restrict_start"`
RestrictEnd int64 `json:"restrict_end"`
RestrictPeriods []map[string]any `json:"restrict_periods,omitempty"`
DayMask map[string]any `json:"day_mask,omitempty"`
CreateAt int64 `json:"create_at"`
CreateBy int64 `json:"create_by"`
UpdateAt int64 `json:"update_at"`
UpdateBy int64 `json:"update_by"`
LayerName string `json:"layer_name,omitempty"`
FairRotation bool `json:"fair_rotation,omitempty"`
LayerStart int64 `json:"layer_start,omitempty"`
LayerEnd *int64 `json:"layer_end,omitempty"`
RotationUnit string `json:"rotation_unit,omitempty"`
RotationValue int64 `json:"rotation_value,omitempty"`
MaskContinuousEnabled bool `json:"mask_continuous_enabled,omitempty"`
}
// ScheduleCalculatedSchedule represents a computed slot inside a layer.
type ScheduleCalculatedSchedule struct {
Start int64 `json:"start"`
End int64 `json:"end"`
Group ScheduleGroup `json:"group"`
Index int `json:"index"`
}
// ScheduleCalculatedLayer represents computed schedule slots for a single layer.
type ScheduleCalculatedLayer struct {
LayerName string `json:"layer_name"`
Name string `json:"name"`
Mode int `json:"mode"`
Schedules []ScheduleCalculatedSchedule `json:"schedules"`
}
// ScheduleNotifyWebhook represents a configured schedule notification target.
type ScheduleNotifyWebhook struct {
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Token string `json:"token,omitempty"`
URL string `json:"url,omitempty"`
}
// ScheduleNotify represents schedule notification settings.
type ScheduleNotify struct {
AdvanceInTime int64 `json:"advance_in_time,omitempty"`
FixedTime map[string]any `json:"fixed_time,omitempty"`
By map[string]any `json:"by,omitempty"`
IM map[string]string `json:"im,omitempty"`
Webhooks []ScheduleNotifyWebhook `json:"webhooks,omitempty"`
}
// ScheduleOncallGroup represents the current or next on-call group snapshot.
type ScheduleOncallGroup struct {
Start int64 `json:"start"`
End int64 `json:"end"`
Group ScheduleGroup `json:"group"`
UpdateAt int64 `json:"update_at"`
Weight int `json:"weight"`
Index int `json:"index"`
}
// ScheduleDetail represents the schedule payload returned by /schedule/list and /schedule/info.
type ScheduleDetail struct {
ID *int64 `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
AccountID int64 `json:"account_id"`
GroupID *int64 `json:"group_id,omitempty"`
Disabled *int `json:"disabled,omitempty"`
CreateAt int64 `json:"create_at"`
CreateBy int64 `json:"create_by"`
UpdateAt int64 `json:"update_at"`
UpdateBy int64 `json:"update_by"`
Layers []ScheduleLayer `json:"layers,omitempty"`
Field string `json:"field,omitempty"`
ScheduleLayers []ScheduleCalculatedLayer `json:"schedule_layers,omitempty"`
FinalSchedule ScheduleCalculatedLayer `json:"final_schedule"`
Start int64 `json:"start,omitempty"`
End int64 `json:"end,omitempty"`
Notify ScheduleNotify `json:"notify,omitempty"`
ScheduleID int64 `json:"schedule_id"`
ScheduleName *string `json:"schedule_name,omitempty"`
TeamID *int64 `json:"team_id,omitempty"`
Description *string `json:"description,omitempty"`
LayerSchedules []ScheduleCalculatedLayer `json:"layer_schedules,omitempty"`
Status *int `json:"status,omitempty"`
CurOncall *ScheduleOncallGroup `json:"cur_oncall,omitempty"`
NextOncall *ScheduleOncallGroup `json:"next_oncall,omitempty"`
}
// ListSchedulesWithSlotsOutput contains schedules with computed on-call slots
type ListSchedulesWithSlotsOutput struct {
Schedules []ScheduleDetail `json:"schedules"`
Total int64 `json:"total"`
}
// ListSchedulesWithSlots queries schedules with computed on-call slots for a time range
func (c *Client) ListSchedulesWithSlots(ctx context.Context, input *ListSchedulesWithSlotsInput) (*ListSchedulesWithSlotsOutput, error) {
if input == nil {
return nil, fmt.Errorf("list schedules input is required")
}
if input.Start <= 0 || input.End <= 0 {
return nil, fmt.Errorf("start and end are required")
}
if input.IsMyTeam && input.IsMyManage {
return nil, fmt.Errorf("is_my_team and is_my_manage cannot both be true")
}
limit := input.Limit
if limit <= 0 {
limit = defaultQueryLimit
}
page := input.Page
if page <= 0 {
page = 1
}
requestBody := map[string]any{
"start": input.Start,
"end": input.End,
"limit": limit,
"p": page,
}
if input.Query != "" {
requestBody["query"] = input.Query
}
if input.IsMyTeam {
requestBody["is_my_team"] = true
}
if input.IsMyManage {
requestBody["is_my_manage"] = true
}
teamIDs := input.TeamIDs
if len(teamIDs) == 0 && input.TeamID > 0 {
teamIDs = []int64{input.TeamID}
}
if len(teamIDs) > 0 {
requestBody["team_ids"] = teamIDs
}
result, err := postData[struct {
Items []ScheduleDetail `json:"items"`
Total int64 `json:"total"`
}](c, ctx, "/schedule/list", requestBody, "failed to list schedules")
if err != nil {
return nil, err
}
schedules := []ScheduleDetail{}
total := int64(0)
if result != nil {
schedules = result.Items
total = result.Total
}
return &ListSchedulesWithSlotsOutput{
Schedules: schedules,
Total: total,
}, nil
}
// GetScheduleDetailInput contains parameters for getting schedule detail
type GetScheduleDetailInput struct {
ScheduleID int64 // Required
Start int64 // Required: Unix seconds, start of time range
End int64 // Required: Unix seconds, end of time range
}
// GetScheduleDetailOutput contains full schedule detail
type GetScheduleDetailOutput struct {
Schedule ScheduleDetail `json:"schedule"`
}
// GetScheduleDetail fetches detailed schedule information with computed slots
func (c *Client) GetScheduleDetail(ctx context.Context, input *GetScheduleDetailInput) (*GetScheduleDetailOutput, error) {
if input == nil {
return nil, fmt.Errorf("get schedule detail input is required")
}
if input.ScheduleID <= 0 {
return nil, fmt.Errorf("schedule_id is required")
}
if input.Start <= 0 || input.End <= 0 {
return nil, fmt.Errorf("start and end are required")
}
requestBody := map[string]any{
"schedule_id": input.ScheduleID,
"start": input.Start,
"end": input.End,
}
schedule, err := postOptionalData[ScheduleDetail](c, ctx, "/schedule/info", requestBody, "failed to get schedule detail")
if err != nil {
return nil, err
}
if schedule == nil {
return nil, fmt.Errorf("schedule not found: %d", input.ScheduleID)
}
return &GetScheduleDetailOutput{Schedule: *schedule}, nil
}