about summary refs log tree commit diff
path: root/uploader/species
diff options
context:
space:
mode:
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"]))