Passed
Push — master ( 4ce3bc...a2c608 )
by Victor Hugo
01:06 queued 11s
created

devto.*ArticlesResource.ListForUser   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 3
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
package devto
2
3
import (
4
	"context"
5
	"encoding/json"
6
	"fmt"
7
	"net/http"
8
	"strings"
9
10
	"github.com/google/go-querystring/query"
11
)
12
13
// ArticlesResource implements the APIResource interface
14
// for devto articles.
15
type ArticlesResource struct {
16
	API *Client
17
}
18
19
// List will return the articles uploaded to devto, the result
20
// can be narrowed down, filtered or enhanced using query
21
// parameters as specified on the documentation.
22
// See: https://docs.dev.to/api/#tag/articles/paths/~1articles/get
23
func (ar *ArticlesResource) List(ctx context.Context, opt ArticleListOptions) ([]ListedArticle, error) {
24 1
	var l []ListedArticle
25 1
	q, err := query.Values(opt)
26 1
	if err != nil {
27
		return nil, err
28
	}
29 1
	req, err := ar.API.NewRequest(http.MethodGet, fmt.Sprintf("api/articles?%s", q.Encode()), nil)
30 1
	if err != nil {
31
		return nil, err
32
	}
33
34 1
	res, err := ar.API.HTTPClient.Do(req)
35 1
	if err != nil {
36
		return nil, err
37
	}
38 1
	defer res.Body.Close()
39
40 1
	cont := decodeResponse(res)
41 1
	if err := json.Unmarshal(cont, &l); err != nil {
42
		return nil, err
43
	}
44 1
	return l, nil
45
}
46
47
// ListForTag is a convenience method for retrieving articles
48
// for a particular tag, calling the base List method.
49
func (ar *ArticlesResource) ListForTag(ctx context.Context, tag string, page int) ([]ListedArticle, error) {
50 1
	return ar.List(ctx, ArticleListOptions{Tags: tag, Page: page})
51
}
52
53
// ListForUser is a convenience method for retrieving articles
54
// written by a particular user, calling the base List method.
55
func (ar *ArticlesResource) ListForUser(ctx context.Context, username string, page int) ([]ListedArticle, error) {
56 1
	return ar.List(ctx, ArticleListOptions{Username: username, Page: page})
57
}
58
59
// ListMyPublishedArticles lists all published articles
60
// written by the user authenticated with this client,
61
// erroring if the caller is not authenticated. Articles in
62
// the response will be listed in reverse chronological order
63
// by their publication times.
64
//
65
// If opts is nil, then no query parameters will be sent; the
66
// page number will be 1 and the page size will be 30
67
// articles.
68
func (ar *ArticlesResource) ListMyPublishedArticles(ctx context.Context, opts *MyArticlesOptions) ([]ListedArticle, error) {
69 1
	return ar.listMyArticles(ctx, "api/articles/me/published", opts)
70
}
71
72
// ListMyUnpublishedArticles lists all unpublished articles
73
// written by the user authenticated with this client,
74
// erroring if the caller is not authenticated. Articles in
75
// the response will be listed in reverse chronological order
76
// by their creation times.
77
//
78
// If opts is nil, then no query parameters will be sent; the
79
// page number will be 1 and the page size will be 30
80
// articles.
81
func (ar *ArticlesResource) ListMyUnpublishedArticles(ctx context.Context, opts *MyArticlesOptions) ([]ListedArticle, error) {
82 1
	return ar.listMyArticles(ctx, "api/articles/me/unpublished", opts)
83
}
84
85
// ListAllMyArticles lists all articles written by the user
86
// authenticated with this client, erroring if the caller is
87
// not authenticated. Articles in the response will be listed
88
// in reverse chronological order by their creation times,
89
// with unpublished articles listed before published articles.
90
//
91
// If opts is nil, then no query parameters will be sent; the
92
// page number will be 1 and the page size will be 30
93
// articles.
94
func (ar *ArticlesResource) ListAllMyArticles(ctx context.Context, opts *MyArticlesOptions) ([]ListedArticle, error) {
95 1
	return ar.listMyArticles(ctx, "api/articles/me/all", opts)
96
}
97
98
// listMyArticles serves for handling roundtrips to the
99
// /api/articles/me/* endpoints, requesting articles from the
100
// endpoint passed in, and returning a list of articles.
101
func (ar *ArticlesResource) listMyArticles(
102
	ctx context.Context,
103
	endpoint string,
104
	opts *MyArticlesOptions,
105
) ([]ListedArticle, error) {
106 1
	if ar.API.Config.InsecureOnly {
107 1
		return nil, ErrProtectedEndpoint
108
	}
109
110 1
	req, err := ar.API.NewRequest(http.MethodGet, endpoint, nil)
111 1
	if err != nil {
112
		return nil, err
113
	}
114 1
	req.Header.Add(APIKeyHeader, ar.API.Config.APIKey)
115
116 1
	if opts != nil {
117 1
		q, err := query.Values(opts)
118 1
		if err != nil {
119
			return nil, err
120
		}
121 1
		req.URL.RawQuery = q.Encode()
122
	}
123
124 1
	res, err := ar.API.HTTPClient.Do(req)
125 1
	if err != nil {
126
		return nil, err
127
	}
128 1
	defer res.Body.Close()
129
130 1
	var articles []ListedArticle
131 1
	if err := json.NewDecoder(res.Body).Decode(&articles); err != nil {
132
		return nil, err
133
	}
134 1
	return articles, nil
135
}
136
137
// Find will retrieve an Article matching the ID passed.
138
func (ar *ArticlesResource) Find(ctx context.Context, id uint32) (Article, error) {
139 1
	var art Article
140 1
	req, err := ar.API.NewRequest(http.MethodGet, fmt.Sprintf("api/articles/%d", id), nil)
141 1
	if err != nil {
142
		return art, err
143
	}
144
145 1
	res, err := ar.API.HTTPClient.Do(req)
146 1
	if err != nil {
147
		return art, err
148
	}
149 1
	cont := decodeResponse(res)
150 1
	if err := json.Unmarshal(cont, &art); err != nil {
151
		return Article{}, err
152
	}
153 1
	return art, nil
154
}
155
156
// New will create a new article on dev.to
157
func (ar *ArticlesResource) New(ctx context.Context, u ArticleUpdate) (Article, error) {
158 1
	if ar.API.Config.InsecureOnly {
159 1
		return Article{}, ErrProtectedEndpoint
160
	}
161 1
	cont, err := json.Marshal(&u)
162 1
	if err != nil {
163
		return Article{}, err
164
	}
165 1
	req, err := ar.API.NewRequest(http.MethodPost, "api/articles", strings.NewReader(string(cont)))
166 1
	if err != nil {
167
		return Article{}, err
168
	}
169 1
	req.Header.Add(APIKeyHeader, ar.API.Config.APIKey)
170 1
	res, err := ar.API.HTTPClient.Do(req)
171 1
	if err != nil {
172
		return Article{}, err
173
	}
174
175 1
	var a Article
176 1
	content := decodeResponse(res)
177 1
	if err := json.Unmarshal(content, &a); err != nil {
178
		return Article{}, err
179
	}
180 1
	return a, nil
181
}
182
183
// Update will mutate the resource by id, and all the changes
184
// performed to the Article will be applied, thus validation
185
// on the API side.
186
func (ar *ArticlesResource) Update(ctx context.Context, u ArticleUpdate, id uint32) (Article, error) {
187 1
	if ar.API.Config.InsecureOnly {
188 1
		return Article{}, ErrProtectedEndpoint
189
	}
190 1
	cont, err := json.Marshal(&u)
191 1
	if err != nil {
192
		return Article{}, err
193
	}
194 1
	req, err := ar.API.NewRequest(http.MethodPut, fmt.Sprintf("api/articles/%d", id), strings.NewReader(string(cont)))
195 1
	if err != nil {
196
		return Article{}, err
197
	}
198 1
	req.Header.Add(APIKeyHeader, ar.API.Config.APIKey)
199 1
	res, err := ar.API.HTTPClient.Do(req)
200 1
	if err != nil {
201
		return Article{}, err
202
	}
203
204 1
	var a Article
205 1
	content := decodeResponse(res)
206 1
	if err := json.Unmarshal(content, &a); err != nil {
207
		return Article{}, err
208
	}
209 1
	return a, nil
210
}
211