about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--__pycache__/main.cpython-36.pycbin0 -> 2716 bytes
-rw-r--r--main.py98
-rw-r--r--pages/index.html28
-rw-r--r--templates/error.html19
-rw-r--r--templates/success.html24
5 files changed, 169 insertions, 0 deletions
diff --git a/__pycache__/main.cpython-36.pyc b/__pycache__/main.cpython-36.pyc
new file mode 100644
index 0000000..250c562
--- /dev/null
+++ b/__pycache__/main.cpython-36.pyc
Binary files differdiff --git a/main.py b/main.py
new file mode 100644
index 0000000..630669c
--- /dev/null
+++ b/main.py
@@ -0,0 +1,98 @@
+import tempfile
+import shutil
+import subprocess
+import os
+from flask import Flask, request, redirect, send_file, send_from_directory, render_template
+
+app = Flask(__name__, static_url_path='/static', static_folder='static')
+
+# Limit file upload size. We shouldn't be working with anything over 1 MB; these are small genomes.
+# We will enforce the limit ourselves and set a higher safety limit here.
+app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024
+
+# When a file is too big we get a 413.
+@app.errorhandler(413)
+def handle_large_file(e):
+    return (render_template('error.html',
+        error_message="One of your files is too large. The maximum file size is 1 megabyte."), 413)
+
+@app.route('/')
+def send_form():
+    """
+    Send the file upload form/front page.
+    """
+    return send_from_directory('pages', 'index.html')
+    
+class FileTooBigError(RuntimeError):
+    """
+    Raised when the user gives a file that is too large.
+    """
+    pass
+    
+def copy_with_limit(in_file, out_file, limit=1024*1024):
+    """
+    Copy a file stream, and raise FileTooBigError if the file is too big.
+    """
+    
+    bytes_used = 0
+    buf_size = 65536
+    
+    buf = in_file.read(buf_size)
+    bytes_used += len(buf)
+    while buf:
+        if bytes_used > limit:
+            raise FileTooBigError('Hit file length limit')
+        out_file.write(buf)
+        buf = in_file.read(buf_size)
+        bytes_used += len(buf)
+    
+    
+@app.route('/submit', methods=['POST'])
+def recieve_files():
+    """
+    Recieve the uploaded files.
+    """
+    
+    # We're going to work in one directory per request
+    dest_dir = tempfile.mkdtemp()
+    try:
+    
+        print(request)
+        print(request.files)
+    
+        if 'fasta' not in request.files:
+            return (render_template('error.html',
+                error_message="You did not include a FASTA file."), 403)
+        if 'metadata' not in request.files:
+            return (render_template('error.html',
+                error_message="You did not include a metadata file."), 403)
+        
+        fasta_dest = os.path.join(dest_dir, 'fasta.fa')
+        metadata_dest = os.path.join(dest_dir, 'metadata.json')
+                
+        try:
+            with open(fasta_dest, 'wb') as out_stream:
+                copy_with_limit(request.files.get('fasta').stream, out_stream)
+            with open(metadata_dest, 'wb') as out_stream:
+                copy_with_limit(request.files.get('metadata').stream, out_stream)
+        except FileTooBigError as e:
+            # Delegate to the 413 error handler
+            return handle_large_file(e)
+            
+        # Try and upload files to Arvados
+        result = subprocess.run(['bh20-seq-uploader', fasta_dest, metadata_dest],
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            
+        if result.returncode != 0:
+            # It didn't work. Complain.
+            error_message="Upload failed. Uploader returned {} and said:\n{}".format(result.returncode, result.stderr)
+            return (render_template('error.html', error_message=error_message), 403)
+        else:
+            # It worked. Say so.
+            return render_template('success.html', log=result.stdout.decode('utf-8', errors='replace'))
+    finally:
+        shutil.rmtree(dest_dir)
+        
+    
+    
+
diff --git a/pages/index.html b/pages/index.html
new file mode 100644
index 0000000..2269791
--- /dev/null
+++ b/pages/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+        <title>Simple Web Uploader for Public SARS-CoV-2 Sequence Resource</title>
+    </head>
+    <body>
+        <h1>Simple Web Uploader for Public SARS-CoV-2 Sequence Resource</h1>
+        <hr>
+        <p>
+            This tool can be used to upload sequenced genomes of SARS-CoV-2 samples to the <a href="https://workbench.lugli.arvadosapi.com/collections/lugli-4zz18-z513nlpqm03hpca">Public SARS-CoV-2 Sequence Resource</a>. Your uploaded sequence will automatically be processed and incorporated into the public pangenome.
+        </p>
+        <hr>
+        <form action="/submit" method="POST" enctype="multipart/form-data">
+            <label for="fasta">Select FASTA file for assembled genome (max 1MB):</label>
+            <br>
+            <input type="file" id="fasta" name="fasta" accept=".fa,.fasta,.fna">
+            <br>
+            <label for="metadata">Select JSON-LD metadata file following <a href="https://raw.githubusercontent.com/arvados/bh20-seq-resource/master/bh20sequploader/bh20seq-schema.yml">this schema</a> (max 1MB):</label>
+            <br>
+            <input type="file" id="metadata" name="metadata" accept=".json">
+            <br>
+            <input type="submit" value="Add to Pangenome">
+        </form>
+        <hr>
+    </body>
+</html>
diff --git a/templates/error.html b/templates/error.html
new file mode 100644
index 0000000..c2ab0a4
--- /dev/null
+++ b/templates/error.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+        <title>Upload Failed</title>
+    </head>
+    <body>
+        <h1>Upload Failed</h1>
+        <hr>
+        <p>
+            Your upload has failed. {{error_message}}
+        </p>
+        <p>
+            <a href="/">Click here to try again.</a>
+        </p>
+        <hr>
+    </body>
+</html>
diff --git a/templates/success.html b/templates/success.html
new file mode 100644
index 0000000..1be7861
--- /dev/null
+++ b/templates/success.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+        <title>Upload Successful</title>
+    </head>
+    <body>
+        <h1>Upload Successful</h1>
+        <hr>
+        <p>
+            Your files have been uploaded. They should soon appear as part of the <a href="https://workbench.lugli.arvadosapi.com/collections/lugli-4zz18-z513nlpqm03hpca">Public SARS-CoV-2 Sequence Resource</a>.
+        </p>
+        <p>
+            The upload log was:
+        </p>
+        <pre>{{log}}</pre>
+        <hr>
+        <p>
+            <a href="/">Click here to upload more files.</a>
+        </p>
+        <hr>
+    </body>
+</html>