aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/ride-filters.go7
-rw-r--r--web/ride-filters_test.go23
-rw-r--r--web/rides.go17
-rw-r--r--web/server_test.go71
-rw-r--r--web/sync.go12
-rw-r--r--web/templates.templ2
-rw-r--r--web/views.go27
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)