1package pagerduty
2
3import (
4	"fmt"
5	"net/http"
6
7	"github.com/google/go-querystring/query"
8)
9
10// Integration is an endpoint (like Nagios, email, or an API call) that generates events, which are normalized and de-duplicated by PagerDuty to create incidents.
11type Integration struct {
12	APIObject
13	Name             string     `json:"name,omitempty"`
14	Service          *APIObject `json:"service,omitempty"`
15	CreatedAt        string     `json:"created_at,omitempty"`
16	Vendor           *APIObject `json:"vendor,omitempty"`
17	Type             string     `json:"type,omitempty"`
18	IntegrationKey   string     `json:"integration_key,omitempty"`
19	IntegrationEmail string     `json:"integration_email,omitempty"`
20}
21
22// InlineModel represents when a scheduled action will occur.
23type InlineModel struct {
24	Type string `json:"type,omitempty"`
25	Name string `json:"name,omitempty"`
26}
27
28// ScheduledAction contains scheduled actions for the service.
29type ScheduledAction struct {
30	Type      string      `json:"type,omitempty"`
31	At        InlineModel `json:"at,omitempty"`
32	ToUrgency string      `json:"to_urgency"`
33}
34
35// IncidentUrgencyType are the incidents urgency during or outside support hours.
36type IncidentUrgencyType struct {
37	Type    string `json:"type,omitempty"`
38	Urgency string `json:"urgency,omitempty"`
39}
40
41// SupportHours are the support hours for the service.
42type SupportHours struct {
43	Type       string `json:"type,omitempty"`
44	Timezone   string `json:"time_zone,omitempty"`
45	StartTime  string `json:"start_time,omitempty"`
46	EndTime    string `json:"end_time,omitempty"`
47	DaysOfWeek []uint `json:"days_of_week,omitempty"`
48}
49
50// IncidentUrgencyRule is the default urgency for new incidents.
51type IncidentUrgencyRule struct {
52	Type                string               `json:"type,omitempty"`
53	Urgency             string               `json:"urgency,omitempty"`
54	DuringSupportHours  *IncidentUrgencyType `json:"during_support_hours,omitempty"`
55	OutsideSupportHours *IncidentUrgencyType `json:"outside_support_hours,omitempty"`
56}
57
58// Service represents something you monitor (like a web service, email service, or database service).
59type Service struct {
60	APIObject
61	Name                   string               `json:"name,omitempty"`
62	Description            string               `json:"description,omitempty"`
63	AutoResolveTimeout     *uint                `json:"auto_resolve_timeout"`
64	AcknowledgementTimeout *uint                `json:"acknowledgement_timeout"`
65	CreateAt               string               `json:"created_at,omitempty"`
66	Status                 string               `json:"status,omitempty"`
67	LastIncidentTimestamp  string               `json:"last_incident_timestamp,omitempty"`
68	Integrations           []Integration        `json:"integrations,omitempty"`
69	EscalationPolicy       EscalationPolicy     `json:"escalation_policy,omitempty"`
70	Teams                  []Team               `json:"teams,omitempty"`
71	IncidentUrgencyRule    *IncidentUrgencyRule `json:"incident_urgency_rule,omitempty"`
72	SupportHours           *SupportHours        `json:"support_hours,omitempty"`
73	ScheduledActions       []ScheduledAction    `json:"scheduled_actions,omitempty"`
74	AlertCreation          string               `json:"alert_creation,omitempty"`
75}
76
77// ListServiceOptions is the data structure used when calling the ListServices API endpoint.
78type ListServiceOptions struct {
79	APIListObject
80	TeamIDs  []string `url:"team_ids,omitempty,brackets"`
81	TimeZone string   `url:"time_zone,omitempty"`
82	SortBy   string   `url:"sort_by,omitempty"`
83	Query    string   `url:"query,omitempty"`
84	Includes []string `url:"include,omitempty,brackets"`
85}
86
87// ListServiceResponse is the data structure returned from calling the ListServices API endpoint.
88type ListServiceResponse struct {
89	APIListObject
90	Services []Service
91}
92
93// ListServices lists existing services.
94func (c *Client) ListServices(o ListServiceOptions) (*ListServiceResponse, error) {
95	v, err := query.Values(o)
96	if err != nil {
97		return nil, err
98	}
99	resp, err := c.get("/services?" + v.Encode())
100	if err != nil {
101		return nil, err
102	}
103	var result ListServiceResponse
104	return &result, c.decodeJSON(resp, &result)
105}
106
107// GetServiceOptions is the data structure used when calling the GetService API endpoint.
108type GetServiceOptions struct {
109	Includes []string `url:"include,brackets,omitempty"`
110}
111
112// GetService gets details about an existing service.
113func (c *Client) GetService(id string, o *GetServiceOptions) (*Service, error) {
114	v, err := query.Values(o)
115	resp, err := c.get("/services/" + id + "?" + v.Encode())
116	return getServiceFromResponse(c, resp, err)
117}
118
119// CreateService creates a new service.
120func (c *Client) CreateService(s Service) (*Service, error) {
121	data := make(map[string]Service)
122	data["service"] = s
123	resp, err := c.post("/services", data, nil)
124	return getServiceFromResponse(c, resp, err)
125}
126
127// UpdateService updates an existing service.
128func (c *Client) UpdateService(s Service) (*Service, error) {
129	resp, err := c.put("/services/"+s.ID, s, nil)
130	return getServiceFromResponse(c, resp, err)
131}
132
133// DeleteService deletes an existing service.
134func (c *Client) DeleteService(id string) error {
135	_, err := c.delete("/services/" + id)
136	return err
137}
138
139// CreateIntegration creates a new integration belonging to a service.
140func (c *Client) CreateIntegration(id string, i Integration) (*Integration, error) {
141	data := make(map[string]Integration)
142	data["integration"] = i
143	resp, err := c.post("/services/"+id+"/integrations", data, nil)
144	return getIntegrationFromResponse(c, resp, err)
145}
146
147// GetIntegrationOptions is the data structure used when calling the GetIntegration API endpoint.
148type GetIntegrationOptions struct {
149	Includes []string `url:"include,omitempty,brackets"`
150}
151
152// GetIntegration gets details about an integration belonging to a service.
153func (c *Client) GetIntegration(serviceID, integrationID string, o GetIntegrationOptions) (*Integration, error) {
154	v, queryErr := query.Values(o)
155	if queryErr != nil {
156		return nil, queryErr
157	}
158	resp, err := c.get("/services/" + serviceID + "/integrations/" + integrationID + "?" + v.Encode())
159	return getIntegrationFromResponse(c, resp, err)
160}
161
162// UpdateIntegration updates an integration belonging to a service.
163func (c *Client) UpdateIntegration(serviceID string, i Integration) (*Integration, error) {
164	resp, err := c.put("/services/"+serviceID+"/integrations/"+i.ID, i, nil)
165	return getIntegrationFromResponse(c, resp, err)
166}
167
168// DeleteIntegration deletes an existing integration.
169func (c *Client) DeleteIntegration(serviceID string, integrationID string) error {
170	_, err := c.delete("/services/" + serviceID + "/integrations/" + integrationID)
171	return err
172}
173
174func getServiceFromResponse(c *Client, resp *http.Response, err error) (*Service, error) {
175	if err != nil {
176		return nil, err
177	}
178	var target map[string]Service
179	if dErr := c.decodeJSON(resp, &target); dErr != nil {
180		return nil, fmt.Errorf("Could not decode JSON response: %v", dErr)
181	}
182	rootNode := "service"
183	t, nodeOK := target[rootNode]
184	if !nodeOK {
185		return nil, fmt.Errorf("JSON response does not have %s field", rootNode)
186	}
187	return &t, nil
188}
189
190func getIntegrationFromResponse(c *Client, resp *http.Response, err error) (*Integration, error) {
191	if err != nil {
192		return nil, err
193	}
194	var target map[string]Integration
195	if dErr := c.decodeJSON(resp, &target); dErr != nil {
196		return nil, fmt.Errorf("Could not decode JSON response: %v", err)
197	}
198	rootNode := "integration"
199	t, nodeOK := target[rootNode]
200	if !nodeOK {
201		return nil, fmt.Errorf("JSON response does not have %s field", rootNode)
202	}
203	return &t, nil
204}
205