# -*- coding: utf-8 -*- """ Public section, including homepage and signup. """ from builtins import bytes from collections import OrderedDict from urllib.parse import unquote_plus from flask import ( Blueprint, Request, abort, flash, json, redirect, render_template, request, url_for, ) from flask_login import current_user, login_required, login_user, logout_user from future import standard_library from megaqc.api.utils import ( aggregate_new_parameters, get_dashboard_data, get_dashboards, get_favourite_plot_data, get_plot_favourites, get_queued_uploads, get_report_metadata_fields, get_reports_data, get_samples, get_user_filters, ) from megaqc.extensions import db, login_manager from megaqc.model.models import PlotCategory, PlotConfig, PlotData, Report from megaqc.public.forms import LoginForm from megaqc.user.forms import RegisterForm from megaqc.user.models import User from megaqc.utils import flash_errors, settings from sqlalchemy.sql import distinct, func standard_library.install_aliases() blueprint = Blueprint("public", __name__, static_folder="../static") @login_manager.user_loader def load_user(user_id): """ Load user by ID. """ return User.query.get(int(user_id)) @blueprint.route("/", methods=["GET", "POST"]) def home(): """ Home page. """ return render_template( "public/home.html", num_samples=get_samples(count=True), num_reports=get_reports_data(count=True), num_uploads_processing=get_queued_uploads( count=True, filter_cats=["NOT TREATED", "IN TREATMENT"] ), ) @blueprint.route("/login/", methods=["GET", "POST"]) def login(): """ Log in. """ form = LoginForm(request.form) # Handle logging in if request.method == "POST": if form.validate_on_submit(): login_user(form.user) flash( "Welcome {}! You are now logged in.".format(current_user.first_name), "success", ) redirect_url = request.args.get("next") or url_for("public.home") return redirect(redirect_url) else: flash_errors(form) return render_template("public/login.html", form=form) @blueprint.route("/logout/") @login_required def logout(): """ Logout. """ logout_user() flash("You are logged out.", "info") return redirect(url_for("public.home")) @blueprint.route("/register/", methods=["GET", "POST"]) def register(): """ Register new user. """ form = RegisterForm(request.form) if form.validate_on_submit(): user_cnt = db.session.query(User).count() u = User.create( username=form.username.data, email=form.email.data, password=form.password.data, first_name=form.first_name.data, last_name=form.last_name.data, active=True, is_admin=True if user_cnt == 0 else False, ) flash("Thanks for registering! You're now logged in.", "success") login_user(u) return redirect(url_for("public.home")) else: flash_errors(form) return render_template("public/register.html", form=form) @blueprint.route("/about/") def about(): """ About page. """ form = LoginForm(request.form) return render_template("public/about.html", form=form) @blueprint.route("/plot_type/") def choose_plot_type(): """ Choose plot type. """ return render_template("public/plot_type.html", num_samples=get_samples(count=True)) @blueprint.route("/report_plot/") @login_required def report_plot(): # Get the fields from the add-new-filters form return_data = aggregate_new_parameters(current_user, [], False) sample_filters = order_sample_filters() return render_template( "public/report_plot.html", db=db, User=User, user_token=current_user.api_token, sample_filters=sample_filters, num_samples=return_data[0], report_fields_json=json.dumps(return_data[1]), sample_fields_json=json.dumps(return_data[2]), report_plot_types=return_data[3], ) @blueprint.route("/queued_uploads/") @login_required def queued_uploads(): return render_template( "users/queued_uploads.html", db=db, User=User, user_token=current_user.api_token, uploads=get_queued_uploads(), ) @blueprint.route("/dashboards/") @login_required def list_dashboard(): """ Create a new dashboard. """ return render_template( "users/dashboards.html", dashboards=get_dashboards(User), user_token=current_user.api_token, ) @blueprint.route("/dashboard/create/") @blueprint.route("/dashboard/edit/<dashboard_id>") @login_required def create_dashboard(dashboard_id=None): """ Create a new dashboard. """ return render_template( "users/create_dashboard.html", dashboard_id=dashboard_id, favourite_plots=get_plot_favourites(User), user_token=current_user.api_token, ) @blueprint.route("/dashboard/view/<dashboard_id>") @blueprint.route("/dashboard/view/<dashboard_id>/raw") @login_required def view_dashboard(dashboard_id): """ Create a new dashboard. """ dashboard = get_dashboard_data(current_user, dashboard_id) if dashboard is None: abort(404) return render_template( "public/dashboard.html", dashboard_id=dashboard_id, dashboard=dashboard, raw=request.path.endswith("/raw"), user_token=current_user.api_token, ) @blueprint.route("/plot_favourites/") @login_required def plot_favourites(): """ View and edit saved plots. """ return render_template( "users/plot_favourites.html", favourite_plots=get_plot_favourites(User), user_token=current_user.api_token, ) @blueprint.route("/plot_favourite/<fav_id>") @blueprint.route("/plot_favourite/<fav_id>/raw") @login_required def plot_favourite(fav_id): """ View and edit saved plots. """ return render_template( "users/plot_favourite.html", plot_data=get_favourite_plot_data(current_user, fav_id), raw=request.path.endswith("/raw"), user_token=current_user.api_token, ) @blueprint.route("/edit_filters/") @login_required def edit_filters(): """ Edit saved filters. """ sample_filters = order_sample_filters() sample_filter_counts = {} for sfg in sample_filters: sample_filter_counts[sfg] = {} for sf in sample_filters[sfg]: sample_filter_counts[sf["id"]] = get_samples( filters=sf.get("sample_filter_data", []), count=True ) return render_template( "users/organize_filters.html", sample_filters=sample_filters, sample_filter_counts=sample_filter_counts, user_token=current_user.api_token, num_samples=get_samples(count=True), ) def order_sample_filters(): sample_filters = OrderedDict() sample_filters["Global"] = [{"id": -1, "set": "Global", "name": "All Samples"}] for sf in get_user_filters(current_user): if sf["set"] not in sample_filters: sample_filters[sf["set"]] = list() sample_filters[sf["set"]].append(sf) return sample_filters @blueprint.route("/distributions/") @login_required def distributions(): # Get the fields from the add-new-filters form return_data = aggregate_new_parameters(current_user, [], False) sample_filters = order_sample_filters() return render_template( "public/distributions.html", db=db, User=User, user_token=current_user.api_token, sample_filters=sample_filters, num_samples=return_data[0], report_fields=return_data[1], sample_fields=return_data[2], report_fields_json=json.dumps(return_data[1]), sample_fields_json=json.dumps(return_data[2]), ) @blueprint.route("/trends/") @login_required def trends(): # Get the fields from the add-new-filters form return render_template("public/react.html", entrypoint="trend") @blueprint.route("/admin/") @login_required def admin(): # Get the fields from the add-new-filters form return render_template("public/react.html", entrypoint="admin") @blueprint.route("/comparisons/") @login_required def comparisons(): # Get the fields from the add-new-filters form return_data = aggregate_new_parameters(current_user, [], False) sample_filters = order_sample_filters() return render_template( "public/comparisons.html", db=db, User=User, user_token=current_user.api_token, sample_filters=sample_filters, num_samples=return_data[0], report_fields=return_data[1], sample_fields=return_data[2], report_fields_json=json.dumps(return_data[1]), sample_fields_json=json.dumps(return_data[2]), ) @blueprint.route("/edit_reports/") @login_required def edit_reports(): # Get the fields from the add-new-filters form user_id = None if not current_user.is_admin: user_id = current_user.user_id return_data = get_reports_data(False, user_id) return render_template( "public/reports_management.html", report_data=return_data, report_meta_fields=get_report_metadata_fields(), api_token=current_user.api_token, )