import os from functools import wraps from html import escape from urllib.parse import urlparse from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop from tornado.web import Application from tornado.web import authenticated from tornado.web import RequestHandler from jupyterhub.services.auth import HubOAuthCallbackHandler from jupyterhub.services.auth import HubOAuthenticated from jupyterhub.utils import url_path_join SCOPE_PREFIX = "custom:grades" READ_SCOPE = f"{SCOPE_PREFIX}:read" WRITE_SCOPE = f"{SCOPE_PREFIX}:write" def require_scope(scopes): """Decorator to require scopes For use if multiple methods on one Handler may want different scopes, so class-level .hub_scopes is insufficient (e.g. read for GET, write for POST). """ if isinstance(scopes, str): scopes = [scopes] def wrap(method): """The actual decorator""" @wraps(method) @authenticated def wrapped(self, *args, **kwargs): self.hub_scopes = scopes return method(self, *args, **kwargs) return wrapped return wrap class MyGradesHandler(HubOAuthenticated, RequestHandler): # no hub_scopes, anyone with access to this service # will be able to visit this URL @authenticated def get(self): self.write("
My name is: {escape(name)}
") if name in grades: self.write(f"My grade is: {escape(str(grades[name]))}
") else: self.write("No grade entered
") if READ_SCOPE in self.current_user["scopes"]: self.write('enter grades') class GradesHandler(HubOAuthenticated, RequestHandler): # default scope for this Handler: read-only hub_scopes = [READ_SCOPE] def _render(self): grades = self.settings["grades"] self.write("Student | Grade |
---|---|
{qstudent} | {qgrade} |