From eedbcb81f8cd27ef3c0825c601b81ac96fe03417 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Thu, 12 Feb 2015 23:19:01 -0600 Subject: [PATCH] Add download feature for file batches. --- tailbone/views/batch.py | 47 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tailbone/views/batch.py b/tailbone/views/batch.py index 7329d3bf..45fd18c3 100644 --- a/tailbone/views/batch.py +++ b/tailbone/views/batch.py @@ -35,7 +35,9 @@ import logging import formalchemy from pyramid.renderers import render_to_response +from pyramid.response import FileResponse from pyramid.httpexceptions import HTTPFound, HTTPNotFound +from webhelpers.html.tags import link_to from rattail.db import model from rattail.db import Session as RatSession @@ -517,6 +519,28 @@ class BatchCrud(BaseCrud): return HTTPFound(location=self.view_url(batch.uuid)) +class DownloadLinkRenderer(formalchemy.FieldRenderer): + """ + Field renderer for batch filenames, shows a link to download the file. + """ + + def __init__(self, route_prefix): + self.route_prefix = route_prefix + + def __call__(self, field): + super(DownloadLinkRenderer, self).__init__(field) + return self + + def render_readonly(self, **kwargs): + filename = self.value + if not filename: + return '' + batch = self.field.parent.model + return link_to(filename, self.request.route_url( + '{0}.download'.format(self.route_prefix), + uuid=batch.uuid)) + + class FileBatchCrud(BatchCrud): """ Base CRUD view for batches which involve a file upload as the first step. @@ -545,6 +569,7 @@ class FileBatchCrud(BatchCrud): fs.executed_by.set(label="Executed by", renderer=UserFieldRenderer) fs.append(formalchemy.Field('data_file')) fs.data_file.set(renderer=formalchemy.fields.FileFieldRenderer) + fs.filename.set(renderer=DownloadLinkRenderer(self.route_prefix)) self.configure_fieldset(fs) if self.creating: del fs.created @@ -649,6 +674,20 @@ class FileBatchCrud(BatchCrud): batch.delete_data(self.request.rattail_config) del batch.data_rows[:] + def download(self): + """ + View for downloading the data file associated with a batch. + """ + batch = self.current_batch() + if not batch: + return HTTPNotFound() + config = self.request.rattail_config + path = batch.filepath(config) + response = FileResponse(path, request=self.request) + response.headers[b'Content-Length'] = str(batch.filesize(config)) + response.headers[b'Content-Disposition'] = b'attachment; filename={0}'.format(batch.filename) + return response + class BatchRowGrid(BaseGrid): """ @@ -877,6 +916,12 @@ def defaults(config, batch_grid, batch_crud, row_grid, row_crud, url_prefix, config.add_view(batch_crud, attr='execute', route_name='{0}.execute'.format(route_prefix), permission='{0}.execute'.format(permission_prefix)) + # Download batch data file + if hasattr(batch_crud, 'download'): + config.add_route('{0}.download'.format(route_prefix), '{0}{{uuid}}/download'.format(url_prefix)) + config.add_view(batch_crud, attr='download', route_name='{0}.download'.format(route_prefix), + permission='{0}.download'.format(permission_prefix)) + # Delete batch config.add_route('{0}.delete'.format(route_prefix), '{0}{{uuid}}/delete'.format(url_prefix)) config.add_view(batch_crud, attr='delete', route_name='{0}.delete'.format(route_prefix), @@ -891,7 +936,7 @@ def defaults(config, batch_grid, batch_crud, row_grid, row_crud, url_prefix, # Bulk delete batch rows config.add_route('{0}.rows.bulk_delete'.format(route_prefix), '{0}{{uuid}}/rows/delete'.format(url_prefix)) config.add_view(row_grid, attr='bulk_delete', route_name='{0}.rows.bulk_delete'.format(route_prefix), - permission='{0}.delete'.format(permission_prefix)) + permission='{0}.edit'.format(permission_prefix)) # Delete batch row config.add_route('{0}.rows.delete'.format(route_prefix), '{0}delete-row/{{uuid}}'.format(url_prefix))