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