diff options
Diffstat (limited to 'uploader/samples')
-rw-r--r-- | uploader/samples/__init__.py | 1 | ||||
-rw-r--r-- | uploader/samples/views.py | 122 |
2 files changed, 57 insertions, 66 deletions
diff --git a/uploader/samples/__init__.py b/uploader/samples/__init__.py new file mode 100644 index 0000000..1bd6d2d --- /dev/null +++ b/uploader/samples/__init__.py @@ -0,0 +1 @@ +"""Samples package. Handle samples uploads and editing.""" diff --git a/uploader/samples/views.py b/uploader/samples/views.py index 6e3dc4b..ed79101 100644 --- a/uploader/samples/views.py +++ b/uploader/samples/views.py @@ -3,42 +3,37 @@ import os import sys import uuid from pathlib import Path -from typing import Iterator -import MySQLdb as mdb from redis import Redis -from MySQLdb.cursors import DictCursor -from flask import ( - flash, - request, - url_for, - redirect, - Blueprint, - render_template, - current_app as app) +from flask import (flash, + request, + url_for, + redirect, + Blueprint, + current_app as app) from uploader import jobs from uploader.files import save_file -from uploader.datautils import order_by_family +from uploader.ui import make_template_renderer from uploader.authorisation import require_login +from uploader.request_checks import with_population from uploader.input_validation import is_integer_input -from uploader.db_utils import ( - with_db_connection, - database_connection, - with_redis_connection) +from uploader.datautils import safe_int, order_by_family, enumerate_sequence +from uploader.population.models import population_by_id, populations_by_species +from uploader.db_utils import (with_db_connection, + database_connection, + with_redis_connection) from uploader.species.models import (all_species, species_by_id, order_species_by_family) -from uploader.population.models import(save_population, - population_by_id, - populations_by_species, - population_by_species_and_id) from .models import samples_by_species_and_population samplesbp = Blueprint("samples", __name__) +render_template = make_template_renderer("samples") @samplesbp.route("/samples", methods=["GET"]) +@require_login def index(): """Direct entry-point for uploading/handling the samples.""" with database_connection(app.config["SQL_URI"]) as conn: @@ -56,6 +51,7 @@ def index(): @samplesbp.route("<int:species_id>/samples/select-population", methods=["GET"]) +@require_login def select_population(species_id: int): """Select the population to use for the samples.""" with database_connection(app.config["SQL_URI"]) as conn: @@ -86,6 +82,7 @@ def select_population(species_id: int): population_id=population["Id"])) @samplesbp.route("<int:species_id>/populations/<int:population_id>/samples") +@require_login def list_samples(species_id: int, population_id: int): """ List the samples in a particular population and give the ability to upload @@ -104,13 +101,11 @@ def list_samples(species_id: int, population_id: int): "species.populations.samples.select_population", species_id=species_id)) - all_samples = samples_by_species_and_population( - conn, species_id, population_id) + all_samples = enumerate_sequence(samples_by_species_and_population( + conn, species_id, population_id)) total_samples = len(all_samples) - offset = int(request.args.get("from") or 0) - if offset < 0: - offset = 0 - count = int(request.args.get("count") or 10) + offset = max(safe_int(request.args.get("from") or 0), 0) + count = int(request.args.get("count") or 20) return render_template("samples/list-samples.html", species=species, population=population, @@ -197,6 +192,11 @@ def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-ma redisuri = app.config["REDIS_URL"] with Redis.from_url(redisuri, decode_responses=True) as rconn: + #TODO: Add a QC step here — what do we check? + # 1. Does any sample in the uploaded file exist within the database? + # If yes, what is/are its/their species and population? + # 2. If yes 1. above, provide error with notes on which species and + # populations already own the samples. the_job = jobs.launch_job( jobs.initialise_job( rconn, @@ -224,55 +224,45 @@ def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-ma @samplesbp.route("<int:species_id>/populations/<int:population_id>/" "upload-samples/status/<uuid:job_id>", methods=["GET"]) -def upload_status(species_id: int, population_id: int, job_id: uuid.UUID): +@require_login +@with_population(species_redirect_uri="species.populations.samples.index", + redirect_uri="species.populations.samples.select_population") +def upload_status(species: dict, population: dict, job_id: uuid.UUID, **kwargs):# pylint: disable=[unused-argument] """Check on the status of a samples upload job.""" - with database_connection(app.config["SQL_URI"]) as conn: - species = species_by_id(conn, species_id) - if not bool(species): - flash("You must provide a valid species.", "alert-danger") - return redirect(url_for("species.populations.samples.index")) + job = with_redis_connection(lambda rconn: jobs.job( + rconn, jobs.jobsnamespace(), job_id)) + if job: + status = job["status"] + if status == "success": + return render_template("samples/upload-success.html", + job=job, + species=species, + population=population,) - population = population_by_species_and_id( - conn, species_id, population_id) - if not bool(population): - flash("You must provide a valid population.", "alert-danger") + if status == "error": return redirect(url_for( - "species.populations.samples.select_population", - species_id=species_id)) + "species.populations.samples.upload_failure", job_id=job_id)) - job = with_redis_connection(lambda rconn: jobs.job( - rconn, jobs.jobsnamespace(), job_id)) - if job: - status = job["status"] - if status == "success": - return render_template("samples/upload-success.html", - job=job, - species=species, - population=population,) - - if status == "error": + error_filename = Path(jobs.error_filename( + job_id, f"{app.config['UPLOAD_FOLDER']}/job_errors")) + if error_filename.exists(): + stat = os.stat(error_filename) + if stat.st_size > 0: return redirect(url_for( - "species.populations.samples.upload_failure", job_id=job_id)) - - error_filename = Path(jobs.error_filename( - job_id, f"{app.config['UPLOAD_FOLDER']}/job_errors")) - if error_filename.exists(): - stat = os.stat(error_filename) - if stat.st_size > 0: - return redirect(url_for( - "samples.upload_failure", job_id=job_id)) + "samples.upload_failure", job_id=job_id)) - return render_template("samples/upload-progress.html", - species=species, - population=population, - job=job) # maybe also handle this? - - return render_template("no_such_job.html", - job_id=job_id, + return render_template("samples/upload-progress.html", species=species, - population=population), 400 + population=population, + job=job) # maybe also handle this? + + return render_template("no_such_job.html", + job_id=job_id, + species=species, + population=population), 400 @samplesbp.route("/upload/failure/<uuid:job_id>", methods=["GET"]) +@require_login def upload_failure(job_id: uuid.UUID): """Display the errors of the samples upload failure.""" job = with_redis_connection(lambda rconn: jobs.job( |