~azzar1/unity/add-show-desktop-key

1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
1
# IVLE
2
# Copyright (C) 2010 The University of Melbourne
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
1606.1.2 by William Grant
Add a FormEncode validator that matches the DB's valid_url_name.
18
import re
1721 by Matt Giuca
forms: Added DateTimeValidator, which validates datestamps in our preferred format.
19
import datetime
1606.1.2 by William Grant
Add a FormEncode validator that matches the DB's valid_url_name.
20
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
21
import formencode
1606.1.2 by William Grant
Add a FormEncode validator that matches the DB's valid_url_name.
22
import formencode.validators
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
23
from genshi.filters import HTMLFormFiller
24
25
from ivle.webapp.base.xhtml import XHTMLView
26
1606.1.2 by William Grant
Add a FormEncode validator that matches the DB's valid_url_name.
27
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
28
class BaseFormView(XHTMLView):
29
    """A base form view."""
30
1541 by William Grant
Document BaseFormView.
31
    @property
32
    def validator(self):
1545 by William Grant
Document the validator's state.
33
        """The FormEncode validator to use.
34
35
        The request will be passed in as state, after potentially being
36
        modified by populate_state().
37
        """
1541 by William Grant
Document BaseFormView.
38
        raise NotImplementedError()
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
39
40
    def populate_state(self, state):
1541 by William Grant
Document BaseFormView.
41
        """Populate the state given to the FormEncode validator.
42
43
        Subclasses can override this and set additional attributes.
44
        """
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
45
        pass
46
47
    def get_return_url(self, obj):
1541 by William Grant
Document BaseFormView.
48
        """Return the URL to which the completed form should redirect.
49
50
        By default this will redirect to the saved object.
51
        """
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
52
        return self.req.publisher.generate(obj)
53
54
    def get_default_data(self, req):
1541 by William Grant
Document BaseFormView.
55
        """Return a dict mapping field names to default form values.
56
57
        For an edit form, this should return the object's existing data.
58
        For a creation form, this should probably return an empty dict.
59
60
        This must be overridden by subclasses.
61
        """
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
62
        raise NotImplementedError()
63
64
    def save_object(self, req, data):
1541 by William Grant
Document BaseFormView.
65
        """Take the validated form data and turn it into an object.
66
67
        The object must then be returned.
68
69
        For an edit form, this should just overwrite data on an existing
70
        object.
71
        For a creation form, this should create a new object with the given
72
        data and add it to the request's store.
73
        """
74
        raise NotImplementedError()
75
76
    def filter(self, stream, ctx):
77
        return stream | HTMLFormFiller(data=ctx['data'])
1539 by William Grant
Move BaseFormView into ivle.webapp.base.forms.
78
79
    def populate(self, req, ctx):
80
        if req.method == 'POST':
81
            data = dict(req.get_fieldstorage())
82
            try:
83
                self.populate_state(req)
84
                data = self.validator.to_python(data, state=req)
85
86
                obj = self.save_object(req, data)
87
88
                req.store.commit()
89
                req.throw_redirect(self.get_return_url(obj))
90
            except formencode.Invalid, e:
91
                error_value = e.msg
92
                errors = e.unpack_errors()
93
        else:
94
            data = self.get_default_data(req)
95
            error_value = None
96
            errors = {}
97
98
        if errors:
99
            req.store.rollback()
100
101
        ctx['req'] = req
102
        ctx['context'] = self.context
103
        ctx['data'] = data or {}
104
        ctx['errors'] = errors
105
        # If all of the fields validated, set the global form error.
106
        if isinstance(errors, basestring):
107
            ctx['error_value'] = errors
108
109
1606.1.15 by William Grant
Permit underscores in all names.
110
VALID_URL_NAME = re.compile(r'^[a-z0-9][a-z0-9_\+\.\-]*$')
1606.1.2 by William Grant
Add a FormEncode validator that matches the DB's valid_url_name.
111
112
113
class URLNameValidator(formencode.validators.UnicodeString):
114
    def validate_python(self, value, state):
115
        super(URLNameValidator, self).validate_python(value, state)
116
        if not VALID_URL_NAME.match(value):
117
            raise formencode.Invalid(
1606.1.16 by William Grant
Fix validation messages to inform users that alphanumerics in names must be lowercase.
118
                'Must consist of a lowercase alphanumeric character followed '
119
                'by any number of lowercase alphanumerics, ., +, - or _.',
1606.1.2 by William Grant
Add a FormEncode validator that matches the DB's valid_url_name.
120
                value, state)
1721 by Matt Giuca
forms: Added DateTimeValidator, which validates datestamps in our preferred format.
121
122
class DateTimeValidator(formencode.validators.FancyValidator):
123
    """Accepts a date/time in YYYY-MM-DD HH:MM:SS format. Converts to a
124
    datetime.datetime object."""
125
    def _to_python(self, value, state):
126
        """Validate and convert."""
127
        try:
128
            return datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
129
        except ValueError, e:
130
            raise formencode.Invalid("Must be a timestamp in "
131
                "YYYY-MM-DD HH:MM:SS format", value, state)
132
    def _from_python(self, value, state):
133
        try:
134
            return value.strftime("%Y-%m-%d %H:%M:%S")
135
        except AttributeError:
136
            raise formencode.Invalid("Must be a datetime.datetime object")