Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tickets/DM-46010: add GET portal query path #34

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rsp-jupyter-extensions",
"version": "0.12.0",
"version": "0.13.0",
"description": "Jupyter Extensions for the Rubin Science Platform",
"keywords": [
"jupyter",
Expand Down
17 changes: 9 additions & 8 deletions rsp_jupyter_extensions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .handlers.environment import Environment_handler
from .handlers.execution import Execution_handler
from .handlers.hub import Hub_handler
from .handlers.query import Query_handler
from .handlers.environment import EnvironmentHandler
from .handlers.execution import ExecutionHandler
from .handlers.hub import HubHandler
from .handlers.query import PostQueryHandler, GetQueryHandler

from jupyter_server.utils import url_path_join as ujoin

Expand Down Expand Up @@ -29,10 +29,11 @@ def _setup_handlers(server_app) -> None:
"""Sets up the route handlers to call the appropriate functionality."""
web_app = server_app.web_app
extmap = {
r"/rubin/environment": Environment_handler,
r"/rubin/execution": Execution_handler,
r"/rubin/hub": Hub_handler,
r"/rubin/query": Query_handler,
r"/rubin/environment": EnvironmentHandler,
r"/rubin/execution": ExecutionHandler,
r"/rubin/hub": HubHandler,
r"/rubin/query": PostQueryHandler,
r"/rubin/portal_query/(.*)": GetQueryHandler,
}

# add the baseurl to our paths...
Expand Down
2 changes: 1 addition & 1 deletion rsp_jupyter_extensions/handlers/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from jupyter_server.base.handlers import JupyterHandler


class Environment_handler(JupyterHandler):
class EnvironmentHandler(JupyterHandler):
"""
Environment Handler. Return the JSON representation of our OS environment
settings.
Expand Down
2 changes: 1 addition & 1 deletion rsp_jupyter_extensions/handlers/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
NBFORMAT_VERSION = 4


class Execution_handler(JupyterHandler):
class ExecutionHandler(JupyterHandler):
"""
RSP templated Execution Handler.
"""
Expand Down
2 changes: 1 addition & 1 deletion rsp_jupyter_extensions/handlers/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from jupyter_server.utils import url_path_join as ujoin


class Hub_handler(JupyterHandler):
class HubHandler(JupyterHandler):
"""
Hub Handler. Currently all we do is DELETE (to shut down a running Lab
instance) but we could extend this to do anything in the Hub REST API.
Expand Down
79 changes: 51 additions & 28 deletions rsp_jupyter_extensions/handlers/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import tornado

from jupyter_server.base.handlers import JupyterHandler
from urllib.parse import urljoin


class UnsupportedQueryTypeError(Exception):
Expand All @@ -20,7 +21,7 @@ class UnimplementedQueryResolutionError(Exception):
pass


class Query_handler(JupyterHandler):
class QueryHandler(JupyterHandler):
"""
RSP templated Query Handler.
"""
Expand All @@ -33,33 +34,6 @@ def initialize(self) -> None:
def rubinquery(self) -> dict[str, str]:
return self.settings["rubinquery"]

@tornado.web.authenticated
def post(self) -> None:
"""POST receives the query type and the query value as a JSON
object containing "type" and "value" keys. Each is a string.

"type" is currently limited to "portal".

For a Portal Query, "value" is the URL referring to that query.
The interpretation of "value" is query-type dependent.

We should have some sort of template service. For right now, we're
just going to go with a very dumb string substitution.

It will then use the value to resolve the template, and will write
a file with the template resolved under the user's
"$HOME/notebooks/queries" directory. That filename will also be
derived from the type and value.
"""
input_str = self.request.body.decode("utf-8")
input_document = json.loads(input_str)
q_type = input_document["type"]
q_value = input_document["value"]
if q_type != "portal":
raise UnsupportedQueryTypeError(f"{q_type} is not a supported query type")
q_fn = self._create_portal_query(q_value)
self.write(q_fn)

def _create_portal_query(self, q_value: str) -> str:
# The value should be a URL
url = q_value
Expand Down Expand Up @@ -110,3 +84,52 @@ def _get_portal_query_notebook(self, url: str) -> str:
# string representing the rendered notebook "in unicode", which I
# think means, "a string represented in the default encoding".
return self._client.get(rendered_url, params=params).text


class PostQueryHandler(QueryHandler):
@tornado.web.authenticated
def post(self) -> None:
"""POST receives the query type and the query value as a JSON
object containing "type" and "value" keys. Each is a string.

"type" is currently limited to "portal".

For a Portal Query, "value" is the URL referring to that query.
The interpretation of "value" is query-type dependent.

It will then use the value to resolve the template, and will write
a file with the template resolved under the user's
"$HOME/notebooks/queries" directory. That filename will also be
derived from the type and value.
"""
input_str = self.request.body.decode("utf-8")
input_document = json.loads(input_str)
q_type = input_document["type"]
q_value = input_document["value"]
if q_type != "portal":
raise UnsupportedQueryTypeError(f"{q_type} is not a supported query type")
q_fn = self._create_portal_query(q_value)
self.write(q_fn)


class GetQueryHandler(JupyterHandler):
"""
Get query with /rubin/portal_query/<q_id>.

This is a convenience route to make writing a redirection route
easier (since we just need to fill in q_id, and don't have to issue
a POST).
"""

@tornado.web.authenticated
def get(self):
components = [x for x in self.request.path.split("/") if x]
if (len(components) < 2) or (components[-2] != "portal_query"):
raise UnimplementedQueryResolutionError(
f"{self.request.path} is not a supported query url"
)
q_id = components[-1]
base_url = self.request.host
q_url = str(urljoin(base_url, f"/api/tap/async/{q_id}"))
q_fn = self._create_portal_query(q_url)
self.write(q_fn)
Loading