aboutsummaryrefslogtreecommitdiff
path: root/uploader/species
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-08-29 15:21:27 -0500
committerFrederick Muriuki Muriithi2024-08-30 15:06:24 -0500
commite49b4367f1dab1c3acb3cd5d71ba09359c5ab4ee (patch)
tree63035669dd9a82bccee60b572a565d028cf3ef38 /uploader/species
parentf95037b93329d5a4953b81ba1b58e4028a6274e8 (diff)
downloadgn-uploader-e49b4367f1dab1c3acb3cd5d71ba09359c5ab4ee.tar.gz
Initialise package for dealing with Species.
Diffstat (limited to 'uploader/species')
-rw-r--r--uploader/species/__init__.py2
-rw-r--r--uploader/species/models.py22
-rw-r--r--uploader/species/views.py91
3 files changed, 115 insertions, 0 deletions
diff --git a/uploader/species/__init__.py b/uploader/species/__init__.py
new file mode 100644
index 0000000..83f2165
--- /dev/null
+++ b/uploader/species/__init__.py
@@ -0,0 +1,2 @@
+"""Package to handle creation and management of species."""
+from .views import speciesbp
diff --git a/uploader/species/models.py b/uploader/species/models.py
new file mode 100644
index 0000000..98337a3
--- /dev/null
+++ b/uploader/species/models.py
@@ -0,0 +1,22 @@
+"""Database functions for species."""
+import MySQLdb as mdb
+from MySQLdb.cursors import DictCursor
+
+def all_species(conn: mdb.Connection) -> tuple:
+ "Retrieve the species from the database."
+ with conn.cursor(cursorclass=DictCursor) as cursor:
+ cursor.execute(
+ "SELECT SpeciesId, SpeciesName, LOWER(Name) AS Name, MenuName, "
+ "FullName, TaxonomyId FROM Species")
+ return tuple(cursor.fetchall())
+
+ return tuple()
+
+def species_by_id(conn: mdb.Connection, speciesid) -> dict:
+ "Retrieve the species from the database by id."
+ with conn.cursor(cursorclass=DictCursor) as cursor:
+ cursor.execute(
+ "SELECT SpeciesId, SpeciesName, LOWER(Name) AS Name, MenuName, "
+ "FullName FROM Species WHERE SpeciesId=%s",
+ (speciesid,))
+ return cursor.fetchone()
diff --git a/uploader/species/views.py b/uploader/species/views.py
new file mode 100644
index 0000000..af66de3
--- /dev/null
+++ b/uploader/species/views.py
@@ -0,0 +1,91 @@
+"""Endpoints handling species."""
+from flask import (flash,
+ request,
+ url_for,
+ redirect,
+ Blueprint,
+ current_app as app,
+ render_template as flask_render_template)
+
+from uploader.db_utils import database_connection
+
+from .models import all_species, save_species, species_by_id
+
+
+speciesbp = Blueprint("species", __name__)
+
+
+def render_template(template, **kwargs):
+ """Render template for species."""
+ return flask_render_template(template, **kwargs, activelink="species")
+
+
+@speciesbp.route("/", methods=["GET"])
+def list_species():
+ """List and display all the species in the database."""
+ with database_connection(app.config["SQL_URI"]) as conn:
+ return render_template("species/list-species.html",
+ allspecies=all_species(conn))
+
+@speciesbp.route("/<int:species_id>", methods=["GET"])
+def view_species(species_id: int):
+ """View details of a particular species and menus to act upon it."""
+ with database_connection(app.config["SQL_URI"]) as conn:
+ return species_by_id(conn, species_id)
+
+@speciesbp.route("/create", methods=["GET", "POST"])
+def create_species():
+ """Create a new species."""
+ # We can use uniprot's API to fetch the details with something like
+ # https://rest.uniprot.org/taxonomy/<taxonID> e.g.
+ # https://rest.uniprot.org/taxonomy/6239
+ if request.method == "GET":
+ return render_template("species/create-species.html")
+
+ with (database_connection(app.config["SQL_URI"]) as conn,
+ conn.cursor() as cursor):
+ error = False
+ taxon_id = request.form.get("taxon_id", "").strip() or None
+
+ common_name = request.form.get("common_name", "").strip()
+ if not bool(common_name):
+ flash("The common species name MUST be provided.", "alert-danger")
+ error = True
+
+ scientific_name = request.form.get("scientific_name", "").strip()
+ if not bool(scientific_name):
+ flash("The species' scientific name MUST be provided.",
+ "alert-danger")
+ error = True
+
+ parts = tuple(name.strip() for name in scientific_name.split(" "))
+ if len(parts) != 2 or not all(bool(name) for name in parts):
+ flash("The scientific name you provided is invalid.", "alert-danger")
+ error = True
+
+ cursor.execute(
+ "SELECT * FROM Species WHERE FullName=%s", (scientific_name,))
+ res = cursor.fetchone()
+ if bool(res):
+ flash("A species already exists with the provided scientific name.",
+ "alert-danger")
+ error = True
+
+ if bool(taxon_id):
+ cursor.execute(
+ "SELECT * FROM Species WHERE TaxonomyId=%s", (taxon_id,))
+ res = cursor.fetchone()
+ if bool(res):
+ flash("A species already exists with the provided scientific name.",
+ "alert-danger")
+ error = True
+
+ if error:
+ return redirect(url_for("species.create_species",
+ common_name=common_name,
+ scientific_name=scientific_name,
+ taxon_id=taxon_id))
+
+ species = save_species(conn, common_name, scientific_name, taxon_id)
+ flash("Species saved successfully!", "alert-success")
+ return redirect(url_for("species.view_species", species_id=species["species_id"]))