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

devto.*listedArticleJSON.listedArticle   A

Complexity

Conditions 2

Size

Total Lines 33
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 25
nop 0
dl 0
loc 33
ccs 5
cts 5
cp 1
crap 2
rs 9.28
c 0
b 0
f 0
1
package devto
2
3
import (
4
	"encoding/json"
5
	"net/url"
6
	"strings"
7
	"time"
8
)
9
10
// User contains information about a devto account
11
type User struct {
12
	Name            string  `json:"name,omitempty"`
13
	Username        string  `json:"username,omitempty"`
14
	TwitterUsername string  `json:"twitter_username,omitempty"`
15
	GithubUsername  string  `json:"github_username,omitempty"`
16
	WebsiteURL      *WebURL `json:"website_url,omitempty"`
17
	ProfileImage    *WebURL `json:"profile_image,omitempty"`
18
	ProfileImage90  *WebURL `json:"profile_image_90,omitempty"`
19
}
20
21
// Organization describes a company or group that
22
// publishes content to devto.
23
type Organization struct {
24
	Name           string  `json:"name,omitempty"`
25
	Username       string  `json:"username,omitempty"`
26
	Slug           string  `json:"slug,omitempty"`
27
	ProfileImage   *WebURL `json:"profile_image,omitempty"`
28
	ProfileImage90 *WebURL `json:"profile_image_90,omitempty"`
29
}
30
31
// FlareTag represents an article's flare tag, if the article
32
// has one.
33
type FlareTag struct {
34
	Name         string `json:"name"`
35
	BGColorHex   string `json:"bg_color_hex"`
36
	TextColorHex string `json:"text_color_hex"`
37
}
38
39
// Tags are a group of topics related to an article
40
type Tags []string
41
42
// This deserialization logic is so that if a listed article
43
// originates from the /articles endpoint instead of
44
// /articles/me/*, its Published field is returned as true,
45
// since /articles exclusively returns articles that have been
46
// published.
47
type listedArticleJSON struct {
48
	TypeOf                 string        `json:"type_of,omitempty"`
49
	ID                     uint32        `json:"id,omitempty"`
50
	Title                  string        `json:"title,omitempty"`
51
	Description            string        `json:"description,omitempty"`
52
	CoverImage             *WebURL       `json:"cover_image,omitempty"`
53
	PublishedAt            *time.Time    `json:"published_at,omitempty"`
54
	PublishedTimestamp     string        `json:"published_timestamp,omitempty"`
55
	TagList                Tags          `json:"tag_list,omitempty"`
56
	Slug                   string        `json:"slug,omitempty"`
57
	Path                   string        `json:"path,omitempty"`
58
	URL                    *WebURL       `json:"url,omitempty"`
59
	CanonicalURL           *WebURL       `json:"canonical_url,omitempty"`
60
	CommentsCount          uint          `json:"comments_count,omitempty"`
61
	PositiveReactionsCount uint          `json:"positive_reactions_count,omitempty"`
62
	User                   User          `json:"user,omitempty"`
63
	Organization           *Organization `json:"organization,omitempty"`
64
	FlareTag               *FlareTag     `json:"flare_tag,omitempty"`
65
	BodyMarkdown           string        `json:"body_markdown,omitempty"`
66
	Published              *bool         `json:"published,omitempty"`
67
}
68
69
func (j *listedArticleJSON) listedArticle() ListedArticle {
70 1
	a := ListedArticle{
71
		TypeOf:                 j.TypeOf,
72
		ID:                     j.ID,
73
		Title:                  j.Title,
74
		Description:            j.Description,
75
		CoverImage:             j.CoverImage,
76
		PublishedAt:            j.PublishedAt,
77
		PublishedTimestamp:     j.PublishedTimestamp,
78
		TagList:                j.TagList,
79
		Slug:                   j.Slug,
80
		Path:                   j.Path,
81
		URL:                    j.URL,
82
		CanonicalURL:           j.CanonicalURL,
83
		CommentsCount:          j.CommentsCount,
84
		PositiveReactionsCount: j.PositiveReactionsCount,
85
		User:                   j.User,
86
		Organization:           j.Organization,
87
		FlareTag:               j.FlareTag,
88
		BodyMarkdown:           j.BodyMarkdown,
89
	}
90
91 1
	if j.Published != nil {
92 1
		a.Published = *j.Published
93
	} else {
94
		// "published" currently is included in the API
95
		// response for dev.to's /articles/me/* endpoints,
96
		// but not in /articles, so we are setting this
97
		// to true since /articles only returns articles
98
		// that are published.
99 1
		a.Published = true
100
	}
101 1
	return a
102
}
103
104
// ListedArticle represents an article returned from one of
105
// the list articles endpoints (/articles, /articles/me/*).
106
type ListedArticle struct {
107
	TypeOf                 string        `json:"type_of,omitempty"`
108
	ID                     uint32        `json:"id,omitempty"`
109
	Title                  string        `json:"title,omitempty"`
110
	Description            string        `json:"description,omitempty"`
111
	CoverImage             *WebURL       `json:"cover_image,omitempty"`
112
	PublishedAt            *time.Time    `json:"published_at,omitempty"`
113
	PublishedTimestamp     string        `json:"published_timestamp,omitempty"`
114
	TagList                Tags          `json:"tag_list,omitempty"`
115
	Slug                   string        `json:"slug,omitempty"`
116
	Path                   string        `json:"path,omitempty"`
117
	URL                    *WebURL       `json:"url,omitempty"`
118
	CanonicalURL           *WebURL       `json:"canonical_url,omitempty"`
119
	CommentsCount          uint          `json:"comments_count,omitempty"`
120
	PositiveReactionsCount uint          `json:"positive_reactions_count,omitempty"`
121
	User                   User          `json:"user,omitempty"`
122
	Organization           *Organization `json:"organization,omitempty"`
123
	FlareTag               *FlareTag     `json:"flare_tag,omitempty"`
124
	// Only present in "/articles/me/*" endpoints
125
	BodyMarkdown string `json:"body_markdown,omitempty"`
126
	Published    bool   `json:"published,omitempty"`
127
}
128
129
// UnmarshalJSON implements the JSON Unmarshaler interface.
130
func (a *ListedArticle) UnmarshalJSON(b []byte) error {
131 1
	var j listedArticleJSON
132 1
	if err := json.Unmarshal(b, &j); err != nil {
133
		return err
134
	}
135
136 1
	*a = j.listedArticle()
137 1
	return nil
138
}
139
140
// Article contains all the information related to a single
141
// information resource from devto.
142
type Article struct {
143
	TypeOf                 string     `json:"type_of,omitempty"`
144
	ID                     uint32     `json:"id,omitempty"`
145
	Title                  string     `json:"title,omitempty"`
146
	Description            string     `json:"description,omitempty"`
147
	CoverImage             *WebURL    `json:"cover_image,omitempty"`
148
	SocialImage            *WebURL    `json:"social_image,omitempty"`
149
	ReadablePublishDate    string     `json:"readable_publish_date"`
150
	Published              bool       `json:"published,omitempty"`
151
	PublishedAt            *time.Time `json:"published_at,omitempty"`
152
	CreatedAt              *time.Time `json:"created_at,omitempty"`
153
	EditedAt               *time.Time `json:"edited_at,omitempty"`
154
	CrossPostedAt          *time.Time `json:"crossposted_at,omitempty"`
155
	LastCommentAt          *time.Time `json:"last_comment_at,omitempty"`
156
	TagList                string     `json:"tag_list,omitempty"`
157
	Tags                   Tags       `json:"tags,omitempty"`
158
	Slug                   string     `json:"slug,omitempty"`
159
	Path                   *WebURL    `json:"path,omitempty"`
160
	URL                    *WebURL    `json:"url,omitempty"`
161
	CanonicalURL           *WebURL    `json:"canonical_url,omitempty"`
162
	CommentsCount          uint       `json:"comments_count,omitempty"`
163
	PositiveReactionsCount uint       `json:"positive_reactions_count,omitempty"`
164
	User                   User       `json:"user,omitempty"`
165
	BodyHTML               string     `json:"body_html,omitempty"`
166
	BodyMarkdown           string     `json:"body_markdown,omitempty"`
167
}
168
169
// ArticleUpdate represents an update to an article; it is
170
// used as the payload in POST and PUT requests for writing
171
// articles.
172
type ArticleUpdate struct {
173
	Title          string   `json:"title"`
174
	BodyMarkdown   string   `json:"body_markdown"`
175
	Published      bool     `json:"published"`
176
	Series         *string  `json:"series"`
177
	MainImage      string   `json:"main_image,omitempty"`
178
	CanonicalURL   string   `json:"canonical_url,omitempty"`
179
	Description    string   `json:"description,omitempty"`
180
	Tags           []string `json:"tags,omitempty"`
181
	OrganizationID int32    `json:"organization_id,omitempty"`
182
}
183
184
// ArticleListOptions holds the query values to pass as
185
// query string parameter to the Articles List action.
186
type ArticleListOptions struct {
187
	Tags     string `url:"tag,omitempty"`
188
	Username string `url:"username,omitempty"`
189
	State    string `url:"state,omitempty"`
190
	Top      string `url:"top,omitempty"`
191
	Page     int    `url:"page,omitempty"`
192
}
193
194
// MyArticlesOptions defines pagination options used as query
195
// params in the dev.to "list my articles" endpoints.
196
type MyArticlesOptions struct {
197
	Page    int `url:"page,omitempty"`
198
	PerPage int `url:"per_page,omitempty"`
199
}
200
201
// WebURL is a class embed to override default unmarshal
202
// behavior.
203
type WebURL struct {
204
	*url.URL
205
}
206
207
// UnmarshalJSON overrides the default unmarshal behaviour
208
// for URL
209
func (s *WebURL) UnmarshalJSON(b []byte) error {
210 1
	c := string(b)
211 1
	c = strings.Trim(c, "\"")
212 1
	uri, err := url.Parse(c)
213 1
	if err != nil {
214 1
		return err
215
	}
216 1
	s.URL = uri
217 1
	return nil
218
}
219