about summary refs log tree commit diff
path: root/uploader/population/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'uploader/population/views.py')
-rw-r--r--uploader/population/views.py104
1 files changed, 63 insertions, 41 deletions
diff --git a/uploader/population/views.py b/uploader/population/views.py
index 003787a..87a33d9 100644
--- a/uploader/population/views.py
+++ b/uploader/population/views.py
@@ -1,8 +1,10 @@
 """Views dealing with populations/inbredsets"""
-import re
 import json
 import base64
 
+from markupsafe import escape
+from MySQLdb.cursors import DictCursor
+from gn_libs.mysqldb import database_connection
 from flask import (flash,
                    request,
                    url_for,
@@ -10,13 +12,17 @@ from flask import (flash,
                    Blueprint,
                    current_app as app)
 
+from uploader.samples.views import samplesbp
+from uploader.oauth2.client import oauth2_post
 from uploader.ui import make_template_renderer
 from uploader.authorisation import require_login
-from uploader.db_utils import database_connection
-from uploader.samples.views import samplesbp
-from uploader.species.models import (all_species,
-                                     species_by_id,
-                                     order_species_by_family)
+from uploader.genotypes.views import genotypesbp
+from uploader.datautils import enumerate_sequence
+from uploader.phenotypes.views import phenotypesbp
+from uploader.expression_data.views import exprdatabp
+from uploader.species.models import all_species, species_by_id
+from uploader.monadic_requests import make_either_error_handler
+from uploader.input_validation import is_valid_representative_name
 
 from .models import (save_population,
                      population_families,
@@ -27,6 +33,9 @@ from .models import (save_population,
 __active_link__ = "populations"
 popbp = Blueprint("populations", __name__)
 popbp.register_blueprint(samplesbp, url_prefix="/")
+popbp.register_blueprint(genotypesbp, url_prefix="/")
+popbp.register_blueprint(phenotypesbp, url_prefix="/")
+popbp.register_blueprint(exprdatabp, url_prefix="/")
 render_template = make_template_renderer("populations")
 
 
@@ -38,7 +47,15 @@ def index():
         if not bool(request.args.get("species_id")):
             return render_template(
                 "populations/index.html",
-                species=order_species_by_family(all_species(conn)))
+                species=all_species(conn),
+                activelink="populations")
+
+        species_id = request.args.get("species_id")
+        if species_id == "CREATE-SPECIES":
+            return redirect(url_for(
+                "species.create_species",
+                return_to="species.populations.list_species_populations"))
+
         species = species_by_id(conn, request.args.get("species_id"))
         if not bool(species):
             flash("Invalid species identifier provided!", "alert-danger")
@@ -58,38 +75,17 @@ def list_species_populations(species_id: int):
         return render_template(
             "populations/list-populations.html",
             species=species,
-            populations=populations_by_species(conn, species_id),
+            populations=enumerate_sequence(populations_by_species(
+                conn, species_id)),
             activelink="list-populations")
 
 
-def valid_population_name(population_name: str) -> bool:
-    """
-    Check whether the given name is a valid population name.
-
-    Parameters
-    ----------
-    population_name: a string of characters.
-
-    Checks For
-    ----------
-    * The name MUST start with an alphabet [a-zA-Z]
-    * The name MUST end with an alphabet [a-zA-Z] or number [0-9]
-    * The name MUST be composed of alphabets [a-zA-Z], numbers [0-9],
-      underscores (_) and/or hyphens (-).
-
-    Returns
-    -------
-    Boolean indicating whether or not the name is valid.
-    """
-    pattern = re.compile(r"^[a-zA-Z]+[a-zA-Z0-9_-]*[a-zA-Z0-9]$")
-    return bool(pattern.match(population_name))
-
-
 @popbp.route("/<int:species_id>/populations/create", methods=["GET", "POST"])
 @require_login
 def create_population(species_id: int):
     """Create a new population."""
-    with database_connection(app.config["SQL_URI"]) as conn:
+    with (database_connection(app.config["SQL_URI"]) as conn,
+          conn.cursor(cursorclass=DictCursor) as cursor):
         species = species_by_id(conn, species_id)
 
         if request.method == "GET":
@@ -100,11 +96,11 @@ def create_population(species_id: int):
                 ).decode("utf8")
 
             error_values = json.loads(base64.b64decode(
-                error_values.encode("utf8")).decode("utf8"))
+                error_values.encode("utf8")).decode("utf8"))# type: ignore[union-attr]
             return render_template(
                 "populations/create-population.html",
                 species=species,
-                families = population_families(conn),
+                families = population_families(conn, species["SpeciesId"]),
                 genetic_types = population_genetic_types(conn),
                 mapping_methods=(
                     {"id": "0", "value": "No mapping support"},
@@ -112,6 +108,7 @@ def create_population(species_id: int):
                     {"id": "2", "value": "GEMMA"},
                     {"id": "3", "value": "R/qtl"},
                     {"id": "4", "value": "GEMMA, PLINK"}),
+                return_to=(request.args.get("return_to") or ""),
                 activelink="create-population",
                 **error_values)
 
@@ -119,7 +116,7 @@ def create_population(species_id: int):
             flash("You must select a species.", "alert-danger")
             return redirect(url_for("species.populations.index"))
 
-        errors = tuple()
+        errors: tuple[tuple[str, str], ...] = tuple()
 
         population_name = (request.form.get(
             "population_name") or "").strip()
@@ -127,7 +124,7 @@ def create_population(species_id: int):
             errors = errors + (("population_name",
                                 "You must provide a name for the population!"),)
 
-        if not valid_population_name(population_name):
+        if not is_valid_representative_name(population_name):
             errors = errors + ((
                 "population_name",
                 "The population name can only contain letters, numbers, "
@@ -149,21 +146,46 @@ def create_population(species_id: int):
                                     species_id=species["SpeciesId"],
                                     error_values=values))
 
-        new_population = save_population(conn, {
+        new_population = save_population(cursor, {
             "SpeciesId": species["SpeciesId"],
             "Name": population_name,
             "InbredSetName": population_fullname,
             "FullName": population_fullname,
             "InbredSetCode": request.form.get("population_code") or None,
             "Description": request.form.get("population_description") or None,
-            "Family": request.form.get("population_family") or None,
+            "Family": request.form.get("population_family").strip() or None,
             "MappingMethodId": request.form.get("population_mapping_method_id"),
             "GeneticType": request.form.get("population_genetic_type") or None
         })
 
-        return redirect(url_for("species.populations.view_population",
-                                species_id=species["SpeciesId"],
-                                population_id=new_population["InbredSetId"]))
+        def __flash_success__(_success):
+            flash("Successfully created population "
+                  f"{escape(new_population['FullName'])}.",
+                  "alert-success")
+            return_to = request.form.get("return_to") or ""
+            if return_to:
+                return redirect(url_for(
+                    return_to,
+                    species_id=species["SpeciesId"],
+                    population_id=new_population["InbredSetId"]))
+            return redirect(url_for(
+                "species.populations.view_population",
+                species_id=species["SpeciesId"],
+                population_id=new_population["InbredSetId"]))
+
+        app.logger.debug("We begin setting up the privileges here…")
+        return oauth2_post(
+            "auth/resource/populations/create",
+            json={
+                **dict(request.form),
+                "species_id": species_id,
+                "population_id": new_population["Id"],
+                "public": "on"
+            }
+        ).either(
+            make_either_error_handler(
+                "There was an error creating the population"),
+            __flash_success__)
 
 
 @popbp.route("/<int:species_id>/populations/<int:population_id>",