From a8a1759836f3243b51d959431567df42c1a7fff4 Mon Sep 17 00:00:00 2001
From: Thomas NOEL <tnoel@entrouvert.com>
Date: Wed, 26 Feb 2020 11:46:31 +0100
Subject: [PATCH] handle storage error on file upload (#40044)

---
 tests/test_form_pages.py | 14 ++++++++++++++
 wcs/qommon/form.py       |  9 +++++++--
 wcs/root.py              | 15 ++++++++++-----
 3 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index 2b3fb317..89f1e8c0 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -2895,6 +2895,20 @@ def test_form_preupload_file_field_submit(pub):
     assert resp.content_type == 'text/plain'
     assert resp.text == 'foobar'
 
+    # upload error if file storage is unknown (out of order)
+    formdef.fields[0].storage = 'unknown-storage'
+    formdef.store()
+    resp = app.get('/test/')
+    resp.form['f0$file'] = upload
+    # javascript simulation
+    upload_url = resp.form['f0$file'].attrs['data-url']
+    upload_resp = app.post(upload_url, params=resp.form.submit_fields())
+    assert upload_resp.json == [{'error': 'Failed to store file (system error)'}]
+    # try to post the form anyway (with file in f0$file, i.e. "no javascript")
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' not in resp.text
+    assert 'failed to store file (system error)' in resp.text
+
 
 def test_form_file_field_image_submit(pub):
     formdef = create_formdef()
diff --git a/wcs/qommon/form.py b/wcs/qommon/form.py
index e158fd03..7b2a9f51 100644
--- a/wcs/qommon/form.py
+++ b/wcs/qommon/form.py
@@ -80,7 +80,7 @@ from .humantime import humanduration2seconds, seconds2humanduration, timewords
 from .misc import strftime, C_, HAS_PDFTOPPM, json_loads
 from .publisher import get_cfg
 from .template_utils import render_block_to_string
-from .upload_storage import PicklableUpload
+from .upload_storage import PicklableUpload, UploadStorageError
 
 
 QuixoteForm = Form
@@ -749,7 +749,11 @@ class FileWithPreviewWidget(CompositeWidget):
         if self.get('token'):
             token = self.get('token')
         elif self.get('file'):
-            token = get_session().add_tempfile(self.get('file'), storage=self.storage)['token']
+            try:
+                token = get_session().add_tempfile(self.get('file'), storage=self.storage)['token']
+            except UploadStorageError as e:
+                self.error = _('failed to store file (system error)')
+                return
             request.form[self.get_widget('token').get_name()] = token
         else:
             token = None
@@ -764,6 +768,7 @@ class FileWithPreviewWidget(CompositeWidget):
 
         if self.storage and self.storage != self.storage:
             self.error = _('unknown storage system (system error)')
+            return
 
         # Don't trust the browser supplied MIME type, update the Upload object
         # with a MIME type created with magic (or based on the extension if the
diff --git a/wcs/root.py b/wcs/root.py
index 205ecf96..e5c51f22 100644
--- a/wcs/root.py
+++ b/wcs/root.py
@@ -36,6 +36,7 @@ from .qommon import template
 from .qommon.form import *
 from .qommon import ident
 from .qommon import pages
+from .qommon.upload_storage import UploadStorageError
 
 from .qommon.afterjobs import AfterJobStatusDirectory
 
@@ -295,11 +296,15 @@ class RootDirectory(Directory):
         storage = get_request().form.get('storage')
         for k, v in get_request().form.items():
             if hasattr(v, 'fp'):
-                tempfile = get_session().add_tempfile(v, storage=storage)
-                results.append({'name': tempfile.get('base_filename'),
-                                'type': tempfile.get('content_type'),
-                                'size': tempfile.get('size'),
-                                'token': tempfile.get('token')})
+                try:
+                    tempfile = get_session().add_tempfile(v, storage=storage)
+                    results.append({'name': tempfile.get('base_filename'),
+                                    'type': tempfile.get('content_type'),
+                                    'size': tempfile.get('size'),
+                                    'token': tempfile.get('token')})
+                except UploadStorageError as e:
+                    get_logger().error('upload storage error: %s' % e)
+                    results.append({'error': _('Failed to store file (system error)')})
 
         get_response().set_content_type('application/json')
         useragent = get_request().get_header('User-agent') or ''
-- 
2.25.0

