Skip to content

Commit 5cfcf73

Browse files
committed
added template list
1 parent 9fcda19 commit 5cfcf73

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

cli/template/list.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package template
19+
20+
import (
21+
"fmt"
22+
"os"
23+
24+
"github.com/arduino/arduino-cli/cli/errorcodes"
25+
"github.com/arduino/arduino-cli/cli/feedback"
26+
"github.com/arduino/arduino-cloud-cli/command/template"
27+
"github.com/arduino/arduino-cloud-cli/config"
28+
"github.com/spf13/cobra"
29+
)
30+
31+
func initTemplateListCommand() *cobra.Command {
32+
listCommand := &cobra.Command{
33+
Use: "list",
34+
Short: "List templates",
35+
Long: "List available templates",
36+
Run: func(cmd *cobra.Command, args []string) {
37+
if err := runTemplateListCommand(); err != nil {
38+
feedback.Errorf("Error during template list: %v", err)
39+
os.Exit(errorcodes.ErrGeneric)
40+
}
41+
},
42+
}
43+
44+
return listCommand
45+
}
46+
47+
func runTemplateListCommand() error {
48+
cred, err := config.RetrieveCredentials()
49+
if err != nil {
50+
return fmt.Errorf("retrieving credentials: %w", err)
51+
}
52+
return template.ListustomTemplate(cred)
53+
}

cli/template/template.go

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func NewCommand() *cobra.Command {
3030

3131
templateCommand.AddCommand(initTemplateImportCommand())
3232
templateCommand.AddCommand(initTemplateExportCommand())
33+
templateCommand.AddCommand(initTemplateListCommand())
3334

3435
return templateCommand
3536
}

command/template/list.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package template
19+
20+
import (
21+
"github.com/arduino/arduino-cli/cli/feedback"
22+
"github.com/arduino/arduino-cloud-cli/config"
23+
storageapi "github.com/arduino/arduino-cloud-cli/internal/storage-api"
24+
)
25+
26+
func ListustomTemplate(cred *config.Credentials) error {
27+
28+
apiclient := storageapi.NewClient(cred)
29+
30+
templates, err := apiclient.ListCustomTemplate()
31+
if err != nil {
32+
return err
33+
}
34+
35+
feedback.PrintResult(templates)
36+
37+
return nil
38+
}

internal/storage-api/client.go

+71
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,22 @@ func (c *StorageApiClient) performBinaryGetRequest(endpoint, token string) (*htt
125125
return res, nil
126126
}
127127

128+
func (c *StorageApiClient) performBinaryPostRequest(endpoint, token string, body io.Reader) (*http.Response, error) {
129+
req, err := http.NewRequest("POST", endpoint, body)
130+
if err != nil {
131+
return nil, err
132+
}
133+
req.Header.Add("Authorization", "Bearer "+token)
134+
if c.organization != "" {
135+
req.Header.Add("X-Organization", c.organization)
136+
}
137+
res, err := c.client.Do(req)
138+
if err != nil {
139+
return nil, err
140+
}
141+
return res, nil
142+
}
143+
128144
func (c *StorageApiClient) ImportCustomTemplate(templateFile string) (*ImportCustomTemplateResponse, error) {
129145

130146
if templateFile == "" {
@@ -273,3 +289,58 @@ func extractFileNameFromHeader(res *http.Response) string {
273289
}
274290
return ""
275291
}
292+
293+
type listPostRequest struct {
294+
Sort string `json:"sort"`
295+
}
296+
297+
func (c *StorageApiClient) ListCustomTemplate() (*TemplatesListResponse, error) {
298+
userRequestToken, err := c.src.Token()
299+
if err != nil {
300+
if strings.Contains(err.Error(), "401") {
301+
return nil, errors.New("wrong credentials")
302+
}
303+
return nil, fmt.Errorf("cannot retrieve a valid token: %w", err)
304+
}
305+
306+
request := listPostRequest{
307+
Sort: "asc",
308+
}
309+
jsonRequest, err := json.Marshal(request)
310+
if err != nil {
311+
return nil, err
312+
}
313+
314+
endpoint := c.host + "/storage/template/v1/list"
315+
res, err := c.performBinaryPostRequest(endpoint, userRequestToken.AccessToken, bytes.NewReader(jsonRequest))
316+
if err != nil {
317+
return nil, err
318+
}
319+
defer res.Body.Close()
320+
321+
logrus.Debugf("List templates API call status: %d", res.StatusCode)
322+
323+
if res.StatusCode == 200 || res.StatusCode == 201 {
324+
var templatesListResponse TemplatesListResponse
325+
respBytes, err := io.ReadAll(res.Body)
326+
if err != nil {
327+
return nil, err
328+
}
329+
err = json.Unmarshal(respBytes, &templatesListResponse)
330+
if err != nil {
331+
return nil, err
332+
}
333+
return &templatesListResponse, nil
334+
} else if res.StatusCode == 400 {
335+
bodyb, _ := io.ReadAll(res.Body)
336+
return nil, fmt.Errorf("bad request: %s", string(bodyb))
337+
} else if res.StatusCode == 401 {
338+
return nil, errors.New("unauthorized request")
339+
} else if res.StatusCode == 403 {
340+
return nil, errors.New("forbidden request")
341+
} else if res.StatusCode == 500 {
342+
return nil, errors.New("internal server error")
343+
}
344+
345+
return nil, err
346+
}

internal/storage-api/dto.go

+45
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,55 @@
1717

1818
package storageapi
1919

20+
import (
21+
"time"
22+
23+
"github.com/arduino/arduino-cli/table"
24+
)
25+
2026
type (
2127
ImportCustomTemplateResponse struct {
2228
Message string `json:"message"`
2329
Name string `json:"name"`
2430
TemplateId string `json:"template_id"`
2531
}
32+
TemplateEntry struct {
33+
TemplateId string `json:"template_id"`
34+
Name string `json:"name"`
35+
CreatedAt string `json:"created_at"`
36+
}
37+
TemplatesListResponse struct {
38+
Templates []TemplateEntry `json:"templates"`
39+
}
2640
)
41+
42+
func (r *TemplatesListResponse) Data() interface{} {
43+
return r.Templates
44+
}
45+
46+
func (r *TemplatesListResponse) String() string {
47+
if len(r.Templates) == 0 {
48+
return ""
49+
}
50+
t := table.New()
51+
t.SetHeader("Template ID", "Name", "Created At")
52+
53+
// Now print the table
54+
for _, tem := range r.Templates {
55+
line := []any{tem.TemplateId, tem.Name, formatHumanReadableTs(tem.CreatedAt)}
56+
t.AddRow(line...)
57+
}
58+
59+
return t.Render()
60+
}
61+
62+
func formatHumanReadableTs(ts string) string {
63+
if ts == "" {
64+
return ""
65+
}
66+
parsed, err := time.Parse(time.RFC3339Nano, ts)
67+
if err != nil {
68+
return ts
69+
}
70+
return parsed.Format(time.RFC3339)
71+
}

0 commit comments

Comments
 (0)