diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 8cb5c423..75eb3fbc 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -135,6 +135,16 @@ class User(Base): id = Column(Integer, primary_key=True, autoincrement=True) name = Column(Unicode(255), unique=True) + # properties on the spawner wrapper + # some APIs get these low-level objects + # when the spawner isn't running, + # for which these should all be False + active = running = ready = False + pending = None + @property + def orm_spawner(self): + return self + _orm_spawners = relationship( "Spawner", backref="user", diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index 1fa2897e..1436dea6 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -133,6 +133,10 @@ class Spawner(LoggingConfigurable): proxy_spec = Unicode() + @property + def last_activity(self): + return self.orm_spawner.last_activity + @property def server(self): if hasattr(self, '_server'): diff --git a/jupyterhub/user.py b/jupyterhub/user.py index 6f812103..d3b0560c 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -182,6 +182,26 @@ class User: await self.save_auth_state(auth_state) return auth_state + + def all_spawners(self, include_default=True): + """Generator yielding all my spawners + + including those that are not running. + + Spawners that aren't running will be low-level orm.Spawner objects, + while those that are will be higher-level Spawner wrapper objects. + """ + + for name, orm_spawner in sorted(self.orm_user.orm_spawners.items()): + if name == '' and not include_default: + continue + if name in self.spawners: + # yield wrapper if it exists + yield self.spawners[name] + else: + # otherwise, yield low-level object + yield orm_spawner + def _new_spawner(self, server_name, spawner_class=None, **kwargs): """Create a new spawner""" if spawner_class is None: @@ -321,6 +341,13 @@ class User: else: return self.base_url + def server_url(self, server_name=''): + """Get the url for a server with a given name""" + if not server_name: + return self.url + else: + return url_path_join(self.url, server_name) + def progress_url(self, server_name=''): """API URL for progress endpoint for a server with a given name""" url_parts = [self.settings['hub'].base_url, 'api/users', self.escaped_name]