diff options
author | Frederick Muriuki Muriithi | 2024-06-12 12:48:56 -0500 |
---|---|---|
committer | Frederick Muriuki Muriithi | 2024-06-12 12:48:56 -0500 |
commit | 5e96d27f3d96c84fc5a15d7040843b379b701d20 (patch) | |
tree | ad283df6ef65ed66f800d79446f04b19c2d08768 /qc_app/samples.py | |
parent | 3abf09f5d5a0ab7fb3b1ca2be981c364ef68a8cb (diff) | |
download | gn-uploader-5e96d27f3d96c84fc5a15d7040843b379b701d20.tar.gz |
Make URI and UI correspond to each other.
Formerly, the URI and UI were not corresponding to each other,
e.g. the URI /upload/samples/select_species would display the UI for
selecting/creating the population. This was very confusing. This
commit fixes that.
The commit also adds in user input validation to catch input errors.
Diffstat (limited to 'qc_app/samples.py')
-rw-r--r-- | qc_app/samples.py | 240 |
1 files changed, 138 insertions, 102 deletions
diff --git a/qc_app/samples.py b/qc_app/samples.py index e7be458..804f262 100644 --- a/qc_app/samples.py +++ b/qc_app/samples.py @@ -22,7 +22,7 @@ from functional_tools import take from qc_app import jobs from qc_app.files import save_file -from qc_app.input_validation import is_empty_input, is_integer_input +from qc_app.input_validation import is_integer_input from qc_app.db_utils import ( with_db_connection, database_connection, @@ -31,13 +31,18 @@ from qc_app.db import ( species_by_id, save_population, population_by_id, - populations_by_species) + populations_by_species, + species as fetch_species) samples = Blueprint("samples", __name__) -@samples.route("/upload/species", methods=["POST"]) +@samples.route("/upload/species", methods=["GET", "POST"]) def select_species(): """Select the species.""" + if request.method == "GET": + return render_template("samples/select-species.html", + species=with_db_connection(fetch_species)) + index_page = redirect(url_for("entry.upload_file")) species_id = request.form.get("species_id") if bool(species_id): @@ -45,23 +50,31 @@ def select_species(): species = with_db_connection( lambda conn: species_by_id(conn, species_id)) if bool(species): - return render_template( - "samples/select-population.html", - species=species, - populations=with_db_connection( - lambda conn: populations_by_species(conn, species_id))) + return redirect(url_for( + "samples.select_population", species_id=species_id)) flash("Invalid species selected!", "alert-error") flash("You need to select a species", "alert-error") return index_page -@samples.route("/upload/create-population", methods=["POST"]) -def create_population(): +@samples.route("/upload/species/<int:species_id>/create-population", + methods=["POST"]) +def create_population(species_id: int): """Create new grouping/population.""" + if not is_integer_input(species_id): + flash("You did not provide a valid species. Please select one to " + "continue.", + "alert-danger") + return redirect(url_for("samples.select_species")) + species = with_db_connection(lambda conn: species_by_id(conn, species_id)) + if not bool(species): + flash("Species with given ID was not found.", "alert-danger") + return redirect(url_for("samples.select_species")) + species_page = redirect(url_for("samples.select_species"), code=307) with database_connection(app.config["SQL_URI"]) as conn: - species = species_by_id(conn, request.form.get("species_id")) - pop_name = request.form.get("inbredset_name").strip() - pop_fullname = request.form.get("inbredset_fullname").strip() + species = species_by_id(conn, species_id) + pop_name = request.form.get("inbredset_name", "").strip() + pop_fullname = request.form.get("inbredset_fullname", "").strip() if not bool(species): flash("Invalid species!", "alert-error error-create-population") @@ -81,33 +94,50 @@ def create_population(): }) flash("Grouping/Population created successfully.", "alert-success") - return render_template( - "samples/upload-samples.html", - species=species, - population=with_db_connection( - lambda conn: population_by_id(conn, pop["population_id"]))) + return redirect(url_for("samples.upload_samples", + species_id=species_id, + population_id=pop["population_id"])) -@samples.route("/upload/select-population", methods=["POST"]) -def select_population(): +@samples.route("/upload/species/<int:species_id>/population", + methods=["GET", "POST"]) +def select_population(species_id: int): """Select from existing groupings/populations.""" - species_page = redirect(url_for("samples.select_species"), code=307) - with database_connection(app.config["SQL_URI"]) as conn: - species = species_by_id(conn, request.form.get("species_id")) - pop_id = int(request.form.get("inbredset_id")) - population = with_db_connection(lambda conn: population_by_id(conn, pop_id)) - + if not is_integer_input(species_id): + flash("You did not provide a valid species. Please select one to " + "continue.", + "alert-danger") + return redirect(url_for("samples.select_species")) + species = with_db_connection(lambda conn: species_by_id(conn, species_id)) if not bool(species): - flash("Invalid species!", "alert-error error-select-population") - return species_page + flash("Species with given ID was not found.", "alert-danger") + return redirect(url_for("samples.select_species")) + if request.method == "GET": + return render_template( + "samples/select-population.html", + species=species, + populations=with_db_connection( + lambda conn: populations_by_species(conn, species_id))) + + population_page = redirect(url_for( + "samples.select_population", species_id=species_id), code=307) + _population_id = request.form.get("inbredset_id") + if not is_integer_input(_population_id): + flash("You did not provide a valid population. Please select one to " + "continue.", + "alert-danger") + return population_page + population = with_db_connection( + lambda conn: population_by_id(conn, _population_id)) if not bool(population): flash("Invalid grouping/population!", "alert-error error-select-population") - return species_page + return population_page - return render_template("samples/upload-samples.html", - species=species, - population=population) + return redirect(url_for("samples.upload_samples", + species_id=species_id, + population_id=_population_id), + code=307) def read_samples_file(filepath, separator: str, firstlineheading: bool, **kwargs) -> Iterator[dict]: """Read the samples file.""" @@ -201,77 +231,83 @@ def build_sample_upload_job(# pylint: disable=[too-many-arguments] f"--quotechar={quotechar}" ] + (["--firstlineheading"] if firstlineheading else []) -@samples.route("/upload/samples", methods=["POST"]) -def upload_samples(): +@samples.route("/upload/species/<int:species_id>/populations/<int:population_id>/samples", + methods=["GET", "POST"]) +def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-many-return-statements] """Upload the samples.""" - samples_uploads_page = redirect(url_for("samples.select_population"), - code=307) - - with database_connection(app.config["SQL_URI"]) as conn: - _speciesid = request.form.get("species_id") - if is_integer_input(_speciesid): - flash("You did not provide a valid species. Please select one to " - "continue.", - "alert-danger") - return redirect(url_for("entry.upload_file")) - species = species_by_id(conn, _speciesid) - if not bool(species): - flash("Invalid species!", "alert-error") - return samples_uploads_page - - _population_id = request.form.get("inbredset_id") - if not is_integer_input(_population_id): - flash("You did not provide a valid population. Please select one " - "to continue.", - "alert-danger") - return redirect("samples.select_species", code=307) - population = with_db_connection( - lambda conn: population_by_id( - conn, int(_population_id))) - if not bool(population): - flash("Invalid grouping/population!", "alert-error") - return samples_uploads_page - - try: - samples_file = save_file(request.files["samples_file"], - Path(app.config["UPLOAD_FOLDER"])) - except AssertionError: - flash("You need to provide a file with the samples data.", - "alert-error") - return samples_uploads_page - - firstlineheading = (request.form.get("first_line_heading") == "on") - - separator = request.form.get("separator") - if separator == "other": - separator = request.form.get("other_separator") - if not bool(separator): - flash("You need to provide a separator character.", "alert-error") - return samples_uploads_page - - quotechar = (request.form.get("field_delimiter", '"') or '"') - - redisuri = app.config["REDIS_URL"] - with Redis.from_url(redisuri, decode_responses=True) as rconn: - the_job = jobs.launch_job( - jobs.initialise_job( - rconn, - jobs.jobsnamespace(), - str(uuid.uuid4()), - build_sample_upload_job( - species["SpeciesId"], - population["InbredSetId"], - samples_file, - separator, - firstlineheading, - quotechar), - "samples_upload", - app.config["JOBS_TTL_SECONDS"], - {"job_name": f"Samples Upload: {samples_file.name}"}), - redisuri, - f"{app.config['UPLOAD_FOLDER']}/job_errors") - return redirect(url_for( - "samples.upload_status", job_id=the_job["jobid"])) + samples_uploads_page = redirect(url_for("samples.upload_samples", + species_id=species_id, + population_id=population_id)) + if not is_integer_input(species_id): + flash("You did not provide a valid species. Please select one to " + "continue.", + "alert-danger") + return redirect(url_for("samples.select_species")) + species = with_db_connection(lambda conn: species_by_id(conn, species_id)) + if not bool(species): + flash("Species with given ID was not found.", "alert-danger") + return redirect(url_for("samples.select_species")) + + if not is_integer_input(population_id): + flash("You did not provide a valid population. Please select one " + "to continue.", + "alert-danger") + return redirect(url_for("samples.select_population", + species_id=species_id), + code=307) + population = with_db_connection( + lambda conn: population_by_id(conn, int(population_id))) + if not bool(population): + flash("Invalid grouping/population!", "alert-error") + return redirect(url_for("samples.select_population", + species_id=species_id), + code=307) + + if request.method == "GET" or request.files.get("samples_file") is None: + return render_template("samples/upload-samples.html", + species=species, + population=population) + + try: + samples_file = save_file(request.files["samples_file"], + Path(app.config["UPLOAD_FOLDER"])) + except AssertionError: + flash("You need to provide a file with the samples data.", + "alert-error") + return samples_uploads_page + + firstlineheading = (request.form.get("first_line_heading") == "on") + + separator = request.form.get("separator", ",") + if separator == "other": + separator = request.form.get("other_separator", ",") + if not bool(separator): + flash("You need to provide a separator character.", "alert-error") + return samples_uploads_page + + quotechar = (request.form.get("field_delimiter", '"') or '"') + + redisuri = app.config["REDIS_URL"] + with Redis.from_url(redisuri, decode_responses=True) as rconn: + the_job = jobs.launch_job( + jobs.initialise_job( + rconn, + jobs.jobsnamespace(), + str(uuid.uuid4()), + build_sample_upload_job( + species["SpeciesId"], + population["InbredSetId"], + samples_file, + separator, + firstlineheading, + quotechar), + "samples_upload", + app.config["JOBS_TTL_SECONDS"], + {"job_name": f"Samples Upload: {samples_file.name}"}), + redisuri, + f"{app.config['UPLOAD_FOLDER']}/job_errors") + return redirect(url_for( + "samples.upload_status", job_id=the_job["jobid"])) @samples.route("/upload/status/<uuid:job_id>", methods=["GET"]) def upload_status(job_id: uuid.UUID): |