From 1a21390ba6b771c16e09185eef567bff77d23958 Mon Sep 17 00:00:00 2001
From: Justin Ehlert <justinehlert@flywheel.io>
Date: Wed, 14 Feb 2018 08:58:04 -0600
Subject: [PATCH] Fix handling of multi-value file fields

Some clients (e.g. Swagger), rather than specifying `file1`, `file2`, etc... will
specify multiple values for `file` when uploading multiple files.
This code change will handle lists of values for individual fields.
---
 api/upload.py                                 | 20 +++++++++++++++----
 .../integration_tests/python/test_uploads.py  |  7 ++++++-
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/api/upload.py b/api/upload.py
index 617a3035..75de2e47 100644
--- a/api/upload.py
+++ b/api/upload.py
@@ -91,16 +91,13 @@ def process_upload(request, strategy, container_type=None, id_=None, origin=None
     # Here, we accept any
 
     # Non-file form fields may have an empty string as filename, check for 'falsy' values
-    file_fields = [x for x in form if form[x].filename]
+    file_fields = extract_file_fields(form)
     # TODO: Change schemas to enabled targeted uploads of more than one file.
     # Ref docs from placer.TargetedPlacer for details.
     if strategy == Strategy.targeted and len(file_fields) > 1:
         raise FileFormException("Targeted uploads can only send one file")
 
-
-
     for field in file_fields:
-        field = form[field]
         # Augment the cgi.FieldStorage with a variety of custom fields.
         # Not the best practice. Open to improvements.
         # These are presumbed to be required by every function later called with field as a parameter.
@@ -270,3 +267,18 @@ class Upload(base.RequestHandler):
                 'directories': cleaned,
             }
         }
+
+def extract_file_fields(form):
+    """Returns a list of file fields in the form, handling multiple values""" 
+    result = []
+    for fieldname in form:
+        field = form[fieldname]
+        if isinstance(field, list):
+            for field_entry in field:
+                if field_entry.filename:
+                    result.append(field_entry)
+
+        elif field.filename:
+            result.append(field)
+
+    return result
diff --git a/tests/integration_tests/python/test_uploads.py b/tests/integration_tests/python/test_uploads.py
index e17a9dbf..d97fa8b8 100644
--- a/tests/integration_tests/python/test_uploads.py
+++ b/tests/integration_tests/python/test_uploads.py
@@ -1197,9 +1197,14 @@ def test_packfile_upload(data_builder, file_form, as_admin, as_root, api_db):
     assert r.ok
     token = r.json()['token']
 
+    files = [ 
+        ('file', file_form('two.csv')['file']) , 
+        ('file', file_form('three.csv')['file']) 
+    ]
+
     # upload to packfile
     r = as_admin.post('/projects/' + project + '/packfile',
-        params={'token': token}, files=file_form('two.csv'))
+        params={'token': token}, files=files)
     assert r.ok
 
     # expire upload token
-- 
GitLab