1// Copyright 2013 The go-github AUTHORS. All rights reserved.
2//
3// Use of this source code is governed by BSD-style
4// license that can be found in the LICENSE file.
5
6package github
7
8import (
9	"context"
10	"fmt"
11	"time"
12)
13
14// GistsService handles communication with the Gist related
15// methods of the GitHub API.
16//
17// GitHub API docs: https://developer.github.com/v3/gists/
18type GistsService service
19
20// Gist represents a GitHub's gist.
21type Gist struct {
22	ID          *string                   `json:"id,omitempty"`
23	Description *string                   `json:"description,omitempty"`
24	Public      *bool                     `json:"public,omitempty"`
25	Owner       *User                     `json:"owner,omitempty"`
26	Files       map[GistFilename]GistFile `json:"files,omitempty"`
27	Comments    *int                      `json:"comments,omitempty"`
28	HTMLURL     *string                   `json:"html_url,omitempty"`
29	GitPullURL  *string                   `json:"git_pull_url,omitempty"`
30	GitPushURL  *string                   `json:"git_push_url,omitempty"`
31	CreatedAt   *time.Time                `json:"created_at,omitempty"`
32	UpdatedAt   *time.Time                `json:"updated_at,omitempty"`
33	NodeID      *string                   `json:"node_id,omitempty"`
34}
35
36func (g Gist) String() string {
37	return Stringify(g)
38}
39
40// GistFilename represents filename on a gist.
41type GistFilename string
42
43// GistFile represents a file on a gist.
44type GistFile struct {
45	Size     *int    `json:"size,omitempty"`
46	Filename *string `json:"filename,omitempty"`
47	Language *string `json:"language,omitempty"`
48	Type     *string `json:"type,omitempty"`
49	RawURL   *string `json:"raw_url,omitempty"`
50	Content  *string `json:"content,omitempty"`
51}
52
53func (g GistFile) String() string {
54	return Stringify(g)
55}
56
57// GistCommit represents a commit on a gist.
58type GistCommit struct {
59	URL          *string      `json:"url,omitempty"`
60	Version      *string      `json:"version,omitempty"`
61	User         *User        `json:"user,omitempty"`
62	ChangeStatus *CommitStats `json:"change_status,omitempty"`
63	CommittedAt  *Timestamp   `json:"committed_at,omitempty"`
64	NodeID       *string      `json:"node_id,omitempty"`
65}
66
67func (gc GistCommit) String() string {
68	return Stringify(gc)
69}
70
71// GistFork represents a fork of a gist.
72type GistFork struct {
73	URL       *string    `json:"url,omitempty"`
74	User      *User      `json:"user,omitempty"`
75	ID        *string    `json:"id,omitempty"`
76	CreatedAt *Timestamp `json:"created_at,omitempty"`
77	UpdatedAt *Timestamp `json:"updated_at,omitempty"`
78	NodeID    *string    `json:"node_id,omitempty"`
79}
80
81func (gf GistFork) String() string {
82	return Stringify(gf)
83}
84
85// GistListOptions specifies the optional parameters to the
86// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods.
87type GistListOptions struct {
88	// Since filters Gists by time.
89	Since time.Time `url:"since,omitempty"`
90
91	ListOptions
92}
93
94// List gists for a user. Passing the empty string will list
95// all public gists if called anonymously. However, if the call
96// is authenticated, it will returns all gists for the authenticated
97// user.
98//
99// GitHub API docs: https://developer.github.com/v3/gists/#list-gists-for-a-user
100// GitHub API docs: https://developer.github.com/v3/gists/#list-gists-for-the-authenticated-user
101func (s *GistsService) List(ctx context.Context, user string, opts *GistListOptions) ([]*Gist, *Response, error) {
102	var u string
103	if user != "" {
104		u = fmt.Sprintf("users/%v/gists", user)
105	} else {
106		u = "gists"
107	}
108	u, err := addOptions(u, opts)
109	if err != nil {
110		return nil, nil, err
111	}
112
113	req, err := s.client.NewRequest("GET", u, nil)
114	if err != nil {
115		return nil, nil, err
116	}
117
118	var gists []*Gist
119	resp, err := s.client.Do(ctx, req, &gists)
120	if err != nil {
121		return nil, resp, err
122	}
123
124	return gists, resp, nil
125}
126
127// ListAll lists all public gists.
128//
129// GitHub API docs: https://developer.github.com/v3/gists/#list-public-gists
130func (s *GistsService) ListAll(ctx context.Context, opts *GistListOptions) ([]*Gist, *Response, error) {
131	u, err := addOptions("gists/public", opts)
132	if err != nil {
133		return nil, nil, err
134	}
135
136	req, err := s.client.NewRequest("GET", u, nil)
137	if err != nil {
138		return nil, nil, err
139	}
140
141	var gists []*Gist
142	resp, err := s.client.Do(ctx, req, &gists)
143	if err != nil {
144		return nil, resp, err
145	}
146
147	return gists, resp, nil
148}
149
150// ListStarred lists starred gists of authenticated user.
151//
152// GitHub API docs: https://developer.github.com/v3/gists/#list-starred-gists
153func (s *GistsService) ListStarred(ctx context.Context, opts *GistListOptions) ([]*Gist, *Response, error) {
154	u, err := addOptions("gists/starred", opts)
155	if err != nil {
156		return nil, nil, err
157	}
158
159	req, err := s.client.NewRequest("GET", u, nil)
160	if err != nil {
161		return nil, nil, err
162	}
163
164	var gists []*Gist
165	resp, err := s.client.Do(ctx, req, &gists)
166	if err != nil {
167		return nil, resp, err
168	}
169
170	return gists, resp, nil
171}
172
173// Get a single gist.
174//
175// GitHub API docs: https://developer.github.com/v3/gists/#get-a-gist
176func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) {
177	u := fmt.Sprintf("gists/%v", id)
178	req, err := s.client.NewRequest("GET", u, nil)
179	if err != nil {
180		return nil, nil, err
181	}
182
183	gist := new(Gist)
184	resp, err := s.client.Do(ctx, req, gist)
185	if err != nil {
186		return nil, resp, err
187	}
188
189	return gist, resp, nil
190}
191
192// GetRevision gets a specific revision of a gist.
193//
194// GitHub API docs: https://developer.github.com/v3/gists/#get-a-gist-revision
195func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) {
196	u := fmt.Sprintf("gists/%v/%v", id, sha)
197	req, err := s.client.NewRequest("GET", u, nil)
198	if err != nil {
199		return nil, nil, err
200	}
201
202	gist := new(Gist)
203	resp, err := s.client.Do(ctx, req, gist)
204	if err != nil {
205		return nil, resp, err
206	}
207
208	return gist, resp, nil
209}
210
211// Create a gist for authenticated user.
212//
213// GitHub API docs: https://developer.github.com/v3/gists/#create-a-gist
214func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) {
215	u := "gists"
216	req, err := s.client.NewRequest("POST", u, gist)
217	if err != nil {
218		return nil, nil, err
219	}
220
221	g := new(Gist)
222	resp, err := s.client.Do(ctx, req, g)
223	if err != nil {
224		return nil, resp, err
225	}
226
227	return g, resp, nil
228}
229
230// Edit a gist.
231//
232// GitHub API docs: https://developer.github.com/v3/gists/#update-a-gist
233func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) {
234	u := fmt.Sprintf("gists/%v", id)
235	req, err := s.client.NewRequest("PATCH", u, gist)
236	if err != nil {
237		return nil, nil, err
238	}
239
240	g := new(Gist)
241	resp, err := s.client.Do(ctx, req, g)
242	if err != nil {
243		return nil, resp, err
244	}
245
246	return g, resp, nil
247}
248
249// ListCommits lists commits of a gist.
250//
251// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-commits
252func (s *GistsService) ListCommits(ctx context.Context, id string, opts *ListOptions) ([]*GistCommit, *Response, error) {
253	u := fmt.Sprintf("gists/%v/commits", id)
254	u, err := addOptions(u, opts)
255	if err != nil {
256		return nil, nil, err
257	}
258
259	req, err := s.client.NewRequest("GET", u, nil)
260	if err != nil {
261		return nil, nil, err
262	}
263
264	var gistCommits []*GistCommit
265	resp, err := s.client.Do(ctx, req, &gistCommits)
266	if err != nil {
267		return nil, resp, err
268	}
269
270	return gistCommits, resp, nil
271}
272
273// Delete a gist.
274//
275// GitHub API docs: https://developer.github.com/v3/gists/#delete-a-gist
276func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) {
277	u := fmt.Sprintf("gists/%v", id)
278	req, err := s.client.NewRequest("DELETE", u, nil)
279	if err != nil {
280		return nil, err
281	}
282	return s.client.Do(ctx, req, nil)
283}
284
285// Star a gist on behalf of authenticated user.
286//
287// GitHub API docs: https://developer.github.com/v3/gists/#star-a-gist
288func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) {
289	u := fmt.Sprintf("gists/%v/star", id)
290	req, err := s.client.NewRequest("PUT", u, nil)
291	if err != nil {
292		return nil, err
293	}
294	return s.client.Do(ctx, req, nil)
295}
296
297// Unstar a gist on a behalf of authenticated user.
298//
299// GitHub API docs: https://developer.github.com/v3/gists/#unstar-a-gist
300func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) {
301	u := fmt.Sprintf("gists/%v/star", id)
302	req, err := s.client.NewRequest("DELETE", u, nil)
303	if err != nil {
304		return nil, err
305	}
306	return s.client.Do(ctx, req, nil)
307}
308
309// IsStarred checks if a gist is starred by authenticated user.
310//
311// GitHub API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred
312func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) {
313	u := fmt.Sprintf("gists/%v/star", id)
314	req, err := s.client.NewRequest("GET", u, nil)
315	if err != nil {
316		return false, nil, err
317	}
318	resp, err := s.client.Do(ctx, req, nil)
319	starred, err := parseBoolResponse(err)
320	return starred, resp, err
321}
322
323// Fork a gist.
324//
325// GitHub API docs: https://developer.github.com/v3/gists/#fork-a-gist
326func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) {
327	u := fmt.Sprintf("gists/%v/forks", id)
328	req, err := s.client.NewRequest("POST", u, nil)
329	if err != nil {
330		return nil, nil, err
331	}
332
333	g := new(Gist)
334	resp, err := s.client.Do(ctx, req, g)
335	if err != nil {
336		return nil, resp, err
337	}
338
339	return g, resp, nil
340}
341
342// ListForks lists forks of a gist.
343//
344// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-forks
345func (s *GistsService) ListForks(ctx context.Context, id string, opts *ListOptions) ([]*GistFork, *Response, error) {
346	u := fmt.Sprintf("gists/%v/forks", id)
347	u, err := addOptions(u, opts)
348	if err != nil {
349		return nil, nil, err
350	}
351
352	req, err := s.client.NewRequest("GET", u, nil)
353	if err != nil {
354		return nil, nil, err
355	}
356
357	var gistForks []*GistFork
358	resp, err := s.client.Do(ctx, req, &gistForks)
359	if err != nil {
360		return nil, resp, err
361	}
362
363	return gistForks, resp, nil
364}
365