1//
2// Copyright 2021, Sander van Harmelen
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package gitlab
18
19import (
20	"bytes"
21	"fmt"
22	"net/http"
23	"time"
24)
25
26// SnippetsService handles communication with the snippets
27// related methods of the GitLab API.
28//
29// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html
30type SnippetsService struct {
31	client *Client
32}
33
34// Snippet represents a GitLab snippet.
35//
36// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html
37type Snippet struct {
38	ID          int    `json:"id"`
39	Title       string `json:"title"`
40	FileName    string `json:"file_name"`
41	Description string `json:"description"`
42	Author      struct {
43		ID        int        `json:"id"`
44		Username  string     `json:"username"`
45		Email     string     `json:"email"`
46		Name      string     `json:"name"`
47		State     string     `json:"state"`
48		CreatedAt *time.Time `json:"created_at"`
49	} `json:"author"`
50	UpdatedAt *time.Time `json:"updated_at"`
51	CreatedAt *time.Time `json:"created_at"`
52	WebURL    string     `json:"web_url"`
53	RawURL    string     `json:"raw_url"`
54	Files     []struct {
55		Path   string `json:"path"`
56		RawURL string `json:"raw_url"`
57	} `json:"files"`
58}
59
60func (s Snippet) String() string {
61	return Stringify(s)
62}
63
64// ListSnippetsOptions represents the available ListSnippets() options.
65//
66// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets
67type ListSnippetsOptions ListOptions
68
69// ListSnippets gets a list of snippets.
70//
71// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets
72func (s *SnippetsService) ListSnippets(opt *ListSnippetsOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) {
73	req, err := s.client.NewRequest(http.MethodGet, "snippets", opt, options)
74	if err != nil {
75		return nil, nil, err
76	}
77
78	var ps []*Snippet
79	resp, err := s.client.Do(req, &ps)
80	if err != nil {
81		return nil, resp, err
82	}
83
84	return ps, resp, err
85}
86
87// GetSnippet gets a single snippet
88//
89// GitLab API docs:
90// https://docs.gitlab.com/ce/api/snippets.html#single-snippet
91func (s *SnippetsService) GetSnippet(snippet int, options ...RequestOptionFunc) (*Snippet, *Response, error) {
92	u := fmt.Sprintf("snippets/%d", snippet)
93
94	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
95	if err != nil {
96		return nil, nil, err
97	}
98
99	ps := new(Snippet)
100	resp, err := s.client.Do(req, ps)
101	if err != nil {
102		return nil, resp, err
103	}
104
105	return ps, resp, err
106}
107
108// SnippetFile represents the object that is used to create snippets
109//
110// GitLab API docs:
111// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet
112type SnippetFile struct {
113	FilePath *string `url:"file_path,omitempty" json:"file_path,omitempty"`
114	Content  *string `url:"content,omitempty" json:"content,omitempty"`
115}
116
117// CreateSnippetOptions represents the available CreateSnippet() options.
118//
119// GitLab API docs:
120// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet
121type CreateSnippetOptions struct {
122	Title       *string          `url:"title,omitempty" json:"title,omitempty"`
123	FileName    *string          `url:"file_name,omitempty" json:"file_name,omitempty"`
124	Description *string          `url:"description,omitempty" json:"description,omitempty"`
125	Content     *string          `url:"content,omitempty" json:"content,omitempty"`
126	Visibility  *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
127	Files       *[]*SnippetFile  `url:"files,omitempty" json:"files,omitempty"`
128}
129
130// CreateSnippet creates a new snippet. The user must have permission
131// to create new snippets.
132//
133// GitLab API docs:
134// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet
135func (s *SnippetsService) CreateSnippet(opt *CreateSnippetOptions, options ...RequestOptionFunc) (*Snippet, *Response, error) {
136	req, err := s.client.NewRequest(http.MethodPost, "snippets", opt, options)
137	if err != nil {
138		return nil, nil, err
139	}
140
141	ps := new(Snippet)
142	resp, err := s.client.Do(req, ps)
143	if err != nil {
144		return nil, resp, err
145	}
146
147	return ps, resp, err
148}
149
150// UpdateSnippetOptions represents the available UpdateSnippet() options.
151//
152// GitLab API docs:
153// https://docs.gitlab.com/ce/api/snippets.html#update-snippet
154type UpdateSnippetOptions struct {
155	Title       *string          `url:"title,omitempty" json:"title,omitempty"`
156	FileName    *string          `url:"file_name,omitempty" json:"file_name,omitempty"`
157	Description *string          `url:"description,omitempty" json:"description,omitempty"`
158	Content     *string          `url:"content,omitempty" json:"content,omitempty"`
159	Visibility  *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
160}
161
162// UpdateSnippet updates an existing snippet. The user must have
163// permission to change an existing snippet.
164//
165// GitLab API docs:
166// https://docs.gitlab.com/ce/api/snippets.html#update-snippet
167func (s *SnippetsService) UpdateSnippet(snippet int, opt *UpdateSnippetOptions, options ...RequestOptionFunc) (*Snippet, *Response, error) {
168	u := fmt.Sprintf("snippets/%d", snippet)
169
170	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
171	if err != nil {
172		return nil, nil, err
173	}
174
175	ps := new(Snippet)
176	resp, err := s.client.Do(req, ps)
177	if err != nil {
178		return nil, resp, err
179	}
180
181	return ps, resp, err
182}
183
184// DeleteSnippet deletes an existing snippet. This is an idempotent
185// function and deleting a non-existent snippet still returns a 200 OK status
186// code.
187//
188// GitLab API docs:
189// https://docs.gitlab.com/ce/api/snippets.html#delete-snippet
190func (s *SnippetsService) DeleteSnippet(snippet int, options ...RequestOptionFunc) (*Response, error) {
191	u := fmt.Sprintf("snippets/%d", snippet)
192
193	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
194	if err != nil {
195		return nil, err
196	}
197
198	return s.client.Do(req, nil)
199}
200
201// SnippetContent returns the raw snippet as plain text.
202//
203// GitLab API docs:
204// https://docs.gitlab.com/ce/api/snippets.html#snippet-content
205func (s *SnippetsService) SnippetContent(snippet int, options ...RequestOptionFunc) ([]byte, *Response, error) {
206	u := fmt.Sprintf("snippets/%d/raw", snippet)
207
208	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
209	if err != nil {
210		return nil, nil, err
211	}
212
213	var b bytes.Buffer
214	resp, err := s.client.Do(req, &b)
215	if err != nil {
216		return nil, resp, err
217	}
218
219	return b.Bytes(), resp, err
220}
221
222// ExploreSnippetsOptions represents the available ExploreSnippets() options.
223//
224// GitLab API docs:
225// https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets
226type ExploreSnippetsOptions ListOptions
227
228// ExploreSnippets gets the list of public snippets.
229//
230// GitLab API docs:
231// https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets
232func (s *SnippetsService) ExploreSnippets(opt *ExploreSnippetsOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) {
233	req, err := s.client.NewRequest(http.MethodGet, "snippets/public", opt, options)
234	if err != nil {
235		return nil, nil, err
236	}
237
238	var ps []*Snippet
239	resp, err := s.client.Do(req, &ps)
240	if err != nil {
241		return nil, resp, err
242	}
243
244	return ps, resp, err
245}
246