aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fietsboek/views/profile.py86
1 files changed, 59 insertions, 27 deletions
diff --git a/fietsboek/views/profile.py b/fietsboek/views/profile.py
index 6aef499..2a4203e 100644
--- a/fietsboek/views/profile.py
+++ b/fietsboek/views/profile.py
@@ -1,6 +1,7 @@
"""Endpoints for the user profile pages."""
import datetime
import sqlite3
+from dataclasses import dataclass
from pyramid.httpexceptions import HTTPNotFound
from pyramid.request import Request
@@ -14,6 +15,54 @@ from ..data import UserDataDir
from ..models.track import TrackType, TrackWithMetadata
+@dataclass
+class CumulativeStats:
+ """Cumulative user stats.
+
+ The values start out with default values, and tracks can be merged in via
+ :meth:`add`.
+ """
+
+ count: int = 0
+ """Number of tracks added."""
+
+ length: float = 0.0
+ """Total length, in meters."""
+
+ uphill: float = 0.0
+ """Total uphill, in meters."""
+
+ downhill: float = 0.0
+ """Total downhill, in meters."""
+
+ moving_time: datetime.timedelta = datetime.timedelta(0)
+ """Total time spent moving."""
+
+ stopped_time: datetime.timedelta = datetime.timedelta(0)
+ """Total time standing still."""
+
+ max_speed: float = 0.0
+ """Overall maximum speed, in m/s."""
+
+ def add(self, track: TrackWithMetadata):
+ """Adds a track to this stats collection.
+
+ :param track: The track to add, with accompanying metadata.
+ """
+ self.count += 1
+ self.length += track.length
+ self.uphill += track.uphill
+ self.downhill += track.downhill
+ self.moving_time += track.moving_time
+ self.stopped_time += track.stopped_time
+ self.max_speed = max(self.max_speed, track.max_speed)
+
+ @property
+ def avg_speed(self) -> float:
+ """Average speed, in m/s."""
+ return self.length / self.moving_time.total_seconds()
+
+
def round_to_seconds(value: datetime.timedelta) -> datetime.timedelta:
"""Round a timedelta to full seconds.
@@ -34,31 +83,14 @@ def profile(request: Request) -> dict:
:param request: The pyramid request.
:return: The template parameters.
"""
- total_length = 0.0
- total_uphill = 0.0
- total_downhill = 0.0
- total_moving_time = datetime.timedelta(0)
- total_stopped_time = datetime.timedelta(0)
- max_speed = 0.0
- number_of_tracks = 0
+ total = CumulativeStats()
query = request.context.all_tracks_query()
query = select(aliased(models.Track, query)).where(query.c.type == TrackType.ORGANIC)
track: models.Track
for track in request.dbsession.execute(query).scalars():
meta = TrackWithMetadata(track, request.data_manager)
-
- total_length += meta.length
- total_uphill += meta.uphill
- total_downhill += meta.downhill
- total_moving_time += meta.moving_time
- total_stopped_time += meta.stopped_time
- max_speed = max(max_speed, meta.max_speed)
- number_of_tracks += 1
-
- avg_speed = total_length / total_moving_time.total_seconds()
- total_moving_time = round_to_seconds(total_moving_time)
- total_stopped_time = round_to_seconds(total_stopped_time)
+ total.add(meta)
heatmap_url = None
tilehunt_url = None
@@ -94,15 +126,15 @@ def profile(request: Request) -> dict:
return {
"user": request.context,
- "total_length": total_length,
- "total_uphill": total_uphill,
- "total_downhill": total_downhill,
- "total_moving_time": total_moving_time,
- "total_stopped_time": total_stopped_time,
- "max_speed": max_speed,
- "avg_speed": avg_speed,
+ "total_length": total.length,
+ "total_uphill": total.uphill,
+ "total_downhill": total.downhill,
+ "total_moving_time": round_to_seconds(total.moving_time),
+ "total_stopped_time": round_to_seconds(total.stopped_time),
+ "max_speed": total.max_speed,
+ "avg_speed": total.avg_speed,
"mps_to_kph": util.mps_to_kph,
- "number_of_tracks": number_of_tracks,
+ "number_of_tracks": total.count,
"heatmap_url": heatmap_url,
"tilehunt_url": tilehunt_url,
}