mirror of
https://github.com/Xevion/todoist-late-reset.git
synced 2025-12-06 01:16:37 -06:00
project init
This commit is contained in:
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# todoist-late-reset
|
||||||
|
|
||||||
|
A basic Go program to reset certain tasks in Todoist if they're completed 'late'.
|
||||||
|
|
||||||
|
## Story
|
||||||
|
|
||||||
|
I need tasks that I complete after midnight to be automatically rescheduled for the same day so that I can still complete them the next day (without having to manually reschedule each one I complete late).
|
||||||
|
|
||||||
|
This is effective for people like me who are still active (or may review their tasks) after midnight.
|
||||||
35
api.go
Normal file
35
api.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getRecentlyCompleted() (string, error) {
|
||||||
|
baseURL := "https://api.todoist.com/sync/v9/activity/get"
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("event_type", "completed")
|
||||||
|
|
||||||
|
fullURL := baseURL + "?" + params.Encode()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", fullURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+todoistApiToken)
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(body), nil
|
||||||
|
}
|
||||||
15
go.mod
Normal file
15
go.mod
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
module github.com/Xevion/todoist-late-reset
|
||||||
|
|
||||||
|
go 1.22.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/go-co-op/gocron/v2 v2.12.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.4.0 // indirect
|
||||||
|
github.com/redis/go-redis/v9 v9.6.1 // indirect
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
|
||||||
|
)
|
||||||
18
go.sum
Normal file
18
go.sum
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/go-co-op/gocron/v2 v2.12.0 h1:JuvX4J//Mdw18tN82ZwD9VYwOaL1aSCIu7HQyIhhrAE=
|
||||||
|
github.com/go-co-op/gocron/v2 v2.12.0/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||||
|
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||||
|
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
|
||||||
|
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||||
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||||
77
main.go
Normal file
77
main.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Uses go cron to schedule a job to run every 3 minutes from 1AM to 3AM.
|
||||||
|
// Queries the todoist API for task completion
|
||||||
|
// Tasks that are completed between 12AM and 3AM are considered 'not too late' and will be rescheduled one day earlier (if they are recurring tasks).
|
||||||
|
// Only tasks with the included label (e.g. well-being) are considered.
|
||||||
|
// Most tasks are scheduled daily, so this means they'll be rescheduled for the current day. But not all.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-co-op/gocron/v2"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
todoistApiToken = os.Getenv("TODOIST_API_TOKEN")
|
||||||
|
redisURL = os.Getenv("REDIS_URL")
|
||||||
|
cronSchedule = os.Getenv("CRON_SCHEDULE")
|
||||||
|
client = &http.Client{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Load .env file if available
|
||||||
|
err := godotenv.Load()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(".env file not loaded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
opt, _ := redis.ParseURL(redisURL)
|
||||||
|
client := redis.NewClient(opt)
|
||||||
|
|
||||||
|
// create a scheduler
|
||||||
|
s, err := gocron.NewScheduler()
|
||||||
|
if err != nil {
|
||||||
|
// TODO: handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a job to the scheduler
|
||||||
|
_, err = s.NewJob(
|
||||||
|
gocron.CronJob(cronSchedule, false),
|
||||||
|
gocron.NewTask(
|
||||||
|
func(a string, b int) {
|
||||||
|
fmt.Println("Current time:", time.Now().Format(time.RFC3339))
|
||||||
|
},
|
||||||
|
"hello",
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the scheduler
|
||||||
|
s.Start()
|
||||||
|
|
||||||
|
// Setup signal handler channel
|
||||||
|
stop := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(stop, os.Interrupt) // Ctrl+C signal
|
||||||
|
signal.Notify(stop, syscall.SIGTERM) // Container stop signal
|
||||||
|
|
||||||
|
// Wait for signal (indefinite)
|
||||||
|
closingSignal := <-stop
|
||||||
|
|
||||||
|
fmt.Println("Gracefully shutting down, received signal:", closingSignal.String())
|
||||||
|
err = s.Shutdown()
|
||||||
|
if err != nil {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user