113
114
code = formencode.validators.UnicodeString(not_empty=True)
116
class SubjectFormView(XHTMLView):
117
class SubjectFormView(BaseFormView):
117
118
"""An abstract form to add or edit a subject."""
120
121
def authorize(self, req):
121
122
return req.user is not None and req.user.admin
123
def filter(self, stream, ctx):
124
return stream | HTMLFormFiller(data=ctx['data'])
126
124
def populate_state(self, state):
127
125
state.existing_subject = None
129
def populate(self, req, ctx):
130
if req.method == 'POST':
131
data = dict(req.get_fieldstorage())
133
validator = SubjectSchema()
134
self.populate_state(req)
135
data = validator.to_python(data, state=req)
137
subject = self.update_subject_object(req, data)
140
req.throw_redirect(req.publisher.generate(subject))
141
except formencode.Invalid, e:
142
errors = e.unpack_errors()
144
data = self.get_default_data(req)
150
ctx['context'] = self.context
151
ctx['data'] = data or {}
152
ctx['errors'] = errors
129
return SubjectSchema()
131
def get_return_url(self, obj):
155
135
class SubjectNew(SubjectFormView):
156
136
"""A form to create a subject."""
157
137
template = 'templates/subject-new.html'
159
def populate_state(self, state):
160
state.existing_subject = self.context
162
139
def get_default_data(self, req):
165
def update_subject_object(self, req, data):
142
def save_object(self, req, data):
166
143
new_subject = Subject()
167
144
new_subject.short_name = data['short_name']
168
145
new_subject.name = data['name']
194
171
return self.context
174
class SemesterUniquenessValidator(formencode.FancyValidator):
175
"""A FormEncode validator that checks that a semester is unique.
177
There cannot be more than one semester for the same year and semester.
179
def _to_python(self, value, state):
180
if (state.store.find(
181
Semester, year=value['year'], semester=value['semester']
183
raise formencode.Invalid(
184
'Semester already exists', value, state)
188
class SemesterSchema(formencode.Schema):
189
year = formencode.validators.UnicodeString()
190
semester = formencode.validators.UnicodeString()
191
chained_validators = [SemesterUniquenessValidator()]
194
class SemesterNew(BaseFormView):
195
"""A form to create a semester."""
196
template = 'templates/semester-new.html'
199
def authorize(self, req):
200
return req.user is not None and req.user.admin
204
return SemesterSchema()
206
def get_default_data(self, req):
209
def save_object(self, req, data):
210
new_semester = Semester()
211
new_semester.year = data['year']
212
new_semester.semester = data['semester']
214
req.store.add(new_semester)
217
def get_return_url(self, obj):
197
221
class OfferingView(XHTMLView):
198
222
"""The home page of an offering."""
199
223
template = 'templates/offering.html'
234
259
problems_done, problems_total))
262
class SubjectValidator(formencode.FancyValidator):
263
"""A FormEncode validator that turns a subject name into a subject.
265
The state must have a 'store' attribute, which is the Storm store
268
def _to_python(self, value, state):
269
subject = state.store.find(Subject, short_name=value).one()
273
raise formencode.Invalid('Subject does not exist', value, state)
276
class SemesterValidator(formencode.FancyValidator):
277
"""A FormEncode validator that turns a string into a semester.
279
The string should be of the form 'year/semester', eg. '2009/1'.
281
The state must have a 'store' attribute, which is the Storm store
284
def _to_python(self, value, state):
286
year, semester = value.split('/')
288
year = semester = None
290
semester = state.store.find(
291
Semester, year=year, semester=semester).one()
295
raise formencode.Invalid('Semester does not exist', value, state)
298
class OfferingUniquenessValidator(formencode.FancyValidator):
299
"""A FormEncode validator that checks that an offering is unique.
301
There cannot be more than one offering in the same year and semester.
303
The offering referenced by state.existing_offering is permitted to
304
hold that year and semester tuple. If any other object holds it, the
307
def _to_python(self, value, state):
308
if (state.store.find(
309
Offering, subject=value['subject'],
310
semester=value['semester']).one() not in
311
(None, state.existing_offering)):
312
raise formencode.Invalid(
313
'Offering already exists', value, state)
237
317
class OfferingSchema(formencode.Schema):
238
318
description = formencode.validators.UnicodeString(
239
319
if_missing=None, not_empty=False)
240
320
url = formencode.validators.URL(if_missing=None, not_empty=False)
243
class OfferingEdit(XHTMLView):
323
class OfferingAdminSchema(OfferingSchema):
324
subject = formencode.All(
325
SubjectValidator(), formencode.validators.UnicodeString())
326
semester = formencode.All(
327
SemesterValidator(), formencode.validators.UnicodeString())
328
chained_validators = [OfferingUniquenessValidator()]
331
class OfferingEdit(BaseFormView):
244
332
"""A form to edit an offering's details."""
245
333
template = 'templates/offering-edit.html'
247
335
permission = 'edit'
249
def filter(self, stream, ctx):
250
return stream | HTMLFormFiller(data=ctx['data'])
252
def populate(self, req, ctx):
253
if req.method == 'POST':
254
data = dict(req.get_fieldstorage())
256
validator = OfferingSchema()
257
data = validator.to_python(data, state=req)
259
self.context.url = unicode(data['url']) if data['url'] else None
260
self.context.description = data['description']
262
req.throw_redirect(req.publisher.generate(self.context))
263
except formencode.Invalid, e:
264
errors = e.unpack_errors()
339
if self.req.user.admin:
340
return OfferingAdminSchema()
267
'url': self.context.url,
268
'description': self.context.description,
342
return OfferingSchema()
344
def populate(self, req, ctx):
345
super(OfferingEdit, self).populate(req, ctx)
346
ctx['subjects'] = req.store.find(Subject)
347
ctx['semesters'] = req.store.find(Semester)
349
def populate_state(self, state):
350
state.existing_offering = self.context
352
def get_default_data(self, req):
354
'subject': self.context.subject.short_name,
355
'semester': self.context.semester.year + '/' +
356
self.context.semester.semester,
357
'url': self.context.url,
358
'description': self.context.description,
272
ctx['data'] = data or {}
273
ctx['context'] = self.context
274
ctx['errors'] = errors
361
def save_object(self, req, data):
363
self.context.subject = data['subject']
364
self.context.semester = data['semester']
365
self.context.description = data['description']
366
self.context.url = unicode(data['url']) if data['url'] else None
370
class OfferingNew(BaseFormView):
371
"""A form to create an offering."""
372
template = 'templates/offering-new.html'
375
def authorize(self, req):
376
return req.user is not None and req.user.admin
380
return OfferingAdminSchema()
382
def populate(self, req, ctx):
383
super(OfferingNew, self).populate(req, ctx)
384
ctx['subjects'] = req.store.find(Subject)
385
ctx['semesters'] = req.store.find(Semester)
387
def populate_state(self, state):
388
state.existing_offering = None
390
def get_default_data(self, req):
393
def save_object(self, req, data):
394
new_offering = Offering()
395
new_offering.subject = data['subject']
396
new_offering.semester = data['semester']
397
new_offering.description = data['description']
398
new_offering.url = unicode(data['url']) if data['url'] else None
400
req.store.add(new_offering)
277
404
class UserValidator(formencode.FancyValidator):