From 88a7a84281d72291de30f0d8ae24f810d8025fda Mon Sep 17 00:00:00 2001 From: Nicolas Carlier Date: Mon, 22 Aug 2016 11:49:19 +0200 Subject: [PATCH] feat(label): Full feature label commands. --- ROADMAP.md | 5 +- api/label.go | 125 +++++++++++++++++++++++++++++++++++++++-- cmd/cmd.go | 38 ++++++++++--- cmd/create_document.go | 3 +- cmd/create_label.go | 60 ++++++++++++++++++++ cmd/get_document.go | 8 +-- cmd/get_label.go | 55 ++++++++++++++++++ cmd/remove_label.go | 42 ++++++++++++++ cmd/restore_label.go | 46 +++++++++++++++ 9 files changed, 360 insertions(+), 22 deletions(-) create mode 100644 cmd/create_label.go create mode 100644 cmd/get_label.go create mode 100644 cmd/remove_label.go create mode 100644 cmd/restore_label.go diff --git a/ROADMAP.md b/ROADMAP.md index c042aa1..f06f392 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,8 +1,9 @@ # Roadmap -- Full feature document command (update, etc.) -- Full feature label command (CRUD, restore) +- Full feature document command (update, get json, content-type, upload file, + ...) - Full feature attachment command +- Full feature admin commands - Create MAN: https://github.com/spf13/cobra/blob/master/doc/man_docs.md - Have bash completion: https://github.com/spf13/cobra/blob/master/bash_completions.md diff --git a/api/label.go b/api/label.go index 0bca377..35e794c 100644 --- a/api/label.go +++ b/api/label.go @@ -1,20 +1,22 @@ package api import ( + "bytes" "encoding/json" "errors" + "fmt" "io" "net/http" "os" ) type LabelResponse struct { - Id string `json:id` - Label string `json:label` - Color string `json:color` - Date string `json:date` - Owner string `json:owner` - Ghost bool `json:ghost` + Id string `json:"id,omitempty"` + Label string `json:"label,omitempty"` + Color string `json:"color,omitempty"` + Date string `json:"date,omitempty"` + Owner string `json:"owner,omitempty"` + Ghost bool `json:"ghost,omitempty"` } type LabelsResponse struct { @@ -47,3 +49,114 @@ func (k *Client) GetLabels() ([]LabelResponse, error) { err = json.NewDecoder(res.Body).Decode(&result) return result.Labels, err } + +func (k *Client) GetLabel(id string) (*LabelResponse, error) { + accessToken, err := GetAccessToken(k.Config) + if err != nil { + return nil, err + } + + client := &http.Client{} + req, err := http.NewRequest("GET", k.Config.Endpoint+"/v2/label/"+id, nil) + if err != nil { + return nil, err + } + req.Header.Add("Authorization", "Bearer "+accessToken) + res, err := client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode >= 400 { + io.Copy(os.Stderr, res.Body) + return nil, errors.New(res.Status) + } + + var result LabelResponse + err = json.NewDecoder(res.Body).Decode(&result) + return &result, err +} + +func (k *Client) CreateLabel(label *LabelResponse) (*LabelResponse, error) { + accessToken, err := GetAccessToken(k.Config) + if err != nil { + return nil, err + } + + b := new(bytes.Buffer) + json.NewEncoder(b).Encode(label) + fmt.Fprintf(os.Stdout, "Posting: %s", b) + + client := &http.Client{} + req, err := http.NewRequest("POST", k.Config.Endpoint+"/v2/label", b) + if err != nil { + return nil, err + } + req.Header.Add("Authorization", "Bearer "+accessToken) + req.Header.Set("Content-Type", "application/json") + + res, err := client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode >= 400 { + io.Copy(os.Stderr, res.Body) + return nil, errors.New(res.Status) + } + + var result LabelResponse + err = json.NewDecoder(res.Body).Decode(&result) + return &result, err +} + +func (k *Client) RemoveLabel(id string) error { + accessToken, err := GetAccessToken(k.Config) + if err != nil { + return err + } + + client := &http.Client{} + req, err := http.NewRequest("DELETE", k.Config.Endpoint+"/v2/label/"+id, nil) + if err != nil { + return err + } + req.Header.Add("Authorization", "Bearer "+accessToken) + res, err := client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + if res.StatusCode >= 400 { + io.Copy(os.Stderr, res.Body) + return errors.New(res.Status) + } + return nil +} + +func (k *Client) RestoreLabel(id string) (*LabelResponse, error) { + accessToken, err := GetAccessToken(k.Config) + if err != nil { + return nil, err + } + + client := &http.Client{} + req, err := http.NewRequest("POST", k.Config.Endpoint+"/v2/label/"+id+"/restore", nil) + if err != nil { + return nil, err + } + req.Header.Add("Authorization", "Bearer "+accessToken) + res, err := client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode >= 400 { + io.Copy(os.Stderr, res.Body) + return nil, errors.New(res.Status) + } + + var result LabelResponse + err = json.NewDecoder(res.Body).Decode(&result) + return &result, err +} diff --git a/cmd/cmd.go b/cmd/cmd.go index 9fc6b5c..8b26d73 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -64,15 +64,37 @@ func NewKeepctlCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer) *co cmds.AddCommand(NewCmdLogin(f, out)) cmds.AddCommand(NewCmdLogout(f, out)) cmds.AddCommand(NewCmdProfile(f, out)) - cmds.AddCommand(NewCmdGetDocument(f, out)) - cmds.AddCommand(NewCmdCreateDocument(f, out)) - cmds.AddCommand(NewCmdRemoveDocument(f, out)) - cmds.AddCommand(NewCmdRestoreDocument(f, out)) + + // get + cmd_get := NewCmdGetDocument(f, out) + cmd_get.AddCommand(NewCmdGetLabel(f, out)) + cmds.AddCommand(cmd_get) + + // create + cmd_create := NewCmdCreateDocument(f, out) + cmd_create.AddCommand(NewCmdCreateLabel(f, out)) + cmds.AddCommand(cmd_create) + + // rm + cmd_rm := NewCmdRemoveDocument(f, out) + cmd_rm.AddCommand(NewCmdRemoveLabel(f, out)) + cmds.AddCommand(cmd_rm) + + // restore + cmd_re := NewCmdRestoreDocument(f, out) + cmd_re.AddCommand(NewCmdRestoreLabel(f, out)) + cmds.AddCommand(cmd_re) + + // destroy cmds.AddCommand(NewCmdDestroyDocument(f, out)) - cmdList := NewCmdListDocuments(f, out) - cmdList.AddCommand(NewCmdListTrash(f, out)) - cmdList.AddCommand(NewCmdListLabels(f, out)) - cmds.AddCommand(cmdList) + + //ls + cmd_ls := NewCmdListDocuments(f, out) + cmd_ls.AddCommand(NewCmdListTrash(f, out)) + cmd_ls.AddCommand(NewCmdListLabels(f, out)) + cmds.AddCommand(cmd_ls) + + // empty cmds.AddCommand(NewCmdEmptyTrash(f, out)) return cmds diff --git a/cmd/create_document.go b/cmd/create_document.go index 7c19412..1e07b84 100644 --- a/cmd/create_document.go +++ b/cmd/create_document.go @@ -15,7 +15,6 @@ import ( ) type createOptions struct { - stdin bool title string content string url string @@ -50,7 +49,7 @@ func runCreateDocument(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, op content = buf.String() } - if !opts.stdin && opts.title == "" && content == "" && opts.url == "" { + if opts.title == "" && content == "" && opts.url == "" { return errors.New("You have to specify at least a title, a content or an url.") } diff --git a/cmd/create_label.go b/cmd/create_label.go new file mode 100644 index 0000000..41a3561 --- /dev/null +++ b/cmd/create_label.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "errors" + "io" + "text/template" + + "github.com/spf13/cobra" + + "github.com/ncarlier/keeper-cli/api" + cmdutil "github.com/ncarlier/keeper-cli/cmd/util" +) + +type createLabelOptions struct { + label string + color string +} + +func NewCmdCreateLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { + var opts createLabelOptions + cmd := &cobra.Command{ + Use: "label", + Short: "Create a label", + RunE: func(cmd *cobra.Command, args []string) error { + return runCreateLabel(f, out, cmd, &opts) + }, + } + + flags := cmd.Flags() + flags.StringVarP(&opts.label, "label", "l", "", "Label name") + flags.StringVarP(&opts.color, "color", "c", "", "Label color") + return cmd +} + +func runCreateLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, opts *createLabelOptions) error { + if opts.label == "" || opts.color == "" { + return errors.New("You have to specify at least a label and a color.") + } + + c, err := f.Client() + if err != nil { + return err + } + + lbl := &api.LabelResponse{ + Label: opts.label, + Color: opts.color, + } + label, err := c.CreateLabel(lbl) + if err != nil { + return err + } + + tmpl, err := template.New("label").Parse(LabelTmpl) + if err != nil { + return err + } + err = tmpl.Execute(out, label) + return err +} diff --git a/cmd/get_document.go b/cmd/get_document.go index 008142d..560942d 100644 --- a/cmd/get_document.go +++ b/cmd/get_document.go @@ -23,7 +23,7 @@ var DocumentTmpl = `Document: Ghost: {{.Ghost}} ` -type getOptions struct { +type getDocumentOptions struct { attribute string } @@ -34,10 +34,10 @@ func getField(d *api.DocumentResponse, field string) string { } func NewCmdGetDocument(f *cmdutil.Factory, out io.Writer) *cobra.Command { - var opts getOptions + var opts getDocumentOptions cmd := &cobra.Command{ Use: "get (ID)", - Short: "Get a document", + Short: "Get a document (by default) or a label", RunE: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { return errors.New("Document ID required.") @@ -55,7 +55,7 @@ func NewCmdGetDocument(f *cmdutil.Factory, out io.Writer) *cobra.Command { return cmd } -func runGetDocument(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, docid string, opts *getOptions) error { +func runGetDocument(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, docid string, opts *getDocumentOptions) error { c, err := f.Client() if err != nil { return err diff --git a/cmd/get_label.go b/cmd/get_label.go new file mode 100644 index 0000000..0687d03 --- /dev/null +++ b/cmd/get_label.go @@ -0,0 +1,55 @@ +package cmd + +import ( + "errors" + "io" + "text/template" + + "github.com/spf13/cobra" + + cmdutil "github.com/ncarlier/keeper-cli/cmd/util" +) + +var LabelTmpl = `Label: + Id: {{.Id}} + Label: {{.Label}} + Color: {{.Color}} + Date: {{.Date}} + Ghost: {{.Ghost}} +` + +func NewCmdGetLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "label (ID)", + Short: "Get a label", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("Label ID required.") + } + docid := args[0] + + return runGetLabel(f, out, cmd, docid) + }, + } + + return cmd +} + +func runGetLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, id string) error { + c, err := f.Client() + if err != nil { + return err + } + + label, err := c.GetLabel(id) + if err != nil { + return err + } + + tmpl, err := template.New("label").Parse(LabelTmpl) + if err != nil { + return err + } + err = tmpl.Execute(out, label) + return err +} diff --git a/cmd/remove_label.go b/cmd/remove_label.go new file mode 100644 index 0000000..4f87b57 --- /dev/null +++ b/cmd/remove_label.go @@ -0,0 +1,42 @@ +package cmd + +import ( + "errors" + "fmt" + "io" + + "github.com/spf13/cobra" + + cmdutil "github.com/ncarlier/keeper-cli/cmd/util" +) + +func NewCmdRemoveLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "label (ID)", + Short: "Remove a label", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("Label ID required.") + } + docid := args[0] + + return runRemoveLabel(f, out, cmd, docid) + }, + } + return cmd +} + +func runRemoveLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, id string) error { + c, err := f.Client() + if err != nil { + return err + } + + err = c.RemoveLabel(id) + if err != nil { + return err + } + + fmt.Fprintln(out, "Label removed.") + return nil +} diff --git a/cmd/restore_label.go b/cmd/restore_label.go new file mode 100644 index 0000000..763092c --- /dev/null +++ b/cmd/restore_label.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "errors" + "io" + "text/template" + + "github.com/spf13/cobra" + + cmdutil "github.com/ncarlier/keeper-cli/cmd/util" +) + +func NewCmdRestoreLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "label (ID)", + Short: "Restore a deleted label", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("Label ID required.") + } + docid := args[0] + + return runRestoreLabel(f, out, cmd, docid) + }, + } + return cmd +} + +func runRestoreLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, id string) error { + c, err := f.Client() + if err != nil { + return err + } + + label, err := c.RestoreLabel(id) + if err != nil { + return err + } + + tmpl, err := template.New("label").Parse(LabelTmpl) + if err != nil { + return err + } + err = tmpl.Execute(out, label) + return err +}