about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-04-04 15:55:49 +0300
committerFrederick Muriuki Muriithi2023-04-04 15:56:28 +0300
commita2c4047b8ff395d1cef852b8e51fa9bba9be8bd0 (patch)
tree49e5d3857eb9f51bb6029b66ae7c5af080f3acc7
parentfa92004a8bcd0c4a514f75986f8101c9384c6acc (diff)
downloadgenenetwork2-a2c4047b8ff395d1cef852b8e51fa9bba9be8bd0.tar.gz
oauth2: Provide UI for linking genotype datasets.
-rw-r--r--wqflask/wqflask/oauth2/client.py5
-rw-r--r--wqflask/wqflask/oauth2/data.py68
-rw-r--r--wqflask/wqflask/templates/oauth2/data-list-genotype.html167
-rw-r--r--wqflask/wqflask/templates/oauth2/data-list-phenotype.html2
-rw-r--r--wqflask/wqflask/templates/oauth2/data-list.html2
5 files changed, 221 insertions, 23 deletions
diff --git a/wqflask/wqflask/oauth2/client.py b/wqflask/wqflask/oauth2/client.py
index 70cdfbe2..999bbfc8 100644
--- a/wqflask/wqflask/oauth2/client.py
+++ b/wqflask/wqflask/oauth2/client.py
@@ -15,14 +15,15 @@ def oauth2_client():
         scope=SCOPE, token_endpoint_auth_method="client_secret_post",
         token=session.get("oauth2_token"))
 
-def oauth2_get(uri_path: str) -> Either:
+def oauth2_get(uri_path: str, data: dict = {}) -> Either:
     token = session.get("oauth2_token")
     config = app.config
     client = OAuth2Session(
         config["OAUTH2_CLIENT_ID"], config["OAUTH2_CLIENT_SECRET"],
         token=token, scope=SCOPE)
     resp = client.get(
-            urljoin(config["GN_SERVER_URL"], uri_path))
+        urljoin(config["GN_SERVER_URL"], uri_path),
+        data=data)
     if resp.status_code == 200:
         return Right(resp.json())
 
diff --git a/wqflask/wqflask/oauth2/data.py b/wqflask/wqflask/oauth2/data.py
index 963ab547..96acb2c2 100644
--- a/wqflask/wqflask/oauth2/data.py
+++ b/wqflask/wqflask/oauth2/data.py
@@ -18,6 +18,44 @@ def __render_template__(templatepath, **kwargs):
     return render_template(
         templatepath, **kwargs, user_privileges=user_privileges)
 
