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
100func (s *GistsService) List(ctx context.Context, user string, opt *GistListOptions) ([]*Gist, *Response, error) {
101	var u string
102	if user != "" {
103		u = fmt.Sprintf("users/%v/gists", user)
104	} else {
105		u = "gists"
106	}
107	u, err := addOptions(u, opt)
108	if err != nil {
109		return nil, nil, err
110	}
111
112	req, err := s.client.NewRequest("GET", u, nil)
113	if err != nil {
114		return nil, nil, err
115	}
116
117	var gists []*Gist
118	resp, err := s.client.Do(ctx, req, &gists)
119	if err != nil {
120		return nil, resp, err
121	}
122
123	return gists, resp, nil
124}
125
126// ListAll lists all public gists.
127//
128// GitHub API docs: https://developer.github.com/v3/gists/#list-gists
129func (s *GistsService) ListAll(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) {
130	u, err := addOptions("gists/public", opt)
131	if err != nil {
132		return nil, nil, err
133	}
134
135	req, err := s.client.NewRequest("GET", u, nil)
136	if err != nil {
137		return nil, nil, err
138	}
139
140	var gists []*Gist
141	resp, err := s.client.Do(ctx, req, &gists)
142	if err != nil {
143		return nil, resp, err
144	}
145
146	return gists, resp, nil
147}
148
149// ListStarred lists starred gists of authenticated user.
150//
151// GitHub API docs: https://developer.github.com/v3/gists/#list-gists
152func (s *GistsService) ListStarred(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) {
153	u, err := addOptions("gists/starred", opt)
154	if err != nil {
155		return nil, nil, err
156	}
157
158	req, err := s.client.NewRequest("GET", u, nil)
159	if err != nil {
160		return nil, nil, err
161	}
162
163	var gists []*Gist
164	resp, err := s.client.Do(ctx, req, &gists)
165	if err != nil {
166		return nil, resp, err
167	}
168
169	return gists, resp, nil
170}
171
172// Get a single gist.
173//
174// GitHub API docs: https://developer.github.com/v3/gists/#get-a-single-gist
175func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) {
176	u := fmt.Sprintf("gists/%v", id)
177	req, err := s.client.NewRequest("GET", u, nil)
178	if err != nil {
179		return nil, nil, err
180	}
181
182	gist := new(Gist)
183	resp, err := s.client.Do(ctx, req, gist)
184	if err != nil {
185		return nil, resp, err
186	}
187
188	return gist, resp, nil
189}
190
191// GetRevision gets a specific revision of a gist.
192//
193// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist
194func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) {
195	u := fmt.Sprintf("gists/%v/%v", id, sha)
196	req, err := s.client.NewRequest("GET", u, nil)
197	if err != nil {
198		return nil, nil, err
199	}
200
201	gist := new(Gist)
202	resp, err := s.client.Do(ctx, req, gist)
203	if err != nil {
204		return nil, resp, err
205	}
206
207	return gist, resp, nil
208}
209
210// Create a gist for authenticated user.
211//
212// GitHub API docs: https://developer.github.com/v3/gists/#create-a-gist
213func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) {
214	u := "gists"
215	req, err := s.client.NewRequest("POST", u, gist)
216	if err != nil {
217		return nil, nil, err
218	}
219
220	g := new(Gist)
221	resp, err := s.client.Do(ctx, req, g)
222	if err != nil {
223		return nil, resp, err
224	}
225
226	return g, resp, nil
227}
228
229// Edit a gist.
230//
231// GitHub API docs: https://developer.github.com/v3/gists/#edit-a-gist
232func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) {
233	u := fmt.Sprintf("gists/%v", id)
234	req, err := s.client.NewRequest("PATCH", u, gist)
235	if err != nil {
236		return nil, nil, err
237	}
238
239	g := new(Gist)
240	resp, err := s.client.Do(ctx, req, g)
241	if err != nil {
242		return nil, resp, err
243	}
244
245	return g, resp, nil
246}
247
248// ListCommits lists commits of a gist.
249//
250// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-commits
251func (s *GistsService) ListCommits(ctx context.Context, id string, opt *ListOptions) ([]*GistCommit, *Response, error) {
252	u := fmt.Sprintf("gists/%v/commits", id)
253	u, err := addOptions(u, opt)
254	if err != nil {
255		return nil, nil, err
256	}
257
258	req, err := s.client.NewRequest("GET", u, nil)
259	if err != nil {
260		return nil, nil, err
261	}
262
263	var gistCommits []*GistCommit
264	resp, err := s.client.Do(ctx, req, &gistCommits)
265	if err != nil {
266		return nil, resp, err
267	}
268
269	return gistCommits, resp, nil
270}
271
272// Delete a gist.
273//
274// GitHub API docs: https://developer.github.com/v3/gists/#delete-a-gist
275func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) {
276	u := fmt.Sprintf("gists/%v", id)
277	req, err := s.client.NewRequest("DELETE", u, nil)
278	if err != nil {
279		return nil, err
280	}
281	return s.client.Do(ctx, req, nil)
282}
283
284// Star a gist on behalf of authenticated user.
285//
286// GitHub API docs: https://developer.github.com/v3/gists/#star-a-gist
287func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) {
288	u := fmt.Sprintf("gists/%v/star", id)
289	req, err := s.client.NewRequest("PUT", u, nil)
290	if err != nil {
291		return nil, err
292	}
293	return s.client.Do(ctx, req, nil)
294}
295
296// Unstar a gist on a behalf of authenticated user.
297//
298// GitHub API docs: https://developer.github.com/v3/gists/#unstar-a-gist
299func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) {
300	u := fmt.Sprintf("gists/%v/star", id)
301	req, err := s.client.NewRequest("DELETE", u, nil)
302	if err != nil {
303		return nil, err
304	}
305	return s.client.Do(ctx, req, nil)
306}
307
308// IsStarred checks if a gist is starred by authenticated user.
309//
310// GitHub API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred
311func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) {
312	u := fmt.Sprintf("gists/%v/star", id)
313	req, err := s.client.NewRequest("GET", u, nil)
314	if err != nil {
315		return false, nil, err
316	}
317	resp, err := s.client.Do(ctx, req, nil)
318	starred, err := parseBoolResponse(err)
319	return starred, resp, err
320}
321
322// Fork a gist.
323//
324// GitHub API docs: https://developer.github.com/v3/gists/#fork-a-gist
325func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) {
326	u := fmt.Sprintf("gists/%v/forks", id)
327	req, err := s.client.NewRequest("POST", u, nil)
328	if err != nil {
329		return nil, nil, err
330	}
331
332	g := new(Gist)
333	resp, err := s.client.Do(ctx, req, g)
334	if err != nil {
335		return nil, resp, err
336	}
337
338	return g, resp, nil
339}
340
341// ListForks lists forks of a gist.
342//
343// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-forks
344func (s *GistsService) ListForks(ctx context.Context, id string) ([]*GistFork, *Response, error) {
345	u := fmt.Sprintf("gists/%v/forks", id)
346	req, err := s.client.NewRequest("GET", u, nil)
347	if err != nil {
348		return nil, nil, err
349	}
350
351	var gistForks []*GistFork
352	resp, err := s.client.Do(ctx, req, &gistForks)
353	if err != nil {
354		return nil, resp, err
355	}
356
357	return gistForks, resp, nil
358}
359