aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fietsboek/routes.py1
-rw-r--r--fietsboek/templates/browse.jinja252
-rw-r--r--fietsboek/templates/layout.jinja23
-rw-r--r--fietsboek/views/browse.py45
4 files changed, 101 insertions, 0 deletions
diff --git a/fietsboek/routes.py b/fietsboek/routes.py
index b0ee3c4..018c1d3 100644
--- a/fietsboek/routes.py
+++ b/fietsboek/routes.py
@@ -5,6 +5,7 @@ def includeme(config):
config.add_route('home', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
+ config.add_route('browse', '/track/')
config.add_route('password-reset', '/password-reset')
config.add_route('use-token', '/token/{uuid}')
diff --git a/fietsboek/templates/browse.jinja2 b/fietsboek/templates/browse.jinja2
new file mode 100644
index 0000000..174694a
--- /dev/null
+++ b/fietsboek/templates/browse.jinja2
@@ -0,0 +1,52 @@
+{% extends "layout.jinja2" %}
+{% block content %}
+<div class="container">
+ <h1>{{ _("page.browse.title") }}</h1>
+ {% for track in tracks %}
+ <div class="card mb-3">
+ <h5 class="card-header">
+ <a href="{{ request.route_url('details', id=track.id) }}">{{ track.title | default(track.date, true) }}</a>
+ {% if track.text_tags() %}
+ {% for tag in track.tags %}<span class="badge bg-info text-dark">{{ tag.tag }}</span> {% endfor %}
+ {% endif %}
+ </h5>
+ <div class="card-body">
+ <table class="table table-hover table-sm">
+ <tbody>
+ <tr>
+ <th scope="row">{{ _("page.details.date") }}</th>
+ <td>{{ track.date | format_datetime }}</td>
+ <th scope="row">{{ _("page.details.length") }}</th>
+ <td>{{ (track.length / 1000) | round(2) | format_decimal }} km</td>
+ </tr>
+ <tr>
+ <th scope="row">{{ _("page.details.start_time") }}</th>
+ <td>{{ track.start_time | format_datetime }}</td>
+ <th scope="row">{{ _("page.details.end_time") }}</th>
+ <td>{{ track.end_time | format_datetime }}</td>
+ </tr>
+ <tr>
+ <th scope="row">{{ _("page.details.uphill") }}</th>
+ <td>{{ track.uphill | round(2) | format_decimal }} m</td>
+ <th scope="row">{{ _("page.details.downhill") }}</th>
+ <td>{{ track.downhill | round(2) | format_decimal }} m</td>
+ </tr>
+ <tr>
+ <th scope="row">{{ _("page.details.moving_time") }}</th>
+ <td>{{ track.moving_time }}</td>
+ <th scope="row">{{ _("page.details.stopped_time") }}</th>
+ <td>{{ track.stopped_time }}</td>
+ </tr>
+ <tr>
+ <th scope="row">{{ _("page.details.max_speed") }}</th>
+ <td>{{ mps_to_kph(track.max_speed) | round(2) | format_decimal }} km/h</td>
+ <th scope="row">{{ _("page.details.avg_speed") }}</th>
+ <td>{{ mps_to_kph(track.avg_speed) | round(2) | format_decimal }} km/h</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ {% endfor %}
+</div>
+{% endblock %}
diff --git a/fietsboek/templates/layout.jinja2 b/fietsboek/templates/layout.jinja2
index 6caf666..4bbb9c0 100644
--- a/fietsboek/templates/layout.jinja2
+++ b/fietsboek/templates/layout.jinja2
@@ -38,6 +38,9 @@
<li class="nav-item">
<a class="nav-link" href="{{ request.route_url('home') }}">{{ _("page.navbar.home") }}</a>
</li>
+ <li class="nav-item">
+ <a class="nav-link" href="{{ request.route_url('browse') }}">{{ _("page.navbar.browse") }}</a>
+ </li>
{% if request.identity is none %}
<li class="nav-item">
<a class="nav-link" href="{{ request.route_url('login') }}">{{ _("page.navbar.login") }}</a>
diff --git a/fietsboek/views/browse.py b/fietsboek/views/browse.py
new file mode 100644
index 0000000..3739061
--- /dev/null
+++ b/fietsboek/views/browse.py
@@ -0,0 +1,45 @@
+"""Views for browsing all tracks."""
+from pyramid.view import view_config
+
+from sqlalchemy import select
+
+from .. import models, util
+
+
+def visible_tracks(dbsession, user):
+ """Returns all visible tracks for the given user.
+
+ The user might be ``None``, in which case all public tracks are returned.
+
+ :param dbsession: The database session.
+ :type dbsession: sqlalchemy.orm.session.Session
+ :param user: The user to get the tracks for.
+ :type user: fietsboek.models.user.User
+ :return: The list of visible tracks.
+ :rtype: ~collections.abc.Iterable[fietsboek.models.track.Track]
+ """
+ # This is fine for now, but we should try and do most of this work right in
+ # SQL in the future.
+ tracks = dbsession.execute(select(models.Track)).scalars()
+ return sorted(
+ (track for track in tracks if track.is_visible_to(user)),
+ key=lambda t: t.date,
+ reverse=True,
+ )
+
+
+@view_config(route_name="browse", renderer="fietsboek:templates/browse.jinja2",
+ request_method="GET")
+def browse(request):
+ """Returns the page that lets a user browse all visible tracks.
+
+ :param request: The Pyramid request.
+ :type request: pyramid.request.Request
+ :return: The HTTP response.
+ :rtype: pyramid.response.Response
+ """
+ tracks = visible_tracks(request.dbsession, request.identity)
+ return {
+ 'tracks': tracks,
+ 'mps_to_kph': util.mps_to_kph,
+ }