1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/OpenSecurity/install/web.py-0.37/web/form.py Mon Dec 02 14:02:05 2013 +0100
1.3 @@ -0,0 +1,410 @@
1.4 +"""
1.5 +HTML forms
1.6 +(part of web.py)
1.7 +"""
1.8 +
1.9 +import copy, re
1.10 +import webapi as web
1.11 +import utils, net
1.12 +
1.13 +def attrget(obj, attr, value=None):
1.14 + try:
1.15 + if hasattr(obj, 'has_key') and obj.has_key(attr):
1.16 + return obj[attr]
1.17 + except TypeError:
1.18 + # Handle the case where has_key takes different number of arguments.
1.19 + # This is the case with Model objects on appengine. See #134
1.20 + pass
1.21 + if hasattr(obj, attr):
1.22 + return getattr(obj, attr)
1.23 + return value
1.24 +
1.25 +class Form(object):
1.26 + r"""
1.27 + HTML form.
1.28 +
1.29 + >>> f = Form(Textbox("x"))
1.30 + >>> f.render()
1.31 + u'<table>\n <tr><th><label for="x">x</label></th><td><input type="text" id="x" name="x"/></td></tr>\n</table>'
1.32 + """
1.33 + def __init__(self, *inputs, **kw):
1.34 + self.inputs = inputs
1.35 + self.valid = True
1.36 + self.note = None
1.37 + self.validators = kw.pop('validators', [])
1.38 +
1.39 + def __call__(self, x=None):
1.40 + o = copy.deepcopy(self)
1.41 + if x: o.validates(x)
1.42 + return o
1.43 +
1.44 + def render(self):
1.45 + out = ''
1.46 + out += self.rendernote(self.note)
1.47 + out += '<table>\n'
1.48 +
1.49 + for i in self.inputs:
1.50 + html = utils.safeunicode(i.pre) + i.render() + self.rendernote(i.note) + utils.safeunicode(i.post)
1.51 + if i.is_hidden():
1.52 + out += ' <tr style="display: none;"><th></th><td>%s</td></tr>\n' % (html)
1.53 + else:
1.54 + out += ' <tr><th><label for="%s">%s</label></th><td>%s</td></tr>\n' % (i.id, net.websafe(i.description), html)
1.55 + out += "</table>"
1.56 + return out
1.57 +
1.58 + def render_css(self):
1.59 + out = []
1.60 + out.append(self.rendernote(self.note))
1.61 + for i in self.inputs:
1.62 + if not i.is_hidden():
1.63 + out.append('<label for="%s">%s</label>' % (i.id, net.websafe(i.description)))
1.64 + out.append(i.pre)
1.65 + out.append(i.render())
1.66 + out.append(self.rendernote(i.note))
1.67 + out.append(i.post)
1.68 + out.append('\n')
1.69 + return ''.join(out)
1.70 +
1.71 + def rendernote(self, note):
1.72 + if note: return '<strong class="wrong">%s</strong>' % net.websafe(note)
1.73 + else: return ""
1.74 +
1.75 + def validates(self, source=None, _validate=True, **kw):
1.76 + source = source or kw or web.input()
1.77 + out = True
1.78 + for i in self.inputs:
1.79 + v = attrget(source, i.name)
1.80 + if _validate:
1.81 + out = i.validate(v) and out
1.82 + else:
1.83 + i.set_value(v)
1.84 + if _validate:
1.85 + out = out and self._validate(source)
1.86 + self.valid = out
1.87 + return out
1.88 +
1.89 + def _validate(self, value):
1.90 + self.value = value
1.91 + for v in self.validators:
1.92 + if not v.valid(value):
1.93 + self.note = v.msg
1.94 + return False
1.95 + return True
1.96 +
1.97 + def fill(self, source=None, **kw):
1.98 + return self.validates(source, _validate=False, **kw)
1.99 +
1.100 + def __getitem__(self, i):
1.101 + for x in self.inputs:
1.102 + if x.name == i: return x
1.103 + raise KeyError, i
1.104 +
1.105 + def __getattr__(self, name):
1.106 + # don't interfere with deepcopy
1.107 + inputs = self.__dict__.get('inputs') or []
1.108 + for x in inputs:
1.109 + if x.name == name: return x
1.110 + raise AttributeError, name
1.111 +
1.112 + def get(self, i, default=None):
1.113 + try:
1.114 + return self[i]
1.115 + except KeyError:
1.116 + return default
1.117 +
1.118 + def _get_d(self): #@@ should really be form.attr, no?
1.119 + return utils.storage([(i.name, i.get_value()) for i in self.inputs])
1.120 + d = property(_get_d)
1.121 +
1.122 +class Input(object):
1.123 + def __init__(self, name, *validators, **attrs):
1.124 + self.name = name
1.125 + self.validators = validators
1.126 + self.attrs = attrs = AttributeList(attrs)
1.127 +
1.128 + self.description = attrs.pop('description', name)
1.129 + self.value = attrs.pop('value', None)
1.130 + self.pre = attrs.pop('pre', "")
1.131 + self.post = attrs.pop('post', "")
1.132 + self.note = None
1.133 +
1.134 + self.id = attrs.setdefault('id', self.get_default_id())
1.135 +
1.136 + if 'class_' in attrs:
1.137 + attrs['class'] = attrs['class_']
1.138 + del attrs['class_']
1.139 +
1.140 + def is_hidden(self):
1.141 + return False
1.142 +
1.143 + def get_type(self):
1.144 + raise NotImplementedError
1.145 +
1.146 + def get_default_id(self):
1.147 + return self.name
1.148 +
1.149 + def validate(self, value):
1.150 + self.set_value(value)
1.151 +
1.152 + for v in self.validators:
1.153 + if not v.valid(value):
1.154 + self.note = v.msg
1.155 + return False
1.156 + return True
1.157 +
1.158 + def set_value(self, value):
1.159 + self.value = value
1.160 +
1.161 + def get_value(self):
1.162 + return self.value
1.163 +
1.164 + def render(self):
1.165 + attrs = self.attrs.copy()
1.166 + attrs['type'] = self.get_type()
1.167 + if self.value is not None:
1.168 + attrs['value'] = self.value
1.169 + attrs['name'] = self.name
1.170 + return '<input %s/>' % attrs
1.171 +
1.172 + def rendernote(self, note):
1.173 + if note: return '<strong class="wrong">%s</strong>' % net.websafe(note)
1.174 + else: return ""
1.175 +
1.176 + def addatts(self):
1.177 + # add leading space for backward-compatibility
1.178 + return " " + str(self.attrs)
1.179 +
1.180 +class AttributeList(dict):
1.181 + """List of atributes of input.
1.182 +
1.183 + >>> a = AttributeList(type='text', name='x', value=20)
1.184 + >>> a
1.185 + <attrs: 'type="text" name="x" value="20"'>
1.186 + """
1.187 + def copy(self):
1.188 + return AttributeList(self)
1.189 +
1.190 + def __str__(self):
1.191 + return " ".join(['%s="%s"' % (k, net.websafe(v)) for k, v in self.items()])
1.192 +
1.193 + def __repr__(self):
1.194 + return '<attrs: %s>' % repr(str(self))
1.195 +
1.196 +class Textbox(Input):
1.197 + """Textbox input.
1.198 +
1.199 + >>> Textbox(name='foo', value='bar').render()
1.200 + u'<input type="text" id="foo" value="bar" name="foo"/>'
1.201 + >>> Textbox(name='foo', value=0).render()
1.202 + u'<input type="text" id="foo" value="0" name="foo"/>'
1.203 + """
1.204 + def get_type(self):
1.205 + return 'text'
1.206 +
1.207 +class Password(Input):
1.208 + """Password input.
1.209 +
1.210 + >>> Password(name='password', value='secret').render()
1.211 + u'<input type="password" id="password" value="secret" name="password"/>'
1.212 + """
1.213 +
1.214 + def get_type(self):
1.215 + return 'password'
1.216 +
1.217 +class Textarea(Input):
1.218 + """Textarea input.
1.219 +
1.220 + >>> Textarea(name='foo', value='bar').render()
1.221 + u'<textarea id="foo" name="foo">bar</textarea>'
1.222 + """
1.223 + def render(self):
1.224 + attrs = self.attrs.copy()
1.225 + attrs['name'] = self.name
1.226 + value = net.websafe(self.value or '')
1.227 + return '<textarea %s>%s</textarea>' % (attrs, value)
1.228 +
1.229 +class Dropdown(Input):
1.230 + r"""Dropdown/select input.
1.231 +
1.232 + >>> Dropdown(name='foo', args=['a', 'b', 'c'], value='b').render()
1.233 + u'<select id="foo" name="foo">\n <option value="a">a</option>\n <option selected="selected" value="b">b</option>\n <option value="c">c</option>\n</select>\n'
1.234 + >>> Dropdown(name='foo', args=[('a', 'aa'), ('b', 'bb'), ('c', 'cc')], value='b').render()
1.235 + u'<select id="foo" name="foo">\n <option value="a">aa</option>\n <option selected="selected" value="b">bb</option>\n <option value="c">cc</option>\n</select>\n'
1.236 + """
1.237 + def __init__(self, name, args, *validators, **attrs):
1.238 + self.args = args
1.239 + super(Dropdown, self).__init__(name, *validators, **attrs)
1.240 +
1.241 + def render(self):
1.242 + attrs = self.attrs.copy()
1.243 + attrs['name'] = self.name
1.244 +
1.245 + x = '<select %s>\n' % attrs
1.246 +
1.247 + for arg in self.args:
1.248 + x += self._render_option(arg)
1.249 +
1.250 + x += '</select>\n'
1.251 + return x
1.252 +
1.253 + def _render_option(self, arg, indent=' '):
1.254 + if isinstance(arg, (tuple, list)):
1.255 + value, desc= arg
1.256 + else:
1.257 + value, desc = arg, arg
1.258 +
1.259 + if self.value == value or (isinstance(self.value, list) and value in self.value):
1.260 + select_p = ' selected="selected"'
1.261 + else:
1.262 + select_p = ''
1.263 + return indent + '<option%s value="%s">%s</option>\n' % (select_p, net.websafe(value), net.websafe(desc))
1.264 +
1.265 +
1.266 +class GroupedDropdown(Dropdown):
1.267 + r"""Grouped Dropdown/select input.
1.268 +
1.269 + >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', ('Volvo', 'Saab')), ('German Cars', ('Mercedes', 'Audi'))), value='Audi').render()
1.270 + u'<select id="car_type" name="car_type">\n <optgroup label="Swedish Cars">\n <option value="Volvo">Volvo</option>\n <option value="Saab">Saab</option>\n </optgroup>\n <optgroup label="German Cars">\n <option value="Mercedes">Mercedes</option>\n <option selected="selected" value="Audi">Audi</option>\n </optgroup>\n</select>\n'
1.271 + >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', (('v', 'Volvo'), ('s', 'Saab'))), ('German Cars', (('m', 'Mercedes'), ('a', 'Audi')))), value='a').render()
1.272 + u'<select id="car_type" name="car_type">\n <optgroup label="Swedish Cars">\n <option value="v">Volvo</option>\n <option value="s">Saab</option>\n </optgroup>\n <optgroup label="German Cars">\n <option value="m">Mercedes</option>\n <option selected="selected" value="a">Audi</option>\n </optgroup>\n</select>\n'
1.273 +
1.274 + """
1.275 + def __init__(self, name, args, *validators, **attrs):
1.276 + self.args = args
1.277 + super(Dropdown, self).__init__(name, *validators, **attrs)
1.278 +
1.279 + def render(self):
1.280 + attrs = self.attrs.copy()
1.281 + attrs['name'] = self.name
1.282 +
1.283 + x = '<select %s>\n' % attrs
1.284 +
1.285 + for label, options in self.args:
1.286 + x += ' <optgroup label="%s">\n' % net.websafe(label)
1.287 + for arg in options:
1.288 + x += self._render_option(arg, indent = ' ')
1.289 + x += ' </optgroup>\n'
1.290 +
1.291 + x += '</select>\n'
1.292 + return x
1.293 +
1.294 +class Radio(Input):
1.295 + def __init__(self, name, args, *validators, **attrs):
1.296 + self.args = args
1.297 + super(Radio, self).__init__(name, *validators, **attrs)
1.298 +
1.299 + def render(self):
1.300 + x = '<span>'
1.301 + for arg in self.args:
1.302 + if isinstance(arg, (tuple, list)):
1.303 + value, desc= arg
1.304 + else:
1.305 + value, desc = arg, arg
1.306 + attrs = self.attrs.copy()
1.307 + attrs['name'] = self.name
1.308 + attrs['type'] = 'radio'
1.309 + attrs['value'] = value
1.310 + if self.value == value:
1.311 + attrs['checked'] = 'checked'
1.312 + x += '<input %s/> %s' % (attrs, net.websafe(desc))
1.313 + x += '</span>'
1.314 + return x
1.315 +
1.316 +class Checkbox(Input):
1.317 + """Checkbox input.
1.318 +
1.319 + >>> Checkbox('foo', value='bar', checked=True).render()
1.320 + u'<input checked="checked" type="checkbox" id="foo_bar" value="bar" name="foo"/>'
1.321 + >>> Checkbox('foo', value='bar').render()
1.322 + u'<input type="checkbox" id="foo_bar" value="bar" name="foo"/>'
1.323 + >>> c = Checkbox('foo', value='bar')
1.324 + >>> c.validate('on')
1.325 + True
1.326 + >>> c.render()
1.327 + u'<input checked="checked" type="checkbox" id="foo_bar" value="bar" name="foo"/>'
1.328 + """
1.329 + def __init__(self, name, *validators, **attrs):
1.330 + self.checked = attrs.pop('checked', False)
1.331 + Input.__init__(self, name, *validators, **attrs)
1.332 +
1.333 + def get_default_id(self):
1.334 + value = utils.safestr(self.value or "")
1.335 + return self.name + '_' + value.replace(' ', '_')
1.336 +
1.337 + def render(self):
1.338 + attrs = self.attrs.copy()
1.339 + attrs['type'] = 'checkbox'
1.340 + attrs['name'] = self.name
1.341 + attrs['value'] = self.value
1.342 +
1.343 + if self.checked:
1.344 + attrs['checked'] = 'checked'
1.345 + return '<input %s/>' % attrs
1.346 +
1.347 + def set_value(self, value):
1.348 + self.checked = bool(value)
1.349 +
1.350 + def get_value(self):
1.351 + return self.checked
1.352 +
1.353 +class Button(Input):
1.354 + """HTML Button.
1.355 +
1.356 + >>> Button("save").render()
1.357 + u'<button id="save" name="save">save</button>'
1.358 + >>> Button("action", value="save", html="<b>Save Changes</b>").render()
1.359 + u'<button id="action" value="save" name="action"><b>Save Changes</b></button>'
1.360 + """
1.361 + def __init__(self, name, *validators, **attrs):
1.362 + super(Button, self).__init__(name, *validators, **attrs)
1.363 + self.description = ""
1.364 +
1.365 + def render(self):
1.366 + attrs = self.attrs.copy()
1.367 + attrs['name'] = self.name
1.368 + if self.value is not None:
1.369 + attrs['value'] = self.value
1.370 + html = attrs.pop('html', None) or net.websafe(self.name)
1.371 + return '<button %s>%s</button>' % (attrs, html)
1.372 +
1.373 +class Hidden(Input):
1.374 + """Hidden Input.
1.375 +
1.376 + >>> Hidden(name='foo', value='bar').render()
1.377 + u'<input type="hidden" id="foo" value="bar" name="foo"/>'
1.378 + """
1.379 + def is_hidden(self):
1.380 + return True
1.381 +
1.382 + def get_type(self):
1.383 + return 'hidden'
1.384 +
1.385 +class File(Input):
1.386 + """File input.
1.387 +
1.388 + >>> File(name='f').render()
1.389 + u'<input type="file" id="f" name="f"/>'
1.390 + """
1.391 + def get_type(self):
1.392 + return 'file'
1.393 +
1.394 +class Validator:
1.395 + def __deepcopy__(self, memo): return copy.copy(self)
1.396 + def __init__(self, msg, test, jstest=None): utils.autoassign(self, locals())
1.397 + def valid(self, value):
1.398 + try: return self.test(value)
1.399 + except: return False
1.400 +
1.401 +notnull = Validator("Required", bool)
1.402 +
1.403 +class regexp(Validator):
1.404 + def __init__(self, rexp, msg):
1.405 + self.rexp = re.compile(rexp)
1.406 + self.msg = msg
1.407 +
1.408 + def valid(self, value):
1.409 + return bool(self.rexp.match(value))
1.410 +
1.411 +if __name__ == "__main__":
1.412 + import doctest
1.413 + doctest.testmod()