Fix native Python callbacks after refactoring.

pull/7/head
Ferry Boender 9 years ago
parent b0e635b768
commit e511678c07
  1. 10
      README.md
  2. 16
      examples/native/native.json
  3. 28
      examples/native/native.py
  4. 35
      src/scriptform.py

@ -9,8 +9,8 @@ as frontends to scripts.
ScriptForm takes a JSON file which contains form definitions. It then
constructs web forms from this JSON and serves these to users. The user can
select a form and fill it out. When the user submits the form, it is validated
and the associated script is called. Data entered in the form is passed to the
script through the environment.
and the associated script or Python callback is called. Data entered in the
form is passed to the script through the environment.
### Features
@ -22,6 +22,8 @@ script through the environment.
- Uploaded files are automatically saved to temporary files, which are passed
on to the callback.
- Multiple forms in a single JSON definition file.
- Handles script / exception errors, HTML output or lets scripts and Python
callbacks stream their own HTTP response to the browser.
### Use-cases
@ -106,9 +108,7 @@ ScriptForm requires:
## Usage
### Authentication
Passwords are stored in plain text.
FIXME
## License

@ -22,6 +22,22 @@
}
]
},
"export": {
"title": "Export data",
"description": "Export a dump of the database",
"submit_title": "Export",
"fields": [
{
"name": "source_db",
"title": "Database to export",
"type": "select",
"options": [
["devtest", "Dev Test db"],
["prodtest", "Prod Test db"]
]
}
]
},
"add_user": {
"title": "Add user",
"description": "Add a user to the htaccess file or change their password",

@ -1,20 +1,37 @@
#!/usr/bin/python
import scriptform
import sys
def job_import(values):
def job_import(values, request):
return "Importing into database '{}'".format(values['target_db'])
def job_add_user(values):
def job_export(values, request):
size = 4096 * 10000
request.wfile.write('HTTP/1.0 200 Ok\n')
request.wfile.write('Content-Type: application/octet-stream\n')
request.wfile.write('Content-Disposition: attachment; filename="large_file.dat"\n')
request.wfile.write('Content-Length: {0}\n\n'.format(size))
f = file('/dev/urandom', 'r')
sent_size = 0
while True:
buf = f.read(4096)
if sent_size >= size:
break
request.wfile.write(buf)
sent_size += 4096
def job_add_user(values, request):
username = values['username']
password1 = values['password1']
password2 = values['password2']
if not password1:
return "Empty password specified."
raise Exception("Empty password specified")
if password1 != password2:
return "Passwords do not match."
raise Exception("Passwords do not match.")
# We do some stuff here.
@ -23,7 +40,8 @@ def job_add_user(values):
if __name__ == "__main__":
callbacks = {
'import': job_import,
'export': job_export,
'add_user': job_add_user
}
sf = scriptform.ScriptForm('native.json', callbacks)
sf.run(listen_port=8080)
sf.run(listen_port=8000)

@ -6,6 +6,7 @@
# - Default values for input fields.
# - If there are errors in the form, its values are empties.
# - Send responses using self.send_ if possible
# - Complain about no registered callback on startup instead of serving.
import sys
import optparse
@ -214,8 +215,8 @@ class FormConfig:
if not stat.S_IXUSR & os.stat(form_def.script)[stat.ST_MODE]:
raise ScriptFormError("{0} is not executable".format(form_def.script))
else:
if not form_name in self.callbacks:
raise ScriptFormError("No script or callback registered for '{0}'".format(form_name))
if not form_def.name in self.callbacks:
raise ScriptFormError("No script or callback registered for '{0}'".format(form_def.name))
def get_form(self, form_name):
for form_def in self.forms:
@ -224,12 +225,12 @@ class FormConfig:
else:
raise ValueError("No such form: {0}".format(form_name))
def callback(self, form_name, form_values, output_fh=None):
def callback(self, form_name, form_values, request):
form = self.get_form(form_name)
if form.script:
return self.callback_script(form, form_values, output_fh)
return self.callback_script(form, form_values, request.wfile)
else:
return self.callback_python(form, form_values, output_fh)
return self.callback_python(form, form_values, request)
def callback_script(self, form, form_values, output_fh=None):
# Pass form values to the script through the environment as strings.
@ -253,8 +254,26 @@ class FormConfig:
'exitcode': p.returncode
}
def callback_python(self, form, form_values, output_fh=None):
pass
def callback_python(self, form, form_values, request):
callback = self.callbacks[form.name]
try:
result = callback(form_values, request)
if result:
return {
'stdout': result,
'stderr': '',
'exitcode': 0
}
else:
# Raw output
pass
except Exception,e :
return {
'stdout': '',
'stderr': str(e),
'exitcode': 1
}
class FormDefinition:
@ -744,7 +763,7 @@ class ScriptFormWebApp(WebAppHandler):
# in some nice HTML. If no result is returned, the output was raw
# and the callback should have written its own response to the
# self.wfile filehandle.
result = form_config.callback(form_name, form_values, self.wfile)
result = form_config.callback(form_name, form_values, self)
if result:
if result['exitcode'] != 0:
msg = '<span class="error">{0}</span>'.format(cgi.escape(result['stderr']))

Loading…
Cancel
Save