From 480ee0b657b762f1dd0b1164f98ab13bc9a11f56 Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Mon, 23 Sep 2024 16:29:25 -0500 Subject: Initialise "Platforms" section. --- uploader/db/platforms.py | 25 ------ uploader/platforms/__init__.py | 2 + uploader/platforms/models.py | 41 +++++++++ uploader/platforms/views.py | 86 ++++++++++++++++++ uploader/species/views.py | 2 + uploader/templates/platforms/base.html | 13 +++ uploader/templates/platforms/create-platform.html | 103 ++++++++++++++++++++++ uploader/templates/platforms/index.html | 21 +++++ uploader/templates/platforms/list-platforms.html | 93 +++++++++++++++++++ 9 files changed, 361 insertions(+), 25 deletions(-) delete mode 100644 uploader/db/platforms.py create mode 100644 uploader/platforms/__init__.py create mode 100644 uploader/platforms/models.py create mode 100644 uploader/platforms/views.py create mode 100644 uploader/templates/platforms/base.html create mode 100644 uploader/templates/platforms/create-platform.html create mode 100644 uploader/templates/platforms/index.html create mode 100644 uploader/templates/platforms/list-platforms.html diff --git a/uploader/db/platforms.py b/uploader/db/platforms.py deleted file mode 100644 index cb527a7..0000000 --- a/uploader/db/platforms.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Handle db interactions for platforms.""" -from typing import Optional - -import MySQLdb as mdb -from MySQLdb.cursors import DictCursor - -def platforms_by_species( - conn: mdb.Connection, speciesid: int) -> tuple[dict, ...]: - """Retrieve platforms by the species""" - with conn.cursor(cursorclass=DictCursor) as cursor: - cursor.execute("SELECT * FROM GeneChip WHERE SpeciesId=%s " - "ORDER BY GeneChipName ASC", - (speciesid,)) - return tuple(dict(row) for row in cursor.fetchall()) - -def platform_by_id(conn: mdb.Connection, platformid: int) -> Optional[dict]: - """Retrieve a platform by its ID""" - with conn.cursor(cursorclass=DictCursor) as cursor: - cursor.execute("SELECT * FROM GeneChip WHERE Id=%s", - (platformid,)) - result = cursor.fetchone() - if bool(result): - return dict(result) - - return None diff --git a/uploader/platforms/__init__.py b/uploader/platforms/__init__.py new file mode 100644 index 0000000..8cb89c9 --- /dev/null +++ b/uploader/platforms/__init__.py @@ -0,0 +1,2 @@ +"""Module to handle management of genetic platforms.""" +from .views import platformsbp diff --git a/uploader/platforms/models.py b/uploader/platforms/models.py new file mode 100644 index 0000000..adad0b2 --- /dev/null +++ b/uploader/platforms/models.py @@ -0,0 +1,41 @@ +"""Handle db interactions for platforms.""" +from typing import Optional + +import MySQLdb as mdb +from MySQLdb.cursors import DictCursor + +def platforms_by_species( + conn: mdb.Connection, + speciesid: int, + offset: int = 0, + limit: Optional[int] = None +) -> tuple[dict, ...]: + """Retrieve platforms by the species""" + _query = ("SELECT * FROM GeneChip WHERE SpeciesId=%s " + "ORDER BY GeneChipName ASC") + if bool(limit) and limit > 0: + _query = f"{_query} LIMIT {limit} OFFSET {offset}" + with conn.cursor(cursorclass=DictCursor) as cursor: + cursor.execute(_query, (speciesid,)) + return tuple(dict(row) for row in cursor.fetchall()) + + +def species_platforms_count(conn: mdb.Connection, species_id: int) -> int: + """Get the number of platforms in the database for a particular species.""" + with conn.cursor(cursorclass=DictCursor) as cursor: + cursor.execute( + "SELECT COUNT(GeneChipName) AS count FROM GeneChip " + "WHERE SpeciesId=%s", + (species_id,)) + return int(cursor.fetchone()["count"]) + +def platform_by_id(conn: mdb.Connection, platformid: int) -> Optional[dict]: + """Retrieve a platform by its ID""" + with conn.cursor(cursorclass=DictCursor) as cursor: + cursor.execute("SELECT * FROM GeneChip WHERE Id=%s", + (platformid,)) + result = cursor.fetchone() + if bool(result): + return dict(result) + + return None diff --git a/uploader/platforms/views.py b/uploader/platforms/views.py new file mode 100644 index 0000000..56390ab --- /dev/null +++ b/uploader/platforms/views.py @@ -0,0 +1,86 @@ +"""The endpoints for the platforms""" +from flask import ( + flash, + request, + url_for, + redirect, + Blueprint, + current_app as app) + +from uploader.ui import make_template_renderer +from uploader.authorisation import require_login +from uploader.db_utils import database_connection +from uploader.species.models import all_species, species_by_id +from uploader.datautils import safe_int, order_by_family, enumerate_sequence + +from .models import platforms_by_species, species_platforms_count + +platformsbp = Blueprint("platforms", __name__) +render_template = make_template_renderer("platforms") + +@platformsbp.route("platforms", methods=["GET"]) +@require_login +def index(): + """Entry-point to the platforms feature.""" + with database_connection(app.config["SQL_URI"]) as conn: + if not bool(request.args.get("species_id")): + return render_template( + "platforms/index.html", + species=order_by_family(all_species(conn)), + activelink="platforms") + + species = species_by_id(conn, request.args["species_id"]) + if not bool(species): + flash("No species selected.", "alert-danger") + return redirect(url_for("species.platforms.index")) + + return redirect(url_for("species.platforms.list_platforms", + species_id=species["SpeciesId"])) + + +@platformsbp.route("/platforms", methods=["GET"]) +@require_login +def list_platforms(species_id: int): + """List all the available genetic sequencing platforms.""" + with database_connection(app.config["SQL_URI"]) as conn: + species = species_by_id(conn, species_id) + if not bool(species): + flash("No species provided.", "alert-danger") + return redirect(url_for("species.platforms.index")) + + start_from = safe_int(request.args.get("start_from") or 0) + if start_from < 0: + start_from = 0 + count = safe_int(request.args.get("count") or 20) + return render_template( + "platforms/list-platforms.html", + species=species, + platforms=enumerate_sequence( + platforms_by_species(conn, + species_id, + offset=start_from, + limit=count), + start=start_from+1), + start_from=start_from, + count=count, + total_platforms=species_platforms_count(conn, species_id), + activelink="list-platforms") + + +@platformsbp.route("/platforms/create", methods=["GET", "POST"]) +@require_login +def create_platform(species_id: int): + """Create a new genetic sequencing platform.""" + with database_connection(app.config["SQL_URI"]) as conn: + species = species_by_id(conn, species_id) + if not bool(species): + flash("No species provided.", "alert-danger") + return redirect(url_for("species.platforms.index")) + + if request.method == "GET": + return render_template( + "platforms/create-platform.html", + species=species, + activelink="create-platform") + + raise NotImplementedError("This still needs to be implemented.") diff --git a/uploader/species/views.py b/uploader/species/views.py index f478505..10715a5 100644 --- a/uploader/species/views.py +++ b/uploader/species/views.py @@ -8,6 +8,7 @@ from flask import (flash, current_app as app) from uploader.population import popbp +from uploader.platforms import platformsbp from uploader.ui import make_template_renderer from uploader.db_utils import database_connection from uploader.oauth2.client import oauth2_get, oauth2_post @@ -23,6 +24,7 @@ from .models import (all_species, speciesbp = Blueprint("species", __name__) speciesbp.register_blueprint(popbp, url_prefix="/") +speciesbp.register_blueprint(platformsbp, url_prefix="/") render_template = make_template_renderer("species") diff --git a/uploader/templates/platforms/base.html b/uploader/templates/platforms/base.html new file mode 100644 index 0000000..dac965f --- /dev/null +++ b/uploader/templates/platforms/base.html @@ -0,0 +1,13 @@ +{%extends "species/base.html"%} + +{%block lvl3_breadcrumbs%} + +{%block lvl4_breadcrumbs%}{%endblock%} +{%endblock%} diff --git a/uploader/templates/platforms/create-platform.html b/uploader/templates/platforms/create-platform.html new file mode 100644 index 0000000..b5961ce --- /dev/null +++ b/uploader/templates/platforms/create-platform.html @@ -0,0 +1,103 @@ +{%extends "platforms/base.html"%} +{%from "flash_messages.html" import flash_all_messages%} +{%from "species/macro-display-species-card.html" import display_species_card%} + +{%block title%}Platforms — Create Platforms{%endblock%} + +{%block pagetitle%}Platforms — Create Platforms{%endblock%} + +{%block lvl3_breadcrumbs%} + +{%endblock%} + +{%block contents%} +{{flash_all_messages()}} + +
+

Create New Platform

+ +

You can create a new genetic sequencing platform below.

+
+ +
+
+ +
+ + + +

This is the platform's + + accession value on NCBI. If you do not know the value, click the + link and search on NCBI for species '{{species.FullName}}'.

+
+ +
+ + + +

This is name of the genetic sequencing platform.

+
+ +
+ + + +

Use the following conventions for this field: +

    +
  1. Start with a 4-letter vendor code, e.g. "Affy" for "Affymetrix", "Illu" for "Illumina", etc.
  2. +
  3. Append an underscore to the 4-letter vendor code
  4. +
  5. Use the name of the array given by the vendor, e.g. U74AV2, MOE430A, etc.
  6. +
+

+
+
+ +
+ + + +

The full platform title. Sometimes, this is the same as the Platform + Name above.

+
+ +
+ +
+
+
+{%endblock%} + +{%block sidebarcontents%} +{{display_species_card(species)}} +{%endblock%} diff --git a/uploader/templates/platforms/index.html b/uploader/templates/platforms/index.html new file mode 100644 index 0000000..35b6464 --- /dev/null +++ b/uploader/templates/platforms/index.html @@ -0,0 +1,21 @@ +{%extends "platforms/base.html"%} +{%from "flash_messages.html" import flash_all_messages%} +{%from "species/macro-select-species.html" import select_species_form%} + +{%block title%}Platforms{%endblock%} + +{%block pagetitle%}Platforms{%endblock%} + + +{%block contents%} +{{flash_all_messages()}} + +
+

In this section, you will be able to view and manage the sequencing + platforms that are currently supported by GeneNetwork.

+
+ +
+ {{select_species_form(url_for("species.platforms.index"), species)}} +
+{%endblock%} diff --git a/uploader/templates/platforms/list-platforms.html b/uploader/templates/platforms/list-platforms.html new file mode 100644 index 0000000..718dd1d --- /dev/null +++ b/uploader/templates/platforms/list-platforms.html @@ -0,0 +1,93 @@ +{%extends "platforms/base.html"%} +{%from "flash_messages.html" import flash_all_messages%} +{%from "species/macro-display-species-card.html" import display_species_card%} + +{%block title%}Platforms — List Platforms{%endblock%} + +{%block pagetitle%}Platforms — List Platforms{%endblock%} + + +{%block contents%} +{{flash_all_messages()}} + +
+

View the list of the genetic sequencing platforms that are currently + supported by GeneNetwork.

+

If you cannot find the platform you wish to use, you can add it by clicking + the "New Platform" button below.

+

Create Platform

+
+ +
+

Supported Platforms

+ {%if platforms is defined and platforms | length > 0%} +

There are {{total_platforms}} platforms supported by GeneNetwork

+ +
+
+ {%if start_from > 0%} + + + Previous + + {%endif%} +
+
+ Displaying platforms {{start_from+1}} to {{start_from+count if start_from+count < total_platforms else total_platforms}} of + {{total_platforms}} +
+
+ {%if start_from + count < total_platforms%} + + Next + + + {%endif%} +
+
+ + + + + + + + + + + + + {%for platform in platforms%} + + + + + + + {%endfor%} + +
#Platform NameGEO PlatformTitle
{{platform.sequence_number}}{{platform.GeneChipName}}{{platform.GeoPlatform}}{{platform.Title}}
+ {%else%} +

+ + There are no platforms supported at this time!

+ {%endif%} +
+{%endblock%} + +{%block sidebarcontents%} +{{display_species_card(species)}} +{%endblock%} -- cgit v1.2.3