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

« back to all changes in this revision

Viewing changes to ivle/webapp/admin/subject.py

  • Committer: William Grant
  • Date: 2010-02-11 11:33:33 UTC
  • Revision ID: grantw@unimelb.edu.au-20100211113333-0j040ct188bfpjl5
Add subject creation/editing UI. Not linked just yet.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
from genshi.filters import HTMLFormFiller
34
34
from genshi.template import Context, TemplateLoader
35
35
import formencode
 
36
import formencode.validators
36
37
 
37
38
from ivle.webapp.base.xhtml import XHTMLView
38
39
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
76
77
            if len(offerings):
77
78
                ctx['semesters'].append((semester, offerings))
78
79
 
 
80
 
 
81
class SubjectShortNameUniquenessValidator(formencode.FancyValidator):
 
82
    """A FormEncode validator that checks that a subject name is unused.
 
83
 
 
84
    The subject referenced by state.existing_subject is permitted
 
85
    to hold that name. If any other object holds it, the input is rejected.
 
86
    """
 
87
    def __init__(self, matching=None):
 
88
        self.matching = matching
 
89
 
 
90
    def _to_python(self, value, state):
 
91
        if (state.store.find(
 
92
                Subject, short_name=value).one() not in
 
93
                (None, state.existing_subject)):
 
94
            raise formencode.Invalid(
 
95
                'Short name already taken', value, state)
 
96
        return value
 
97
 
 
98
 
 
99
class SubjectSchema(formencode.Schema):
 
100
    short_name = formencode.All(
 
101
        SubjectShortNameUniquenessValidator(),
 
102
        formencode.validators.UnicodeString(not_empty=True))
 
103
    name = formencode.validators.UnicodeString(not_empty=True)
 
104
    code = formencode.validators.UnicodeString(not_empty=True)
 
105
 
 
106
 
 
107
class SubjectFormView(XHTMLView):
 
108
    """An abstract form to add or edit a subject."""
 
109
    tab = 'subjects'
 
110
 
 
111
    def authorize(self, req):
 
112
        return req.user is not None and req.user.admin
 
113
 
 
114
    def filter(self, stream, ctx):
 
115
        return stream | HTMLFormFiller(data=ctx['data'])
 
116
 
 
117
    def populate_state(self, state):
 
118
        state.existing_subject = None
 
119
 
 
120
    def populate(self, req, ctx):
 
121
        if req.method == 'POST':
 
122
            data = dict(req.get_fieldstorage())
 
123
            try:
 
124
                validator = SubjectSchema()
 
125
                self.populate_state(req)
 
126
                data = validator.to_python(data, state=req)
 
127
 
 
128
                subject = self.update_subject_object(req, data)
 
129
 
 
130
                req.store.commit()
 
131
                req.throw_redirect(req.publisher.generate(subject))
 
132
            except formencode.Invalid, e:
 
133
                errors = e.unpack_errors()
 
134
        else:
 
135
            data = self.get_default_data(req)
 
136
            errors = {}
 
137
 
 
138
        if errors:
 
139
            req.store.rollback()
 
140
 
 
141
        ctx['context'] = self.context
 
142
        ctx['data'] = data or {}
 
143
        ctx['errors'] = errors
 
144
 
 
145
 
 
146
class SubjectNew(SubjectFormView):
 
147
    """A form to create a subject."""
 
148
    template = 'templates/subject-new.html'
 
149
 
 
150
    def populate_state(self, state):
 
151
        state.existing_subject = self.context
 
152
 
 
153
    def get_default_data(self, req):
 
154
        return {}
 
155
 
 
156
    def update_subject_object(self, req, data):
 
157
        new_subject = Subject()
 
158
        new_subject.short_name = data['short_name']
 
159
        new_subject.name = data['name']
 
160
        new_subject.code = data['code']
 
161
 
 
162
        req.store.add(new_subject)
 
163
        return new_subject
 
164
 
 
165
 
 
166
class SubjectEdit(SubjectFormView):
 
167
    """A form to edit a subject."""
 
168
    template = 'templates/subject-edit.html'
 
169
 
 
170
    def populate_state(self, state):
 
171
        state.existing_subject = self.context
 
172
 
 
173
    def get_default_data(self, req):
 
174
        return {
 
175
            'short_name': self.context.short_name,
 
176
            'name': self.context.name,
 
177
            'code': self.context.code,
 
178
            }
 
179
 
 
180
    def update_subject_object(self, req, data):
 
181
        self.context.short_name = data['short_name']
 
182
        self.context.name = data['name']
 
183
        self.context.code = data['code']
 
184
 
 
185
        return self.context
 
186
 
 
187
 
79
188
class OfferingView(XHTMLView):
80
189
    """The home page of an offering."""
81
190
    template = 'templates/offering.html'
327
436
    reverse_routes = (subject_url, offering_url, projectset_url, project_url)
328
437
 
329
438
    views = [(ApplicationRoot, ('subjects', '+index'), SubjectsView),
 
439
             (ApplicationRoot, ('subjects', '+new'), SubjectNew),
 
440
             (Subject, '+edit', SubjectEdit),
330
441
             (Offering, '+index', OfferingView),
331
442
             (Offering, '+edit', OfferingEdit),
332
443
             (Offering, ('+enrolments', '+index'), EnrolmentsView),