From e13a694540ee65f401652d9ebdb5f845c15fb97e Mon Sep 17 00:00:00 2001
From: Frederick Muriuki Muriithi
Date: Thu, 5 Sep 2024 12:31:48 -0500
Subject: Provide basic UI for editing the Species details.

---
 uploader/species/models.py |  8 ++++++
 uploader/species/views.py  | 69 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 68 insertions(+), 9 deletions(-)

(limited to 'uploader/species')

diff --git a/uploader/species/models.py b/uploader/species/models.py
index 53e7de0..cea3549 100644
--- a/uploader/species/models.py
+++ b/uploader/species/models.py
@@ -81,3 +81,11 @@ def save_species(conn: mdb.Connection,
             **species,
             "species_id": species_id
         }
+
+
+def species_families(conn: mdb.Connection) -> tuple:
+    """Retrieve the families under which species are grouped."""
+    with conn.cursor(cursorclass=DictCursor) as cursor:
+        cursor.execute(
+            "SELECT DISTINCT(Family) FROM Species WHERE Family IS NOT NULL")
+        return tuple(fam["Family"] for fam in cursor.fetchall())
diff --git a/uploader/species/views.py b/uploader/species/views.py
index 5de5277..d994e41 100644
--- a/uploader/species/views.py
+++ b/uploader/species/views.py
@@ -1,4 +1,5 @@
 """Endpoints handling species."""
+from pymonad.either import Left, Right, Either
 from flask import (flash,
                    request,
                    url_for,
@@ -9,9 +10,10 @@ from flask import (flash,
 from uploader.population import popbp
 from uploader.ui import make_template_renderer
 from uploader.db_utils import database_connection
+from uploader.oauth2.client import oauth2_get, oauth2_post
 from uploader.authorisation import require_login, require_token
 
-from .models import all_species, save_species, species_by_id
+from .models import all_species, save_species, species_by_id, species_families
 
 
 speciesbp = Blueprint("species", __name__)
@@ -100,11 +102,11 @@ def create_species():
         return redirect(url_for("species.view_species", species_id=species["species_id"]))
 
 
-@speciesbp.route("/<int:species_id>/edit")
+@speciesbp.route("/<int:species_id>/edit-extra", methods=["GET", "POST"])
 @require_login
 @require_token
 #def edit_species(species_id: int):
-def edit_species(token: dict, species_id: int):
+def edit_species_extra(token: dict, species_id: int):# pylint: disable=[unused-argument]
     """Edit a species' details.
 
     Parameters
@@ -112,9 +114,58 @@ def edit_species(token: dict, species_id: int):
     token: A JWT token used for authorisation.
     species_id: An identifier for the species being edited.
     """
-    app.logger.debug("======================\n"
-                     "Token: %s\n"
-                     "SpeciesId: %s\n"
-                     "======================",
-                     token, species_id)
-    return "Would edit the species."
+    def __failure__(res):
+        app.logger.debug(
+            "There was an error in the attempt to edit the species: %s", res)
+        flash(res, "alert-danger")
+        return redirect(url_for("species.view_species", species_id=species_id))
+
+    def __system_resource_uuid__(resources) -> Either:
+        sys_res = [
+            resource for resource in resources
+            if resource["resource_category"]["resource_category_key"] == "system"
+        ]
+        if len(sys_res) != 1:
+            return Left("Could not find/identify a valid system resource.")
+        return Right(sys_res[0]["resource_id"])
+
+    def __check_privileges__(authorisations):
+        if len(authorisations.items()) != 1:
+            return Left("Got authorisations for more than a single resource!")
+
+        auths = tuple(authorisations.items())[0][1]
+        authorised = "system:species:edit-extra-info" in tuple(
+            privilege["privilege_id"]
+            for role in auths["roles"]
+            for privilege in role["privileges"])
+        if authorised:
+            return Right(authorised)
+        return Left("You are not authorised to edit species extra details.")
+
+    with database_connection(app.config["SQL_URI"]) as conn:
+        species = species_by_id(conn, species_id)
+        families = species_families(conn)
+        if bool(species) and request.method == "GET":
+            return oauth2_get("auth/user/resources").then(
+                __system_resource_uuid__
+            ).then(
+                lambda resource_id: oauth2_post(
+                    "auth/resource/authorisation",
+                    json={"resource-ids": [resource_id]})
+            ).then(__check_privileges__).then(
+                lambda authorisations: render_template("species/edit-species.html",
+                                                  species=species,
+                                                  families=families,
+                                                  activelink="edit-species")
+            ).either(__failure__, lambda res: res)
+
+        if bool(species) and request.method == "POST":
+            flash("We would have edited the species, but the feature is not "
+                  "currently implemented …",
+                  "alert-danger")
+            return redirect(url_for("species.edit_species_extra",
+                                    species_id=species_id))
+
+        flash("Species with the given identifier was not found!",
+              "alert-danger")
+        return redirect(url_for("species.list_species"))
-- 
cgit v1.2.3