IEEE.org     |     IEEE Xplore Digital Library     |     IEEE Standards     |     IEEE Spectrum     |     More Sites

Verified Commit 1dbd09fa authored by Emi Simpson's avatar Emi Simpson
Browse files

Merge frontend.py and views.py

parent 71a30895
Pipeline #1122 failed with stage
in 49 seconds
......@@ -63,4 +63,3 @@ very professional CDN][3.5]
from mystic import views #type:ignore
from mystic.init_database import setup_database #type:ignore
from mystic.config import create_app #type:ignore
from mystic.frontend import ErrorTuple #type:ignore
"""
Handle computation for incoming requests
The frontend module is responsible for doing the heavy lifting of request processing.
While the `mystic.views` module receives the requests and selects the feeds data into
templates, `mystic.frontend` is the real workhorse.
Most methods in this module specialize in parsing out arguments from forms or query
parameters, deciding what action needs to be taken, then either producing an error on
receiving an invalid request, or handing processing off to another module.
This module also includes methods like `get_user` and `get_project`, which can be used to
determine the active user/project.
"""
from logging import warn
from mystic.analytics.queries import QueryMachine
from mystic.analytics.dashboards import DASHBOARDS, Dashboard
from elasticsearch.client import Elasticsearch
from elasticsearch.exceptions import NotFoundError
from pymysql.cursors import Cursor
from mystic.database import MalformedId, Project, compute_alphaid, parse_alphaid
from logging import warn
from typing import Generator, List, Optional, Tuple
class ErrorTuple(Exception):
"""
An error meant to be sent to the user
This consists of two parts:
- a category, which indicates where the problem occured, and where it should be
displayed.
- an error message, the actual content that should be displayed to the user.
"""
def __init__(self, category: str, message: str):
self.category = category
"""
A string indicating where the error occured, or what component it occured with.
This is often used to communicate what UI component the error message needs to be
displayed alongside, or if it should be displayed as a global error message. The
exact meaning of this field often depends on the method throwing it, so check the
docs!
"""
self.message = message
"""
The actual content of the error to be displayed to the user
All error messages are designed to be human-readable, but error messages that are
likely to occur by a well-meaning user who simply input the wrong data are
designed to be user-readable. For example, a human-reabable error might be
something like "project_id was not specified in request, but is required for
edit_project", while a user-readable error might be something like "Please give
your project a name"
"""
def list_available_dashboards(cursor: Cursor, project: Project) -> List[Tuple[str, Dashboard]]:
"""
Produce a list of dashboards which may be used for this project
Included are the dashboard objects, as well as their alpha IDs, which can be used
later to request one specific dashboard be produced.
"""
return [
(i, d)
for (i, d) in (
(compute_alphaid(i), d.produce_for(cursor, project))
for (i, d)
in enumerate(DASHBOARDS)
)
if d is not None
]
def fetch_dashboard(cursor: Cursor, es: Elasticsearch, db_id: str, project: Project) -> Optional[Dashboard]:
"""
Attempt to get a specific dashboard from it's alphaid
Returns none if:
- The db_id is invalid
- The db_id doesn't refer to a dashboard
- The dashboard isn't valid for the project type
Otherwise, returns the loaded dashboard
"""
try:
dashboard = DASHBOARDS[parse_alphaid(db_id)].produce_for(cursor, project)
if dashboard != None:
qm = QueryMachine()
dashboard.load(es, qm)
return dashboard
else:
return None
except MalformedId | IndexError:
return None
def get_analytics(c: Cursor, es: Elasticsearch, project: Project) -> Generator[Dashboard, None, None]:
dashboards = (
d
for d in (
d.produce_for(c, project)
for d
in DASHBOARDS
)
if d is not None
)
for d in dashboards:
qm = QueryMachine()
try:
d.load(es, qm)
yield d
except NotFoundError:
warn("Not found error indicates that some dashboard isn't set up")
......@@ -4,12 +4,18 @@ The views module is responsible for connecting Jinja templates to the code that
See individual views below for details on exactly what templates are used, and what they
connect up with.
'''
from elasticsearch.client import Elasticsearch
from werkzeug.exceptions import NotFound
from pymysql.cursors import Cursor
from mystic.database import Project
from flask import render_template, Blueprint
from typing import Optional
from mystic.analytics.dashboards import DASHBOARDS, Dashboard
from mystic.analytics.queries import QueryMachine
from mystic.config import get_database, get_elastic
from mystic.frontend import fetch_dashboard
from mystic.database import MalformedId, parse_alphaid
bp = Blueprint("main", __name__, url_prefix="/")
......@@ -40,3 +46,25 @@ def view_dashboard(slug: str, db_id: str) -> str:
"embed.html",
dashboard=dashboard
)
def fetch_dashboard(cursor: Cursor, es: Elasticsearch, db_id: str, project: Project) -> Optional[Dashboard]:
"""
Attempt to get a specific dashboard from it's alphaid
Returns none if:
- The db_id is invalid
- The db_id doesn't refer to a dashboard
- The dashboard isn't valid for the project type
Otherwise, returns the loaded dashboard
"""
try:
dashboard = DASHBOARDS[parse_alphaid(db_id)].produce_for(cursor, project)
if dashboard != None:
qm = QueryMachine()
dashboard.load(es, qm)
return dashboard
else:
return None
except MalformedId | IndexError:
return None
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment