Skip to content

Commit

Permalink
Merge pull request #307 from PagerDuty/ctx_schedule
Browse files Browse the repository at this point in the history
Update schedule.go to accept a context.Context; fix fatal bug
  • Loading branch information
Scott McAllister committed Mar 17, 2021
2 parents 8c36343 + 79165c6 commit 176a8a3
Showing 1 changed file with 135 additions and 43 deletions.
178 changes: 135 additions & 43 deletions schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,29 +68,46 @@ type UserReference struct {
User APIObject `json:"user"`
}

// ListSchedules lists the on-call schedules.
// ListSchedules lists the on-call schedules. It's recommended to use
// ListSchedulesWithContext instead.
func (c *Client) ListSchedules(o ListSchedulesOptions) (*ListSchedulesResponse, error) {
return c.ListSchedulesWithContext(context.Background(), o)
}

// ListSchedulesWithContext lists the on-call schedules.
func (c *Client) ListSchedulesWithContext(ctx context.Context, o ListSchedulesOptions) (*ListSchedulesResponse, error) {
v, err := query.Values(o)
if err != nil {
return nil, err
}
resp, err := c.get(context.TODO(), "/schedules?"+v.Encode())

resp, err := c.get(ctx, "/schedules?"+v.Encode())
if err != nil {
return nil, err
}

var result ListSchedulesResponse
return &result, c.decodeJSON(resp, &result)
if err = c.decodeJSON(resp, &result); err != nil {
return nil, err
}

return &result, nil
}

