From 1393b0a3340a9c631bb8c79a5acdd3bfba3aea32 Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Mon, 21 May 2018 23:32:20 -0500 Subject: [PATCH] add due date to tasks, columns --- Makefile | 4 ++++ README.md | 3 ++- client/client.go | 34 +++++++++++++++++++++++++++++++++- client/labels.go | 4 ++-- client/projects.go | 4 ++-- client/tasks.go | 23 +++++++++++++++-------- cmd/add.go | 4 +++- cmd/labels.go | 5 ++++- cmd/list.go | 5 ++++- cmd/projects.go | 5 ++++- cmd/root.go | 2 ++ config/config.go | 1 + 12 files changed, 76 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index e6eaf57..ab493f9 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,10 @@ go-deps: go-test: go test ${BUILD_OPTS} -cover ./... +git-push: + git push github + git push gitlab + docker-build: docker build -T ${IMAGE_NAME} . diff --git a/README.md b/README.md index d52412c..c6920ae 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,7 @@ Features: - [x] add task labels - [x] config defaults - [x] columns & sort on root +- [x] add due date column - [ ] list project names - [ ] list label names - [ ] test coverage @@ -214,4 +215,4 @@ Features: togo was written by [ssube](https://github.com/ssube) and is not created by, affiliated with, or supported by Doist. -Source, documentation, and everything else in this repository is distributed under the included MIT license. \ No newline at end of file +Source, documentation, and everything else in this repository is distributed under the included MIT license. diff --git a/client/client.go b/client/client.go index f2bee6f..68e8cb7 100644 --- a/client/client.go +++ b/client/client.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" "text/tabwriter" + "time" "github.com/ssube/togo/config" "gopkg.in/resty.v1" @@ -39,8 +40,27 @@ func CreateTable(f *os.File, cols []string) *tabwriter.Writer { return w } +func FormatDate(d DueDate, dateFmt string) (string, error) { + // if no timezone is provided, this is a simple date (day) + if d.Timezone == "" { + return d.Date, nil + } + + zone, err := time.LoadLocation(d.Timezone) + if err != nil { + return d.DateTime, err + } + + local, err := time.ParseInLocation(time.RFC3339, d.DateTime, zone) + if err != nil { + return d.DateTime, err + } + + return local.Format(dateFmt), nil +} + // GetFields from a column list using reflection -func GetFields(val interface{}, cols []string) []string { +func GetFields(val interface{}, cols []string, dateFmt string) []string { out := make([]string, len(cols)) rv := reflect.ValueOf(val).Elem() @@ -59,6 +79,18 @@ func GetFields(val interface{}, cols []string) []string { out[i] = strconv.FormatInt(field.Int(), 10) case reflect.String: out[i] = field.String() + case reflect.Struct: + val := field.Interface() + switch val.(type) { + case DueDate: + fmt, err := FormatDate(val.(DueDate), dateFmt) + if err != nil { + log.Fatalf("unable to format date: %s", err.Error) + } + out[i] = fmt + default: + log.Printf("unknown struct for column %s: %v", c, val) + } case reflect.Slice: fallthrough default: diff --git a/client/labels.go b/client/labels.go index 48529dd..9479371 100644 --- a/client/labels.go +++ b/client/labels.go @@ -26,12 +26,12 @@ func ParseLabels(data []byte) ([]Label, error) { } // PrintLabels after sorting, with column headers -func PrintLabels(f *os.File, labels []Label, cols []string, sortCol string) { +func PrintLabels(f *os.File, labels []Label, cols []string, sortCol string, dateFmt string) { w := CreateTable(f, cols) SortByField(labels, sortCol) for _, l := range labels { - fields := GetFields(&l, cols) + fields := GetFields(&l, cols, dateFmt) fmt.Fprintln(w, Tabulate(fields)...) } diff --git a/client/projects.go b/client/projects.go index 7e928fe..b77f0ca 100644 --- a/client/projects.go +++ b/client/projects.go @@ -27,13 +27,13 @@ func ParseProjects(data []byte) ([]Project, error) { } // PrintProjects after sorting, with column headers -func PrintProjects(f *os.File, projects []Project, cols []string, sortCol string) { +func PrintProjects(f *os.File, projects []Project, cols []string, sortCol string, dateFmt string) { w := CreateTable(f, cols) SortByField(projects, sortCol) // prepare a slice for cols and tabs for _, p := range projects { - fields := GetFields(&p, cols) + fields := GetFields(&p, cols, dateFmt) fmt.Fprintln(w, Tabulate(fields)...) } diff --git a/client/tasks.go b/client/tasks.go index af0c1f3..381c27d 100644 --- a/client/tasks.go +++ b/client/tasks.go @@ -13,25 +13,32 @@ import ( "gopkg.in/yaml.v2" ) +type DueDate struct { + Date string `json:"date" yaml:"date"` + DateTime string `json:"datetime" yaml:"datetime"` + Timezone string `json:"timezone" yaml:"timezone"` +} + // Task model // https://developer.todoist.com/rest/v8/#tasks type Task struct { - Content string `json:"content" yaml:"content"` - ID int `json:"id" yaml:"id,omitempty"` - Labels []int `json:"label_ids" yaml:"label_ids"` - Order int `json:"order" yaml:"order,omitempty"` - Priority int `json:"priority" yaml:"priority,omitempty"` - Project int `json:"project_id" yaml:"project_id"` + Content string `json:"content" yaml:"content"` + Due DueDate `json:"due" yaml:"due"` + ID int `json:"id" yaml:"id,omitempty"` + Labels []int `json:"label_ids" yaml:"label_ids"` + Order int `json:"order" yaml:"order,omitempty"` + Priority int `json:"priority" yaml:"priority,omitempty"` + Project int `json:"project_id" yaml:"project_id"` } // PrintTasks in a table -func PrintTasks(f *os.File, tasks []Task, cols []string, sortCol string) { +func PrintTasks(f *os.File, tasks []Task, cols []string, sortCol string, dateFmt string) { w := CreateTable(f, cols) SortByField(tasks, sortCol) // prepare a slice for cols and tabs for _, t := range tasks { - fields := GetFields(&t, cols) + fields := GetFields(&t, cols, dateFmt) fmt.Fprintln(w, Tabulate(fields)...) } diff --git a/cmd/add.go b/cmd/add.go index 299d72d..17d9ea2 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -53,6 +53,7 @@ func init() { "ID", "Content", } + date := rootConfig.Default.Date done := false labels := rootConfig.Default.Tasks.Labels project := rootConfig.Default.Tasks.Project @@ -76,8 +77,9 @@ func init() { } columns := rootClient.Columns(columns, rootColumns, rootClient.Config().Default.Projects.Columns) + date := rootClient.Sort(date, rootDate, rootClient.Config().Default.Date) sort := rootClient.Sort(sort, rootSort, rootClient.Config().Default.Projects.Sort) - client.PrintTasks(os.Stdout, tasks, columns, sort) + client.PrintTasks(os.Stdout, tasks, columns, sort, date) if done { // this should be a single item for _, t := range tasks { diff --git a/cmd/labels.go b/cmd/labels.go index 09a4204..cc42ecf 100644 --- a/cmd/labels.go +++ b/cmd/labels.go @@ -3,6 +3,7 @@ package cmd import ( "log" "os" + "time" "github.com/spf13/cobra" "github.com/ssube/togo/client" @@ -13,6 +14,7 @@ func init() { "ID", "Name", } + date := time.RFC3339 sort := "Name" labelsCmd := &cobra.Command{ @@ -25,8 +27,9 @@ func init() { } columns := rootClient.Columns(columns, rootColumns, rootClient.Config().Default.Labels.Columns) + date := rootClient.Sort(date, rootDate, rootClient.Config().Default.Date) sort := rootClient.Sort(sort, rootSort, rootClient.Config().Default.Labels.Sort) - client.PrintLabels(os.Stdout, labels, columns, sort) + client.PrintLabels(os.Stdout, labels, columns, sort, date) }, } diff --git a/cmd/list.go b/cmd/list.go index 04045aa..d84ed91 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -4,6 +4,7 @@ import ( "log" "os" "strings" + "time" "github.com/spf13/cobra" "github.com/ssube/togo/client" @@ -14,6 +15,7 @@ func init() { "ID", "Content", } + date := time.RFC3339 labels := rootConfig.Default.Tasks.Labels project := rootConfig.Default.Tasks.Project sort := "ID" @@ -38,8 +40,9 @@ func init() { } columns := rootClient.Columns(columns, rootColumns, rootClient.Config().Default.Tasks.Columns) + date := rootClient.Sort(date, rootDate, rootClient.Config().Default.Date) sort := rootClient.Sort(sort, rootSort, rootClient.Config().Default.Tasks.Sort) - client.PrintTasks(os.Stdout, tasks, columns, sort) + client.PrintTasks(os.Stdout, tasks, columns, sort, date) }, } diff --git a/cmd/projects.go b/cmd/projects.go index 4342bb9..d7d0b42 100644 --- a/cmd/projects.go +++ b/cmd/projects.go @@ -3,6 +3,7 @@ package cmd import ( "log" "os" + "time" "github.com/spf13/cobra" "github.com/ssube/togo/client" @@ -13,6 +14,7 @@ func init() { "ID", "Name", } + date := time.RFC3339 sort := "Name" projectsCmd := &cobra.Command{ @@ -25,8 +27,9 @@ func init() { } columns := rootClient.Columns(columns, rootColumns, rootClient.Config().Default.Projects.Columns) + date := rootClient.Sort(date, rootDate, rootClient.Config().Default.Date) sort := rootClient.Sort(sort, rootSort, rootClient.Config().Default.Projects.Sort) - client.PrintProjects(os.Stdout, projects, columns, sort) + client.PrintProjects(os.Stdout, projects, columns, sort, date) }, } diff --git a/cmd/root.go b/cmd/root.go index 339f8c9..5cd6f33 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,6 +16,7 @@ var rootConfig = &config.Config{} // persistent flags var rootColumns = []string{} +var rootDate = "" var rootSort = "" // flags @@ -46,6 +47,7 @@ func Execute(client *client.Client) { func init() { rootCmd.PersistentFlags().StringSliceVarP(&rootColumns, "columns", "c", []string{}, "display columns") + rootCmd.PersistentFlags().StringVarP(&rootDate, "date", "d", "", "date format") rootCmd.PersistentFlags().StringVarP(&rootSort, "sort", "s", "", "sort column") // root-only flags diff --git a/config/config.go b/config/config.go index 0e2c853..9997e21 100644 --- a/config/config.go +++ b/config/config.go @@ -11,6 +11,7 @@ import ( type Config struct { Default struct { + Date string Labels struct { Columns []string Sort string