aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fietsboek/routes.py2
-rw-r--r--fietsboek/templates/browse.jinja21
-rw-r--r--fietsboek/views/browse.py51
3 files changed, 54 insertions, 0 deletions
diff --git a/fietsboek/routes.py b/fietsboek/routes.py
index dad8026..9b17173 100644
--- a/fietsboek/routes.py
+++ b/fietsboek/routes.py
@@ -7,6 +7,8 @@ def includeme(config):
config.add_route('logout', '/logout')
config.add_route('browse', '/track/')
+ config.add_route('track-archive', '/track/archive')
+
config.add_route('password-reset', '/password-reset')
config.add_route('use-token', '/token/{uuid}')
config.add_route('create-account', '/create-account')
diff --git a/fietsboek/templates/browse.jinja2 b/fietsboek/templates/browse.jinja2
index 10b16e3..1f61bc6 100644
--- a/fietsboek/templates/browse.jinja2
+++ b/fietsboek/templates/browse.jinja2
@@ -5,6 +5,7 @@
{% for track in tracks %}
<div class="card mb-3">
<h5 class="card-header">
+ <input type="checkbox" class="form-check-input" name="track_id[]" value="{{ track.id }}">
<a href="{{ request.route_url('details', track_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 %}
diff --git a/fietsboek/views/browse.py b/fietsboek/views/browse.py
index 3739061..24cf082 100644
--- a/fietsboek/views/browse.py
+++ b/fietsboek/views/browse.py
@@ -1,11 +1,28 @@
"""Views for browsing all tracks."""
+from zipfile import ZipFile
+
from pyramid.view import view_config
+from pyramid.httpexceptions import HTTPForbidden
+from pyramid.response import Response
from sqlalchemy import select
from .. import models, util
+class Stream:
+ def __init__(self):
+ self.buffer = []
+
+ def write(self, b):
+ self.buffer.append(b)
+
+ def readall(self):
+ buf = self.buffer
+ self.buffer = []
+ return b"".join(buf)
+
+
def visible_tracks(dbsession, user):
"""Returns all visible tracks for the given user.
@@ -43,3 +60,37 @@ def browse(request):
'tracks': tracks,
'mps_to_kph': util.mps_to_kph,
}
+
+
+@view_config(route_name="track-archive", request_method="GET")
+def archive(request):
+ """Packs multiple tracks into a single archive.
+
+ :param request: The Pyramid request.
+ :type request: pyramid.request.Request
+ :return: The HTTP response.
+ :rtype: pyramid.response.Response
+ """
+ from pprint import pformat
+
+ track_ids = set(map(int, request.params.getall("track_id[]")))
+ tracks = request.dbsession.execute(
+ select(models.Track).filter(models.Track.id.in_(track_ids))).scalars().fetchall()
+
+ for track in tracks:
+ if not track.is_visible_to(request.identity):
+ return HTTPForbidden()
+
+ def generate():
+ stream = Stream()
+ with ZipFile(stream, "w") as zipfile:
+ for track in tracks:
+ zipfile.writestr(f"track_{track.id}.gpx", track.gpx_data)
+ yield sream.readall()
+ yield stream.readall()
+
+ return Response(
+ app_iter=generate(),
+ content_type="application/zip",
+ content_disposition="attachment; filename=tracks.zip",
+ )