From 557d1d5c19ab518fa7abb3229c6d9042867e6c00 Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Fri, 10 Jun 2022 08:06:47 +0300 Subject: Enable upload of zipfiles --- qc_app/entry.py | 96 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 21 deletions(-) (limited to 'qc_app/entry.py') diff --git a/qc_app/entry.py b/qc_app/entry.py index b7b4b6f..25e2eed 100644 --- a/qc_app/entry.py +++ b/qc_app/entry.py @@ -1,5 +1,10 @@ """Entry-point module""" import os +import random +import string +import mimetypes +from typing import Tuple +from zipfile import ZipFile, is_zipfile from werkzeug.utils import secure_filename from flask import ( @@ -13,38 +18,87 @@ from flask import ( entrybp = Blueprint("entry", __name__) +def errors(request) -> Tuple[str, ...]: + """Return a tuple of the errors found in the `request`. If no error is + found, then an empty tuple is returned.""" + def __filetype_error__(): + return ( + ("Invalid file type provided.",) + if request.form["filetype"] not in ("average", "standard-error") + else tuple()) + + def __file_missing_error__(): + return ( + ("No file was uploaded.",) + if ("qc_text_file" not in request.files or + request.files["qc_text_file"].filename == "") + else tuple()) + + def __file_mimetype_error__(): + text_file = request.files["qc_text_file"] + return ( + ( + ("Invalid file! Expected a tab-separated-values file, or a zip " + "file of the a tab-separated-values file."),) + if text_file.mimetype + not in ("text/tab-separated-values", "application/zip") + else tuple()) + + return ( + __filetype_error__() + + (__file_missing_error__() or __file_mimetype_error__())) + +def zip_file_errors(filepath, upload_dir) -> Tuple[str, ...]: + """Check the uploaded zip file for errors.""" + zfile_errors = ("Fail always!!",) + if is_zipfile(filepath): + zfile = ZipFile(filepath, "r") + infolist = zfile.infolist() + if len(infolist) != 1: + zfile_errors = zfile_errors + ( + ("Expected exactly one (1) member file within the uploaded zip " + "file. Got {len(infolist)} member files.")) + if len(infolist) == 1 and infolist[0].is_dir(): + zfile_errors = zfile_errors + ( + ("Expected a member text file in the uploaded zip file. Got a " + "directory/folder.")) + + if len(infolist) == 1 and not infolist[0].is_dir(): + zfile.extract(infolist[0], path=upload_dir) + mime = mimetypes.guess_type(f"{upload_dir}/{infolist[0].filename}") + if mime[0] != "text/tab-separated-values": + zfile_errors = zfile_errors + ( + ("Expected the member text file in the uploaded zip file to" + " be a tab-separated file.")) + + return zfile_errors + @entrybp.route("/", methods=["GET", "POST"]) def upload_file(): """Enables uploading the files""" + upload_dir = app.config["UPLOAD_FOLDER"] if request.method == "GET": return render_template("index.html") - errors = False - if request.form["filetype"] not in ("average", "standard-error"): - flash("Invalid file type provided.", "alert-error") - errors = True + request_errors = errors(request) + if request_errors: + for error in request_errors: + flash(error, "alert-error") + return render_template("index.html") - if ("qc_text_file" not in request.files or - request.files["qc_text_file"].filename == ""): - flash("No file was uploaded.", "alert-error") - errors = True + filename = secure_filename(request.files["qc_text_file"].filename) + if not os.path.exists(upload_dir): + os.mkdir(upload_dir) - text_file = request.files["qc_text_file"] - if text_file.mimetype != "text/tab-separated-values": - flash("Invalid file! Expected a tab-separated-values file.", - "alert-error") - errors = True + filepath = os.path.join(upload_dir, filename) + request.files["qc_text_file"].save(os.path.join(upload_dir, filename)) - if errors: + zip_errors = zip_file_errors(filepath, upload_dir) + if zip_errors: + for error in zip_errors: + flash(error, "alert-error") return render_template("index.html") - filename = secure_filename(text_file.filename) - if not os.path.exists(app.config["UPLOAD_FOLDER"]): - os.mkdir(app.config["UPLOAD_FOLDER"]) - - filepath = os.path.join(app.config["UPLOAD_FOLDER"], filename) - text_file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename)) - return redirect(url_for( "parse.parse", filename=filename, filetype=request.form["filetype"])) -- cgit v1.2.3