Skip to content

Commit

Permalink
Auto select tasklist (#7)
Browse files Browse the repository at this point in the history
* ✨ added -l persistant flag on tasks command

* added -l flag to select task list. Usage:
gtasks tasks -l "To watch" view|add|rm|done
* defaults to selecting prompt when the flag is missing
* also fixes the bug where incomplete tasks showed with
-i flag

* ♻️ refactor treewide, add logging

* refactored codebase
* added centralised, more configurable logging

* 🎨 moved to better and colorful printing

* utils package handles printing
* needs testing for all commands

* 📝 update root version

* 📄 update README
  • Loading branch information
BRO3886 authored Jun 23, 2021
1 parent 0fdee24 commit 55d6d29
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 276 deletions.
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,45 +75,67 @@ Use "gtasks [command] --help" for more information about a command.

## Commands

### Help
* To see details about a command
```bash
gtasks <COMMAND> help
```

### Login
* Login
```bash
gtasks login
```

### Tasklists
* Viewing Tasklists
```bash
gtasks tasklists view
```

* Creating a Tasklist
```bash
gtasks tasklists create -t 'title'
gtasks tasklists create --title 'title'
```

* Deleting a Tasklist
```bash
gtasks tasklists rm
```

### Tasks
* To pre-select tasklist, provide it's title as follows:
```bash
gtasks tasks -l <title> subcommand [--subcommand-flags]
```
Examples:
```bash
gtasks tasks [--tasklist|-l] "DSC VIT" view [--include-completed | -i]
```
**Note:** If the `-l` flag is not provided you will be able to choose a tasklist from the prompt

* Viewing tasks
```bash
gtasks tasks view
```
* Viewing completed tasks

* Include completed tasks
```bash
gtasks tasks view -c
gtasks tasks view --completed
gtasks tasks view -i
gtasks tasks view --include-completed
```

* Adding a task
```bash
gtasks tasks add
```

* Mark task as completed
```bash
gtasks tasks done
```

* Deleting a task
```bash
gtasks tasks rm
Expand Down
54 changes: 54 additions & 0 deletions api/tasklists.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package api

import (
"errors"

"github.com/BRO3886/gtasks/internal/utils"
"google.golang.org/api/tasks/v1"
)

type TaskList []tasks.TaskList

func (e TaskList) Len() int {
return len(e)
}

func (e TaskList) Less(i, j int) bool {
return e[i].Title < e[j].Title
}

func (e TaskList) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}

func GetTaskLists(srv *tasks.Service) ([]tasks.TaskList, error) {
r, err := srv.Tasklists.List().Do()
if err != nil {
utils.ErrorP("Unable to retrieve task lists. %v\n", err)
}

var list []tasks.TaskList

if len(r.Items) == 0 {
return nil, errors.New("no Tasklist found")
}

for _, item := range r.Items {
list = append(list, *item)
}

return list, nil
}

func UpdateTaskList(srv *tasks.Service, tl *tasks.TaskList) (*tasks.TaskList, error) {
r, err := srv.Tasklists.Patch(tl.Id, tl).Do()
if err != nil {
return nil, err
}
return r, nil
}

func DeleteTaskList(srv *tasks.Service, tID string) error {
err := srv.Tasklists.Delete(tID).Do()
return err
}
23 changes: 17 additions & 6 deletions internal/tasks.go → api/tasks.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package internal
package api

import (
"errors"
"log"

"github.com/BRO3886/gtasks/internal/utils"
"google.golang.org/api/tasks/v1"
)

Expand All @@ -17,15 +17,26 @@ func CreateTask(srv *tasks.Service, task *tasks.Task, tasklistID string) (*tasks
}

//GetTasks used to retreive tasks
func GetTasks(srv *tasks.Service, id string, showCompleted bool) ([]*tasks.Task, error) {
r, err := srv.Tasks.List(id).ShowHidden(showCompleted).Do()
func GetTasks(srv *tasks.Service, id string, includeCompleted bool) ([]*tasks.Task, error) {
r, err := srv.Tasks.List(id).ShowHidden(includeCompleted).Do()
if err != nil {
log.Fatalf("Unable to retrieve tasks. %v", err)
utils.ErrorP("Unable to retrieve tasks. %v", err)
}
if len(r.Items) == 0 {
return nil, errors.New("no Tasks found")
}
return r.Items, nil

if includeCompleted {
return r.Items, nil
} else {
var list []*tasks.Task
for _, task := range r.Items {
if task.Status != "completed" {
list = append(list, task)
}
}
return list, nil
}
}

//GetTaskInfo to get more info about a task
Expand Down
43 changes: 29 additions & 14 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"

"github.com/BRO3886/gtasks/internal"
"github.com/BRO3886/gtasks/internal/config"
"github.com/BRO3886/gtasks/internal/utils"
"github.com/spf13/cobra"
"golang.org/x/oauth2"
"google.golang.org/api/option"
"google.golang.org/api/tasks/v1"
)

// loginCmd represents the login command
Expand All @@ -19,8 +21,8 @@ var loginCmd = &cobra.Command{
Short: "Logging into Google Tasks",
Long: `This command uses the credentials.json file and makes a request to get your tokens`,
Run: func(cmd *cobra.Command, args []string) {
config := internal.ReadCredentials()
getClient(config)
c := config.ReadCredentials()
getClient(c)
},
}

Expand All @@ -29,35 +31,35 @@ func init() {
}

// Retrieve a token, saves the token, then returns the generated client.
func getClient(config *oauth2.Config) *http.Client {
func getClient(c *oauth2.Config) *http.Client {
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
folderPath := internal.GetInstallLocation()
folderPath := config.GetInstallLocation()
// fmt.Println(folderPath)
tokFile := folderPath + "/token.json"
tok, err := tokenFromFile(tokFile)
if err != nil {
tok = getTokenFromWeb(config)
tok = getTokenFromWeb(c)
saveToken(tokFile, tok)
}
return config.Client(context.Background(), tok)
return c.Client(context.Background(), tok)
}

// Request a token from the web, then returns the retrieved token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
fmt.Printf("Go to the following link in your browser then type the "+
"authorization code: \n%v\nEnter the code: ", authURL)
utils.Warn("Go to the following link in your browser then type the "+
"authorization code: \n%v\n\nEnter the code: ", authURL)

var authCode string
if _, err := fmt.Scan(&authCode); err != nil {
log.Fatalf("Unable to read authorization code: %v", err)
utils.ErrorP("Unable to read authorization code: %v", err)
}

tok, err := config.Exchange(context.TODO(), authCode)
if err != nil {
log.Fatalf("Unable to retrieve token from web: %v", err)
utils.ErrorP("Unable to retrieve token from web: %v", err)
}
return tok
}
Expand All @@ -76,11 +78,24 @@ func tokenFromFile(file string) (*oauth2.Token, error) {

// Saves a token to a file path.
func saveToken(path string, token *oauth2.Token) {
fmt.Printf("Saving credential file to: %s\n", path)
utils.Info("Saving credential file to: %s\n", path)
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
utils.ErrorP("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}

//gets the tasks service
func getService() *tasks.Service {
c := config.ReadCredentials()
client := getClient(c)

srv, err := tasks.NewService(context.Background(), option.WithHTTPClient(client))
if err != nil {
utils.ErrorP("Unable to retrieve tasks Client %v", err)
}

return srv
}
10 changes: 4 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package cmd

import (
"fmt"
"os"

"github.com/BRO3886/gtasks/internal/utils"
"github.com/spf13/cobra"

homedir "github.com/mitchellh/go-homedir"
Expand All @@ -16,7 +16,7 @@ var cfgFile string
var rootCmd = &cobra.Command{
Use: "gtasks",
Short: "A CLI Tool for Google Tasks",
Version: "0.9.2",
Version: "0.9.3",
Long: `
A CLI Tool for managing your Google Tasks:
Expand All @@ -31,8 +31,7 @@ var rootCmd = &cobra.Command{
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
utils.ErrorP("%s\n", err.Error())
}
}

Expand All @@ -51,8 +50,7 @@ func initConfig() {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
utils.ErrorP("%v", err)
}

// Search config in home directory with name ".google-tasks-cli" (without extension).
Expand Down
Loading

0 comments on commit 55d6d29

Please sign in to comment.