fizzy-cli 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/API.md +63 -2
- package/package.json +2 -1
- package/.github/workflows/release.yml +0 -29
- package/.github/workflows/tests.yml +0 -24
- package/AGENTS.md +0 -33
- package/CHANGELOG.md +0 -168
- package/Makefile +0 -43
- package/bin/fizzy +0 -0
- package/cmd/account.go +0 -14
- package/cmd/account_list.go +0 -44
- package/cmd/account_list_test.go +0 -118
- package/cmd/board.go +0 -49
- package/cmd/board_create.go +0 -59
- package/cmd/board_create_test.go +0 -141
- package/cmd/board_delete.go +0 -40
- package/cmd/board_delete_test.go +0 -121
- package/cmd/board_list.go +0 -44
- package/cmd/board_list_test.go +0 -115
- package/cmd/board_show.go +0 -40
- package/cmd/board_show_test.go +0 -113
- package/cmd/board_test.go +0 -92
- package/cmd/board_update.go +0 -72
- package/cmd/board_update_test.go +0 -233
- package/cmd/card.go +0 -24
- package/cmd/card_assign.go +0 -55
- package/cmd/card_assign_test.go +0 -130
- package/cmd/card_close.go +0 -46
- package/cmd/card_close_test.go +0 -92
- package/cmd/card_create.go +0 -72
- package/cmd/card_create_test.go +0 -186
- package/cmd/card_delete.go +0 -46
- package/cmd/card_delete_test.go +0 -92
- package/cmd/card_golden.go +0 -46
- package/cmd/card_golden_test.go +0 -92
- package/cmd/card_list.go +0 -53
- package/cmd/card_list_test.go +0 -148
- package/cmd/card_not_now.go +0 -46
- package/cmd/card_not_now_test.go +0 -92
- package/cmd/card_reopen.go +0 -46
- package/cmd/card_reopen_test.go +0 -92
- package/cmd/card_show.go +0 -46
- package/cmd/card_show_test.go +0 -92
- package/cmd/card_tag.go +0 -51
- package/cmd/card_tag_test.go +0 -112
- package/cmd/card_triage.go +0 -46
- package/cmd/card_ungolden.go +0 -46
- package/cmd/card_ungolden_test.go +0 -92
- package/cmd/card_untriage.go +0 -46
- package/cmd/card_untriage_test.go +0 -92
- package/cmd/card_unwatch.go +0 -46
- package/cmd/card_unwatch_test.go +0 -92
- package/cmd/card_update.go +0 -82
- package/cmd/card_update_test.go +0 -149
- package/cmd/card_watch.go +0 -46
- package/cmd/card_watch_test.go +0 -92
- package/cmd/column.go +0 -14
- package/cmd/column_create.go +0 -79
- package/cmd/column_create_test.go +0 -178
- package/cmd/column_delete.go +0 -40
- package/cmd/column_delete_test.go +0 -121
- package/cmd/column_list.go +0 -44
- package/cmd/column_list_test.go +0 -138
- package/cmd/column_show.go +0 -40
- package/cmd/column_show_test.go +0 -111
- package/cmd/column_update.go +0 -67
- package/cmd/column_update_test.go +0 -198
- package/cmd/comment.go +0 -14
- package/cmd/comment_create.go +0 -51
- package/cmd/comment_create_test.go +0 -129
- package/cmd/comment_delete.go +0 -46
- package/cmd/comment_delete_test.go +0 -92
- package/cmd/comment_list.go +0 -51
- package/cmd/comment_list_test.go +0 -132
- package/cmd/comment_show.go +0 -46
- package/cmd/comment_show_test.go +0 -104
- package/cmd/comment_update.go +0 -51
- package/cmd/comment_update_test.go +0 -130
- package/cmd/login.go +0 -81
- package/cmd/login_test.go +0 -98
- package/cmd/notification.go +0 -14
- package/cmd/notification_list.go +0 -69
- package/cmd/notification_list_test.go +0 -288
- package/cmd/notification_read.go +0 -51
- package/cmd/notification_read_all.go +0 -38
- package/cmd/notification_read_all_test.go +0 -75
- package/cmd/notification_read_test.go +0 -138
- package/cmd/notification_unread.go +0 -44
- package/cmd/notification_unread_test.go +0 -99
- package/cmd/reaction.go +0 -13
- package/cmd/reaction_create.go +0 -46
- package/cmd/reaction_create_test.go +0 -113
- package/cmd/reaction_delete.go +0 -46
- package/cmd/reaction_delete_test.go +0 -92
- package/cmd/reaction_list.go +0 -51
- package/cmd/reaction_list_test.go +0 -125
- package/cmd/root.go +0 -38
- package/cmd/step.go +0 -14
- package/cmd/step_create.go +0 -53
- package/cmd/step_create_test.go +0 -171
- package/cmd/step_delete.go +0 -46
- package/cmd/step_delete_test.go +0 -92
- package/cmd/step_update.go +0 -66
- package/cmd/step_update_test.go +0 -190
- package/cmd/tag.go +0 -15
- package/cmd/tag_list.go +0 -47
- package/cmd/tag_list_test.go +0 -109
- package/cmd/use.go +0 -85
- package/cmd/use_test.go +0 -186
- package/go.mod +0 -31
- package/go.sum +0 -53
- package/internal/api/boards.go +0 -93
- package/internal/api/cards.go +0 -288
- package/internal/api/client.go +0 -99
- package/internal/api/columns.go +0 -113
- package/internal/api/comments.go +0 -108
- package/internal/api/identity.go +0 -24
- package/internal/api/notifications.go +0 -89
- package/internal/api/reactions.go +0 -69
- package/internal/api/steps.go +0 -101
- package/internal/api/tags.go +0 -24
- package/internal/api/types.go +0 -190
- package/internal/app/app.go +0 -49
- package/internal/colors/colors.go +0 -32
- package/internal/config/config.go +0 -70
- package/internal/testutil/client.go +0 -26
- package/internal/ui/account_list.go +0 -14
- package/internal/ui/account_selector.go +0 -63
- package/internal/ui/board_list.go +0 -14
- package/internal/ui/board_show.go +0 -17
- package/internal/ui/card_list.go +0 -14
- package/internal/ui/card_show.go +0 -23
- package/internal/ui/column_list.go +0 -28
- package/internal/ui/column_show.go +0 -16
- package/internal/ui/comment_list.go +0 -25
- package/internal/ui/format.go +0 -27
- package/internal/ui/notification_list.go +0 -27
- package/internal/ui/reaction_list.go +0 -14
package/internal/api/cards.go
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
package api
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"fmt"
|
|
6
|
-
"net/http"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
func (c *Client) GetCards(ctx context.Context, filters CardFilters) ([]Card, error) {
|
|
10
|
-
endpointURL := c.AccountBaseURL + "/cards"
|
|
11
|
-
|
|
12
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
13
|
-
if err != nil {
|
|
14
|
-
return nil, fmt.Errorf("failed to create get cards request: %w", err)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if len(filters.BoardIDs) > 0 {
|
|
18
|
-
q := req.URL.Query()
|
|
19
|
-
for _, boardID := range filters.BoardIDs {
|
|
20
|
-
q.Add("board_ids[]", boardID)
|
|
21
|
-
}
|
|
22
|
-
req.URL.RawQuery = q.Encode()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
var response []Card
|
|
26
|
-
_, err = c.decodeResponse(req, &response)
|
|
27
|
-
if err != nil {
|
|
28
|
-
return nil, err
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return response, nil
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
func (c *Client) GetCard(ctx context.Context, cardNumber int) (*Card, error) {
|
|
35
|
-
endpointURL := fmt.Sprintf("%s/cards/%d", c.AccountBaseURL, cardNumber)
|
|
36
|
-
|
|
37
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
38
|
-
if err != nil {
|
|
39
|
-
return nil, fmt.Errorf("failed to create get card by id request: %w", err)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
var response Card
|
|
43
|
-
_, err = c.decodeResponse(req, &response)
|
|
44
|
-
if err != nil {
|
|
45
|
-
return nil, err
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return &response, nil
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
func (c *Client) PostCards(ctx context.Context, payload CreateCardPayload) (bool, error) {
|
|
52
|
-
if c.BoardBaseURL == "" {
|
|
53
|
-
return false, fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
endpointURL := c.BoardBaseURL + "/cards"
|
|
57
|
-
|
|
58
|
-
body := map[string]CreateCardPayload{"card": payload}
|
|
59
|
-
|
|
60
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, body)
|
|
61
|
-
if err != nil {
|
|
62
|
-
return false, fmt.Errorf("failed to create card request: %w", err)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
_, err = c.decodeResponse(req, nil, http.StatusCreated)
|
|
66
|
-
if err != nil {
|
|
67
|
-
return false, err
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return true, nil
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
func (c *Client) PutCard(ctx context.Context, cardNumber int, payload UpdateCardPayload) (*Card, error) {
|
|
74
|
-
endpointURL := fmt.Sprintf("%s/cards/%d", c.AccountBaseURL, cardNumber)
|
|
75
|
-
|
|
76
|
-
body := map[string]UpdateCardPayload{"card": payload}
|
|
77
|
-
|
|
78
|
-
req, err := c.newRequest(ctx, http.MethodPut, endpointURL, body)
|
|
79
|
-
if err != nil {
|
|
80
|
-
return nil, fmt.Errorf("failed to create update card request: %w", err)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
var response Card
|
|
84
|
-
_, err = c.decodeResponse(req, &response, http.StatusOK)
|
|
85
|
-
if err != nil {
|
|
86
|
-
return nil, err
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return &response, nil
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
func (c *Client) DeleteCard(ctx context.Context, cardNumber int) (bool, error) {
|
|
93
|
-
endpointURL := fmt.Sprintf("%s/cards/%d", c.AccountBaseURL, cardNumber)
|
|
94
|
-
|
|
95
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
96
|
-
if err != nil {
|
|
97
|
-
return false, fmt.Errorf("failed to create delete card request: %w", err)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
101
|
-
if err != nil {
|
|
102
|
-
return false, err
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return true, nil
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
func (c *Client) PostCardsClosure(ctx context.Context, cardNumber int) (bool, error) {
|
|
109
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/closure", c.AccountBaseURL, cardNumber)
|
|
110
|
-
|
|
111
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, nil)
|
|
112
|
-
if err != nil {
|
|
113
|
-
return false, fmt.Errorf("failed to create closure card request: %w", err)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
117
|
-
if err != nil {
|
|
118
|
-
return false, err
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return true, nil
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
func (c *Client) PostCardNotNow(ctx context.Context, cardNumber int) (bool, error) {
|
|
125
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/not_now", c.AccountBaseURL, cardNumber)
|
|
126
|
-
|
|
127
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, nil)
|
|
128
|
-
if err != nil {
|
|
129
|
-
return false, fmt.Errorf("failed to create post not now request: %w", err)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
133
|
-
if err != nil {
|
|
134
|
-
return false, err
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return true, nil
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
func (c *Client) PostCardTriage(ctx context.Context, cardNumber int, columnID string) (bool, error) {
|
|
141
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/triage", c.AccountBaseURL, cardNumber)
|
|
142
|
-
|
|
143
|
-
body := map[string]any{"column_id": columnID}
|
|
144
|
-
|
|
145
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, body)
|
|
146
|
-
if err != nil {
|
|
147
|
-
return false, fmt.Errorf("failed to create post triage request: %w", err)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
151
|
-
if err != nil {
|
|
152
|
-
return false, err
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return true, nil
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
func (c *Client) DeleteCardTriage(ctx context.Context, cardNumber int) (bool, error) {
|
|
159
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/triage", c.AccountBaseURL, cardNumber)
|
|
160
|
-
|
|
161
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
162
|
-
if err != nil {
|
|
163
|
-
return false, fmt.Errorf("failed to create delete triage request: %w", err)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
167
|
-
if err != nil {
|
|
168
|
-
return false, err
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return true, nil
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
func (c *Client) PostCardWatch(ctx context.Context, cardNumber int) (bool, error) {
|
|
175
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/watch", c.AccountBaseURL, cardNumber)
|
|
176
|
-
|
|
177
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, nil)
|
|
178
|
-
if err != nil {
|
|
179
|
-
return false, fmt.Errorf("failed to create post watch request: %w", err)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
183
|
-
if err != nil {
|
|
184
|
-
return false, err
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return true, nil
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
func (c *Client) DeleteCardWatch(ctx context.Context, cardNumber int) (bool, error) {
|
|
191
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/watch", c.AccountBaseURL, cardNumber)
|
|
192
|
-
|
|
193
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
194
|
-
if err != nil {
|
|
195
|
-
return false, fmt.Errorf("failed to create delete watch request: %w", err)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
199
|
-
if err != nil {
|
|
200
|
-
return false, err
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return true, nil
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
func (c *Client) PostCardGoldenness(ctx context.Context, cardNumber int) (bool, error) {
|
|
207
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/goldness", c.AccountBaseURL, cardNumber)
|
|
208
|
-
|
|
209
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, nil)
|
|
210
|
-
if err != nil {
|
|
211
|
-
return false, fmt.Errorf("failed to create post goldness request: %w", err)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
215
|
-
if err != nil {
|
|
216
|
-
return false, err
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return true, nil
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
func (c *Client) DeleteCardGoldenness(ctx context.Context, cardNumber int) (bool, error) {
|
|
223
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/goldness", c.AccountBaseURL, cardNumber)
|
|
224
|
-
|
|
225
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
226
|
-
if err != nil {
|
|
227
|
-
return false, fmt.Errorf("failed to create delete goldness request: %w", err)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
231
|
-
if err != nil {
|
|
232
|
-
return false, err
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return true, nil
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
func (c *Client) DeleteCardsClosure(ctx context.Context, cardNumber int) (bool, error) {
|
|
239
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/closure", c.AccountBaseURL, cardNumber)
|
|
240
|
-
|
|
241
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
242
|
-
if err != nil {
|
|
243
|
-
return false, fmt.Errorf("failed to create delete closure card request: %w", err)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
247
|
-
if err != nil {
|
|
248
|
-
return false, err
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return true, nil
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
func (c *Client) PostCardAssignments(ctx context.Context, cardNumber int, userID string) (bool, error) {
|
|
255
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/assignments", c.AccountBaseURL, cardNumber)
|
|
256
|
-
|
|
257
|
-
body := map[string]string{"assignee_id": userID}
|
|
258
|
-
|
|
259
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, body)
|
|
260
|
-
if err != nil {
|
|
261
|
-
return false, fmt.Errorf("failed to create assignment request: %w", err)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
265
|
-
if err != nil {
|
|
266
|
-
return false, err
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return true, nil
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
func (c *Client) PostCardTagging(ctx context.Context, cardNumber int, tagTitle string) (bool, error) {
|
|
273
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/taggings", c.AccountBaseURL, cardNumber)
|
|
274
|
-
|
|
275
|
-
body := map[string]string{"tag_title": tagTitle}
|
|
276
|
-
|
|
277
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, body)
|
|
278
|
-
if err != nil {
|
|
279
|
-
return false, fmt.Errorf("failed to create tagging request: %w", err)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
283
|
-
if err != nil {
|
|
284
|
-
return false, err
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return true, nil
|
|
288
|
-
}
|
package/internal/api/client.go
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// Package api provides the Fizzy API client
|
|
2
|
-
package api
|
|
3
|
-
|
|
4
|
-
import (
|
|
5
|
-
"bytes"
|
|
6
|
-
"context"
|
|
7
|
-
"encoding/json"
|
|
8
|
-
"fmt"
|
|
9
|
-
"io"
|
|
10
|
-
"net/http"
|
|
11
|
-
"os"
|
|
12
|
-
"time"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
type Client struct {
|
|
16
|
-
BaseURL string
|
|
17
|
-
AccountBaseURL string
|
|
18
|
-
BoardBaseURL string
|
|
19
|
-
AccessToken string
|
|
20
|
-
HTTPClient *http.Client
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
func NewClient(accountSlug string, boardID string) (*Client, error) {
|
|
24
|
-
baseURL := "https://app.fizzy.do"
|
|
25
|
-
accountBaseURL := baseURL + accountSlug
|
|
26
|
-
|
|
27
|
-
var boardBaseURL string
|
|
28
|
-
if boardID != "" {
|
|
29
|
-
boardBaseURL = accountBaseURL + "/boards" + "/" + boardID
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
token, isSet := os.LookupEnv("FIZZY_ACCESS_TOKEN")
|
|
33
|
-
if !isSet || token == "" {
|
|
34
|
-
return nil, fmt.Errorf("FIZZY_ACCESS_TOKEN environment variable is not set")
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return &Client{
|
|
38
|
-
BaseURL: baseURL,
|
|
39
|
-
AccountBaseURL: accountBaseURL,
|
|
40
|
-
BoardBaseURL: boardBaseURL,
|
|
41
|
-
AccessToken: token,
|
|
42
|
-
HTTPClient: &http.Client{Timeout: 30 * time.Second},
|
|
43
|
-
}, nil
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// newRequest makes an HTTP request with the required headers setup
|
|
47
|
-
func (c *Client) newRequest(ctx context.Context, method, url string, body any) (*http.Request, error) {
|
|
48
|
-
var bodyReader io.Reader
|
|
49
|
-
if body != nil {
|
|
50
|
-
data, err := json.Marshal(body)
|
|
51
|
-
if err != nil {
|
|
52
|
-
return nil, fmt.Errorf("failed to marshal request body: %w", err)
|
|
53
|
-
}
|
|
54
|
-
bodyReader = bytes.NewReader(data)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
req, err := http.NewRequestWithContext(ctx, method, url, bodyReader)
|
|
58
|
-
if err != nil {
|
|
59
|
-
return nil, err
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.AccessToken))
|
|
63
|
-
req.Header.Set("Accept", "application/json")
|
|
64
|
-
req.Header.Set("Content-Type", "application/json")
|
|
65
|
-
|
|
66
|
-
return req, nil
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// decodeResponse executes a request and decodes the JSON response into v
|
|
70
|
-
// If expectedStatus is 0, it defaults to http.StatusOK
|
|
71
|
-
// If v is nil, the response body is not decoded
|
|
72
|
-
func (c *Client) decodeResponse(req *http.Request, v any, expectedStatus ...int) (int, error) {
|
|
73
|
-
expectedCode := http.StatusOK
|
|
74
|
-
if len(expectedStatus) > 0 {
|
|
75
|
-
expectedCode = expectedStatus[0]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
res, err := c.HTTPClient.Do(req)
|
|
79
|
-
if err != nil {
|
|
80
|
-
return 0, fmt.Errorf("failed to make request: %w", err)
|
|
81
|
-
}
|
|
82
|
-
defer res.Body.Close()
|
|
83
|
-
|
|
84
|
-
if res.StatusCode != expectedCode {
|
|
85
|
-
body, err := io.ReadAll(res.Body)
|
|
86
|
-
if err != nil {
|
|
87
|
-
return 0, fmt.Errorf("unexpected status code %d (failed to read error response: %w)", res.StatusCode, err)
|
|
88
|
-
}
|
|
89
|
-
return 0, fmt.Errorf("unexpected status code %d: %s", res.StatusCode, string(body))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if v != nil {
|
|
93
|
-
if err := json.NewDecoder(res.Body).Decode(v); err != nil {
|
|
94
|
-
return 0, fmt.Errorf("failed to decode response: %w", err)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return res.StatusCode, nil
|
|
99
|
-
}
|
package/internal/api/columns.go
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
package api
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"fmt"
|
|
6
|
-
"net/http"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
func (c *Client) GetColumns(ctx context.Context) ([]Column, error) {
|
|
10
|
-
if c.BoardBaseURL == "" {
|
|
11
|
-
return nil, fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
endpointURL := c.BoardBaseURL + "/columns"
|
|
15
|
-
|
|
16
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
17
|
-
if err != nil {
|
|
18
|
-
return nil, fmt.Errorf("failed to create get columns request: %w", err)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
var response []Column
|
|
22
|
-
_, err = c.decodeResponse(req, &response)
|
|
23
|
-
if err != nil {
|
|
24
|
-
return nil, err
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return response, nil
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
func (c *Client) GetColumn(ctx context.Context, columnID string) (*Column, error) {
|
|
31
|
-
if c.BoardBaseURL == "" {
|
|
32
|
-
return nil, fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
endpointURL := c.BoardBaseURL + "/columns/" + columnID
|
|
36
|
-
|
|
37
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
38
|
-
if err != nil {
|
|
39
|
-
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
var response Column
|
|
43
|
-
_, err = c.decodeResponse(req, &response)
|
|
44
|
-
if err != nil {
|
|
45
|
-
return nil, err
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return &response, nil
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
func (c *Client) PostColumns(ctx context.Context, payload CreateColumnPayload) (bool, error) {
|
|
52
|
-
if c.BoardBaseURL == "" {
|
|
53
|
-
return false, fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
endpointURL := c.BoardBaseURL + "/columns"
|
|
57
|
-
|
|
58
|
-
body := map[string]CreateColumnPayload{"column": payload}
|
|
59
|
-
|
|
60
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, body)
|
|
61
|
-
if err != nil {
|
|
62
|
-
return false, fmt.Errorf("failed to create column request: %w", err)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
_, err = c.decodeResponse(req, nil, http.StatusCreated)
|
|
66
|
-
if err != nil {
|
|
67
|
-
return false, err
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return true, nil
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
func (c *Client) PutColumn(ctx context.Context, columnID string, payload UpdateColumnPayload) error {
|
|
74
|
-
if c.BoardBaseURL == "" {
|
|
75
|
-
return fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
endpointURL := c.BoardBaseURL + "/columns/" + columnID
|
|
79
|
-
|
|
80
|
-
body := map[string]UpdateColumnPayload{"column": payload}
|
|
81
|
-
|
|
82
|
-
req, err := c.newRequest(ctx, http.MethodPut, endpointURL, body)
|
|
83
|
-
if err != nil {
|
|
84
|
-
return fmt.Errorf("failed to create update column request: %w", err)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
88
|
-
if err != nil {
|
|
89
|
-
return err
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return nil
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
func (c *Client) DeleteColumn(ctx context.Context, columnID string) error {
|
|
96
|
-
if c.BoardBaseURL == "" {
|
|
97
|
-
return fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
endpointURL := c.BoardBaseURL + "/columns/" + columnID
|
|
101
|
-
|
|
102
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
103
|
-
if err != nil {
|
|
104
|
-
return fmt.Errorf("failed to create delete column request: %w", err)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
108
|
-
if err != nil {
|
|
109
|
-
return err
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return nil
|
|
113
|
-
}
|
package/internal/api/comments.go
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
package api
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"fmt"
|
|
6
|
-
"io"
|
|
7
|
-
"net/http"
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
func (c *Client) GetCardComments(ctx context.Context, cardNumber int) ([]Comment, error) {
|
|
11
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/comments", c.AccountBaseURL, cardNumber)
|
|
12
|
-
|
|
13
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
14
|
-
if err != nil {
|
|
15
|
-
return nil, fmt.Errorf("failed to create get card comments request: %w", err)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
var response []Comment
|
|
19
|
-
_, err = c.decodeResponse(req, &response)
|
|
20
|
-
if err != nil {
|
|
21
|
-
return nil, err
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return response, nil
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
func (c *Client) GetCardComment(ctx context.Context, cardNumber int, commentID string) (*Comment, error) {
|
|
28
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/comments/%s", c.AccountBaseURL, cardNumber, commentID)
|
|
29
|
-
|
|
30
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
31
|
-
if err != nil {
|
|
32
|
-
return nil, fmt.Errorf("failed to create get card comment request: %w", err)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
var response Comment
|
|
36
|
-
_, err = c.decodeResponse(req, &response)
|
|
37
|
-
if err != nil {
|
|
38
|
-
return nil, err
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return &response, nil
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
func (c *Client) PostCardComment(ctx context.Context, cardNumber int, body string) (*Comment, error) {
|
|
45
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/comments", c.AccountBaseURL, cardNumber)
|
|
46
|
-
|
|
47
|
-
payload := map[string]map[string]string{
|
|
48
|
-
"comment": {"body": body},
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, payload)
|
|
52
|
-
if err != nil {
|
|
53
|
-
return nil, fmt.Errorf("failed to create post card comment request: %w", err)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
res, err := c.HTTPClient.Do(req)
|
|
57
|
-
if err != nil {
|
|
58
|
-
return nil, fmt.Errorf("failed to make request: %w", err)
|
|
59
|
-
}
|
|
60
|
-
defer res.Body.Close()
|
|
61
|
-
|
|
62
|
-
if res.StatusCode != http.StatusCreated {
|
|
63
|
-
body, _ := io.ReadAll(res.Body)
|
|
64
|
-
return nil, fmt.Errorf("unexpected status code %d: %s", res.StatusCode, string(body))
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// API returns 201 Created with Location header, not a response body
|
|
68
|
-
// Return a minimal Comment object with empty fields
|
|
69
|
-
// The comment ID would be in the Location header but we'll use it to fetch full details
|
|
70
|
-
return &Comment{}, nil
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
func (c *Client) PutCardComment(ctx context.Context, cardNumber int, commentID string, body string) (*Comment, error) {
|
|
74
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/comments/%s", c.AccountBaseURL, cardNumber, commentID)
|
|
75
|
-
|
|
76
|
-
payload := map[string]map[string]string{
|
|
77
|
-
"comment": {"body": body},
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
req, err := c.newRequest(ctx, http.MethodPut, endpointURL, payload)
|
|
81
|
-
if err != nil {
|
|
82
|
-
return nil, fmt.Errorf("failed to create put card comment request: %w", err)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
var response Comment
|
|
86
|
-
_, err = c.decodeResponse(req, &response)
|
|
87
|
-
if err != nil {
|
|
88
|
-
return nil, err
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return &response, nil
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
func (c *Client) DeleteCardComment(ctx context.Context, cardNumber int, commentID string) (bool, error) {
|
|
95
|
-
endpointURL := fmt.Sprintf("%s/cards/%d/comments/%s", c.AccountBaseURL, cardNumber, commentID)
|
|
96
|
-
|
|
97
|
-
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
98
|
-
if err != nil {
|
|
99
|
-
return false, fmt.Errorf("failed to create delete card comment request: %w", err)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
103
|
-
if err != nil {
|
|
104
|
-
return false, err
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return true, nil
|
|
108
|
-
}
|
package/internal/api/identity.go
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
package api
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"fmt"
|
|
6
|
-
"net/http"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
func (c *Client) GetMyIdentity(ctx context.Context) (*GetMyIdentityResponse, error) {
|
|
10
|
-
endpointURL := c.BaseURL + "/my/identity"
|
|
11
|
-
|
|
12
|
-
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
13
|
-
if err != nil {
|
|
14
|
-
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
var response GetMyIdentityResponse
|
|
18
|
-
_, err = c.decodeResponse(req, &response)
|
|
19
|
-
if err != nil {
|
|
20
|
-
return nil, err
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return &response, nil
|
|
24
|
-
}
|