refactor forms

This commit is contained in:
Martijn Voncken 2008-02-11 16:59:29 +00:00
parent d32ffa7ace
commit 9df4492083
6 changed files with 231 additions and 153 deletions

View File

@ -31,7 +31,7 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import lib.newforms as forms
import lib.newforms_plus as forms
import page_decorators as deco
import lib.webpy022 as web
from webserver_common import ws
@ -43,37 +43,7 @@ import os
groups = []
blocks = forms.utils.datastructures.SortedDict()
class Form(forms.Form):
info = ""
title = "No Title"
def __init__(self,data = None):
if data == None:
data = self.initial_data()
forms.Form.__init__(self,data)
def initial_data(self):
"override in subclass"
return None
def start_save(self):
"called by config_page"
data = web.Storage(self.clean_data)
self.validate(data)
self.save(data)
self.post_save()
def save(self, vars):
"override in subclass"
raise NotImplementedError()
def post_save(self):
pass
def validate(self, data):
pass
class WebCfgForm(Form):
class WebCfgForm(forms.Form):
"config base for webui"
def initial_data(self):
return ws.config
@ -82,7 +52,7 @@ class WebCfgForm(Form):
ws.config.update(data)
ws.save_config()
class CookieCfgForm(Form):
class CookieCfgForm(forms.Form):
"config base for webui"
def initial_data(self):
return ws.config
@ -92,85 +62,13 @@ class CookieCfgForm(Form):
ws.save_config()
class CfgForm(Form):
class CfgForm(forms.Form):
"config base for deluge-cfg"
def initial_data(self):
return ws.proxy.get_config()
def save(self, data):
ws.proxy.set_config(dict(data))
#convenience Input Fields.
class _IntInput(forms.TextInput):
"""
because deluge-floats are edited as ints.
"""
def render(self, name, value, attrs=None):
try:
value = int(float(value))
if value == -1:
value = _("Unlimited")
except:
pass
return forms.TextInput.render(self, name, value, attrs)
class CheckBox(forms.BooleanField):
"Non Required ChoiceField"
def __init__(self,label, **kwargs):
forms.BooleanField.__init__(self,label=label,required=False,**kwargs)
class IntCombo(forms.ChoiceField):
"""
choices are the display-values
returns int for the chosen display-value.
"""
def __init__(self, label, choices, **kwargs):
forms.ChoiceField.__init__(self, label=label,
choices=enumerate(choices), **kwargs)
def clean(self, value):
return int(forms.ChoiceField.clean(self, value))
class DelugeInt(forms.IntegerField):
def __init__(self, label , **kwargs):
forms.IntegerField.__init__(self, label=label, min_value=-1,
max_value=sys.maxint, widget=_IntInput, **kwargs)
def clean(self, value):
if str(value).lower() == _('Unlimited').lower():
value = -1
return int(forms.IntegerField.clean(self, value))
class DelugeFloat(DelugeInt):
def clean(self, value):
return int(DelugeInt.clean(self, value))
class MultipleChoice(forms.MultipleChoiceField):
#temp/test
def __init__(self, label, choices, **kwargs):
forms.MultipleChoiceField.__init__(self, label=label, choices=choices,
widget=forms.CheckboxSelectMultiple, required=False)
class ServerFolder(forms.CharField):
def __init__(self, label, **kwargs):
forms.CharField.__init__(self, label=label,**kwargs)
def clean(self, value):
value = value.rstrip('/').rstrip('\\')
self.validate(value)
return forms.CharField.clean(self, value)
def validate(self, value):
if (value and not os.path.isdir(value)):
raise forms.ValidationError(_("This folder does not exist."))
class Password(forms.CharField):
def __init__(self, label, **kwargs):
forms.CharField.__init__(self, label=label, widget=forms.PasswordInput,
**kwargs)
#/fields
class config_page:
"""
web.py config page

View File

@ -31,7 +31,7 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import lib.newforms as forms
import lib.newforms_plus as forms
import config
import utils
from webserver_common import ws
@ -42,7 +42,7 @@ class NetworkPorts(config.CfgForm ):
info = _("Restart daemon after changing these values.")
_port_from = forms.IntegerField(_("From"))
_port_to = forms.IntegerField(_("To"))
random_port = config.CheckBox(_("Random"))
random_port = forms.CheckBox(_("Random"))
def initial_data(self):
data = config.CfgForm.initial_data(self)
@ -63,24 +63,24 @@ config.register_block('network','ports', NetworkPorts)
class NetworkExtra(config.CfgForm ):
title = _("Extra's")
dht = config.CheckBox(_("Mainline DHT"))
upnp = config.CheckBox(_("UpNP"))
natpmp = config.CheckBox(_("NAT-PMP"))
utpex = config.CheckBox(_("Peer-Exchange"))
lsd = config.CheckBox(_("LSD"))
dht = forms.CheckBox(_("Mainline DHT"))
upnp = forms.CheckBox(_("UpNP"))
natpmp = forms.CheckBox(_("NAT-PMP"))
utpex = forms.CheckBox(_("Peer-Exchange"))
lsd = forms.CheckBox(_("LSD"))
config.register_block('network','extra', NetworkExtra)
class NetworkEnc(config.CfgForm ):
title = _("Encryption")
_enc_choices = [_("Forced"),_("Enabled"),_("Disabled")]
_level_choices = [_("Handshake"), _("Full") , _("Either")]
_enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")]))
_level_choices = list(enumerate([_("Handshake"), _("Full") , _("Either")]))
enc_in_policy = config.IntCombo(_("Inbound"), _enc_choices)
enc_out_policy = config.IntCombo(_("Outbound"), _enc_choices)
enc_level = config.IntCombo(_("Level"), _level_choices)
enc_prefer_rc4 = config.CheckBox("Prefer to encrypt entire stream")
enc_in_policy = forms.IntChoiceField(_("Inbound"), _enc_choices)
enc_out_policy = forms.IntChoiceField(_("Outbound"), _enc_choices)
enc_level = forms.IntChoiceField(_("Level"), _level_choices)
enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream")
config.register_block('network','encryption', NetworkEnc)
@ -88,44 +88,45 @@ config.register_block('network','encryption', NetworkEnc)
class BandwithGlobal(config.CfgForm):
title = _("Global")
info = _("-1 = Unlimited")
max_connections_global = config.DelugeInt(_("Maximum Connections"))
max_download_speed = config.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
max_upload_speed = config.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
max_upload_slots_global = config.DelugeInt(_("Maximum Upload Slots"))
max_connections_global = forms.DelugeInt(_("Maximum Connections"))
max_download_speed = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
max_upload_slots_global = forms.DelugeInt(_("Maximum Upload Slots"))
config.register_block('bandwidth','global', BandwithGlobal)
class BandwithTorrent(config.CfgForm):
title = _("Per Torrent")
info = _("-1 = Unlimited")
max_connections_per_torrent = config.DelugeInt(_("Maximum Connections"))
max_upload_slots_per_torrent = config.DelugeInt(_("Maximum Upload Slots"))
max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections"))
max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots"))
config.register_block('bandwidth','torrent', BandwithTorrent)
class Download(config.CfgForm):
title = _("Download")
download_location = config.ServerFolder(_("Store all downoads in"))
torrentfiles_location = config.ServerFolder(_("Save .torrent files to"))
autoadd_location = config.ServerFolder(_("Auto Add folder"), required=False)
compact_allocation = config.CheckBox(_('Use Compact Allocation'))
prioritize_first_last_pieces = config.CheckBox(
download_location = forms.ServerFolder(_("Store all downoads in"))
torrentfiles_location = forms.ServerFolder(_("Save .torrent files to"))
autoadd_location = forms.ServerFolder(_("Auto Add folder"), required=False)
compact_allocation = forms.CheckBox(_('Use Compact Allocation'))
prioritize_first_last_pieces = forms.CheckBox(
_('Prioritize first and last pieces'))
config.register_block('deluge','download', Download)
class Daemon(config.CfgForm):
title = _("Daemon")
info = _("Restart daemon and webui after changing these settings")
daemon_port = forms.IntegerField(_("Port"))
allow_remote = config.CheckBox(_("Allow Remote Connections"))
allow_remote = forms.CheckBox(_("Allow Remote Connections"))
config.register_block('deluge','daemon', Daemon)
class Plugins(config.Form):
class Plugins(forms.Form):
title = _("Enabled Plugins")
_choices = [(p,p) for p in ws.proxy.get_available_plugins()]
enabled_plugins = config.MultipleChoice(_(""), _choices)
enabled_plugins = forms.MultipleChoice(_(""), _choices)
def initial_data(self):
return {'enabled_plugins':ws.proxy.get_enabled_plugins()}
@ -136,19 +137,19 @@ class Plugins(config.Form):
config.register_block('deluge','plugins', Plugins)
class Queue(config.Form):
class Queue(forms.Form):
title = _("Queue")
info = _("queue-cfg not finished")
queue_top = config.CheckBox(_("Queue new torrents to top"))
total_active = config.DelugeInt(_("Total active torrents"))
total_seeding = config.DelugeInt(_("Total active seeding"))
total_downloading = config.DelugeInt(_("Total active downloading"))
queue_top = forms.CheckBox(_("Queue new torrents to top"))
total_active = forms.DelugeInt(_("Total active torrents"))
total_seeding = forms.DelugeInt(_("Total active seeding"))
total_downloading = forms.DelugeInt(_("Total active downloading"))
queue_bottom = config.CheckBox(_("Queue completed torrents to bottom"))
stop_on_ratio = config.CheckBox(_("Stop seeding when ratio reaches"))
stop_ratio = config.DelugeInt(_("TODO:float-edit-box"))
remove_after_stop = config.CheckBox(_("Remve torrent when ratio reached"))
queue_bottom = forms.CheckBox(_("Queue completed torrents to bottom"))
stop_on_ratio = forms.CheckBox(_("Stop seeding when ratio reaches"))
stop_ratio = forms.DelugeInt(_("TODO:float-edit-box"))
remove_after_stop = forms.CheckBox(_("Remve torrent when ratio reached"))
def save(self, value):
raise forms.ValidationError("SAVE:TODO")

View File

@ -31,7 +31,7 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import lib.newforms as forms
import lib.newforms_plus as forms
import config
import utils
from webserver_common import ws
@ -41,11 +41,12 @@ class Template(config.WebCfgForm):
title = _("Template")
_templates = [(t,t) for t in ws.get_templates()]
_button_choices = [_('Text and image'), _('Image Only'), _('Text Only')]
_button_choices = enumerate([_('Text and image'), _('Image Only')
, _('Text Only')])
template = forms.ChoiceField( label=_("Template"), choices = _templates)
button_style = config.IntCombo(_("Button style"),_button_choices)
cache_templates = config.CheckBox(_("Cache templates"))
button_style = forms.IntChoiceField(_("Button style"),_button_choices)
cache_templates = forms.CheckBox(_("Cache templates"))
def post_save(self):
from render import render
@ -62,7 +63,7 @@ class Server(config.WebCfgForm):
port = forms.IntegerField(label = _("Port"),min_value=80)
use_https = config.CheckBox(_("Use https"))
use_https = forms.CheckBox(_("Use https"))
def post_save(self):
@ -70,12 +71,12 @@ class Server(config.WebCfgForm):
#raise forms.ValidationError(
# _("Manually restart server to apply these changes."))
class Password(config.Form):
class Password(forms.Form):
title = _("Password")
old_pwd = config.Password(_("Current Password"))
new1 = config.Password(_("New Password"))
new2 = config.Password(_("New Password (Confirm)"))
old_pwd = forms.Password(_("Current Password"))
new1 = forms.Password(_("New Password"))
new2 = forms.Password(_("New Password (Confirm)"))
def save(self,data):
ws.update_pwd(data.new1)

View File

@ -9,7 +9,7 @@ from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput
from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError
import copy
__all__ = ('BaseForm', 'Form')
#__all__ = ('BaseForm', 'Form')
NON_FIELD_ERRORS = '__all__'

View File

@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) Martijn Voncken 2008 <mvoncken@gmail.com>
# Django Lisence, see ./newforms/LICENCE
#
from newforms import *
import newforms
from newforms.forms import BoundField
import sys, os
import webpy022 as web #todo:remove this dependency.
#Form
class FilteredForm(newforms.Form):
"""
used to enable more complex layouts.
the filter argument contains the names of the fields to render.
"""
def _html_output_filtered(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, filter):
"""
Helper function for outputting HTML. Used by as_table(), as_ul(), as_p().
newforms_plus: 99% c&p from newforms, added filter.
"""
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
output, hidden_fields = [], []
for name, field in self.fields.items():
#FilteredForm
if (filter != None) and (not name in filter):
continue
#/FilteredForm
bf = BoundField(self, field, name)
bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
if bf.is_hidden:
if bf_errors:
top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
hidden_fields.append(unicode(bf))
else:
if errors_on_separate_row and bf_errors:
output.append(error_row % bf_errors)
label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
if field.help_text:
help_text = help_text_html % field.help_text
else:
help_text = u''
output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text})
if top_errors:
output.insert(0, error_row % top_errors)
if hidden_fields: # Insert any hidden fields in the last row.
str_hidden = u''.join(hidden_fields)
if output:
last_row = output[-1]
# Chop off the trailing row_ender (e.g. '</td></tr>') and insert the hidden fields.
output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
else: # If there aren't any rows in the output, just append the hidden fields.
output.append(str_hidden)
return u'\n'.join(output)
def as_table(self , filter = None):
"Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
return self._html_output_filtered(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False, filter)
def as_ul(self, filter = None):
"Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
return self._html_output_filtered(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False , filter)
def as_p(self , filter = None):
"Returns this form rendered as HTML <p>s."
return self._html_output_filtered(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True, filter)
class Form(newforms.Form):
info = ""
title = "No Title"
def __init__(self,data = None):
if data == None:
data = self.initial_data()
newforms.Form.__init__(self,data)
def initial_data(self):
"override in subclass"
return None
def start_save(self):
"called by config_page"
data = web.Storage(self.clean_data)
self.validate(data)
self.save(data)
self.post_save()
def save(self, vars):
"override in subclass"
raise NotImplementedError()
def post_save(self):
pass
def validate(self, data):
pass
#convenience Input Fields.
class CheckBox(newforms.BooleanField):
"Non Required BooleanField,why the f is it required by default?"
def __init__(self,label, **kwargs):
newforms.BooleanField.__init__(self,label=label,required=False,**kwargs)
class IntChoiceField(newforms.ChoiceField):
"""same as ChoiceField, but returns an int
hint : Use IntChoiceField(choices=enumerate("list","of","strings"]))
for index-based values on a list of strings.
"""
def __init__(self, label, choices, **kwargs):
newforms.ChoiceField.__init__(self, label=label, choices=choices,**kwargs)
def clean(self, value):
return int(newforms.ChoiceField.clean(self, value))
class MultipleChoice(newforms.MultipleChoiceField):
#temp/test/debug!!
"Non Required MultipleChoiceField,why the f is it required by default?"
def __init__(self, label, choices, **kwargs):
newforms.MultipleChoiceField.__init__(self, label=label, choices=choices,
widget=newforms.CheckboxSelectMultiple, required=False)
class ServerFolder(newforms.CharField):
def __init__(self, label, **kwargs):
newforms.CharField.__init__(self, label=label,**kwargs)
def clean(self, value):
value = value.rstrip('/').rstrip('\\')
self.validate(value)
return newforms.CharField.clean(self, value)
def validate(self, value):
if (value and not os.path.isdir(value)):
raise newforms.ValidationError(_("This folder does not exist."))
class Password(newforms.CharField):
def __init__(self, label, **kwargs):
newforms.CharField.__init__(self, label=label, widget=newforms.PasswordInput,
**kwargs)
#Deluge specific:
class _DelugeIntInput(newforms.TextInput):
"""
because deluge-floats are edited as ints.
"""
def render(self, name, value, attrs=None):
try:
value = int(float(value))
if value == -1:
value = _("Unlimited")
except:
pass
return newforms.TextInput.render(self, name, value, attrs)
class DelugeInt(newforms.IntegerField):
def __init__(self, label , **kwargs):
newforms.IntegerField.__init__(self, label=label, min_value=-1,
max_value=sys.maxint, widget=_DelugeIntInput, **kwargs)
def clean(self, value):
if str(value).lower() == _('Unlimited').lower():
value = -1
return int(newforms.IntegerField.clean(self, value))
class DelugeFloat(DelugeInt):
def clean(self, value):
return int(DelugeInt.clean(self, value))
#/fields

View File

@ -55,7 +55,7 @@ $for t in torrent_list:
</div>
<div id="tableContainer" class="tableContainer">
<table class="torrent_list" border=0 cellspacing=0 cellpadding=2 id="torrent_list">
<table class="torrent_list" border=0 cellspacing=0 cellpadding=2 id="torrent_list" >
<thead class="fixedHeader">
<tr>
$:(sort_head('calc_state_str', 'S'))