options_form is a regular configurable

now that we can assume User.spawner exists at all times
This commit is contained in:
Min RK
2015-12-17 16:00:40 +01:00
parent 41ea696546
commit f9c9c2b471
6 changed files with 29 additions and 21 deletions

View File

@@ -452,12 +452,12 @@ class UserSpawnHandler(BaseHandler):
# spawn has supposedly finished, check on the status
status = yield current_user.spawner.poll()
if status is not None:
if self.spawner_class.options_form:
if current_user.spawner.options_form:
self.redirect(url_path_join(self.hub.server.base_url, 'spawn'))
else:
yield self.spawn_single_user(current_user)
else:
if self.spawner_class.options_form:
if current_user.spawner.options_form:
self.redirect(url_path_join(self.hub.server.base_url, 'spawn'))
else:
yield self.spawn_single_user(current_user)

View File

@@ -68,7 +68,7 @@ class LoginHandler(BaseHandler):
if user.spawner:
status = yield user.spawner.poll()
already_running = (status == None)
if not already_running and not self.spawner_class.options_form:
if not already_running and not user.spawner.options_form:
yield self.spawn_single_user(user)
self.set_login_cookie(user)
next_url = self.get_argument('next', default='')

View File

@@ -63,10 +63,10 @@ class SpawnHandler(BaseHandler):
self.log.debug("User is running: %s", url)
self.redirect(url)
return
if self.spawner_class.options_form:
if user.spawner.options_form:
html = self.render_template('spawn.html',
user=self.get_current_user(),
spawner_options_form=self.spawner_class.options_form,
spawner_options_form=user.spawner.options_form,
)
self.finish(html)
else:
@@ -87,7 +87,7 @@ class SpawnHandler(BaseHandler):
form_options = {}
for key, byte_list in self.request.body_arguments.items():
form_options[key] = [ bs.decode('utf8') for bs in byte_list ]
options = self.spawner_class.options_from_form(form_options)
options = user.spawner.options_from_form(form_options)
yield self.spawn_single_user(user, options=options)
url = user.server.base_url
self.redirect(url)

View File

@@ -73,24 +73,33 @@ class Spawner(LoggingConfigurable):
help="Enable debug-logging of the single-user server"
)
# options_form is a class attribute, defining an HTML form snippet,
# which can be used to specify whether
# (i.e. just the <input> elements, not submit button or the <form> tag).
# This is **not** a configurable,
options_form = ""
@classmethod
def options_from_form(cls, form_data):
options_form = Unicode("", config=True, help="""
An HTML form for options a user can specify on launching their server.
The surrounding `<form>` element and the submit button are already provided.
For example:
Set your key:
<input name="key" val="default_key"></input>
<br>
Choose a letter:
<select name="letter" multiple="true">
<option value="A">The letter A</option>
<option value="B">The letter B</option>
</select>
""")
def options_from_form(self, form_data):
"""Interpret HTTP form data
Form data will always arrive as a dict of lists of strings.
Override this function to understand single-values, numbers, etc.
This should coerce form data into the structure expected by self.options,
This should coerce form data into the structure expected by self.user_options,
which must be a dict.
Instances will receive this data on self.user_options, after passing through this function.
This must be a @classmethod.
Instances will receive this data on self.user_options, after passing through this function,
prior to `Spawner.start`.
"""
return form_data

View File

@@ -76,8 +76,7 @@ class NeverSpawner(MockSpawner):
class FormSpawner(MockSpawner):
options_form = "IMAFORM"
@classmethod
def options_from_form(cls, form_data):
def options_from_form(self, form_data):
options = {}
options['notspecified'] = 5
if 'bounds' in form_data:

View File

@@ -65,14 +65,14 @@ def test_spawn_redirect(app):
assert r.url.endswith('/wash')
def test_spawn_page(app):
with mock.patch.dict(app.tornado_application.settings, {'spawner_class': FormSpawner}):
with mock.patch.dict(app.users.settings, {'spawner_class': FormSpawner}):
cookies = app.login_user('jones')
r = get_page('spawn', app, cookies=cookies)
assert r.url.endswith('/spawn')
assert FormSpawner.options_form in r.text
def test_spawn_form(app, io_loop):
with mock.patch.dict(app.tornado_application.settings, {'spawner_class': FormSpawner}):
with mock.patch.dict(app.users.settings, {'spawner_class': FormSpawner}):
base_url = ujoin(app.proxy.public_server.host, app.hub.server.base_url)
cookies = app.login_user('jones')
orm_u = orm.User.find(app.db, 'jones')