// CreateSchedule creates a new on-call schedule.
// CreateSchedule creates a new on-call schedule. It's recommended to use
// CreateScheduleWithContext instead.
func (c *Client) CreateSchedule(s Schedule) (*Schedule, error) {
data := make(map[string]Schedule)
data["schedule"] = s
resp, err := c.post(context.TODO(), "/schedules", data, nil)
if err != nil {
return nil, err
return c.CreateScheduleWithContext(context.Background(), s)
}

// CreateScheduleWithContext creates a new on-call schedule.
func (c *Client) CreateScheduleWithContext(ctx context.Context, s Schedule) (*Schedule, error) {
d := map[string]Schedule{
"schedule": s,
}
return getScheduleFromResponse(c, resp)

resp, err := c.post(ctx, "/schedules", d, nil)
return getScheduleFromResponse(c, resp, err)
}

// PreviewScheduleOptions is the data structure used when calling the PreviewSchedule API endpoint.
Expand All @@ -101,21 +118,37 @@ type PreviewScheduleOptions struct {
Overflow bool `url:"overflow,omitempty"`
}

// PreviewSchedule previews what an on-call schedule would look like without saving it.
// PreviewSchedule previews what an on-call schedule would look like without
// saving it. It's recommended to use PreviewScheduleWithContext instead.
func (c *Client) PreviewSchedule(s Schedule, o PreviewScheduleOptions) error {
return c.PreviewScheduleWithContext(context.Background(), s, o)
}

// PreviewScheduleWithContext previews what an on-call schedule would look like
// without saving it.
func (c *Client) PreviewScheduleWithContext(ctx context.Context, s Schedule, o PreviewScheduleOptions) error {
v, err := query.Values(o)
if err != nil {
return err
}
var data map[string]Schedule
data["schedule"] = s
_, err = c.post(context.TODO(), "/schedules/preview?"+v.Encode(), data, nil)

d := map[string]Schedule{
"schedule": s,
}

_, err = c.post(ctx, "/schedules/preview?"+v.Encode(), d, nil)
return err
}

// DeleteSchedule deletes an on-call schedule.
// DeleteSchedule deletes an on-call schedule. It's recommended to use
// DeleteScheduleWithContext instead.
func (c *Client) DeleteSchedule(id string) error {
_, err := c.delete(context.TODO(), "/schedules/"+id)
return c.DeleteScheduleWithContext(context.Background(), id)
}

// DeleteScheduleWithContext deletes an on-call schedule.
func (c *Client) DeleteScheduleWithContext(ctx context.Context, id string) error {
_, err := c.delete(ctx, "/schedules/"+id)
return err
}

Expand All @@ -127,33 +160,44 @@ type GetScheduleOptions struct {
Until string `url:"until,omitempty"`
}

// GetSchedule shows detailed information about a schedule, including entries for each layer and sub-schedule.
// GetSchedule shows detailed information about a schedule, including entries
// for each layer and sub-schedule. It's recommended to use
// GetScheduleWithContext instead.
func (c *Client) GetSchedule(id string, o GetScheduleOptions) (*Schedule, error) {
return c.GetScheduleWithContext(context.Background(), id, o)
}

// GetScheduleWithContext shows detailed information about a schedule, including
// entries for each layer and sub-schedule.
func (c *Client) GetScheduleWithContext(ctx context.Context, 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(context.TODO(), "/schedules/"+id+"?"+v.Encode())
if err != nil {
return nil, err
}
return getScheduleFromResponse(c, resp)

resp, err := c.get(ctx, "/schedules/"+id+"?"+v.Encode())
return getScheduleFromResponse(c, resp, err)
}

// 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.
// UpdateSchedule updates an existing on-call schedule. It's recommended to use
// UpdateScheduleWithContext instead.
func (c *Client) UpdateSchedule(id string, s Schedule) (*Schedule, error) {
v := make(map[string]Schedule)
v["schedule"] = s
resp, err := c.put(context.TODO(), "/schedules/"+id, v, nil)
if err != nil {
return nil, err
return c.UpdateScheduleWithContext(context.Background(), id, s)
}

// UpdateScheduleWithContext updates an existing on-call schedule.
func (c *Client) UpdateScheduleWithContext(ctx context.Context, id string, s Schedule) (*Schedule, error) {
d := map[string]Schedule{
"schedule": s,
}
return getScheduleFromResponse(c, resp)

resp, err := c.put(ctx, "/schedules/"+id, d, nil)
return getScheduleFromResponse(c, resp, err)
}

// ListOverridesOptions is the data structure used when calling the ListOverrides API endpoint.
Expand All @@ -179,34 +223,62 @@ type Override struct {
User APIObject `json:"user,omitempty"`
}

// ListOverrides lists overrides for a given time range.
// ListOverrides lists overrides for a given time range. It's recommended to use
// ListOverridesWithContext instead.
func (c *Client) ListOverrides(id string, o ListOverridesOptions) (*ListOverridesResponse, error) {
return c.ListOverridesWithContext(context.Background(), id, o)
}

// ListOverridesWithContext lists overrides for a given time range.
func (c *Client) ListOverridesWithContext(ctx context.Context, id string, o ListOverridesOptions) (*ListOverridesResponse, error) {
v, err := query.Values(o)
if err != nil {
return nil, err
}
resp, err := c.get(context.TODO(), "/schedules/"+id+"/overrides?"+v.Encode())

resp, err := c.get(ctx, "/schedules/"+id+"/overrides?"+v.Encode())
if err != nil {
return nil, err
}

var result ListOverridesResponse
return &result, c.decodeJSON(resp, &result)
if err = c.decodeJSON(resp, &result); err != nil {
return nil, err
}

return &result, nil
}

// CreateOverride creates an override for a specific user covering the specified time range.
// CreateOverride creates an override for a specific user covering the specified
// time range. It's recommended to use CreateOverrideWithContext instead.
func (c *Client) CreateOverride(id string, o Override) (*Override, error) {
data := make(map[string]Override)
data["override"] = o
resp, err := c.post(context.TODO(), "/schedules/"+id+"/overrides", data, nil)
return c.CreateOverrideWithContext(context.Background(), id, o)
}

// CreateOverrideWithContext creates an override for a specific user covering
// the specified time range.
func (c *Client) CreateOverrideWithContext(ctx context.Context, id string, o Override) (*Override, error) {
d := map[string]Override{
"override": o,
}

resp, err := c.post(ctx, "/schedules/"+id+"/overrides", d, nil)
if err != nil {
return nil, err
}

return getOverrideFromResponse(c, resp)
}

// DeleteOverride removes an override.
// DeleteOverride removes an override. It's recommended to use
// DeleteOverrideWithContext instead.
func (c *Client) DeleteOverride(scheduleID, overrideID string) error {
_, err := c.delete(context.TODO(), "/schedules/"+scheduleID+"/overrides/"+overrideID)
return c.DeleteOverrideWithContext(context.Background(), scheduleID, overrideID)
}

// DeleteOverrideWithContext removes an override.
func (c *Client) DeleteOverrideWithContext(ctx context.Context, scheduleID, overrideID string) error {
_, err := c.delete(ctx, "/schedules/"+scheduleID+"/overrides/"+overrideID)
return err
}

Expand All @@ -217,37 +289,55 @@ type ListOnCallUsersOptions struct {
Until string `url:"until,omitempty"`
}

// ListOnCallUsers lists all of the users on call in a given schedule for a given time range.
// ListOnCallUsers lists all of the users on call in a given schedule for a
// given time range. It's recommended to use ListOnCallUsersWithContext instead.
func (c *Client) ListOnCallUsers(id string, o ListOnCallUsersOptions) ([]User, error) {
return c.ListOnCallUsersWithContext(context.Background(), id, o)
}

// ListOnCallUsersWithContext lists all of the users on call in a given schedule
// for a given time range.
func (c *Client) ListOnCallUsersWithContext(ctx context.Context, id string, o ListOnCallUsersOptions) ([]User, error) {
v, err := query.Values(o)
if err != nil {
return nil, err
}
resp, err := c.get(context.TODO(), "/schedules/"+id+"/users?"+v.Encode())

resp, err := c.get(ctx, "/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) {
func getScheduleFromResponse(c *Client, resp *http.Response, err error) (*Schedule, error) {
if err != nil {
return nil, err
}

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"

const rootNode = "schedule"

t, nodeOK := target[rootNode]
if !nodeOK {
return nil, fmt.Errorf("JSON response does not have %s field", rootNode)
}

return &t, nil
}

Expand All @@ -256,10 +346,12 @@ func getOverrideFromResponse(c *Client, resp *http.Response) (*Override, error)
if dErr := c.decodeJSON(resp, &target); dErr != nil {
return nil, fmt.Errorf("Could not decode JSON response: %v", dErr)
}
rootNode := "override"

const rootNode = "override"
o, nodeOK := target[rootNode]
if !nodeOK {
return nil, fmt.Errorf("JSON response does not have %s field", rootNode)
}

return &o, nil
}

0 comments on commit 176a8a3

Please sign in to comment.