diff options
-rw-r--r-- | fietsboek/routes.py | 2 | ||||
-rw-r--r-- | fietsboek/templates/browse.jinja2 | 1 | ||||
-rw-r--r-- | fietsboek/views/browse.py | 51 |
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", + ) |