diff --git a/nbclassic/edit/__init__.py b/nbclassic/edit/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nbclassic/edit/handlers.py b/nbclassic/edit/handlers.py new file mode 100644 index 000000000..b072ff843 --- /dev/null +++ b/nbclassic/edit/handlers.py @@ -0,0 +1,34 @@ +#encoding: utf-8 +"""Tornado handlers for the terminal emulator.""" + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +from tornado import web +from jupyter_server.base.handlers import JupyterHandler, path_regex +from jupyter_server.utils import url_escape +from jupyter_server.extension.handler import ( + ExtensionHandlerMixin, + ExtensionHandlerJinjaMixin +) + +class EditorHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): + """Render the text editor interface.""" + + @web.authenticated + def get(self, path): + path = path.strip('/') + if not self.contents_manager.file_exists(path): + raise web.HTTPError(404, u'File does not exist: %s' % path) + + basename = path.rsplit('/', 1)[-1] + self.write(self.render_template('edit.html', + file_path=url_escape(path), + basename=basename, + page_title=basename + " (editing)", + ) + ) + +default_handlers = [ + (r"/edit%s" % path_regex, EditorHandler), +] diff --git a/nbclassic/notebookapp.py b/nbclassic/notebookapp.py index d6ad70351..07a58cebc 100644 --- a/nbclassic/notebookapp.py +++ b/nbclassic/notebookapp.py @@ -43,9 +43,14 @@ from jupyter_server.log import log_request from jupyter_server.transutils import _ from jupyter_server.serverapp import ( + ServerApp, random_ports, load_handlers ) +from jupyter_server.utils import url_path_join as ujoin + +from .terminal.handlers import TerminalHandler, TermSocket + #----------------------------------------------------------------------------- # Module globals @@ -88,13 +93,13 @@ 'ip': 'ServerApp.ip', 'port': 'ServerApp.port', 'port-retries': 'ServerApp.port_retries', - 'transport': 'ServerApp.KernelManager.transport', + #'transport': 'KernelManager.transport', 'keyfile': 'ServerApp.keyfile', 'certfile': 'ServerApp.certfile', 'client-ca': 'ServerApp.client_ca', 'notebook-dir': 'ServerApp.notebook_dir', 'browser': 'ServerApp.browser', - 'gateway-url': 'ServerApp.GatewayClient.url', + #'gateway-url': 'GatewayClient.url', }) #----------------------------------------------------------------------------- @@ -209,6 +214,21 @@ def initialize_handlers(self): handlers.extend(load_handlers('nbclassic.tree.handlers')) handlers.extend(load_handlers('nbclassic.notebook.handlers')) + handlers.extend(load_handlers('nbclassic.edit.handlers')) + + # Add terminal handlers + try: + term_mgr = self.serverapp.web_app.settings['terminal_manager'] + except KeyError: + pass # Terminals not enabled + else: + handlers.append( + (r"/terminals/(\w+)", TerminalHandler) + ) + handlers.append( + (r"/terminals/websocket/(\w+)", TermSocket, + {'term_manager': term_mgr}) + ) handlers.append( (r"/nbextensions/(.*)", FileFindHandler, { diff --git a/nbclassic/terminal/__init__.py b/nbclassic/terminal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nbclassic/terminal/handlers.py b/nbclassic/terminal/handlers.py new file mode 100644 index 000000000..b25bf5feb --- /dev/null +++ b/nbclassic/terminal/handlers.py @@ -0,0 +1,45 @@ +#encoding: utf-8 +"""Tornado handlers for the terminal emulator.""" + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +from tornado import web +import terminado +from jupyter_server._tz import utcnow +from jupyter_server.base.handlers import JupyterHandler +from jupyter_server.base.zmqhandlers import WebSocketMixin +from jupyter_server.extension.handler import ( + ExtensionHandlerMixin, + ExtensionHandlerJinjaMixin +) + +class TerminalHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler): + """Render the terminal interface.""" + @web.authenticated + def get(self, term_name): + self.write(self.render_template('terminal.html', + ws_path="terminals/websocket/%s" % term_name)) + + +class TermSocket(WebSocketMixin, JupyterHandler, terminado.TermSocket): + + def origin_check(self): + """Terminado adds redundant origin_check + + Tornado already calls check_origin, so don't do anything here. + """ + return True + + def get(self, *args, **kwargs): + if not self.get_current_user(): + raise web.HTTPError(403) + return super(TermSocket, self).get(*args, **kwargs) + + def on_message(self, message): + super(TermSocket, self).on_message(message) + self.application.settings['terminal_last_activity'] = utcnow() + + def write_message(self, message, binary=False): + super(TermSocket, self).write_message(message, binary=binary) + self.application.settings['terminal_last_activity'] = utcnow()