diff --git a/db/integrations/komoot/komoot.go b/db/integrations/komoot/komoot.go index 744e485f..4547778b 100644 --- a/db/integrations/komoot/komoot.go +++ b/db/integrations/komoot/komoot.go @@ -68,25 +68,27 @@ func SyncKomoot(app core.App) error { app.Logger().Warn(warning) continue } - hasNewTours := true - page := 0 - for hasNewTours { - tours, err := k.fetchTours(page) + totalPages := 1 + for page := 0; page < totalPages; page++ { + tours, tp, err := k.fetchTours(page) if err != nil { - warning := fmt.Sprintf("error fetching tours from komoot: %v\n", err) + warning := fmt.Sprintf("error fetching tours from komoot (page %d): %v\n", page, err) fmt.Print(warning) app.Logger().Warn(warning) - continue + break } + totalPages = tp - hasNewTours, err = syncTrailWithTours(app, k, komootIntegration, userId, actorId, tours) + allAlreadySynced, err := syncTrailWithTours(app, k, komootIntegration, userId, actorId, tours) if err != nil { warning := fmt.Sprintf("error syncing komoot tours with trails: %v\n", err) fmt.Print(warning) app.Logger().Warn(warning) - continue + break + } + if allAlreadySynced { + break } - page += 1 } } @@ -156,20 +158,18 @@ func (k *KomootApi) Login(email, password string) error { return nil } -func (k *KomootApi) fetchTours(page int) ([]KomootTour, error) { +func (k *KomootApi) fetchTours(page int) ([]KomootTour, int, error) { currentUri := fmt.Sprintf("https://api.komoot.de/v007/users/%s/tours/?page=%d&sort_field=date&sort_direction=desc&limit=30", k.UserID, page) body, err := sendRequest(currentUri, k.buildHeader()) if err != nil { - return nil, err + return nil, 0, err } var data KomootToursResponse json.Unmarshal(body, &data) - tours := data.Embedded.Tours - - return tours, nil + return data.Embedded.Tours, data.Page.TotalPages, nil } func (k *KomootApi) fetchDetailedTour(tour KomootTour) (*DetailedKomootTour, error) { @@ -184,17 +184,25 @@ func (k *KomootApi) fetchDetailedTour(tour KomootTour) (*DetailedKomootTour, err return data, nil } +// syncTrailWithTours imports tours not yet in the DB. Returns allAlreadySynced=true +// when every tour on this page was already imported, so the caller can stop paginating +// early during incremental syncs. Tours skipped due to type filters do NOT count as +// synced - only tours already present in the DB do. func syncTrailWithTours(app core.App, k *KomootApi, i KomootIntegration, user string, actor string, tours []KomootTour) (bool, error) { - hasNewTours := false + allAlreadySynced := true for _, tour := range tours { trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": strconv.Itoa(int(tour.ID))}) if err != nil { - return hasNewTours, err + return false, err } - if len(trails) != 0 || (tour.Type == "tour_planned" && !i.Planned) || (tour.Type == "tour_recorded" && !i.Completed) { + if len(trails) != 0 { + continue + } + // Tour is not yet in the DB - we must keep paginating regardless of type filter + allAlreadySynced = false + if (tour.Type == "tour_planned" && !i.Planned) || (tour.Type == "tour_recorded" && !i.Completed) { continue } - hasNewTours = true detailedTour, err := k.fetchDetailedTour(tour) if err != nil { app.Logger().Warn(fmt.Sprintf("Unable to fetch details for tour '%s': %v", tour.Name, err)) @@ -217,7 +225,7 @@ func syncTrailWithTours(app core.App, k *KomootApi, i KomootIntegration, user st } } - return hasNewTours, nil + return allAlreadySynced, nil } func createTrailFromTour(app core.App, k *KomootApi, detailedTour *DetailedKomootTour, gpx *filesystem.File, user string, actor string, privacy string) (string, error) {