diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-23 11:09:07 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-23 11:09:07 +0200 |
| commit | 53615a05708ff852af42905e2b5ced66ba70c43d (patch) | |
| tree | 5f936b6bb8a2305cff6c8d086e6ad5af4c1aa491 /web | |
| parent | 765ea1fffcc1bd1af2e6e9645d6f138dfd4ae0eb (diff) | |
Merge ride and rides packages into ride/store following mountain_pass structure
Consolidate persistence (Save, List, Backfill) into ride/store.go alongside
ride.go/climb.go/moving_time.go, rename rides.Ride to ride.StoredRide to
avoid collision with parsed ride.Ride, update all web/cli consumers and
RideView to use named Ride field, adjust templates and regenerate templ files,
and remove rides directory.
Diffstat (limited to 'web')
| -rw-r--r-- | web/ride-filters.go | 7 | ||||
| -rw-r--r-- | web/ride-filters_test.go | 23 | ||||
| -rw-r--r-- | web/rides.go | 17 | ||||
| -rw-r--r-- | web/server_test.go | 71 | ||||
| -rw-r--r-- | web/sync.go | 12 | ||||
| -rw-r--r-- | web/templates.templ | 2 | ||||
| -rw-r--r-- | web/views.go | 27 |
7 files changed, 77 insertions, 82 deletions
diff --git a/web/ride-filters.go b/web/ride-filters.go index 1fb647b..64bade9 100644 --- a/web/ride-filters.go +++ b/web/ride-filters.go @@ -6,7 +6,6 @@ import ( "time" "github.com/martinlehoux/biking_home/ride" - "github.com/martinlehoux/biking_home/rides" ) const ( @@ -321,11 +320,11 @@ func (filters RideFilters) Active() bool { filters.Route != rideRouteFilterAny } -func filterRides(items []rides.Ride, filters RideFilters) []rides.Ride { +func filterRides(items []ride.StoredRide, filters RideFilters) []ride.StoredRide { if !filters.Active() { return items } - filtered := make([]rides.Ride, 0, len(items)) + filtered := make([]ride.StoredRide, 0, len(items)) for _, item := range items { if rideMatchesFilters(item, filters) { filtered = append(filtered, item) @@ -334,7 +333,7 @@ func filterRides(items []rides.Ride, filters RideFilters) []rides.Ride { return filtered } -func rideMatchesFilters(item rides.Ride, filters RideFilters) bool { +func rideMatchesFilters(item ride.StoredRide, filters RideFilters) bool { if filters.DistanceMinKm != nil && item.DistanceM < float64(*filters.DistanceMinKm)*1000 { return false } diff --git a/web/ride-filters_test.go b/web/ride-filters_test.go index 8b470b6..bf1cc6f 100644 --- a/web/ride-filters_test.go +++ b/web/ride-filters_test.go @@ -9,7 +9,6 @@ import ( "time" "github.com/martinlehoux/biking_home/ride" - "github.com/martinlehoux/biking_home/rides" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -88,7 +87,7 @@ func TestParseRideFiltersTreatsFullRangesAsInactive(t *testing.T) { } func TestFilterRidesUsesInclusiveBoundsAndMovingTime(t *testing.T) { - items := []rides.Ride{ + items := []ride.StoredRide{ {Name: "lower boundary", DistanceM: 20_000, ExternalMovingTimeS: 1_800, StartDate: time.Date(2026, 8, 1, 12, 0, 0, 0, time.UTC), GPXPath: "lower.gpx"}, {Name: "upper boundary", DistanceM: 100_000, ExternalMovingTimeS: 10_800, StartDate: time.Date(2026, 8, 31, 12, 0, 0, 0, time.UTC), GPXPath: "upper.gpx"}, {Name: "outside distance", DistanceM: 110_000, ExternalMovingTimeS: 10_800, StartDate: time.Date(2026, 8, 31, 12, 0, 0, 0, time.UTC), GPXPath: "outside-distance.gpx"}, @@ -112,7 +111,7 @@ func TestFilterRidesUsesInclusiveBoundsAndMovingTime(t *testing.T) { } func TestFilterRidesByRouteAvailability(t *testing.T) { - items := []rides.Ride{ + items := []ride.StoredRide{ {Name: "recorded", GPXPath: "recorded.gpx"}, {Name: "metadata only"}, } @@ -128,7 +127,7 @@ func TestFilterRidesByRouteAvailability(t *testing.T) { func TestFilterRidesByCotacolExcludesUnavailableScores(t *testing.T) { _, db := newWebTestServer(t) - current := rides.Ride{ + current := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: testGPXPath(t, "current-cotacol.gpx"), Name: "Current score", @@ -136,7 +135,7 @@ func TestFilterRidesByCotacolExcludesUnavailableScores(t *testing.T) { StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, } - stale := rides.Ride{ + stale := ride.StoredRide{ ExternalID: "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8", GPXPath: testGPXPath(t, "stale-cotacol.gpx"), Name: "Stale score", @@ -144,16 +143,16 @@ func TestFilterRidesByCotacolExcludesUnavailableScores(t *testing.T) { StartDate: time.Date(2026, 8, 2, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, } - unavailable := rides.Ride{ + unavailable := ride.StoredRide{ ExternalID: "strava:7ba7b810-9dad-41d1-80b4-00c04fd430c8", Name: "No score", Type: "VirtualRide", StartDate: time.Date(2026, 8, 3, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, } - require.NoError(t, rides.Save(db, current)) - require.NoError(t, rides.Save(db, stale)) - require.NoError(t, rides.Save(db, unavailable)) + require.NoError(t, ride.Save(db, current)) + require.NoError(t, ride.Save(db, stale)) + require.NoError(t, ride.Save(db, unavailable)) _, err := db.Exec(` UPDATE rides SET cotacol_score = CASE external_id @@ -167,7 +166,7 @@ func TestFilterRidesByCotacolExcludesUnavailableScores(t *testing.T) { WHERE external_id IN (?, ?) `, current.ExternalID, stale.ExternalID, current.ExternalID, ride.CotacolAlgorithmVersion, stale.ExternalID, current.ExternalID, stale.ExternalID) require.NoError(t, err) - items, err := rides.List(db) + items, err := ride.List(db) require.NoError(t, err) filters := parseRideFilters(url.Values{rideFilterCotacolMinParam: {"200"}, rideFilterCotacolMaxParam: {"300"}}) @@ -210,7 +209,7 @@ func TestRideSortHeadersPreserveFilters(t *testing.T) { func TestHandlerFiltersRidesBeforeRenderingSortedResults(t *testing.T) { server, db := newWebTestServer(t) save := func(externalID, name, path string, distance float64) { - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: externalID, GPXPath: testGPXPath(t, path), Name: name, @@ -235,7 +234,7 @@ func TestHandlerFiltersRidesBeforeRenderingSortedResults(t *testing.T) { func TestHandlerRendersFilteredEmptyState(t *testing.T) { server, db := newWebTestServer(t) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:8ba7b810-9dad-41d1-80b4-00c04fd430c8", GPXPath: testGPXPath(t, "empty-filter.gpx"), Name: "Short Ride", diff --git a/web/rides.go b/web/rides.go index cb38b3c..477f066 100644 --- a/web/rides.go +++ b/web/rides.go @@ -9,7 +9,6 @@ import ( "github.com/martinlehoux/biking_home/mountain_pass" "github.com/martinlehoux/biking_home/official_climb" "github.com/martinlehoux/biking_home/ride" - "github.com/martinlehoux/biking_home/rides" "github.com/martinlehoux/kagamigo/kcore" ) @@ -41,7 +40,7 @@ func (s *Server) handleRide(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) return } - item, found, err := rides.GetByID(s.db, id) + item, found, err := ride.GetByID(s.db, id) if err != nil { slog.Error("Failed to load ride", "ride_id", id, "error", err) http.Error(w, "failed to load ride", http.StatusInternalServerError) @@ -103,7 +102,7 @@ func (s *Server) handleAnalytics(w http.ResponseWriter, r *http.Request) { if filters.DistanceMaxKm != nil { maxKm = *filters.DistanceMaxKm } - eligible := make([]rides.Ride, 0, len(items)) + eligible := make([]ride.StoredRide, 0, len(items)) for _, item := range items { distanceKm := int(item.DistanceM / 1000) if distanceKm < minKm || (maxKm != 0 && distanceKm > maxKm) { @@ -130,7 +129,7 @@ func (s *Server) handleCreateOfficialClimb(w http.ResponseWriter, r *http.Reques http.NotFound(w, r) return } - item, found, err := rides.GetByID(s.db, id) + item, found, err := ride.GetByID(s.db, id) if err != nil { slog.Error("Failed to load ride for official climb creation", "ride_id", id, "error", err) http.Error(w, "failed to load ride", http.StatusInternalServerError) @@ -190,18 +189,18 @@ func parseRouteIndex(value string) (int, error) { return index, nil } -func (s *Server) listRides(rideSort RideSort) ([]rides.Ride, error) { +func (s *Server) listRides(rideSort RideSort) ([]ride.StoredRide, error) { column, found := rideSort.databaseColumn() if !found { - return rides.List(s.db) + return ride.List(s.db) } - return rides.ListSorted(s.db, column, rideSort.Descending) + return ride.ListSorted(s.db, column, rideSort.Descending) } const minimumDisplayedDistanceM = 10_000 const rideDetailMountainPassMarginM = 10_000 -func buildRideViews(items []rides.Ride) []RideView { +func buildRideViews(items []ride.StoredRide) []RideView { views := make([]RideView, 0, len(items)) for _, item := range items { if item.DistanceM < minimumDisplayedDistanceM { @@ -212,7 +211,7 @@ func buildRideViews(items []rides.Ride) []RideView { return views } -func buildRideView(item rides.Ride) RideView { +func buildRideView(item ride.StoredRide) RideView { view := RideView{Ride: item, Cotacol: "-", CotacolPer100Km: "-", MovingTime: formatDuration(item.EffectiveMovingTimeS())} cotacol, ready := item.CotacolScore() if ready && item.CotacolAlgorithmVersion() == ride.CotacolAlgorithmVersion && item.DistanceM > 0 { diff --git a/web/server_test.go b/web/server_test.go index 0514dfc..ebedcd6 100644 --- a/web/server_test.go +++ b/web/server_test.go @@ -20,7 +20,6 @@ import ( "github.com/martinlehoux/biking_home/mountain_pass" "github.com/martinlehoux/biking_home/official_climb" "github.com/martinlehoux/biking_home/ride" - "github.com/martinlehoux/biking_home/rides" "github.com/martinlehoux/biking_home/strava" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -73,7 +72,7 @@ const officialClimbTrackGPX = `<?xml version="1.0"?><gpx xmlns="http://www.topog func TestHandlerRendersRidesPage(t *testing.T) { server, db := newWebTestServer(t) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:1234", GPXPath: testGPXPath(t, "long.gpx"), Name: "Long Ride", @@ -81,7 +80,7 @@ func TestHandlerRendersRidesPage(t *testing.T) { StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, })) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:5678", GPXPath: testGPXPath(t, "short.gpx"), Name: "Short Ride", @@ -106,7 +105,7 @@ func TestHandlerRendersRidesPage(t *testing.T) { func TestHandlerRendersRideDetailWithEmbeddedRoute(t *testing.T) { server, db := newWebTestServer(t) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: testGPXPath(t, "detail.gpx"), Name: "Detailed Ride", @@ -122,7 +121,7 @@ func TestHandlerRendersRideDetailWithEmbeddedRoute(t *testing.T) { 2, "Distant pass", 500, 43.2, 5.2, ) require.NoError(t, err) - item, found, err := rides.GetByExternalID(db, "strava:550e8400-e29b-41d4-a716-446655440000") + item, found, err := ride.GetByExternalID(db, "strava:550e8400-e29b-41d4-a716-446655440000") require.NoError(t, err) require.True(t, found) @@ -268,7 +267,7 @@ func TestHandlerCreatesOfficialClimbFromRoutePoints(t *testing.T) { server, db := newWebTestServer(t) routePath := filepath.Join(t.TempDir(), "official-climb.gpx") require.NoError(t, os.WriteFile(routePath, []byte(officialClimbTrackGPX), 0o600)) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: routePath, Name: "Climb Candidate", @@ -276,7 +275,7 @@ func TestHandlerCreatesOfficialClimbFromRoutePoints(t *testing.T) { StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 2_000, })) - item, found, err := rides.GetByExternalID(db, "strava:550e8400-e29b-41d4-a716-446655440000") + item, found, err := ride.GetByExternalID(db, "strava:550e8400-e29b-41d4-a716-446655440000") require.NoError(t, err) require.True(t, found) @@ -325,15 +324,15 @@ func TestHandlerCreatesOfficialClimbFromRoutePoints(t *testing.T) { func TestHandlerRendersRideDetailWithoutRoute(t *testing.T) { server, db := newWebTestServer(t) - item := rides.Ride{ + item := ride.StoredRide{ ExternalID: "strava:14701658670", Name: "Indoor Ride", Type: "VirtualRide", StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, } - require.NoError(t, rides.Save(db, item)) - stored, found, err := rides.GetByExternalID(db, item.ExternalID) + require.NoError(t, ride.Save(db, item)) + stored, found, err := ride.GetByExternalID(db, item.ExternalID) require.NoError(t, err) require.True(t, found) @@ -350,22 +349,22 @@ func TestHandlerRendersRideDetailWithoutRoute(t *testing.T) { func TestHandlerRendersAnalyticsChart(t *testing.T) { server, db := newWebTestServer(t) - first := rides.Ride{ + first := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440001", Name: "Fastish Ride", Type: "Ride", StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 40_000, } - second := rides.Ride{ + second := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440002", Name: "Climbing Ride", Type: "Ride", StartDate: time.Date(2026, 8, 2, 7, 0, 0, 0, time.UTC), DistanceM: 40_000, } - require.NoError(t, rides.Save(db, first)) - require.NoError(t, rides.Save(db, second)) + require.NoError(t, ride.Save(db, first)) + require.NoError(t, ride.Save(db, second)) _, err := db.Exec(` UPDATE rides SET cotacol_score = CASE external_id WHEN ? THEN 20 ELSE 120 END, @@ -392,22 +391,22 @@ func TestHandlerRendersAnalyticsChart(t *testing.T) { func TestHandlerFiltersAnalyticsByDistance(t *testing.T) { server, db := newWebTestServer(t) - short := rides.Ride{ + short := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440003", Name: "Short Ride", Type: "Ride", StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 40_000, } - long := rides.Ride{ + long := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440004", Name: "Long Ride", Type: "Ride", StartDate: time.Date(2026, 8, 2, 7, 0, 0, 0, time.UTC), DistanceM: 100_000, } - require.NoError(t, rides.Save(db, short)) - require.NoError(t, rides.Save(db, long)) + require.NoError(t, ride.Save(db, short)) + require.NoError(t, ride.Save(db, long)) _, err := db.Exec(` UPDATE rides SET cotacol_score = CASE external_id WHEN ? THEN 20 ELSE 120 END, @@ -448,7 +447,7 @@ func TestHandlerShowsErrorForUnavailableRideRoute(t *testing.T) { VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8", "missing.gpx", "Unavailable Route", "Ride", "2026-08-01T07:00:00Z", 20_000, 0, 0, 0, 0) require.NoError(t, err) - item, found, err := rides.GetByExternalID(db, "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8") + item, found, err := ride.GetByExternalID(db, "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8") require.NoError(t, err) require.True(t, found) @@ -567,10 +566,10 @@ func TestSyncRidesContinuesAfterInvalidActivity(t *testing.T) { require.NoError(t, err) assert.Equal(t, SyncProgress{Total: 2, Completed: 2, Imported: 1, Skipped: 1}, progress) assert.Len(t, updates, 3) - _, found, err := rides.GetByExternalID(db, "strava:14701658670") + _, found, err := ride.GetByExternalID(db, "strava:14701658670") require.NoError(t, err) assert.False(t, found) - _, found, err = rides.GetByExternalID(db, "strava:14701658671") + _, found, err = ride.GetByExternalID(db, "strava:14701658671") require.NoError(t, err) assert.True(t, found) assert.NoFileExists(t, filepath.Join(gpxDir, "activity_14701658670.gpx")) @@ -599,14 +598,14 @@ func TestSyncRidesSavesActivityWithoutRoute(t *testing.T) { require.NoError(t, err) assert.Equal(t, SyncProgress{Total: 2, Completed: 2, Imported: 2}, progress) - indoor, found, err := rides.GetByExternalID(db, "strava:14701658670") + indoor, found, err := ride.GetByExternalID(db, "strava:14701658670") require.NoError(t, err) require.True(t, found) assert.Empty(t, indoor.GPXPath) _, ready := indoor.CotacolScore() assert.False(t, ready) assert.NoFileExists(t, staleGPXPath) - _, found, err = rides.GetByExternalID(db, "strava:14701658671") + _, found, err = ride.GetByExternalID(db, "strava:14701658671") require.NoError(t, err) assert.True(t, found) } @@ -712,7 +711,7 @@ func TestRideSortHeadersToggleDirection(t *testing.T) { func TestBuildRideViewsUsesStoredCotacol(t *testing.T) { _, db := newWebTestServer(t) - ride := rides.Ride{ + stored := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: testGPXPath(t, "stored.gpx"), Name: "Stored Ride", @@ -720,10 +719,10 @@ func TestBuildRideViewsUsesStoredCotacol(t *testing.T) { StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, } - require.NoError(t, rides.Save(db, ride)) - _, err := db.Exec("UPDATE rides SET gpx_path = ? WHERE external_id = ?", "missing.gpx", ride.ExternalID) + require.NoError(t, ride.Save(db, stored)) + _, err := db.Exec("UPDATE rides SET gpx_path = ? WHERE external_id = ?", "missing.gpx", stored.ExternalID) require.NoError(t, err) - items, err := rides.List(db) + items, err := ride.List(db) require.NoError(t, err) views := buildRideViews(items) @@ -733,7 +732,7 @@ func TestBuildRideViewsUsesStoredCotacol(t *testing.T) { func TestBuildRideViewMovingTimePrefersCanonical(t *testing.T) { _, db := newWebTestServer(t) - ride := rides.Ride{ + stored := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: testGPXPath(t, "moving.gpx"), Name: "Moving Ride", @@ -742,8 +741,8 @@ func TestBuildRideViewMovingTimePrefersCanonical(t *testing.T) { DistanceM: 20_000, ExternalMovingTimeS: 7_200, } - require.NoError(t, rides.Save(db, ride)) - items, err := rides.List(db) + require.NoError(t, ride.Save(db, stored)) + items, err := ride.List(db) require.NoError(t, err) require.Len(t, items, 1) @@ -752,7 +751,7 @@ func TestBuildRideViewMovingTimePrefersCanonical(t *testing.T) { func TestHandlerSortsRidesByDistance(t *testing.T) { server, db := newWebTestServer(t) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: testGPXPath(t, "near.gpx"), Name: "Near Ride", @@ -760,7 +759,7 @@ func TestHandlerSortsRidesByDistance(t *testing.T) { StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, })) - require.NoError(t, rides.Save(db, rides.Ride{ + require.NoError(t, ride.Save(db, ride.StoredRide{ ExternalID: "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8", GPXPath: testGPXPath(t, "far.gpx"), Name: "Far Ride", @@ -781,7 +780,7 @@ func TestHandlerSortsRidesByDistance(t *testing.T) { func TestHandlerSortsRidesByCotacol(t *testing.T) { server, db := newWebTestServer(t) - first := rides.Ride{ + first := ride.StoredRide{ ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", GPXPath: testGPXPath(t, "first.gpx"), Name: "Low Cotacol", @@ -789,7 +788,7 @@ func TestHandlerSortsRidesByCotacol(t *testing.T) { StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), DistanceM: 20_000, } - second := rides.Ride{ + second := ride.StoredRide{ ExternalID: "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8", GPXPath: testGPXPath(t, "second.gpx"), Name: "High Cotacol", @@ -797,8 +796,8 @@ func TestHandlerSortsRidesByCotacol(t *testing.T) { StartDate: time.Date(2026, 8, 2, 7, 0, 0, 0, time.UTC), DistanceM: 40_000, } - require.NoError(t, rides.Save(db, first)) - require.NoError(t, rides.Save(db, second)) + require.NoError(t, ride.Save(db, first)) + require.NoError(t, ride.Save(db, second)) _, err := db.Exec(` UPDATE rides SET cotacol_score = CASE external_id WHEN ? THEN 1 ELSE 4 END diff --git a/web/sync.go b/web/sync.go index 4a6ba5f..b491ee0 100644 --- a/web/sync.go +++ b/web/sync.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/martinlehoux/biking_home/rides" + "github.com/martinlehoux/biking_home/ride" "github.com/martinlehoux/biking_home/strava" "github.com/martinlehoux/kagamigo/kcore" ) @@ -104,7 +104,7 @@ func (s *Server) syncRides(client syncClient, gpxDir string, from, to time.Time, } for _, summary := range activities { externalID := fmt.Sprintf("strava:%d", summary.ID) - _, exists, err := rides.GetByExternalID(s.db, externalID) + _, exists, err := ride.GetByExternalID(s.db, externalID) if err != nil { return progress, err } @@ -120,7 +120,7 @@ func (s *Server) syncRides(client syncClient, gpxDir string, from, to time.Time, if err != nil { if errors.Is(err, strava.ErrNoTrackPoints) { _ = os.Remove(filepath.Join(gpxDir, fmt.Sprintf("activity_%d.gpx", summary.ID))) - if saveErr := rides.Save(s.db, rideFromActivity(externalID, "", activity)); saveErr != nil { + if saveErr := ride.Save(s.db, rideFromActivity(externalID, "", activity)); saveErr != nil { if reportErr := skipSyncActivity(&progress, report, summary, fmt.Errorf("save metadata: %w", saveErr)); reportErr != nil { return progress, reportErr } @@ -147,7 +147,7 @@ func (s *Server) syncRides(client syncClient, gpxDir string, from, to time.Time, } continue } - if err := rides.Save(s.db, rideFromActivity(externalID, gpxPath, activity)); err != nil { + if err := ride.Save(s.db, rideFromActivity(externalID, gpxPath, activity)); err != nil { _ = os.Remove(gpxPath) if reportErr := skipSyncActivity(&progress, report, summary, fmt.Errorf("save activity: %w", err)); reportErr != nil { return progress, reportErr @@ -164,12 +164,12 @@ func (s *Server) syncRides(client syncClient, gpxDir string, from, to time.Time, return progress, nil } -func rideFromActivity(externalID, gpxPath string, activity strava.Activity) rides.Ride { +func rideFromActivity(externalID, gpxPath string, activity strava.Activity) ride.StoredRide { activityType := activity.SportType if activityType == "" { activityType = activity.Type } - return rides.Ride{ + return ride.StoredRide{ ExternalID: externalID, GPXPath: gpxPath, Name: activity.Name, diff --git a/web/templates.templ b/web/templates.templ index f2b62f8..0660d07 100644 --- a/web/templates.templ +++ b/web/templates.templ @@ -84,7 +84,7 @@ templ RidesContent(data RidesPageData) { </tr></thead> <tbody> for _, item := range data.Items { - <tr><td><strong><a href={ templ.URL(rideDetailURL(item.ID)) }>{ item.Name }</a></strong><br/><small>{ item.Type }</small></td><td>{ formatRideDate(item.StartDate) }</td><td class="numeric">{ formatDistance(item.DistanceM) }</td><td class="numeric">{ item.MovingTime }</td><td class="numeric">{ formatSpeed(item.AverageSpeedMps) }</td><td class="numeric">{ formatElevation(item.TotalElevationGainM) }</td><td class="numeric">{ item.Cotacol }</td><td class="numeric">{ item.CotacolPer100Km }</td></tr> + <tr><td><strong><a href={ templ.URL(rideDetailURL(item.Ride.ID)) }>{ item.Ride.Name }</a></strong><br/><small>{ item.Ride.Type }</small></td><td>{ formatRideDate(item.Ride.StartDate) }</td><td class="numeric">{ formatDistance(item.Ride.DistanceM) }</td><td class="numeric">{ item.MovingTime }</td><td class="numeric">{ formatSpeed(item.Ride.AverageSpeedMps) }</td><td class="numeric">{ formatElevation(item.Ride.TotalElevationGainM) }</td><td class="numeric">{ item.Cotacol }</td><td class="numeric">{ item.CotacolPer100Km }</td></tr> } </tbody> </table> diff --git a/web/views.go b/web/views.go index 7a5a461..64afb82 100644 --- a/web/views.go +++ b/web/views.go @@ -9,11 +9,10 @@ import ( "github.com/martinlehoux/biking_home/official_climb" "github.com/martinlehoux/biking_home/ride" "github.com/martinlehoux/biking_home/rideanalysis" - "github.com/martinlehoux/biking_home/rides" ) type RideView struct { - rides.Ride + Ride ride.StoredRide Cotacol string CotacolPer100Km string MovingTime string @@ -39,7 +38,7 @@ type AnalyticsPoint struct { CotacolPer100Km float64 `json:"cotacolPer100Km"` } -func buildAnalyticsPoints(items []rides.Ride) []AnalyticsPoint { +func buildAnalyticsPoints(items []ride.StoredRide) []AnalyticsPoint { points := make([]AnalyticsPoint, 0, len(items)) for _, item := range items { cotacol, ready := item.CotacolScore() @@ -194,16 +193,16 @@ func parseRideSort(query url.Values) RideSort { return RideSort{Column: column, Descending: direction != "asc"} } -func (s RideSort) databaseColumn() (rides.SortColumn, bool) { - columns := map[string]rides.SortColumn{ - rideSortName: rides.SortName, - rideSortStarted: rides.SortStartDate, - rideSortDistance: rides.SortDistance, - rideSortMovingTime: rides.SortMovingTime, - rideSortSpeed: rides.SortSpeed, - rideSortElevation: rides.SortElevation, - rideSortCotacol: rides.SortCotacol, - rideSortCotacolKm: rides.SortCotacolKm, +func (s RideSort) databaseColumn() (ride.SortColumn, bool) { + columns := map[string]ride.SortColumn{ + rideSortName: ride.SortName, + rideSortStarted: ride.SortStartDate, + rideSortDistance: ride.SortDistance, + rideSortMovingTime: ride.SortMovingTime, + rideSortSpeed: ride.SortSpeed, + rideSortElevation: ride.SortElevation, + rideSortCotacol: ride.SortCotacol, + rideSortCotacolKm: ride.SortCotacolKm, } column, found := columns[s.Column] return column, found @@ -277,7 +276,7 @@ func officialClimbCreateURL(id int64) string { return fmt.Sprintf("/rides/%d/official-climbs", id) } -func buildRideDetailView(item rides.Ride, parsed ride.Ride, passes []mountain_pass.MountainPass, officialClimbs []official_climb.OfficialClimb, matchPolicy official_climb.MatchPolicy) RideDetailView { +func buildRideDetailView(item ride.StoredRide, parsed ride.Ride, passes []mountain_pass.MountainPass, officialClimbs []official_climb.OfficialClimb, matchPolicy official_climb.MatchPolicy) RideDetailView { coordinates := make([][]float64, parsed.Len()) for i := 0; i < parsed.Len(); i++ { coordinate := parsed.Coord(i) |
