mirror of
https://github.com/Xevion/todoist-late-reset.git
synced 2025-12-07 03:16:48 -06:00
remove get() body param, begin parsing sync response
This commit is contained in:
@@ -29,10 +29,10 @@ func main() {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
client = api.NewSyncClient(os.Getenv("TODOIST_API_KEY"))
|
client = api.NewSyncClient(os.Getenv("TODOIST_API_KEY"))
|
||||||
client.sync(true)
|
client.Synchronize(true)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_, changes, err := client.sync(false)
|
changes, err := client.Synchronize(false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error syncing:", err)
|
fmt.Println("Error syncing:", err)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -27,17 +26,12 @@ type Event struct {
|
|||||||
|
|
||||||
func (sc *SyncClient) RecentlyCompleted() (*ActivityLog, error) {
|
func (sc *SyncClient) RecentlyCompleted() (*ActivityLog, error) {
|
||||||
params := url.Values{"event_type": {"completed"}}
|
params := url.Values{"event_type": {"completed"}}
|
||||||
req, err := http.NewRequest("GET", API_BASE_URL+"/activity/get?"+params.Encode(), nil)
|
|
||||||
|
resp, err := sc.get("activity/get", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+sc.ApiToken)
|
|
||||||
|
|
||||||
resp, err := sc.Http.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
|||||||
@@ -1,7 +1,38 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
type ClientState struct {
|
import "encoding/json"
|
||||||
// Items map[string]Item
|
|
||||||
|
type SyncResponse struct {
|
||||||
|
// The new token to use for the next incremental sync.
|
||||||
|
SyncToken string `json:"sync_token"`
|
||||||
|
// If true, this response is a full sync and the client should not merge but instead replace it's state.
|
||||||
|
FullSync bool `json:"full_sync"`
|
||||||
|
// Used for commands where local IDs are temporarily chosen by the client and need to be mapped to the server's IDs.
|
||||||
|
TempIDMapping map[string]interface{} `json:"temp_id_mapping"`
|
||||||
|
Items []interface{} `json:"items"`
|
||||||
|
// CompletedInfo []interface{} `json:"completed_info"`
|
||||||
|
// Collaborators []interface{} `json:"collaborators"`
|
||||||
|
// CollaboratorStates []interface{} `json:"collaborator_states"`
|
||||||
|
// DayOrders map[string]interface{} `json:"day_orders"`
|
||||||
|
// Filters []interface{} `json:"filters"`
|
||||||
|
// Labels []interface{} `json:"labels"`
|
||||||
|
// LiveNotifications []interface{} `json:"live_notifications"`
|
||||||
|
// LiveNotificationsLastReadID string `json:"live_notifications_last_read_id"`
|
||||||
|
// Locations []interface{} `json:"locations"`
|
||||||
|
// Notes []interface{} `json:"notes"`
|
||||||
|
// ProjectNotes []interface{} `json:"project_notes"`
|
||||||
|
// Projects []interface{} `json:"projects"`
|
||||||
|
// Reminders []interface{} `json:"reminders"`
|
||||||
|
// Sections []interface{} `json:"sections"`
|
||||||
|
// Stats map[string]interface{} `json:"stats"`
|
||||||
|
// SettingsNotifications map[string]interface{} `json:"settings_notifications"`
|
||||||
|
// User map[string]interface{} `json:"user"`
|
||||||
|
// UserPlanLimits map[string]interface{} `json:"user_plan_limits"`
|
||||||
|
// UserSettings map[string]interface{} `json:"user_settings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type State struct {
|
||||||
|
Items map[string]Item
|
||||||
}
|
}
|
||||||
|
|
||||||
type Changes struct {
|
type Changes struct {
|
||||||
@@ -23,6 +54,54 @@ type Changes struct {
|
|||||||
// int - the number of changes synchronized.
|
// int - the number of changes synchronized.
|
||||||
// *Changes - a pointer to a Changes struct containing the details of the changes.
|
// *Changes - a pointer to a Changes struct containing the details of the changes.
|
||||||
// error - an error object if an error occurred during synchronization, otherwise nil.
|
// error - an error object if an error occurred during synchronization, otherwise nil.
|
||||||
func (sc *SyncClient) sync(full bool) (int, *Changes, error) {
|
func (sc *SyncClient) Synchronize(full bool) (*Changes, error) {
|
||||||
return 0, nil, nil
|
if sc.RequireFullSync {
|
||||||
|
sc.syncToken = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"sync_token": sc.syncToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBody, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := sc.post("/sync", nil, jsonBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
var syncResponse SyncResponse
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&syncResponse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.syncToken = syncResponse.SyncToken
|
||||||
|
|
||||||
|
// changes := &Changes{
|
||||||
|
// Added: []string{},
|
||||||
|
// Updated: []string{},
|
||||||
|
// Deleted: []string{},
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Process the items in syncResponse.Items to populate changes
|
||||||
|
// for _, item := range syncResponse.Items {
|
||||||
|
// // Assuming item is a map[string]interface{} and has a "status" field
|
||||||
|
// itemMap := item.(map[string]interface{})
|
||||||
|
// if status, ok := itemMap["status"].(string); ok {
|
||||||
|
// switch status {
|
||||||
|
// case "added":
|
||||||
|
// changes.Added = append(changes.Added, itemMap["id"].(string))
|
||||||
|
// case "updated":
|
||||||
|
// changes.Updated = append(changes.Updated, itemMap["id"].(string))
|
||||||
|
// case "deleted":
|
||||||
|
// changes.Deleted = append(changes.Deleted, itemMap["id"].(string))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return changes, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ func init() {
|
|||||||
// and the types of resources to be synchronized.
|
// and the types of resources to be synchronized.
|
||||||
type SyncClient struct {
|
type SyncClient struct {
|
||||||
Http *http.Client
|
Http *http.Client
|
||||||
SyncToken string
|
syncToken string
|
||||||
ApiToken string
|
ApiToken string
|
||||||
// LastSync is the timestamp of the last synchronization, full or incremental.
|
// LastSync is the timestamp of the last synchronization, full or incremental.
|
||||||
LastSync time.Time
|
LastSync time.Time
|
||||||
@@ -48,7 +49,7 @@ func NewSyncClient(apiToken string) *SyncClient {
|
|||||||
return &SyncClient{
|
return &SyncClient{
|
||||||
Http: &http.Client{},
|
Http: &http.Client{},
|
||||||
ApiToken: apiToken,
|
ApiToken: apiToken,
|
||||||
SyncToken: "*",
|
syncToken: "*",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,18 +71,44 @@ func (sc *SyncClient) UseResources(resourceTypes ...ResourceType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// headers applies common headers to the given request.
|
||||||
|
func (sc *SyncClient) headers(req *http.Request) {
|
||||||
|
req.Header.Set("Authorization", "Bearer "+sc.ApiToken)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
}
|
||||||
|
|
||||||
// get performs a GET request to the Todoist API, building a request with the given path and parameters.
|
// get performs a GET request to the Todoist API, building a request with the given path and parameters.
|
||||||
// It will also apply Authorization, Content-Type, Accept, and User-Agent headers.
|
// It will also apply Authorization, Content-Type, Accept, and User-Agent headers.
|
||||||
func (sc *SyncClient) get(path string, params url.Values) (*http.Response, error) {
|
func (sc *SyncClient) get(path string, params url.Values) (*http.Response, error) {
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", API_BASE_URL+path+"?"+params.Encode(), nil)
|
req, err := http.NewRequest("GET", API_BASE_URL+path+"?"+params.Encode(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+sc.ApiToken)
|
sc.headers(req)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("Accept", "application/json")
|
return sc.Http.Do(req)
|
||||||
req.Header.Set("User-Agent", userAgent)
|
}
|
||||||
|
|
||||||
|
// post performs a POST request to the Todoist API, building a request with the given path and parameters.
|
||||||
|
// It will also apply Authorization, Content-Type, Accept, and User-Agent headers.
|
||||||
|
func (sc *SyncClient) post(path string, params url.Values, body []byte) (*http.Response, error) {
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", API_BASE_URL+path+"?"+params.Encode(), strings.NewReader(string(body)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.headers(req)
|
||||||
|
|
||||||
return sc.Http.Do(req)
|
return sc.Http.Do(req)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user