"""Handle linking data to groups."""
import sys
import json
import uuid
from datetime import datetime
from urllib.parse import urljoin
from redis import Redis
from flask import (
flash, request, jsonify, url_for, redirect, Response, Blueprint,
current_app as app)
from gn2.wqflask.oauth2.request_utils import with_flash_error
from gn2.jobs import jobs
from .ui import render_ui
from .request_utils import process_error
from .client import oauth2_get, oauth2_post, authserver_uri
data = Blueprint("data", __name__)
def __search_mrna__(query, template, **kwargs):
species_name = kwargs["species_name"]
search_uri = urljoin(authserver_uri(), "auth/data/search")
datasets = oauth2_get(
"auth/data/search",
json = {
"query": query,
"dataset_type": "mrna",
"species_name": species_name,
"selected": __selected_datasets__()
}).either(
lambda err: {"datasets_error": process_error(err)},
lambda datasets: {"datasets": datasets})
return render_ui(template, search_uri=search_uri, **datasets, **kwargs)
def __selected_datasets__():
if bool(request.json):
return request.json.get(
"selected",
request.args.get("selected",
request.form.get("selected", [])))
return request.args.get("selected",
request.form.get("selected", []))
def __search_genotypes__(query, template, **kwargs):
species_name = kwargs["species_name"]
search_uri = urljoin(authserver_uri(), "auth/data/search")
datasets = oauth2_get(
"auth/data/search",
json = {
"query": query,
"dataset_type": "genotype",
"species_name": species_name,
"selected": __selected_datasets__()
}).either(
lambda err: {"datasets_error": process_error(err)},
lambda datasets: {"datasets": datasets})
return render_ui(template, search_uri=search_uri, **datasets, **kwargs)
def __search_phenotypes__(query, template, **kwargs):
from gn2.utility.tools import GN_SERVER_URL
page = int(request.args.get("page", 1))
per_page = int(request.args.get("per_page", 50))
selected_traits = request.form.getlist("selected_traits")
def __search_success__(search_results):
job_id = uuid.UUID(search_results["job_id"])
return render_ui(
template, traits=[], per_page=per_page, query=query,
selected_traits=selected_traits, search_results=search_results,
search_endpoint=urljoin(
request.host_url, "oauth2/data/phenotype/search"),
auth_server_url=authserver_uri(),
pheno_results_template=urljoin(
authserver_uri(), "auth/data/search/phenotype/<jobid>"),
results_endpoint=urljoin(
authserver_uri(),
f"auth/data/search/phenotype/{job_id}"),
**kwargs)
return oauth2_get("auth/data/search", json={
"dataset_type": "phenotype",
"species_name": kwargs["species_name"],
"per_page": per_page,
"page": page,
"gn3_server_uri": GN_SERVER_URL
}).either(
with_flash_error(redirect(url_for('oauth2.data.list_data'))),
__search_success__)
@data.route("/genotype/search", methods=["POST"])
def json_search_genotypes() -> Response:
def __handle_error__(err):
error = process_error(err)
return jsonify(error), error["status_code"]
return oauth2_get(
"auth/data/search",
json = {
"query": request.json["query"],
"dataset_type": "genotype",
"species_name": request.json["species_name"],
"selected": __selected_datasets__()
}).either(
__handle_error__,
lambda datasets: jsonify(datasets))
@data.route("/mrna/search", methods=["POST"])
def json_search_mrna() -> Response:
def __handle_error__(err):
error = process_error(err)
return jsonify(error), error["status_code"]
return oauth2_get(
"auth/data/search",
json = {
"query": request.json["query"],
"dataset_type": "mrna",
"species_name": request.json["species_name"],
"selected": __selected_datasets__()
}).either(
__handle_error__,
lambda datasets: jsonify(datasets))
@data.route("/phenotype/search", methods=["POST"])
def json_search_phenotypes() -> Response:
"""Search for phenotypes."""
from gn2.utility.tools import GN_SERVER_URL
form = request.json
def __handle_error__(err):
error = process_error(err)
return jsonify(error), error["status_code"]
return oauth2_get(
"auth/data/search",
json={
"dataset_type": "phenotype",
"species_name": form["species_name"],
"query": form.get("query", ""),
"per_page": int(form.get("per_page", 50)),
"page": int(form.get("page", 1)),
"auth_server_uri": authserver_uri(),
"gn3_server_uri": GN_SERVER_URL,
"selected_traits": form.get("selected_traits", [])
}).either(__handle_error__, jsonify)
@data.route("/<string:species_name>/<string:dataset_type>/list",
methods=["GET", "POST"])
def list_data_by_species_and_dataset(
species_name: str, dataset_type: str) -> Response:
templates = {
"mrna": "oauth2/data-list-mrna.html",
"genotype": "oauth2/data-list-genotype.html",
"phenotype": "oauth2/data-list-phenotype.html"
}
search_fns = {
"mrna": __search_mrna__,
"genotype": __search_genotypes__,
"phenotype": __search_phenotypes__
}
groups = oauth2_get("auth/group/list").either(
lambda err: {"groups_error": process_error(err)},
lambda grps: {"groups": grps})
query = request.args.get("query", "")
return search_fns[dataset_type](
query, templates[dataset_type], **groups, species_name=species_name,
dataset_type=dataset_type)
@data.route("/list", methods=["GET", "POST"])
def list_data():
"""List ungrouped data."""
def __render__(**kwargs):
roles = kwargs.get("roles", [])
user_privileges = tuple(
privilege["privilege_id"] for role in roles
for privilege in role["privileges"])
return render_ui(
"oauth2/data-list.html",
groups=kwargs.get("groups", []),
data_items=kwargs.get("data_items", []),
user_privileges=user_privileges,
**{key:val for key,val in kwargs.items()
if key not in ("groups", "data_items", "user_privileges")})
groups = oauth2_get("auth/group/list").either(
lambda err: {"groups_error": process_error(err)},
lambda grp: {"groups": grp})
roles = oauth2_get("auth/system/roles").either(
lambda err: {"roles_error": process_error(err)},
lambda roles: {"roles": roles})
species = oauth2_get("auth/data/species").either(
lambda err: {"species_error": process_error(err)},
lambda species: {"species": species})
if request.method == "GET":
return __render__(**{**groups, **roles, **species})
species_name = request.form["species_name"]
dataset_type = request.form["dataset_type"]
if dataset_type not in ("mrna", "genotype", "phenotype"):
flash("InvalidDatasetType: An invalid dataset type was provided",
"alert-danger")
return __render__(**{**groups, **roles, **species})
return redirect(url_for(
"oauth2.data.list_data_by_species_and_dataset",
species_name=species_name, dataset_type=dataset_type))
@data.route("/link", methods=["POST"])
def link_data():
"""Link the selected data to a specific group."""
def __error__(err, form_data):
error = process_error(err)
flash(f"{error['error']}: {error['error_description']}", "alert-danger")
return redirect(url_for("oauth2.data.list_data", **form_data), code=307)
def __success__(success, form_data):
flash("Data successfully linked!", "alert-success")
return redirect(url_for("oauth2.data.list_data", **form_data), code=307)
form = request.form
try:
keys = ("dataset_type", "group_id")
assert all(item in form for item in keys)
assert all(bool(form[item]) for item in keys)
state_data = {
"dataset_type": form["dataset_type"],
"offset": form.get("offset", 0)}
dataset_ids = form.getlist("dataset_ids")
if len(dataset_ids) == 0:
flash("You must select at least one item to link", "alert-danger")
return redirect(url_for(
"oauth2.data.list_data", **state_data))
return oauth2_post(
"auth/group/data/link",
data={
"dataset_type": form["dataset_type"],
"dataset_ids": dataset_ids,
"group_id": form["group_id"]
}).either(lambda err: __error__(err, state_data),
lambda success: __success__(success, state_data))
except AssertionError as aserr:
flash("You must provide all the expected data.", "alert-danger")
return redirect(url_for("oauth2.data.list_data"))
@data.route("/link/genotype", methods=["POST"])
def link_genotype_data():
"""Link genotype data to a group."""
form = request.form
link_source_url = redirect(url_for("oauth2.data.list_data"))
if bool(form.get("species_name")):
link_source_url = redirect(url_for(
"oauth2.data.list_data_by_species_and_dataset",
species_name=form["species_name"], dataset_type="genotype"))
def __link_error__(err):
flash(f"{err['error']}: {err['error_description']}", "alert-danger")
return link_source_url
def __link_success__(success):
flash(success["description"], "alert-success")
return link_source_url
return oauth2_post("auth/data/link/genotype", json={
"species_name": form.get("species_name"),
"group_id": form.get("group_id"),
"selected": tuple(json.loads(dataset) for dataset
in form.getlist("selected"))
}).either(lambda err: __link_error__(process_error(err)), __link_success__)
@data.route("/link/mrna", methods=["POST"])
def link_mrna_data():
"""Link mrna data to a group."""
form = request.form
link_source_url = redirect(url_for("oauth2.data.list_data"))
if bool(form.get("species_name")):
link_source_url = redirect(url_for(
"oauth2.data.list_data_by_species_and_dataset",
species_name=form["species_name"], dataset_type="mrna"))
def __link_error__(err):
error = process_error(err)
flash(f"{err['error']}: {err['error_description']}", "alert-danger")
return link_source_url
def __link_success__(success):
flash(success["description"], "alert-success")
return link_source_url
return oauth2_post("auth/data/link/mrna", json={
"species_name": form.get("species_name"),
"group_id": form.get("group_id"),
"selected": tuple(json.loads(dataset) for dataset
in form.getlist("selected"))
}).either(lambda err: __link_error__(process_error(err)), __link_success__)
@data.route("/link/phenotype", methods=["POST"])
def link_phenotype_data():
"""Link phenotype data to a group."""
form = request.form
link_source_url = redirect(url_for("oauth2.data.list_data"))
if bool(form.get("species_name")):
link_source_url = redirect(url_for(
"oauth2.data.list_data_by_species_and_dataset",
species_name=form["species_name"], dataset_type="phenotype"))
def __link_error__(err):
error = process_error(err)
flash(f"{error['error']}: {error['error_description']}", "alert-danger")
return link_source_url
def __link_success__(success):
flash(success["description"], "alert-success")
return link_source_url
return oauth2_post("auth/data/link/phenotype", json={
"species_name": form.get("species_name"),
"group_id": form.get("group_id"),
"selected": tuple(
json.loads(trait) for trait in form.getlist("selected"))}).either(
__link_error__, __link_success__)