From 43f1daf40c388a0aa40f7fd6a8db4c78308d4efd Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 18 Feb 2022 20:00:42 +0100 Subject: [PATCH] fix: microsoft todo migration not importing all tasks Previously, we did not check if a list has more tasks than the ones returned. By default, the Microsoft Graph API only returns 10 tasks. If the user had more they would not get imported. Now we check if there are more pages with tasks and pull them all in until we have everything. --- .../microsoft-todo/microsoft_todo.go | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/pkg/modules/migration/microsoft-todo/microsoft_todo.go b/pkg/modules/migration/microsoft-todo/microsoft_todo.go index 64d20e41a..0cf390f7f 100644 --- a/pkg/modules/migration/microsoft-todo/microsoft_todo.go +++ b/pkg/modules/migration/microsoft-todo/microsoft_todo.go @@ -23,6 +23,7 @@ import ( "fmt" "net/http" "net/url" + "strings" "time" "code.vikunja.io/api/pkg/config" @@ -33,6 +34,7 @@ import ( ) const apiScopes = `tasks.read tasks.read.shared` +const apiPrefix = `https://graph.microsoft.com/v1.0/me/todo/` type Migration struct { Code string `json:"code"` @@ -92,6 +94,7 @@ type recurrence struct { type tasksResponse struct { OdataContext string `json:"@odata.context"` + Nextlink string `json:"@odata.nextLink"` Value []*task `json:"value"` } @@ -178,7 +181,7 @@ func getMicrosoftGraphAuthToken(code string) (accessToken string, err error) { } func makeAuthenticatedGetRequest(token, urlPart string, v interface{}) error { - req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://graph.microsoft.com/v1.0/me/todo/"+urlPart, nil) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, apiPrefix+urlPart, nil) if err != nil { return err } @@ -224,17 +227,30 @@ func getMicrosoftTodoData(token string) (microsoftTodoData []*list, err error) { log.Debugf("[Microsoft Todo Migration] Got %d lists", len(lists.Value)) for _, list := range lists.Value { - tasksResponse := &tasksResponse{} - err = makeAuthenticatedGetRequest(token, "lists/"+list.ID+"/tasks", tasksResponse) - if err != nil { - log.Errorf("[Microsoft Todo Migration] Could not get tasks for list %s: %s", list.ID, err) - return + link := "lists/" + list.ID + "/tasks" + list.Tasks = []*task{} + + // Microsoft's Graph API has pagination, so we're going through all pages to get all tasks + for { + tr := &tasksResponse{} + + err = makeAuthenticatedGetRequest(token, link, tr) + if err != nil { + log.Errorf("[Microsoft Todo Migration] Could not get tasks for list %s: %s", list.ID, err) + return + } + + log.Debugf("[Microsoft Todo Migration] Got %d tasks for list %s", len(tr.Value), list.ID) + + list.Tasks = append(list.Tasks, tr.Value...) + + if tr.Nextlink == "" { + break + } + + link = strings.ReplaceAll(tr.Nextlink, apiPrefix, "") } - log.Debugf("[Microsoft Todo Migration] Got %d tasks for list %s", len(tasksResponse.Value), list.ID) - - list.Tasks = tasksResponse.Value - microsoftTodoData = append(microsoftTodoData, list) }