1package pagerduty 2 3import ( 4 "fmt" 5 "net/http" 6 7 "github.com/google/go-querystring/query" 8) 9 10// Restriction limits on-call responsibility for a layer to certain times of the day or week. 11type Restriction struct { 12 Type string `json:"type,omitempty"` 13 StartTimeOfDay string `json:"start_time_of_day,omitempty"` 14 StartDayOfWeek uint `json:"start_day_of_week,omitempty"` 15 DurationSeconds uint `json:"duration_seconds,omitempty"` 16} 17 18// RenderedScheduleEntry represents the computed set of schedule layer entries that put users on call for a schedule, and cannot be modified directly. 19type RenderedScheduleEntry struct { 20 Start string `json:"start,omitempty"` 21 End string `json:"end,omitempty"` 22 User APIObject `json:"user,omitempty"` 23} 24 25// ScheduleLayer is an entry that puts users on call for a schedule. 26type ScheduleLayer struct { 27 APIObject 28 Name string `json:"name,omitempty"` 29 Start string `json:"start,omitempty"` 30 End string `json:"end,omitempty"` 31 RotationVirtualStart string `json:"rotation_virtual_start,omitempty"` 32 RotationTurnLengthSeconds uint `json:"rotation_turn_length_seconds,omitempty"` 33 Users []UserReference `json:"users,omitempty"` 34 Restrictions []Restriction `json:"restrictions,omitempty"` 35 RenderedScheduleEntries []RenderedScheduleEntry `json:"rendered_schedule_entries,omitempty"` 36 RenderedCoveragePercentage float64 `json:"rendered_coverage_percentage,omitempty"` 37} 38 39// Schedule determines the time periods that users are on call. 40type Schedule struct { 41 APIObject 42 Name string `json:"name,omitempty"` 43 TimeZone string `json:"time_zone,omitempty"` 44 Description string `json:"description,omitempty"` 45 EscalationPolicies []APIObject `json:"escalation_policies,omitempty"` 46 Users []APIObject `json:"users,omitempty"` 47 ScheduleLayers []ScheduleLayer `json:"schedule_layers,omitempty"` 48 OverrideSubschedule ScheduleLayer `json:"override_subschedule,omitempty"` 49 FinalSchedule ScheduleLayer `json:"final_schedule,omitempty"` 50} 51 52// ListSchedulesOptions is the data structure used when calling the ListSchedules API endpoint. 53type ListSchedulesOptions struct { 54 APIListObject 55 Query string `url:"query,omitempty"` 56} 57 58// ListSchedulesResponse is the data structure returned from calling the ListSchedules API endpoint. 59type ListSchedulesResponse struct { 60 APIListObject 61 Schedules []Schedule `json:"schedules"` 62} 63 64// UserReference is a reference to an authorized PagerDuty user. 65type UserReference struct { 66 User APIObject `json:"user"` 67} 68 69// ListSchedules lists the on-call schedules. 70func (c *Client) ListSchedules(o ListSchedulesOptions) (*ListSchedulesResponse, error) { 71 v, err := query.Values(o) 72 if err != nil { 73 return nil, err 74 } 75 resp, err := c.get("/schedules?" + v.Encode()) 76 if err != nil { 77 return nil, err 78 } 79 var result ListSchedulesResponse 80 return &result, c.decodeJSON(resp, &result) 81} 82 83// CreateSchedule creates a new on-call schedule. 84func (c *Client) CreateSchedule(s Schedule) (*Schedule, error) { 85 data := make(map[string]Schedule) 86 data["schedule"] = s 87 resp, err := c.post("/schedules", data, nil) 88 if err != nil { 89 return nil, err 90 } 91 return getScheduleFromResponse(c, resp) 92} 93 94// PreviewScheduleOptions is the data structure used when calling the PreviewSchedule API endpoint. 95type PreviewScheduleOptions struct { 96 APIListObject 97 Since string `url:"since,omitempty"` 98 Until string `url:"until,omitempty"` 99 Overflow bool `url:"overflow,omitempty"` 100} 101 102// PreviewSchedule previews what an on-call schedule would look like without saving it. 103func (c *Client) PreviewSchedule(s Schedule, o PreviewScheduleOptions) error { 104 v, err := query.Values(o) 105 if err != nil { 106 return err 107 } 108 var data map[string]Schedule 109 data["schedule"] = s 110 _, e := c.post("/schedules/preview?"+v.Encode(), data, nil) 111 return e 112} 113 114// DeleteSchedule deletes an on-call schedule. 115func (c *Client) DeleteSchedule(id string) error { 116 _, err := c.delete("/schedules/" + id) 117 return err 118} 119 120// GetScheduleOptions is the data structure used when calling the GetSchedule API endpoint. 121type GetScheduleOptions struct { 122 APIListObject 123 TimeZone string `url:"time_zone,omitempty"` 124 Since string `url:"since,omitempty"` 125 Until string `url:"until,omitempty"` 126} 127 128// GetSchedule shows detailed information about a schedule, including entries for each layer and sub-schedule. 129func (c *Client) GetSchedule(id string, o GetScheduleOptions) (*Schedule, error) { 130 v, err := query.Values(o) 131 if err != nil { 132 return nil, fmt.Errorf("Could not parse values for query: %v", err) 133 } 134 resp, err := c.get("/schedules/" + id + "?" + v.Encode()) 135 if err != nil { 136 return nil, err 137 } 138 return getScheduleFromResponse(c, resp) 139} 140 141// UpdateScheduleOptions is the data structure used when calling the UpdateSchedule API endpoint. 142type UpdateScheduleOptions struct { 143 Overflow bool `url:"overflow,omitempty"` 144} 145 146// UpdateSchedule updates an existing on-call schedule. 147func (c *Client) UpdateSchedule(id string, s Schedule) (*Schedule, error) { 148 v := make(map[string]Schedule) 149 v["schedule"] = s 150 resp, err := c.put("/schedules/"+id, v, nil) 151 if err != nil { 152 return nil, err 153 } 154 return getScheduleFromResponse(c, resp) 155} 156 157// ListOverridesOptions is the data structure used when calling the ListOverrides API endpoint. 158type ListOverridesOptions struct { 159 APIListObject 160 Since string `url:"since,omitempty"` 161 Until string `url:"until,omitempty"` 162 Editable bool `url:"editable,omitempty"` 163 Overflow bool `url:"overflow,omitempty"` 164} 165 166// Overrides are any schedule layers from the override layer. 167type Override struct { 168 ID string `json:"id,omitempty"` 169 Start string `json:"start,omitempty"` 170 End string `json:"end,omitempty"` 171 User APIObject `json:"user,omitempty"` 172} 173 174// ListOverrides lists overrides for a given time range. 175func (c *Client) ListOverrides(id string, o ListOverridesOptions) ([]Override, error) { 176 v, err := query.Values(o) 177 if err != nil { 178 return nil, err 179 } 180 resp, err := c.get("/schedules/" + id + "/overrides?" + v.Encode()) 181 if err != nil { 182 return nil, err 183 } 184 var result map[string][]Override 185 if err := c.decodeJSON(resp, &result); err != nil { 186 return nil, err 187 } 188 overrides, ok := result["overrides"] 189 if !ok { 190 return nil, fmt.Errorf("JSON response does not have overrides field") 191 } 192 return overrides, nil 193} 194 195// CreateOverride creates an override for a specific user covering the specified time range. 196func (c *Client) CreateOverride(id string, o Override) (*Override, error) { 197 data := make(map[string]Override) 198 data["override"] = o 199 resp, err := c.post("/schedules/"+id+"/overrides", data, nil) 200 if err != nil { 201 return nil, err 202 } 203 return getOverrideFromResponse(c, resp) 204} 205 206// DeleteOverride removes an override. 207func (c *Client) DeleteOverride(scheduleID, overrideID string) error { 208 _, err := c.delete("/schedules/" + scheduleID + "/overrides/" + overrideID) 209 return err 210} 211 212// ListOnCallUsersOptions is the data structure used when calling the ListOnCallUsers API endpoint. 213type ListOnCallUsersOptions struct { 214 APIListObject 215 Since string `url:"since,omitempty"` 216 Until string `url:"until,omitempty"` 217} 218 219// ListOnCallUsers lists all of the users on call in a given schedule for a given time range. 220func (c *Client) ListOnCallUsers(id string, o ListOnCallUsersOptions) ([]User, error) { 221 v, err := query.Values(o) 222 if err != nil { 223 return nil, err 224 } 225 resp, err := c.get("/schedules/" + id + "/users?" + v.Encode()) 226 if err != nil { 227 return nil, err 228 } 229 var result map[string][]User 230 if err := c.decodeJSON(resp, &result); err != nil { 231 return nil, err 232 } 233 u, ok := result["users"] 234 if !ok { 235 return nil, fmt.Errorf("JSON response does not have users field") 236 } 237 return u, nil 238} 239 240func getScheduleFromResponse(c *Client, resp *http.Response) (*Schedule, error) { 241 var target map[string]Schedule 242 if dErr := c.decodeJSON(resp, &target); dErr != nil { 243 return nil, fmt.Errorf("Could not decode JSON response: %v", dErr) 244 } 245 rootNode := "schedule" 246 t, nodeOK := target[rootNode] 247 if !nodeOK { 248 return nil, fmt.Errorf("JSON response does not have %s field", rootNode) 249 } 250 return &t, nil 251} 252 253func getOverrideFromResponse(c *Client, resp *http.Response) (*Override, error) { 254 var target map[string]Override 255 if dErr := c.decodeJSON(resp, &target); dErr != nil { 256 return nil, fmt.Errorf("Could not decode JSON response: %v", dErr) 257 } 258 rootNode := "override" 259 o, nodeOK := target[rootNode] 260 if !nodeOK { 261 return nil, fmt.Errorf("JSON response does not have %s field", rootNode) 262 } 263 return &o, nil 264} 265