From fad99a22623889d94065e0c6f63aa5a9a4a58cb3 Mon Sep 17 00:00:00 2001 From: Chris Cummer Date: Wed, 11 Jul 2018 10:00:00 -0700 Subject: [PATCH] Add todoist dependency --- Gopkg.lock | 2 +- .../github.com/darkSasori/todoist/.gitignore | 2 + .../github.com/darkSasori/todoist/.travis.yml | 19 +++ .../github.com/darkSasori/todoist/Gopkg.lock | 21 +++ .../github.com/darkSasori/todoist/Gopkg.toml | 34 ++++ vendor/github.com/darkSasori/todoist/LICENSE | 21 +++ .../github.com/darkSasori/todoist/README.md | 6 + .../github.com/darkSasori/todoist/projects.go | 149 +++++++++++++++++ vendor/github.com/darkSasori/todoist/task.go | 158 ++++++++++++++++++ .../github.com/darkSasori/todoist/todoist.go | 145 ++++++++++++++++ 10 files changed, 556 insertions(+), 1 deletion(-) create mode 100644 vendor/github.com/darkSasori/todoist/.gitignore create mode 100644 vendor/github.com/darkSasori/todoist/.travis.yml create mode 100644 vendor/github.com/darkSasori/todoist/Gopkg.lock create mode 100644 vendor/github.com/darkSasori/todoist/Gopkg.toml create mode 100644 vendor/github.com/darkSasori/todoist/LICENSE create mode 100644 vendor/github.com/darkSasori/todoist/README.md create mode 100644 vendor/github.com/darkSasori/todoist/projects.go create mode 100644 vendor/github.com/darkSasori/todoist/task.go create mode 100644 vendor/github.com/darkSasori/todoist/todoist.go diff --git a/Gopkg.lock b/Gopkg.lock index 9c34c32e..bfa5b6c7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -207,6 +207,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "04892edb6b5f0be61b391ccead307ed15899532db05a17b9e28c00ee32a34861" + inputs-digest = "9eaa70ed639c832e3cde26a4270f4c7b9124960952aa76506f702c2c296d5019" solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/github.com/darkSasori/todoist/.gitignore b/vendor/github.com/darkSasori/todoist/.gitignore new file mode 100644 index 00000000..9a990fe4 --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/.gitignore @@ -0,0 +1,2 @@ +*.out +vendor/* diff --git a/vendor/github.com/darkSasori/todoist/.travis.yml b/vendor/github.com/darkSasori/todoist/.travis.yml new file mode 100644 index 00000000..0052d33c --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/.travis.yml @@ -0,0 +1,19 @@ +language: go + +notifications: + email: false + +go: + - "1.10.3" + - master + +before_install: + - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + - go get -u github.com/golang/lint/golint + +install: + - dep ensure + +script: + - golint -set_exit_status + - go test -v diff --git a/vendor/github.com/darkSasori/todoist/Gopkg.lock b/vendor/github.com/darkSasori/todoist/Gopkg.lock new file mode 100644 index 00000000..99656b15 --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/Gopkg.lock @@ -0,0 +1,21 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/darkSasori/todoist" + packages = ["."] + revision = "ab3a9f0b9d551ab4e57f1caae9bb20d5aa51ec10" + +[[projects]] + branch = "v1" + name = "gopkg.in/jarcoal/httpmock.v1" + packages = ["."] + revision = "16f9a43967d613f0adc2000f0094a17b9f6c4c20" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "4d0d4d6dd7b4141be119cb48281ea7c10f05d3037c0e4ac49560cf4af21917a7" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/darkSasori/todoist/Gopkg.toml b/vendor/github.com/darkSasori/todoist/Gopkg.toml new file mode 100644 index 00000000..ec866dff --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + branch = "v1" + name = "gopkg.in/jarcoal/httpmock.v1" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/darkSasori/todoist/LICENSE b/vendor/github.com/darkSasori/todoist/LICENSE new file mode 100644 index 00000000..cc68e07a --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Lineu Felipe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/darkSasori/todoist/README.md b/vendor/github.com/darkSasori/todoist/README.md new file mode 100644 index 00000000..8ffc3976 --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/README.md @@ -0,0 +1,6 @@ +# todoist +[![godoc](https://godoc.org/github.com/darkSasori/todoist?status.svg)](https://godoc.org/github.com/darkSasori/todoist) +[![Build Status](https://travis-ci.org/darkSasori/todoist.svg?branch=master)](https://travis-ci.org/darkSasori/todoist) +[![Go Report Card](https://goreportcard.com/badge/github.com/darkSasori/todoist)](https://goreportcard.com/report/github.com/darkSasori/todoist) + +Unofficial todoist api implementation diff --git a/vendor/github.com/darkSasori/todoist/projects.go b/vendor/github.com/darkSasori/todoist/projects.go new file mode 100644 index 00000000..9493b18a --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/projects.go @@ -0,0 +1,149 @@ +package todoist + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +// Project is a model of todoist project entity +type Project struct { + ID int `json:"id"` + Name string `json:"name"` + CommentCount int `json:"comment_count"` + Order int `json:"order"` + Indent int `json:"indent"` +} + +func decodeProject(body io.ReadCloser) (Project, error) { + defer body.Close() + decoder := json.NewDecoder(body) + var project Project + + if err := decoder.Decode(&project); err != nil { + return Project{}, err + } + return project, nil +} + +// ListProject return all projects +// +// Example: +// todoist.Token = "your token" +// projects, err := todoist.ListProject() +// if err != nil { +// panic(err) +// } +// fmt.Println(projects) +func ListProject() ([]Project, error) { + res, err := makeRequest(http.MethodGet, "projects", nil) + if err != nil { + return []Project{}, err + } + + defer res.Body.Close() + decoder := json.NewDecoder(res.Body) + var projects []Project + + if err := decoder.Decode(&projects); err != nil { + return []Project{}, err + } + + return projects, nil +} + +// GetProject return a project by id +// +// Example: +// todoist.Token = "your token" +// project, err := todoist.GetProject(1) +// if err != nil { +// panic(err) +// } +// fmt.Println(project) +func GetProject(id int) (Project, error) { + path := fmt.Sprintf("projects/%d", id) + res, err := makeRequest(http.MethodGet, path, nil) + if err != nil { + return Project{}, err + } + + return decodeProject(res.Body) +} + +// CreateProject create a new project with a name +// +// Example: +// todoist.Token = "your token" +// project, err := todoist.CreateProject("New Project") +// if err != nil { +// panic(err) +// } +// fmt.Println(project) +func CreateProject(name string) (Project, error) { + project := struct { + Name string `json:"name"` + }{ + name, + } + + res, err := makeRequest(http.MethodPost, "projects", project) + if err != nil { + return Project{}, err + } + + return decodeProject(res.Body) +} + +// Delete project +// +// Example: +// todoist.Token = "your token" +// project, err := todoist.GetProject(1) +// if err != nil { +// panic(err) +// } +// err = project.Delete() +// if err != nil { +// panic(err) +// } +func (p Project) Delete() error { + path := fmt.Sprintf("projects/%d", p.ID) + _, err := makeRequest(http.MethodDelete, path, nil) + if err != nil { + return err + } + + return nil +} + +// Update project +// +// Example: +// todoist.Token = "your token" +// project, err := todoist.GetProject(1) +// if err != nil { +// panic(err) +// } +// project.Name = "updated" +// err = project.Update() +// if err != nil { +// panic(err) +// } +// fmt.Println(project) +func (p Project) Update() error { + path := fmt.Sprintf("projects/%d", p.ID) + project := struct { + Name string `json:"name"` + }{ + p.Name, + } + + _, err := makeRequest(http.MethodPost, path, project) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/darkSasori/todoist/task.go b/vendor/github.com/darkSasori/todoist/task.go new file mode 100644 index 00000000..f2c0ce06 --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/task.go @@ -0,0 +1,158 @@ +package todoist + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +// Task is a model of todoist project entity +type Task struct { + ID int `json:"id"` + CommentCount int `json:"comment_count"` + Completed bool `json:"completed"` + Content string `json:"content"` + Indent int `json:"indent"` + LabelIDs []int `json:"label_ids"` + Order int `json:"order"` + Priority int `json:"priority"` + ProjectID int `json:"project_id"` + Due Due `json:"due"` +} + +// Due is a model of todoist project entity +type Due struct { + String string `json:"string"` + Date string `json:"date"` + Datetime CustomTime `json:"datetime"` + Timezone string `json:"timezone"` +} + +func (t Task) taskSave() taskSave { + return taskSave{ + t.Content, + t.ProjectID, + t.Order, + t.LabelIDs, + t.Priority, + t.Due.String, + t.Due.Datetime, + "en", + } +} + +func decodeTask(body io.ReadCloser) (Task, error) { + defer body.Close() + decoder := json.NewDecoder(body) + var task Task + + if err := decoder.Decode(&task); err != nil { + return Task{}, err + } + return task, nil +} + +// QueryParam is a map[string]string to build http query +type QueryParam map[string]string + +func (qp QueryParam) String() string { + if len(qp) == 0 { + return "" + } + + ret := "?" + for key, value := range qp { + if ret != "?" { + ret = ret + "&" + } + ret = ret + key + "=" + value + } + + return ret +} + +// ListTask return all task, you can filter using QueryParam +// See documentation: https://developer.todoist.com/rest/v8/#get-tasks +func ListTask(qp QueryParam) ([]Task, error) { + path := fmt.Sprintf("tasks%s", qp) + res, err := makeRequest(http.MethodGet, path, nil) + if err != nil { + return []Task{}, err + } + + defer res.Body.Close() + decoder := json.NewDecoder(res.Body) + var tasks []Task + + if err := decoder.Decode(&tasks); err != nil { + return []Task{}, err + } + + return tasks, nil +} + +// GetTask return a task by id +func GetTask(id int) (Task, error) { + path := fmt.Sprintf("tasks/%d", id) + res, err := makeRequest(http.MethodGet, path, nil) + if err != nil { + return Task{}, err + } + + return decodeTask(res.Body) +} + +// CreateTask create a new task +func CreateTask(task Task) (Task, error) { + res, err := makeRequest(http.MethodPost, "tasks", task.taskSave()) + if err != nil { + return Task{}, err + } + + return decodeTask(res.Body) +} + +// Delete remove a task +func (t Task) Delete() error { + path := fmt.Sprintf("tasks/%d", t.ID) + _, err := makeRequest(http.MethodDelete, path, nil) + if err != nil { + return err + } + + return nil +} + +// Update a task +func (t Task) Update() error { + path := fmt.Sprintf("tasks/%d", t.ID) + _, err := makeRequest(http.MethodPost, path, t.taskSave()) + if err != nil { + return err + } + + return nil +} + +// Close mask task as done +func (t Task) Close() error { + path := fmt.Sprintf("tasks/%d/close", t.ID) + _, err := makeRequest(http.MethodPost, path, nil) + if err != nil { + return err + } + + return nil +} + +// Reopen a task +func (t Task) Reopen() error { + path := fmt.Sprintf("tasks/%d/reopen", t.ID) + _, err := makeRequest(http.MethodPost, path, nil) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/darkSasori/todoist/todoist.go b/vendor/github.com/darkSasori/todoist/todoist.go new file mode 100644 index 00000000..d487426c --- /dev/null +++ b/vendor/github.com/darkSasori/todoist/todoist.go @@ -0,0 +1,145 @@ +package todoist + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + "time" +) + +// Token save the personal token from todoist +var Token string +var todoistURL = "https://beta.todoist.com/API/v8/" + +func makeRequest(method, endpoint string, data interface{}) (*http.Response, error) { + url := todoistURL + endpoint + body := bytes.NewBuffer([]byte{}) + + if data != nil { + json, err := json.Marshal(data) + if err != nil { + return nil, err + } + body = bytes.NewBuffer(json) + } + + req, err := http.NewRequest(method, url, body) + if err != nil { + return nil, err + } + + bearer := fmt.Sprintf("Bearer %s", Token) + req.Header.Add("Authorization", bearer) + + if data != nil { + req.Header.Add("Content-Type", "application/json") + } + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + return nil, err + } + + if res.StatusCode >= 400 { + defer res.Body.Close() + str, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + return nil, fmt.Errorf(string(str)) + } + + return res, nil +} + +const ctLayout = "2006-01-02T15:04:05+00:00" + +// CustomTime had a custom json date format +type CustomTime struct { + time.Time +} + +// UnmarshalJSON convert from []byte to CustomTime +func (ct *CustomTime) UnmarshalJSON(b []byte) (err error) { + s := strings.Trim(string(b), "\"") + if s == "null" { + ct.Time = time.Time{} + return nil + } + + ct.Time, err = time.Parse(ctLayout, s) + return err +} + +// MarshalJSON convert CustomTime to []byte +func (ct CustomTime) MarshalJSON() ([]byte, error) { + if ct.Time.IsZero() { + return []byte("null"), nil + } + return []byte(`"` + ct.Time.Format(ctLayout) + `"`), nil +} + +type taskSave struct { + Content string `json:"content"` + ProjectID int `json:"project_id,omitempty"` + Order int `json:"order,omitempty"` + LabelIDs []int `json:"label_ids,omitempty"` + Priority int `json:"priority,omitempty"` + DueString string `json:"due_string,omitempty"` + DueDateTime CustomTime `json:"due_datetime,omitempty"` + DueLang string `json:"due_lang,omitempty"` +} + +func (ts taskSave) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBufferString("{") + + if ts.Content == "" { + return nil, fmt.Errorf("Content is empty") + } + buffer.WriteString(fmt.Sprintf("\"content\":\"%s\"", ts.Content)) + + if ts.ProjectID != 0 { + buffer.WriteString(fmt.Sprintf(",\"project_id\":%d", ts.ProjectID)) + } + + if ts.Order != 0 { + buffer.WriteString(fmt.Sprintf(",\"order\":%d", ts.Order)) + } + + if !ts.DueDateTime.IsZero() { + buffer.WriteString(",\"due_datetime\":") + json, err := json.Marshal(ts.DueDateTime) + if err != nil { + return nil, err + } + buffer.Write(json) + } + + if len(ts.LabelIDs) != 0 { + buffer.WriteString(",\"label_ids\":") + json, err := json.Marshal(ts.LabelIDs) + if err != nil { + return nil, err + } + buffer.Write(json) + } + + if ts.Priority != 0 { + buffer.WriteString(fmt.Sprintf(",\"priority\":%d", ts.Priority)) + } + + if ts.DueString != "" { + buffer.WriteString(fmt.Sprintf(",\"due_string\":\"%s\"", ts.DueString)) + } + + if ts.DueLang != "" { + buffer.WriteString(fmt.Sprintf(",\"due_lang\":\"%s\"", ts.DueLang)) + } + + buffer.WriteString("}") + return buffer.Bytes(), nil +}