OpenSecurity/install/web.py-0.37/web/form.py
changeset 3 65432e6c6042
     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()