-
Notifications
You must be signed in to change notification settings - Fork 1
/
graph.go
350 lines (303 loc) · 11.2 KB
/
graph.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
package pixela
import (
"encoding/json"
"fmt"
"net/http"
"github.com/pkg/errors"
)
// A Graph manages communication with the Pixela graph API.
type Graph struct {
UserName string
Token string
GraphID string
}
// Create creates a new pixelation graph definition.
func (g *Graph) Create(name, unit, quantityType, color, timezone, selfSufficient string, isSecret, publishOptionalData bool) (*Result, error) {
param, err := g.createCreateRequestParameter(name, unit, quantityType, color, timezone, selfSufficient, isSecret, publishOptionalData)
if err != nil {
return &Result{}, errors.Wrapf(err, "failed to create graph create parameter")
}
return doRequestAndParseResponse(param)
}
func (g *Graph) createCreateRequestParameter(name, unit, quantityType, color, timezone, selfSufficient string, isSecret, publishOptionalData bool) (*requestParameter, error) {
create := graphCreate{
ID: g.GraphID,
Name: name,
Unit: unit,
Type: quantityType,
Color: color,
TimeZone: timezone,
SelfSufficient: selfSufficient,
IsSecret: isSecret,
PublishOptionalData: publishOptionalData,
}
b, err := json.Marshal(create)
if err != nil {
return &requestParameter{}, errors.Wrap(err, "failed to marshal json")
}
return &requestParameter{
Method: http.MethodPost,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs", g.UserName),
Header: map[string]string{userToken: g.Token},
Body: b,
}, nil
}
type graphCreate struct {
ID string `json:"id"`
Name string `json:"name"`
Unit string `json:"unit"`
Type string `json:"type"`
Color string `json:"color"`
TimeZone string `json:"timezone"`
SelfSufficient string `json:"selfSufficient"`
IsSecret bool `json:"isSecret"`
PublishOptionalData bool `json:"publishOptionalData"`
}
// It is the type of quantity to be handled in the graph.
// Only int or float are supported.
const (
TypeInt = "int"
TypeFloat = "float"
)
// Defines the display color of the pixel in the pixelation graph.
// shibafu (green), momiji (red), sora (blue), ichou (yellow), ajisai (purple) and kuro (black) are supported as color kind.
const (
ColorShibafu = "shibafu"
ColorMomiji = "momiji"
ColorSora = "sora"
ColorIchou = "ichou"
ColorAjisai = "ajisai"
ColorKuro = "kuro"
)
// If SVG graph with this field increment or decrement is referenced, Pixel of this graph itself will be incremented or decremented.
// It is suitable when you want to record the PVs on a web page or site simultaneously.
// The specification of increment or decrement is the same as Increment a Pixel and Decrement a Pixel with webhook.
// If not specified, it is treated as none .
const (
SelfSufficientIncrement = "increment"
SelfSufficientDecrement = "decrement"
SelfSufficientNone = "none"
)
// GetAll gets all predefined pixelation graph definitions.
func (g *Graph) GetAll() (*GraphDefinitions, error) {
param, err := g.createGetAllRequestParameter()
if err != nil {
return &GraphDefinitions{}, errors.Wrapf(err, "failed to create get all graph parameter")
}
b, err := doRequest(param)
if err != nil {
return &GraphDefinitions{}, errors.Wrapf(err, "failed to do request")
}
var definitions GraphDefinitions
if err := json.Unmarshal(b, &definitions); err != nil {
return &GraphDefinitions{}, errors.Wrapf(err, "failed to unmarshal json")
}
definitions.IsSuccess = definitions.Message == ""
return &definitions, nil
}
func (g *Graph) createGetAllRequestParameter() (*requestParameter, error) {
return &requestParameter{
Method: http.MethodGet,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs", g.UserName),
Header: map[string]string{userToken: g.Token},
Body: []byte{},
}, nil
}
// GraphDefinitions is graph definition list.
type GraphDefinitions struct {
Graphs []GraphDefinition `json:"graphs"`
Result
}
// GraphDefinition is graph definition.
type GraphDefinition struct {
ID string `json:"id"`
Name string `json:"name"`
Unit string `json:"unit"`
Type string `json:"type"`
Color string `json:"color"`
TimeZone string `json:"timezone"`
PurgeCacheURLs []string `json:"purgeCacheURLs"`
SelfSufficient string `json:"selfSufficient"`
IsSecret bool `json:"isSecret"`
PublishOptionalData bool `json:"publishOptionalData"`
}
// GetSVG get a graph expressed in SVG format diagram that based on the registered information.
func (g *Graph) GetSVG(date, mode string) (string, error) {
param, err := g.createGetSVGRequestParameter(date, mode)
if err != nil {
return "", errors.Wrapf(err, "failed to create get svg parameter")
}
b, err := mustDoRequest(param)
if err != nil {
return "", errors.Wrapf(err, "failed to do request")
}
return string(b), nil
}
func (g *Graph) createGetSVGRequestParameter(date, mode string) (*requestParameter, error) {
return &requestParameter{
Method: http.MethodGet,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s?date=%s&mode=%s", g.UserName, g.GraphID, date, mode),
Header: map[string]string{userToken: token},
Body: []byte{},
}, nil
}
// Specify the graph display mode.
// Supported modes are short (for displaying only about 90 days), badge (Badge format pasted on GitHub README.
// Information for the last 49 days is expressed in 7 pixels.), and line .
const (
ModeShort = "short"
ModeBadge = "badge"
ModeLine = "line"
)
// Specify the graph display mode in html format.
const (
ModeSimple = "simple"
ModeSimpleShort = "simple-short"
)
// URL displays the details of the graph in html format.
func (g *Graph) URL(mode string) string {
if len(mode) == 0 {
return fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s.html", g.UserName, g.GraphID)
}
return fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s.html?mode=%s", g.UserName, g.GraphID, mode)
}
// GraphsURL displays graph list by detail in html format.
func (g *Graph) GraphsURL() string {
return fmt.Sprintf(APIBaseURL+"/users/%s/graphs.html", g.UserName)
}
// Stats is various statistics based on the registered information.
type Stats struct {
TotalPixelsCount int `json:"totalPixelsCount"`
MaxQuantity int `json:"maxQuantity"`
MinQuantity int `json:"minQuantity"`
TotalQuantity int `json:"totalQuantity"`
AvgQuantity float64 `json:"avgQuantity"`
TodaysQuantity int `json:"todaysQuantity"`
Result
}
// Stats gets various statistics based on the registered information.
func (g *Graph) Stats() (*Stats, error) {
param, err := g.createStatsRequestParameter()
if err != nil {
return nil, errors.Wrapf(err, "failed to create graph stats request parameter")
}
b, err := doRequest(param)
if err != nil {
return nil, errors.Wrapf(err, "failed to do request")
}
var stats Stats
if err := json.Unmarshal(b, &stats); err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal json")
}
stats.IsSuccess = stats.Message == ""
return &stats, nil
}
func (g *Graph) createStatsRequestParameter() (*requestParameter, error) {
return &requestParameter{
Method: http.MethodGet,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s/stats", g.UserName, g.GraphID),
Header: map[string]string{},
Body: []byte{},
}, nil
}
// Update updates predefined pixelation graph definitions.
// The items that can be updated are limited as compared with the pixelation graph definition creation.
func (g *Graph) Update(name, unit, color, timezone string, purgeCacheUrls []string, selfSufficient string, isSecret bool, publishOptionalData bool) (*Result, error) {
param, err := g.createUpdateRequestParameter(name, unit, color, timezone, purgeCacheUrls, selfSufficient, isSecret, publishOptionalData)
if err != nil {
return &Result{}, errors.Wrapf(err, "failed to create graph update parameter")
}
return doRequestAndParseResponse(param)
}
func (g *Graph) createUpdateRequestParameter(name, unit, color, timezone string, purgeCacheUrls []string, selfSufficient string, isSecret, publishOptionalData bool) (*requestParameter, error) {
update := graphUpdate{
Name: name,
Unit: unit,
Color: color,
TimeZone: timezone,
PurgeCacheURLs: purgeCacheUrls,
SelfSufficient: selfSufficient,
IsSecret: isSecret,
PublishOptionalData: publishOptionalData,
}
b, err := json.Marshal(update)
if err != nil {
return &requestParameter{}, errors.Wrap(err, "failed to marshal json")
}
return &requestParameter{
Method: http.MethodPut,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s", g.UserName, g.GraphID),
Header: map[string]string{userToken: g.Token},
Body: b,
}, nil
}
type graphUpdate struct {
Name string `json:"name"`
Unit string `json:"unit"`
Color string `json:"color"`
TimeZone string `json:"timezone"`
PurgeCacheURLs []string `json:"purgeCacheURLs"`
SelfSufficient string `json:"selfSufficient"`
IsSecret bool `json:"isSecret"`
PublishOptionalData bool `json:"publishOptionalData"`
}
// Delete deletes the predefined pixelation graph definition.
func (g *Graph) Delete() (*Result, error) {
param, err := g.createDeleteRequestParameter()
if err != nil {
return &Result{}, errors.Wrapf(err, "failed to create graph delete parameter")
}
return doRequestAndParseResponse(param)
}
func (g *Graph) createDeleteRequestParameter() (*requestParameter, error) {
return &requestParameter{
Method: http.MethodDelete,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s", g.UserName, g.GraphID),
Header: map[string]string{userToken: g.Token},
Body: []byte{},
}, nil
}
// GetPixelDates gets a Date list of Pixel registered in the graph specified by graphID.
// You can specify a period with from and to parameters.
//
// If you do not specify both from and to;
// You will get a list of 365 days ago from today.
//
// If you specify from only;
// You will get a list of 365 days from from date.
//
// If you specify to only;
// You will get a list of 365 days ago from to date.
//
// If you specify both from andto;
// You will get a list you specify.
// You can not specify a period greater than 365 days.
func (g *Graph) GetPixelDates(from, to string) (*Pixels, error) {
param, err := g.createGetPixelDatesRequestParameter(from, to)
if err != nil {
return &Pixels{}, errors.Wrapf(err, "failed to create get pixel dates parameter")
}
b, err := doRequest(param)
if err != nil {
return &Pixels{}, errors.Wrapf(err, "failed to do request")
}
var pixels Pixels
if err := json.Unmarshal(b, &pixels); err != nil {
return &Pixels{}, errors.Wrapf(err, "failed to unmarshal json")
}
pixels.IsSuccess = pixels.Message == ""
return &pixels, nil
}
// Pixels is Date list of Pixel registered in the graph.
type Pixels struct {
Pixels []string `json:"pixels"`
Result
}
func (g *Graph) createGetPixelDatesRequestParameter(from, to string) (*requestParameter, error) {
return &requestParameter{
Method: http.MethodGet,
URL: fmt.Sprintf(APIBaseURL+"/users/%s/graphs/%s/pixels?from=%s&to=%s", g.UserName, g.GraphID, from, to),
Header: map[string]string{userToken: g.Token},
Body: []byte{},
}, nil
}