+def __search_mrna__(query, template, **kwargs):
+    return __render_template__(template, **kwargs)
+
+def __search_genotypes__(query, template, **kwargs):
+    species_name = kwargs["species_name"]
+    datasets = oauth2_get(
+        "oauth2/data/search",
+        data = {
+            "query": query,
+            "dataset_type": "genotype",
+            "species_name": species_name
+        }).either(
+            lambda err: {"datasets_error": process_error(err)},
+            lambda datasets: {"datasets": tuple({
+                "index": idx, **dataset
+            } for idx,dataset in enumerate(datasets, start=1))})
+    return __render_template__(template, **datasets, **kwargs)
+
+def __search_phenotypes__(query, template, **kwargs):
+    per_page = int(request.args.get("per_page", 500))
+    species_name = kwargs["species_name"]
+    search_uri = (f"search/?type=phenotype&per_page={per_page}&query="
+                  f"species:{species_name}") + (
+                      f" AND ({query})" if bool(query) else "")
+    traits = oauth2_get(search_uri).either(
+             lambda err: {"traits_error": process_error(err)},
+             lambda trts: {"traits": tuple({
+                 "index": idx, **trait
+             } for idx, trait in enumerate(trts, start=1))})
+
+    selected_traits = request.form.getlist("selected_traits")
+
+    return __render_template__(
+        template, **traits, per_page=per_page, query=query,
+        selected_traits=selected_traits,
+        search_endpoint=urljoin(app.config["GN_SERVER_URL"], "search/"),
+        **kwargs)
+
 @data.route("/<string:species_name>/<string:dataset_type>/list",
             methods=["GET", "POST"])
 def list_data_by_species_and_dataset(
@@ -25,31 +63,23 @@ def list_data_by_species_and_dataset(
     templates = {
         "mrna": "oauth2/data-list-mrna.html",
         "genotype": "oauth2/data-list-genotype.html",
-        "phenotype": "oauth2/data-list-phenotype.html"}
+        "phenotype": "oauth2/data-list-phenotype.html"
+    }
+    search_fns = {
+        "mrna": __search_mrna__,
+        "genotype": __search_genotypes__,
+        "phenotype": __search_phenotypes__
+    }
     roles = oauth2_get("oauth2/user/roles").either(
         lambda err: {"roles_error": process_error(err)},
         lambda roles: {"roles": roles})
-    query = request.args.get("query", "")
-    per_page = int(request.args.get("per_page", 500))
-    search_uri = (f"search/?type={dataset_type}&per_page={per_page}&query="
-                  f"species:{species_name}") + (
-                      f" AND ({query})" if bool(query) else "")
-    traits = oauth2_get(search_uri).either(
-             lambda err: {"traits_error": process_error(err)},
-             lambda trts: {"traits": tuple({
-                 "index": idx, **trait
-             } for idx, trait in enumerate(trts, start=1))})
     groups = oauth2_get("oauth2/group/list").either(
         lambda err: {"groups_error": process_error(err)},
         lambda grps: {"groups": grps})
-
-    selected_traits = request.form.getlist("selected_traits")
-
-    return __render_template__(
-        templates[dataset_type], **roles, **traits, **groups,
-        species_name=species_name, dataset_type=dataset_type, per_page=per_page,
-        query=query, selected_traits=selected_traits,
-        search_endpoint=urljoin(app.config["GN_SERVER_URL"], "search/"))
+    query = request.args.get("query", "")
+    return search_fns[dataset_type](
+        query, templates[dataset_type], **roles, **groups,
+        species_name=species_name, dataset_type=dataset_type)
 
 @data.route("/list", methods=["GET", "POST"])
 def list_data():
diff --git a/wqflask/wqflask/templates/oauth2/data-list-genotype.html b/wqflask/wqflask/templates/oauth2/data-list-genotype.html
new file mode 100644
index 00000000..6dbcbd38
--- /dev/null
+++ b/wqflask/wqflask/templates/oauth2/data-list-genotype.html
@@ -0,0 +1,167 @@
+{%extends "base.html"%}
+{%from "oauth2/profile_nav.html" import profile_nav%}
+{%from "oauth2/display_error.html" import display_error%}
+
+{%block title%}Link Data: Genotype{%endblock%}
+
+{%block css%}
+<link rel="stylesheet" type="text/css"
+      href="/css/DataTables/css/jquery.dataTables.css" />
+<link rel="stylesheet" type="text/css"
+      href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
+<link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" />
+{%endblock%}
+
+{%block content%}
+<div class="container" style="min-width: 1250px;">
+  {{profile_nav("data", user_privileges)}}
+
+  {{flash_me()}}
+
+  <div class="row">
+    <noscript>This page needs javascript to work correctly</noscript>
+  </div>
+
+  <div class="row">
+    <form id="frm-link-genotypes">
+      <legend>Link Genotype Traits to Group</legend>
+
+      <div class="form-group">
+	<label for="select-group">Group</label>
+	<select id="select-group" name="group_id" required="required"
+		class="form-control">
+	  <option value="">Select group</option>
+	  {%for group in groups%}
+	  <option value="{{group.group_id}}">{{group.group_name}}</option>
+	  {%endfor%}
+	</select>
+      </div>
+
+      <table id="tbl-link-genotypes" class="table-hover table-striped cell-border">
+	<tbody>
+	  <tr>
+	    <td colspan="100%" align="center" style="text-align: center;">
+	      <br/><b><font size="4">
+	      <span class="glyphicon glyphicon-info-sign text-info"></span>
+	      &nbsp;
+	      There are no selected genotype datasets to link to the group.
+	      </font></b><br />
+	    </td>
+	  </tr>
+	</tbody>
+      </table>
+
+      {%if groups | length > 0%}
+      <input type="submit" value="Link Selected" class="btn btn-primary" />
+      {%else%}
+      <input type="submit" value="No group to link to" class="btn btn-warning"
+	     disabled="disabled" />
+      {%endif%}
+    </form>
+  </div>
+
+  <div class="row">
+    <span id="search-messages" class="alert-danger" style="display:none"></span>
+    <form id="frm-search-traits"
+	  action="#"
+	  method="POST">
+      <legend>Search: Genotype</legend>
+      <input type="hidden" value="{{species_name}}" name="species"
+	     id="txt-species" />
+      <input type="hidden" value="{{dataset_type}}" name="dataset_type"
+	     id="txt-dataset-type"  />
+      <input type="hidden" value="{{per_page}}" name="per_page"
+	     id="txt-per-page"  />
+
+      <div class="form-group">
+	<label for="txt-query">Dataset Search String</label>
+	<input type="text" id="txt-query" name="query" class="form-control"
+	       value="{{query}}"/>
+      </div>
+    </form>
+  </div>
+
+  <div class="row">
+    <table id="tbl-genotypes" class="table-hover table-striped cell-border">
+      <tbody>
+	<tr>
+	  <td colspan="100%" align="center">
+	    <br><b><font size="15">Loading...</font></b><br>
+	  </td>
+	</tr>
+    </table>
+  </div>
+
+
+</div>
+{%endblock%}
+
+{%block js%}
+<script language="javascript" type="text/javascript"
+	src="/js/DataTables/js/jquery.dataTables.min.js"></script>
+
+<script language="javascript" type="text/javascript"
+	src="/js/DataTablesExtensions/plugins/sorting/natural.js"></script>
+
+<script language="javascript" type="text/javascript"
+	src="/js/DataTablesExtensions/colReorder/js/dataTables.colReorder.js">
+</script>
+
+<script language="javascript" type="text/javascript"
+	src="/js/DataTablesExtensions/colResize/dataTables.colResize.js">
+</script>
+
+<script language="javascript" type="text/javascript"
+	src="/static/new/javascript/create_datatable.js"></script>
+
+<script language="javascript" type="text/javascript">
+  var common_column_definitions = [
+      {"title": "Index", "data": "index"},
+      {"title": "Group", "data": "InbredSetName"},
+      {"title": "Dataset", "data": "dataset_name"},
+      {"title": "Dataset FullName", "data": "dataset_fullname"},
+      {"title": "Dataset ShortName", "data": "dataset_shortname"}
+  ];
+
+  var search_column_definitions = [{"data": null, "render": function(data) {
+      return (
+	  '<input type="checkbox" name="geno_datasets" ' +
+	      'class="checkbox" value="' +
+	      JSON.stringify(data) + '" />');
+  }},].concat(common_column_definitions);
+
+  var selected_column_definitions = [{"data": null, "render": function(data) {
+      return (
+	  '<input type="checkbox" name="selected_datasets" ' +
+	      'class="checkbox" value="' +
+	      data.name + ':' + data.dataset +
+	      '" />');
+  }},].concat(common_column_definitions);
+
+  var table_settings = {
+      "scrollY": "40vh",
+      "language": {
+	  "emptyTable": "No datasets to display!",
+	  "info": "Showing _START_ to _END_ of _TOTAL_ entries",
+	  "infoEmpty": "No entries to show",
+	  "loadingRecords": "Loading entries ..."
+      }
+  }
+
+  $(document).ready(function() {
+      $("#frm-search-traits").submit(function(event) {
+	  event.preventDefault();
+	  return false;
+      });
+      /* $("#txt-query").keyup(debounced_search()); */
+      create_table(tableId="tbl-genotypes",
+		   tableData={{datasets | list | tojson}},
+		   columnDefs=search_column_definitions,
+		  customSettings=table_settings);
+      create_table(tableId="tbl-link-genotypes",
+		   tableData={{selected_datasets | list | tojson}},
+		   columnDefs=selected_column_definitions,
+		   customSettings=table_settings);
+  });
+</script>
+{%endblock%}
diff --git a/wqflask/wqflask/templates/oauth2/data-list-phenotype.html b/wqflask/wqflask/templates/oauth2/data-list-phenotype.html
index 0e94bcfa..53c6ce8c 100644
--- a/wqflask/wqflask/templates/oauth2/data-list-phenotype.html
+++ b/wqflask/wqflask/templates/oauth2/data-list-phenotype.html
@@ -2,7 +2,7 @@
 {%from "oauth2/profile_nav.html" import profile_nav%}
 {%from "oauth2/display_error.html" import display_error%}
 
-{%block title%}View User{%endblock%}
+{%block title%}Link Data: Phenotype{%endblock%}
 
 {%block css%}
 <link rel="stylesheet" type="text/css"
diff --git a/wqflask/wqflask/templates/oauth2/data-list.html b/wqflask/wqflask/templates/oauth2/data-list.html
index b7c526c6..8a8f6694 100644
--- a/wqflask/wqflask/templates/oauth2/data-list.html
+++ b/wqflask/wqflask/templates/oauth2/data-list.html
@@ -1,7 +1,7 @@
 {%extends "base.html"%}
 {%from "oauth2/profile_nav.html" import profile_nav%}
 {%from "oauth2/display_error.html" import display_error%}
-{%block title%}View User{%endblock%}
+{%block title%}Link Data{%endblock%}
 {%block content%}
 <div class="container" style="min-width: 1250px;">
   {{profile_nav("data", user_privileges)}}