about summary refs log tree commit diff
path: root/uploader
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-09-23 16:29:25 -0500
committerFrederick Muriuki Muriithi2024-09-23 16:35:39 -0500
commit480ee0b657b762f1dd0b1164f98ab13bc9a11f56 (patch)
tree28c7e8e450112039bb764a6fe967838369aba937 /uploader
parent4285cc10e24d6410206329ba079406e9aa21cc30 (diff)
downloadgn-uploader-480ee0b657b762f1dd0b1164f98ab13bc9a11f56.tar.gz
Initialise "Platforms" section.
Diffstat (limited to 'uploader')
-rw-r--r--uploader/db/platforms.py25
-rw-r--r--uploader/platforms/__init__.py2
-rw-r--r--uploader/platforms/models.py41
-rw-r--r--uploader/platforms/views.py86
-rw-r--r--uploader/species/views.py2
-rw-r--r--uploader/templates/platforms/base.html13
-rw-r--r--uploader/templates/platforms/create-platform.html103
-rw-r--r--uploader/templates/platforms/index.html21
-rw-r--r--uploader/templates/platforms/list-platforms.html93
9 files changed, 361 insertions, 25 deletions
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("<int:species_id>/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("<int:species_id>/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%}
+<li {%if activelink=="platforms"%}
+    class="breadcrumb-item active"
+    {%else%}
+    class="breadcrumb-item"
+    {%endif%}>
+  <a href="{{url_for('species.populations.platforms.index')}}">
+    Sequencing Platforms</a>
+</li>
+{%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 &mdash; Create Platforms{%endblock%}
+
+{%block pagetitle%}Platforms &mdash; Create Platforms{%endblock%}
+
+{%block lvl3_breadcrumbs%}
+<li {%if activelink=="create-platform"%}
+    class="breadcrumb-item active"
+    {%else%}
+    class="breadcrumb-item"
+    {%endif%}>
+  <a href="{{url_for('species.platforms.create_platform',
+           species_id=species.SpeciesId)}}">create platform</a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <h2>Create New Platform</h2>
+
+  <p>You can create a new genetic sequencing platform below.</p>
+</div>
+
+<div class="row">
+  <form id="frm-create-platform"
+        method="POST"
+        action="{{url_for('species.platforms.create_platform',
+                species_id=species.SpeciesId)}}">
+
+    <div class="form-group">
+      <label for="txt-geo-platform" class="form-label">GEO Platform</label>
+      <input type="text"
+             id="txt-geo-platform"
+             name="geo-platform"
+             required="required"
+             class="form-control"  />
+      <small class="form-text text-muted">
+        <p>This is the platform's
+          <a href="https://www.ncbi.nlm.nih.gov/geo/browse/?view=platforms&tax={{species.TaxonomyId}}"
+             title="Platforms for '{{species.FullName}}' on NCBI">
+            accession value on NCBI</a>. If you do not know the value, click the
+          link and search on NCBI for species '{{species.FullName}}'.</p></small>
+    </div>
+
+    <div class="form-group">
+      <label for="txt-platform-name" class="form-label">Platform Name</label>
+      <input type="text"
+             id="txt-platform-name"
+             name="platform-name"
+             required="required"
+             class="form-control" />
+      <small class="form-text text-muted">
+        <p>This is name of the genetic sequencing platform.</p></small>
+    </div>
+
+    <div class="form-group">
+      <label for="txt-platform-shortname" class="form-label">
+        Platform Short Name</label>
+      <input type="text"
+             id="txt-platform-shortname"
+             name="platform-shortname"
+             required="required"
+             class="form-control" />
+      <small class="form-text text-muted">
+        <p>Use the following conventions for this field:
+          <ol>
+            <li>Start with a 4-letter vendor code, e.g. "Affy" for "Affymetrix", "Illu" for "Illumina", etc.</li>
+            <li>Append an underscore to the 4-letter vendor code</li>
+            <li>Use the name of the array given by the vendor, e.g.  U74AV2, MOE430A, etc.</li>
+          </ol>
+        </p>
+      </small>
+    </div>
+
+    <div class="form-group">
+      <label for="txt-platform-title" class="form-label">Platform Title</label>
+      <input type="text"
+             id="txt-platform-title"
+             name="platform-title"
+             required="required"
+             class="form-control"  />
+      <small class="form-text text-muted">
+        <p>The full platform title. Sometimes, this is the same as the Platform
+          Name above.</p></small>
+    </div>
+
+    <div class="form-group">
+      <input type="submit"
+             value="create new platform"
+             class="btn btn-primary"  />
+    </div>
+  </form>
+</div>
+{%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()}}
+
+<div class="row">
+  <p>In this section, you will be able to view and manage the sequencing
+    platforms that are currently supported by GeneNetwork.</p>
+</div>
+
+<div class="row">
+  {{select_species_form(url_for("species.platforms.index"), species)}}
+</div>
+{%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 &mdash; List Platforms{%endblock%}
+
+{%block pagetitle%}Platforms &mdash; List Platforms{%endblock%}
+
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <p>View the list of the genetic sequencing platforms that are currently
+    supported by GeneNetwork.</p>
+  <p>If you cannot find the platform you wish to use, you can add it by clicking
+    the "New Platform" button below.</p>
+  <p><a href="{{url_for('species.platforms.create_platform',
+              species_id=species.SpeciesId)}}"
+        title="Create a new genetic sequencing platform for species {{species.FullName}}"
+        class="btn btn-primary">Create Platform</a></p>
+</div>
+
+<div class="row">
+  <h2>Supported Platforms</h2>
+  {%if platforms is defined and platforms | length > 0%}
+  <p>There are {{total_platforms}} platforms supported by GeneNetwork</p>
+
+  <div class="row">
+    <div class="col-md-2" style="text-align: start;">
+      {%if start_from > 0%}
+      <a href="{{url_for('species.platforms.list_platforms',
+               species_id=species.SpeciesId,
+               start_from=start_from-count,
+               count=count)}}">
+        <span class="glyphicon glyphicon-backward"></span>
+        Previous
+      </a>
+      {%endif%}
+    </div>
+    <div class="col-md-8" style="text-align: center;">
+      Displaying platforms {{start_from+1}} to {{start_from+count if start_from+count < total_platforms else total_platforms}} of
+      {{total_platforms}}
+    </div>
+    <div class="col-md-2" style="text-align: end;">
+      {%if start_from + count < total_platforms%}
+      <a href="{{url_for('species.platforms.list_platforms',
+               species_id=species.SpeciesId,
+               start_from=start_from+count,
+               count=count)}}">
+        Next
+        <span class="glyphicon glyphicon-forward"></span>
+      </a>
+      {%endif%}
+    </div>
+  </div>
+
+  <table class="table">
+    <thead>
+      <tr>
+        <th>#</th>
+        <th>Platform Name</th>
+        <th><a href="https://www.ncbi.nlm.nih.gov/geo/browse/?view=platforms&tax={{species.TaxonomyId}}"
+               title="Gene Expression Omnibus: Platforms section"
+               target="_blank">GEO Platform</a></th>
+        <th>Title</th>
+      </tr>
+    </thead>
+
+    <tbody>
+      {%for platform in platforms%}
+      <tr>
+        <td>{{platform.sequence_number}}</td>
+        <td>{{platform.GeneChipName}}</td>
+        <td><a href="https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc={{platform.GeoPlatform}}"
+               title="View platform on the Gene Expression Omnibus"
+               target="_blank">{{platform.GeoPlatform}}</a></td>
+        <td>{{platform.Title}}</td>
+      </tr>
+      {%endfor%}
+    </tbody>
+  </table>
+  {%else%}
+  <p class="text-warning">
+    <span class="glyphicon glyphicon-exclamation-sign"></span>
+    There are no platforms supported at this time!</p>
+  {%endif%}
+</div>
+{%endblock%}
+
+{%block sidebarcontents%}
+{{display_species_card(species)}}
+{%endblock%}