mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Merge branch 'darkSasori-master'
This commit is contained in:
commit
8267c3aa93
8
Gopkg.lock
generated
8
Gopkg.lock
generated
@ -25,6 +25,12 @@
|
||||
packages = ["."]
|
||||
revision = "6a9abf92e34f4de62ac671caee3143f10b98892d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/darkSasori/todoist"
|
||||
packages = ["."]
|
||||
revision = "ec6b38b374ab9c60cc9716d2083ae66eb9383d03"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
@ -201,6 +207,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "04892edb6b5f0be61b391ccead307ed15899532db05a17b9e28c00ee32a34861"
|
||||
inputs-digest = "9eaa70ed639c832e3cde26a4270f4c7b9124960952aa76506f702c2c296d5019"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -85,6 +85,10 @@
|
||||
name = "github.com/adlio/trello"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/darkSasori/todoist"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
88
_site/content/posts/modules/todoist.md
Normal file
88
_site/content/posts/modules/todoist.md
Normal file
@ -0,0 +1,88 @@
|
||||
---
|
||||
title: "Todoist"
|
||||
date: 2018-07-05T22:55:55-03:00
|
||||
draft: false
|
||||
---
|
||||
|
||||
Displays all itens on specified project.
|
||||
|
||||
<img src="/imgs/modules/todoist.png" alt="todoist screenshot" />
|
||||
|
||||
## Source Code
|
||||
|
||||
```bash
|
||||
wtf/todoist/
|
||||
```
|
||||
|
||||
## Required ENV Variables
|
||||
|
||||
<span class="caption">Key:</span> `WTF_TODOIST_TOKEN` <br />
|
||||
<span class="caption">Value:</span> Your Todoist API Token. <br />
|
||||
|
||||
_You can get your API Token at: todoist.com/prefs/integrations._
|
||||
|
||||
## Keyboard Commands
|
||||
|
||||
<span class="caption">Key:</span> `h` <br />
|
||||
<span class="caption">Action:</span> Show the previous project.
|
||||
|
||||
<span class="caption">Key:</span> `←` <br />
|
||||
<span class="caption">Action:</span←> Show the previous project.
|
||||
|
||||
<span class="caption">Key:</span> `l` <br />
|
||||
<span class="caption">Action:</span←> Show the next project.
|
||||
|
||||
<span class="caption">Key:</span> `→` <br />
|
||||
<span class="caption">Action:</span> Show the next project.
|
||||
|
||||
<span class="caption">Key:</span> `j` <br />
|
||||
<span class="caption">Action:</span> Select the next item in the list.
|
||||
|
||||
<span class="caption">Key:</span> `↓` <br />
|
||||
<span class="caption">Action:</span> Select the next item in the list.
|
||||
|
||||
<span class="caption">Key:</span> `k` <br />
|
||||
<span class="caption">Action:</span> Select the previous item in the list.
|
||||
|
||||
<span class="caption">Key:</span> `↑` <br />
|
||||
<span class="caption">Action:</span> Select the previous item in the list.
|
||||
|
||||
<span class="caption">Key:</span> `c` <br />
|
||||
<span class="caption">Action:</span> Close current item.
|
||||
|
||||
<span class="caption">Key:</span> `d` <br />
|
||||
<span class="caption">Action:</span> Delete current item.
|
||||
|
||||
<span class="caption">Key:</span> `r` <br />
|
||||
<span class="caption">Action:</span> Reload all projects.
|
||||
|
||||
## Configuration
|
||||
|
||||
```yaml
|
||||
todoist:
|
||||
projects:
|
||||
- project_id
|
||||
enabled: true
|
||||
position:
|
||||
height: 1
|
||||
left: 2
|
||||
top: 0
|
||||
width: 1
|
||||
refreshInterval: 3600
|
||||
```
|
||||
|
||||
### Attributes
|
||||
|
||||
`enabled` <br />
|
||||
Determines whether or not this module is executed and if its data displayed onscreen. <br />
|
||||
Values: `true`, `false`.
|
||||
|
||||
`projects` <br />
|
||||
The todoist projects to fetch items from. <br />
|
||||
|
||||
`refreshInterval` <br />
|
||||
How often, in seconds, this module will update its data. <br />
|
||||
Values: A positive integer, `0..n`.
|
||||
|
||||
`position` <br />
|
||||
Where in the grid this module's widget will be displayed. <br />
|
BIN
_site/static/imgs/modules/todoist.png
Normal file
BIN
_site/static/imgs/modules/todoist.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -47,6 +47,7 @@
|
||||
<li class="sidebar-list-item-2"><a href="/posts/modules/security/">Security</a></li>
|
||||
<li class="sidebar-list-item-2"><a href="/posts/modules/textfile/">Text File</a></li>
|
||||
<li class="sidebar-list-item-2"><a href="/posts/modules/todo/">Todo</a></li>
|
||||
<li class="sidebar-list-item-2"><a href="/posts/modules/todoist/">Todoist</a></li>
|
||||
<li class="sidebar-list-item-2"><a href="/posts/modules/trello/">Trello</a></li>
|
||||
<li class="sidebar-list-item-2"><a href="/posts/modules/weather/">Weather</a></li>
|
||||
</ul>
|
||||
|
64
todoist/display.go
Normal file
64
todoist/display.go
Normal file
@ -0,0 +1,64 @@
|
||||
package todoist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/senorprogrammer/wtf/wtf"
|
||||
)
|
||||
|
||||
func (w *Widget) display() {
|
||||
if len(w.list) == 0 {
|
||||
return
|
||||
}
|
||||
list := w.list[w.idx]
|
||||
|
||||
w.View.SetTitle(fmt.Sprintf("%s- [green]%s[white] ", w.Name, list.Project.Name))
|
||||
str := wtf.SigilStr(len(w.list), w.idx, w.View) + "\n"
|
||||
|
||||
for index, item := range list.items {
|
||||
if index == list.index {
|
||||
str = str + fmt.Sprintf("[%s]", wtf.Config.UString("wtf.colors.border.focused", "grey"))
|
||||
}
|
||||
str = str + fmt.Sprintf("| | %s[white]\n", tview.Escape(item.Content))
|
||||
}
|
||||
|
||||
w.View.Clear()
|
||||
w.View.SetText(str)
|
||||
}
|
||||
|
||||
func (w *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
|
||||
if len(w.list) == 0 {
|
||||
return event
|
||||
}
|
||||
|
||||
switch string(event.Rune()) {
|
||||
case "r":
|
||||
w.Refresh()
|
||||
return nil
|
||||
case "d":
|
||||
w.Delete()
|
||||
return nil
|
||||
case "c":
|
||||
w.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
switch fromVim(event) {
|
||||
case tcell.KeyLeft:
|
||||
w.Prev()
|
||||
return nil
|
||||
case tcell.KeyRight:
|
||||
w.Next()
|
||||
return nil
|
||||
case tcell.KeyUp:
|
||||
w.UP()
|
||||
return nil
|
||||
case tcell.KeyDown:
|
||||
w.Down()
|
||||
return nil
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
79
todoist/list.go
Normal file
79
todoist/list.go
Normal file
@ -0,0 +1,79 @@
|
||||
package todoist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/darkSasori/todoist"
|
||||
)
|
||||
|
||||
type List struct {
|
||||
todoist.Project
|
||||
items []todoist.Task
|
||||
index int
|
||||
}
|
||||
|
||||
func NewList(id int) *List {
|
||||
project, err := todoist.GetProject(id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
list := &List{
|
||||
Project: project,
|
||||
index: -1,
|
||||
}
|
||||
list.loadItems()
|
||||
return list
|
||||
}
|
||||
|
||||
func (l List) isFirst() bool {
|
||||
return l.index == 0
|
||||
}
|
||||
|
||||
func (l List) isLast() bool {
|
||||
return l.index >= len(l.items)-1
|
||||
}
|
||||
|
||||
func (l *List) up() {
|
||||
l.index = l.index - 1
|
||||
if l.index < 0 {
|
||||
l.index = len(l.items) - 1
|
||||
}
|
||||
}
|
||||
|
||||
func (l *List) down() {
|
||||
if l.index == -1 {
|
||||
l.index = 0
|
||||
return
|
||||
}
|
||||
|
||||
l.index = l.index + 1
|
||||
if l.index >= len(l.items) {
|
||||
l.index = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (l *List) loadItems() {
|
||||
tasks, err := todoist.ListTask(todoist.QueryParam{"project_id": fmt.Sprintf("%d", l.ID)})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
l.items = tasks
|
||||
}
|
||||
|
||||
func (l *List) close() {
|
||||
if err := l.items[l.index].Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
l.loadItems()
|
||||
}
|
||||
|
||||
func (l *List) delete() {
|
||||
if err := l.items[l.index].Delete(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
l.loadItems()
|
||||
}
|
113
todoist/widget.go
Normal file
113
todoist/widget.go
Normal file
@ -0,0 +1,113 @@
|
||||
package todoist
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/darkSasori/todoist"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/senorprogrammer/wtf/wtf"
|
||||
)
|
||||
|
||||
type Widget struct {
|
||||
wtf.TextWidget
|
||||
|
||||
app *tview.Application
|
||||
pages *tview.Pages
|
||||
list []*List
|
||||
idx int
|
||||
}
|
||||
|
||||
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
|
||||
widget := Widget{
|
||||
TextWidget: wtf.NewTextWidget(" Todoist ", "todoist", true),
|
||||
|
||||
app: app,
|
||||
pages: pages,
|
||||
}
|
||||
|
||||
todoist.Token = os.Getenv("WTF_TODOIST_TOKEN")
|
||||
widget.list = loadProjects()
|
||||
widget.View.SetInputCapture(widget.keyboardIntercept)
|
||||
|
||||
return &widget
|
||||
}
|
||||
|
||||
func (w *Widget) Refresh() {
|
||||
if w.Disabled() || len(w.list) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
w.UpdateRefreshedAt()
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) Next() {
|
||||
w.idx = w.idx + 1
|
||||
if w.idx == len(w.list) {
|
||||
w.idx = 0
|
||||
}
|
||||
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) Prev() {
|
||||
w.idx = w.idx - 1
|
||||
if w.idx < 0 {
|
||||
w.idx = len(w.list) - 1
|
||||
}
|
||||
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) Down() {
|
||||
w.list[w.idx].down()
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) UP() {
|
||||
w.list[w.idx].up()
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) Close() {
|
||||
w.list[w.idx].close()
|
||||
if w.list[w.idx].isLast() {
|
||||
w.UP()
|
||||
return
|
||||
}
|
||||
w.Down()
|
||||
}
|
||||
|
||||
func (w *Widget) Delete() {
|
||||
w.list[w.idx].close()
|
||||
if w.list[w.idx].isLast() {
|
||||
w.UP()
|
||||
return
|
||||
}
|
||||
w.Down()
|
||||
}
|
||||
|
||||
func loadProjects() []*List {
|
||||
lists := []*List{}
|
||||
for _, id := range wtf.Config.UList("wtf.mods.todoist.projects") {
|
||||
list := NewList(id.(int))
|
||||
lists = append(lists, list)
|
||||
}
|
||||
|
||||
return lists
|
||||
}
|
||||
|
||||
func fromVim(event *tcell.EventKey) tcell.Key {
|
||||
switch string(event.Rune()) {
|
||||
case "h":
|
||||
return tcell.KeyLeft
|
||||
case "l":
|
||||
return tcell.KeyRight
|
||||
case "k":
|
||||
return tcell.KeyUp
|
||||
case "j":
|
||||
return tcell.KeyDown
|
||||
}
|
||||
return event.Key()
|
||||
}
|
2
vendor/github.com/darkSasori/todoist/.gitignore
generated
vendored
Normal file
2
vendor/github.com/darkSasori/todoist/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.out
|
||||
vendor/*
|
19
vendor/github.com/darkSasori/todoist/.travis.yml
generated
vendored
Normal file
19
vendor/github.com/darkSasori/todoist/.travis.yml
generated
vendored
Normal file
@ -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
|
21
vendor/github.com/darkSasori/todoist/Gopkg.lock
generated
vendored
Normal file
21
vendor/github.com/darkSasori/todoist/Gopkg.lock
generated
vendored
Normal file
@ -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
|
34
vendor/github.com/darkSasori/todoist/Gopkg.toml
generated
vendored
Normal file
34
vendor/github.com/darkSasori/todoist/Gopkg.toml
generated
vendored
Normal file
@ -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
|
21
vendor/github.com/darkSasori/todoist/LICENSE
generated
vendored
Normal file
21
vendor/github.com/darkSasori/todoist/LICENSE
generated
vendored
Normal file
@ -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.
|
6
vendor/github.com/darkSasori/todoist/README.md
generated
vendored
Normal file
6
vendor/github.com/darkSasori/todoist/README.md
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# todoist
|
||||
[](https://godoc.org/github.com/darkSasori/todoist)
|
||||
[](https://travis-ci.org/darkSasori/todoist)
|
||||
[](https://goreportcard.com/report/github.com/darkSasori/todoist)
|
||||
|
||||
Unofficial todoist api implementation
|
149
vendor/github.com/darkSasori/todoist/projects.go
generated
vendored
Normal file
149
vendor/github.com/darkSasori/todoist/projects.go
generated
vendored
Normal file
@ -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
|
||||
}
|
158
vendor/github.com/darkSasori/todoist/task.go
generated
vendored
Normal file
158
vendor/github.com/darkSasori/todoist/task.go
generated
vendored
Normal file
@ -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
|
||||
}
|
145
vendor/github.com/darkSasori/todoist/todoist.go
generated
vendored
Normal file
145
vendor/github.com/darkSasori/todoist/todoist.go
generated
vendored
Normal file
@ -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
|
||||
}
|
4
wtf.go
4
wtf.go
@ -39,6 +39,7 @@ import (
|
||||
"github.com/senorprogrammer/wtf/system"
|
||||
"github.com/senorprogrammer/wtf/textfile"
|
||||
"github.com/senorprogrammer/wtf/todo"
|
||||
"github.com/senorprogrammer/wtf/todoist"
|
||||
"github.com/senorprogrammer/wtf/trello"
|
||||
"github.com/senorprogrammer/wtf/weatherservices/prettyweather"
|
||||
"github.com/senorprogrammer/wtf/weatherservices/weather"
|
||||
@ -218,6 +219,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) {
|
||||
Widgets = append(Widgets, textfile.NewWidget(app, pages))
|
||||
case "todo":
|
||||
Widgets = append(Widgets, todo.NewWidget(app, pages))
|
||||
case "todoist":
|
||||
Widgets = append(Widgets, todoist.NewWidget(app, pages))
|
||||
case "trello":
|
||||
Widgets = append(Widgets, trello.NewWidget())
|
||||
case "weather":
|
||||
@ -233,7 +236,6 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) {
|
||||
if enabled := Config.UBool("wtf.mods."+mod+".enabled", false); enabled {
|
||||
addWidget(app, pages, mod)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user