diff options
-rw-r--r-- | fietsboek/views/profile.py | 86 |
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, } |