263 lines
8.5 KiB
Go
263 lines
8.5 KiB
Go
|
package pagerduty
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"github.com/google/go-querystring/query"
|
||
|
"net/http"
|
||
|
)
|
||
|
|
||
|
// Restriction limits on-call responsibility for a layer to certain times of the day or week.
|
||
|
type Restriction struct {
|
||
|
Type string `json:"type,omitempty"`
|
||
|
StartTimeOfDay string `json:"start_time_of_day,omitempty"`
|
||
|
DurationSeconds uint `json:"duration_seconds,omitempty"`
|
||
|
}
|
||
|
|
||
|
// RenderedScheduleEntry represents the computed set of schedule layer entries that put users on call for a schedule, and cannot be modified directly.
|
||
|
type RenderedScheduleEntry struct {
|
||
|
Start string `json:"start,omitempty"`
|
||
|
End string `json:"end,omitempty"`
|
||
|
User APIObject `json:"user,omitempty"`
|
||
|
}
|
||
|
|
||
|
// ScheduleLayer is an entry that puts users on call for a schedule.
|
||
|
type ScheduleLayer struct {
|
||
|
APIObject
|
||
|
Name string `json:"name,omitempty"`
|
||
|
Start string `json:"start,omitempty"`
|
||
|
End string `json:"end,omitempty"`
|
||
|
RotationVirtualStart string `json:"rotation_virtual_start,omitempty"`
|
||
|
RotationTurnLengthSeconds uint `json:"rotation_turn_length_seconds,omitempty"`
|
||
|
Users []UserReference `json:"users,omitempty"`
|
||
|
Restrictions []Restriction `json:"restrictions,omitempty"`
|
||
|
RenderedScheduleEntries []RenderedScheduleEntry `json:"rendered_schedule_entries,omitempty"`
|
||
|
RenderedCoveragePercentage float64 `json:"rendered_coverage_percentage,omitempty"`
|
||
|
}
|
||
|
|
||
|
// Schedule determines the time periods that users are on call.
|
||
|
type Schedule struct {
|
||
|
APIObject
|
||
|
Name string `json:"name,omitempty"`
|
||
|
TimeZone string `json:"time_zone,omitempty"`
|
||
|
Description string `json:"description,omitempty"`
|
||
|
EscalationPolicies []APIObject `json:"escalation_policies,omitempty"`
|
||
|
Users []APIObject `json:"users,omitempty"`
|
||
|
ScheduleLayers []ScheduleLayer `json:"schedule_layers,omitempty"`
|
||
|
OverrideSubschedule ScheduleLayer `json:"override_subschedule,omitempty"`
|
||
|
FinalSchedule ScheduleLayer `json:"final_schedule,omitempty"`
|
||
|
}
|
||
|
|
||
|
// ListSchedulesOptions is the data structure used when calling the ListSchedules API endpoint.
|
||
|
type ListSchedulesOptions struct {
|
||
|
APIListObject
|
||
|
Query string `url:"query,omitempty"`
|
||
|
}
|
||
|
|
||
|
// ListSchedulesResponse is the data structure returned from calling the ListSchedules API endpoint.
|
||
|
type ListSchedulesResponse struct {
|
||
|
APIListObject
|
||
|
Schedules []Schedule
|
||
|
}
|
||
|
|
||
|
// UserReference is a reference to an authorized PagerDuty user.
|
||
|
type UserReference struct {
|
||
|
User APIObject `json:"user"`
|
||
|
}
|
||
|
|
||
|
// ListSchedules lists the on-call schedules.
|
||
|
func (c *Client) ListSchedules(o ListSchedulesOptions) (*ListSchedulesResponse, error) {
|
||
|
v, err := query.Values(o)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
resp, err := c.get("/schedules?" + v.Encode())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var result ListSchedulesResponse
|
||
|
return &result, c.decodeJSON(resp, &result)
|
||
|
}
|
||
|
|
||
|
// CreateSchedule creates a new on-call schedule.
|
||
|
func (c *Client) CreateSchedule(s Schedule) (*Schedule, error) {
|
||
|
data := make(map[string]Schedule)
|
||
|
data["schedule"] = s
|
||
|
resp, err := c.post("/schedules", data)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return getScheduleFromResponse(c, resp)
|
||
|
}
|
||
|
|
||
|
// PreviewScheduleOptions is the data structure used when calling the PreviewSchedule API endpoint.
|
||
|
type PreviewScheduleOptions struct {
|
||
|
APIListObject
|
||
|
Since string `url:"since,omitempty"`
|
||
|
Until string `url:"until,omitempty"`
|
||
|
Overflow bool `url:"overflow,omitempty"`
|
||
|
}
|
||
|
|
||
|
// PreviewSchedule previews what an on-call schedule would look like without saving it.
|
||
|
func (c *Client) PreviewSchedule(s Schedule, o PreviewScheduleOptions) error {
|
||
|
v, err := query.Values(o)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
var data map[string]Schedule
|
||
|
data["schedule"] = s
|
||
|
_, e := c.post("/schedules/preview?"+v.Encode(), data)
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
// DeleteSchedule deletes an on-call schedule.
|
||
|
func (c *Client) DeleteSchedule(id string) error {
|
||
|
_, err := c.delete("/schedules/" + id)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// GetScheduleOptions is the data structure used when calling the GetSchedule API endpoint.
|
||
|
type GetScheduleOptions struct {
|
||
|
APIListObject
|
||
|
TimeZone string `url:"time_zone,omitempty"`
|
||
|
Since string `url:"since,omitempty"`
|
||
|
Until string `url:"until,omitempty"`
|
||
|
}
|
||
|
|
||
|
// GetSchedule shows detailed information about a schedule, including entries for each layer and sub-schedule.
|
||
|
func (c *Client) GetSchedule(id string, o GetScheduleOptions) (*Schedule, error) {
|
||
|
v, err := query.Values(o)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("Could not parse values for query: %v", err)
|
||
|
}
|
||
|
resp, err := c.get("/schedules/" + id + "?" + v.Encode())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return getScheduleFromResponse(c, resp)
|
||
|
}
|
||
|
|
||
|
// UpdateScheduleOptions is the data structure used when calling the UpdateSchedule API endpoint.
|
||
|
type UpdateScheduleOptions struct {
|
||
|
Overflow bool `url:"overflow,omitempty"`
|
||
|
}
|
||
|
|
||
|
// UpdateSchedule updates an existing on-call schedule.
|
||
|
func (c *Client) UpdateSchedule(id string, s Schedule) (*Schedule, error) {
|
||
|
v := make(map[string]Schedule)
|
||
|
v["schedule"] = s
|
||
|
resp, err := c.put("/schedules/"+id, v, nil)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return getScheduleFromResponse(c, resp)
|
||
|
}
|
||
|
|
||
|
// ListOverridesOptions is the data structure used when calling the ListOverrides API endpoint.
|
||
|
type ListOverridesOptions struct {
|
||
|
APIListObject
|
||
|
Since string `url:"since,omitempty"`
|
||
|
Until string `url:"until,omitempty"`
|
||
|
Editable bool `url:"editable,omitempty"`
|
||
|
Overflow bool `url:"overflow,omitempty"`
|
||
|
}
|
||
|
|
||
|
// Overrides are any schedule layers from the override layer.
|
||
|
type Override struct {
|
||
|
ID string `json:"id,omitempty"`
|
||
|
Start string `json:"start,omitempty"`
|
||
|
End string `json:"end,omitempty"`
|
||
|
User APIObject `json:"user,omitempty"`
|
||
|
}
|
||
|
|
||
|
// ListOverrides lists overrides for a given time range.
|
||
|
func (c *Client) ListOverrides(id string, o ListOverridesOptions) ([]Override, error) {
|
||
|
v, err := query.Values(o)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
resp, err := c.get("/schedules/" + id + "/overrides?" + v.Encode())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var result map[string][]Override
|
||
|
if err := c.decodeJSON(resp, &result); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
overrides, ok := result["overrides"]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("JSON response does not have overrides field")
|
||
|
}
|
||
|
return overrides, nil
|
||
|
}
|
||
|
|
||
|
// CreateOverride creates an override for a specific user covering the specified time range.
|
||
|
func (c *Client) CreateOverride(id string, o Override) (*Override, error) {
|
||
|
data := make(map[string]Override)
|
||
|
data["override"] = o
|
||
|
resp, err := c.post("/schedules/"+id+"/overrides", data)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return getOverrideFromResponse(c, resp)
|
||
|
}
|
||
|
|
||
|
// DeleteOverride removes an override.
|
||
|
func (c *Client) DeleteOverride(scheduleID, overrideID string) error {
|
||
|
_, err := c.delete("/schedules/" + scheduleID + "/overrides/" + overrideID)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// ListOnCallUsersOptions is the data structure used when calling the ListOnCallUsers API endpoint.
|
||
|
type ListOnCallUsersOptions struct {
|
||
|
APIListObject
|
||
|
Since string `url:"since,omitempty"`
|
||
|
Until string `url:"until,omitempty"`
|
||
|
}
|
||
|
|
||
|
// ListOnCallUsers lists all of the users on call in a given schedule for a given time range.
|
||
|
func (c *Client) ListOnCallUsers(id string, o ListOnCallUsersOptions) ([]User, error) {
|
||
|
v, err := query.Values(o)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
resp, err := c.get("/schedules/" + id + "/users?" + v.Encode())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var result map[string][]User
|
||
|
if err := c.decodeJSON(resp, &result); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
u, ok := result["users"]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("JSON response does not have users field")
|
||
|
}
|
||
|
return u, nil
|
||
|
}
|
||
|
|
||
|
func getScheduleFromResponse(c *Client, resp *http.Response) (*Schedule, error) {
|
||
|
var target map[string]Schedule
|
||
|
if dErr := c.decodeJSON(resp, &target); dErr != nil {
|
||
|
return nil, fmt.Errorf("Could not decode JSON response: %v", dErr)
|
||
|
}
|
||
|
rootNode := "schedule"
|
||
|
t, nodeOK := target[rootNode]
|
||
|
if !nodeOK {
|
||
|
return nil, fmt.Errorf("JSON response does not have %s field", rootNode)
|
||
|
}
|
||
|
return &t, nil
|
||
|
}
|
||
|
|
||
|
func getOverrideFromResponse(c *Client, resp *http.Response) (*Override, error) {
|
||
|
var target map[string]Override
|
||
|
if dErr := c.decodeJSON(resp, &target); dErr != nil {
|
||
|
return nil, fmt.Errorf("Could not decode JSON response: %v", dErr)
|
||
|
}
|
||
|
rootNode := "override"
|
||
|
o, nodeOK := target[rootNode]
|
||
|
if !nodeOK {
|
||
|
return nil, fmt.Errorf("JSON response does not have %s field", rootNode)
|
||
|
}
|
||
|
return &o, nil
|
||
|
}
|