Skip to content

Commit

Permalink
Support tree handler
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrochart committed Oct 26, 2021
1 parent edcee7c commit b34f18b
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 42 deletions.
55 changes: 51 additions & 4 deletions fps_plugins/voila/fps_voila/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,32 @@
from typing import Optional

from voila.handler import _VoilaHandler, _get
from voila.treehandler import _VoilaTreeHandler, _get as _get_tree

from mimetypes import guess_type
from fastapi import APIRouter, Depends
from fastapi.responses import RedirectResponse, StreamingResponse, Response
from fastapi.responses import RedirectResponse, StreamingResponse, HTMLResponse, Response
from fastapi.staticfiles import StaticFiles
from fps.hooks import register_router # type: ignore

from .config import get_voila_config


class FPSVoilaTreeHandler(_VoilaTreeHandler):
is_fps = True

def redirect(self, url):
return RedirectResponse(url)

def write(self, html):
return HTMLResponse(html)

def render_template(self, name, **kwargs):
kwargs["base_url"] = self.base_url
template = self.jinja2_env.get_template(name)
return template.render(**kwargs)


class FPSVoilaHandler(_VoilaHandler):
is_fps = True
fps_arguments = {}
Expand Down Expand Up @@ -46,8 +62,11 @@ def init_voila_handler(
server_root_dir,
config_manager,
static_paths,
settings,
log,
):
global fps_voila_handler
global fps_voila_handler, fps_voila_tree_handler

fps_voila_handler = FPSVoilaHandler()
fps_voila_handler.initialize(
notebook_path=notebook_path,
Expand All @@ -68,15 +87,43 @@ def init_voila_handler(
fps_voila_handler.config_manager = config_manager
fps_voila_handler.static_paths = static_paths

fps_voila_tree_handler = FPSVoilaTreeHandler()
fps_voila_tree_handler.initialize(
voila_configuration=voila_configuration,
)
fps_voila_tree_handler.contents_manager = contents_manager
fps_voila_tree_handler.base_url = base_url
fps_voila_tree_handler.voila_jinja2_env = voila_jinja2_env
fps_voila_tree_handler.jinja2_env = jinja2_env
fps_voila_tree_handler.settings = settings
fps_voila_tree_handler.log = log
settings["contents_manager"] = contents_manager


router = APIRouter()

@router.get("/notebooks/{path:path}")
async def get_root(path, voila_template: Optional[str] = None, voila_theme: Optional[str] = None, voila_config=Depends(get_voila_config)):
return StreamingResponse(_get(fps_voila_handler, path))


@router.get("/")
async def get_root(voila_template: Optional[str] = None, voila_theme: Optional[str] = None, voila_config=Depends(get_voila_config)):
fps_voila_handler.fps_arguments["voila-template"] = voila_template
fps_voila_handler.fps_arguments["voila-theme"] = voila_theme
path = "" #voila_config.notebook_path or "/"
return StreamingResponse(_get(fps_voila_handler, path))
path = voila_config.notebook_path or "/"
if path == "/":
return _get_tree(fps_voila_tree_handler, "/")
else:
return StreamingResponse(_get(fps_voila_handler, ""))

@router.get("/voila/render/{name}")
async def get_path(name):
return _get_tree(fps_voila_tree_handler, name)

@router.get("/voila/tree{path:path}")
async def get_tree(path):
return _get_tree(fps_voila_tree_handler, path)

@router.get("/voila/static/{path}")
def get_file1(path):
Expand Down
2 changes: 2 additions & 0 deletions voila/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ def start(self):
'/',
self.config_manager,
self.static_paths,
self.tornado_settings,
self.log,
)
fps_app()
else:
Expand Down
85 changes: 47 additions & 38 deletions voila/treehandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,50 @@
from .utils import get_server_root_dir


class VoilaTreeHandler(JupyterHandler):
def _get(self, path=''):
cm = self.contents_manager

if cm.dir_exists(path=path):
if cm.is_hidden(path) and not cm.allow_hidden:
self.log.info("Refusing to serve hidden directory, via 404 Error")
raise web.HTTPError(404)
breadcrumbs = self.generate_breadcrumbs(path)
page_title = self.generate_page_title(path)
contents = cm.get(path)

def allowed_content(content):
if content['type'] in ['directory', 'notebook']:
return True
__, ext = os.path.splitext(content.get('path'))
return ext in self.allowed_extensions

contents['content'] = sorted(contents['content'], key=lambda i: i['name'])
contents['content'] = filter(allowed_content, contents['content'])
return self.write(self.render_template('tree.html',
page_title=page_title,
notebook_path=path,
breadcrumbs=breadcrumbs,
contents=contents,
terminals_available=False,
server_root=get_server_root_dir(self.settings)))
elif cm.file_exists(path):
# it's not a directory, we have redirecting to do
model = cm.get(path, content=False)
# redirect to /api/notebooks if it's a notebook, otherwise /api/files
service = 'notebooks' if model['type'] == 'notebook' else 'files'
url = url_path_join(
self.base_url, service, url_escape(path),
)
if not self.is_fps:
self.log.debug("Redirecting %s to %s", self.request.path, url)
return self.redirect(url)
else:
raise web.HTTPError(404)


class _VoilaTreeHandler:
is_fps = False

def initialize(self, **kwargs):
self.voila_configuration = kwargs['voila_configuration']
self.allowed_extensions = list(self.voila_configuration.extension_language_mapping.keys()) + ['.ipynb']
Expand Down Expand Up @@ -46,42 +89,8 @@ def generate_page_title(self, path):
else:
return 'Voilà Home'


class VoilaTreeHandler(_VoilaTreeHandler, JupyterHandler):
@web.authenticated
def get(self, path=''):
cm = self.contents_manager

if cm.dir_exists(path=path):
if cm.is_hidden(path) and not cm.allow_hidden:
self.log.info("Refusing to serve hidden directory, via 404 Error")
raise web.HTTPError(404)
breadcrumbs = self.generate_breadcrumbs(path)
page_title = self.generate_page_title(path)
contents = cm.get(path)

def allowed_content(content):
if content['type'] in ['directory', 'notebook']:
return True
__, ext = os.path.splitext(content.get('path'))
return ext in self.allowed_extensions

contents['content'] = sorted(contents['content'], key=lambda i: i['name'])
contents['content'] = filter(allowed_content, contents['content'])
self.write(self.render_template('tree.html',
page_title=page_title,
notebook_path=path,
breadcrumbs=breadcrumbs,
contents=contents,
terminals_available=False,
server_root=get_server_root_dir(self.settings)))
elif cm.file_exists(path):
# it's not a directory, we have redirecting to do
model = cm.get(path, content=False)
# redirect to /api/notebooks if it's a notebook, otherwise /api/files
service = 'notebooks' if model['type'] == 'notebook' else 'files'
url = url_path_join(
self.base_url, service, url_escape(path),
)
self.log.debug("Redirecting %s to %s", self.request.path, url)
self.redirect(url)
else:
raise web.HTTPError(404)
return _get(self, path=path)

0 comments on commit b34f18b

Please sign in to comment.