source: main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py @ 6697

Last change on this file since 6697 was 6696, checked in by Henrik Bettermann, 14 years ago

Add reg_number attribute which is needed for first-time login (admission checking).

  • Property svn:keywords set to Id
File size: 17.4 KB
Line 
1## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
2## This program is free software; you can redistribute it and/or modify
3## it under the terms of the GNU General Public License as published by
4## the Free Software Foundation; either version 2 of the License, or
5## (at your option) any later version.
6##
7## This program is distributed in the hope that it will be useful,
8## but WITHOUT ANY WARRANTY; without even the implied warranty of
9## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10## GNU General Public License for more details.
11##
12## You should have received a copy of the GNU General Public License
13## along with this program; if not, write to the Free Software
14## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15##
16"""UI components for students and related components.
17"""
18import sys
19import grok
20
21from datetime import datetime
22from zope.formlib.widget import CustomWidgetFactory
23from zope.formlib.form import setUpEditWidgets
24from zope.securitypolicy.interfaces import IPrincipalRoleManager
25from zope.traversing.browser import absoluteURL
26from zope.component import (
27    createObject,)
28
29from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
30from reportlab.pdfgen import canvas
31from reportlab.lib.units import cm
32from reportlab.lib.pagesizes import A4
33from reportlab.lib.styles import getSampleStyleSheet
34from reportlab.platypus import (Frame, Paragraph, Image,
35    Table, Spacer)
36from reportlab.platypus.tables import TableStyle
37
38from waeup.sirp.accesscodes import invalidate_accesscode, get_access_code
39from waeup.sirp.accesscodes.workflow import USED
40from waeup.sirp.browser import (
41    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage)
42from waeup.sirp.browser.breadcrumbs import Breadcrumb
43from waeup.sirp.browser.layout import NullValidator
44from waeup.sirp.browser.pages import add_local_role, del_local_roles
45from waeup.sirp.browser.resources import datepicker, tabs, datatable
46from waeup.sirp.browser.viewlets import (
47    ManageActionButton, PrimaryNavTab,
48    AddActionButton, ActionButton, PlainActionButton,
49    )
50from waeup.sirp.image.browser.widget import (
51    ThumbnailWidget, EncodingImageFileWidget,
52    )
53from waeup.sirp.image.image import createWAeUPImageFile
54from waeup.sirp.interfaces import (
55    IWAeUPObject, ILocalRolesAssignable, IUserAccount,
56    )
57from waeup.sirp.permissions import get_users_with_local_roles
58from waeup.sirp.university.interfaces import ICertificate
59from waeup.sirp.widgets.datewidget import (
60    FriendlyDateWidget, FriendlyDateDisplayWidget)
61from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
62from waeup.sirp.widgets.objectwidget import (
63    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
64from waeup.sirp.students.interfaces import (
65    IStudentsContainer, IStudent, IStudentClearance,
66    IStudentPersonal, IStudentBase, IStudentStudyCourse,
67    IStudentPayments, IStudentAccommodation, IStudentNavigation,
68    IStudentBaseEdit, IStudentClearanceEdit,
69    )
70from waeup.sirp.students.student import Student
71from waeup.sirp.students.catalog import search
72
73class StudentsTab(PrimaryNavTab):
74    """Students tab in primary navigation.
75    """
76
77    grok.context(IWAeUPObject)
78    grok.order(3)
79    grok.require('waeup.viewStudent')
80    grok.template('primarynavtab')
81
82    pnav = 4
83    tab_title = u'Students'
84
85    @property
86    def link_target(self):
87        return self.view.application_url('students')
88
89class StudentsBreadcrumb(Breadcrumb):
90    """A breadcrumb for the students container.
91    """
92    grok.context(IStudentsContainer)
93    title = u'Students'
94
95class SudyCourseBreadcrumb(Breadcrumb):
96    """A breadcrumb for the student study course.
97    """
98    grok.context(IStudentStudyCourse)
99    title = u'Study Course'
100
101class PaymentsBreadcrumb(Breadcrumb):
102    """A breadcrumb for the student payments folder.
103    """
104    grok.context(IStudentPayments)
105    title = u'Payments'
106
107class AccommodationBreadcrumb(Breadcrumb):
108    """A breadcrumb for the student accommodation folder.
109    """
110    grok.context(IStudentAccommodation)
111    title = u'Accommodation'
112
113class StudentsContainerPage(WAeUPPage):
114    """The standard view for student containers.
115    """
116    grok.context(IStudentsContainer)
117    grok.name('index')
118    grok.require('waeup.viewStudent')
119    grok.template('containerpage')
120    label = 'Student Section'
121    title = 'Students'
122    pnav = 4
123
124    def update(self, *args, **kw):
125        datatable.need()
126        form = self.request.form
127        self.hitlist = []
128        if 'searchterm' in form and form['searchterm']:
129            self.searchterm = form['searchterm']
130            self.searchtype = form['searchtype']
131        elif 'old_searchterm' in form:
132            self.searchterm = form['old_searchterm']
133            self.searchtype = form['old_searchtype']
134        else:
135            if 'search' in form:
136                self.flash('Empty search string.')
137            return
138        self.hitlist = search(query=self.searchterm,
139            searchtype=self.searchtype, view=self)
140        if not self.hitlist:
141            self.flash('No student found.')
142        return
143
144class StudentsContainerManageActionButton(ManageActionButton):
145    grok.order(1)
146    grok.context(IStudentsContainer)
147    grok.view(StudentsContainerPage)
148    grok.require('waeup.manageStudents')
149    text = 'Manage student section'
150
151
152class StudentsContainerManagePage(WAeUPPage):
153    """The manage page for student containers.
154    """
155    grok.context(IStudentsContainer)
156    grok.name('manage')
157    grok.require('waeup.manageStudents')
158    grok.template('containermanagepage')
159    pnav = 4
160    title = 'Manage student section'
161
162    @property
163    def label(self):
164        return self.title
165
166    def update(self, *args, **kw):
167        datatable.need()
168        form = self.request.form
169        self.hitlist = []
170        if 'searchterm' in form and form['searchterm']:
171            self.searchterm = form['searchterm']
172            self.searchtype = form['searchtype']
173        elif 'old_searchterm' in form:
174            self.searchterm = form['old_searchterm']
175            self.searchtype = form['old_searchtype']
176        else:
177            if 'search' in form:
178                self.flash('Empty search string.')
179            return
180        if not 'entries' in form:
181            self.hitlist = search(query=self.searchterm,
182                searchtype=self.searchtype, view=self)
183            if not self.hitlist:
184                self.flash('No student found.')
185            return
186        entries = form['entries']
187        if isinstance(entries, basestring):
188            entries = [entries]
189        deleted = []
190        for entry in entries:
191            if 'remove' in form:
192                del self.context[entry]
193                deleted.append(entry)
194        self.hitlist = search(query=self.searchterm,
195            searchtype=self.searchtype, view=self)
196        if len(deleted):
197            self.flash('Successfully removed: %s' % ', '.join(deleted))
198        return
199
200class StudentsContainerAddActionButton(AddActionButton):
201    grok.order(1)
202    grok.context(IStudentsContainer)
203    grok.view(StudentsContainerManagePage)
204    grok.require('waeup.manageStudents')
205    text = 'Add student'
206    target = 'addstudent'
207
208class StudentAddFormPage(WAeUPAddFormPage):
209    """Add-form to add a student.
210    """
211    grok.context(IStudentsContainer)
212    grok.require('waeup.manageStudents')
213    grok.name('addstudent')
214    grok.template('studentaddpage')
215    form_fields = grok.AutoFields(IStudent)
216    title = 'Students'
217    label = 'Add student'
218    pnav = 4
219
220    @grok.action('Create student record')
221    def addStudent(self, **data):
222        student = createObject(u'waeup.Student')
223        self.applyData(student, **data)
224        self.context.addStudent(student)
225        self.flash('Student record created.')
226        self.redirect(self.url(self.context[student.student_id], 'index'))
227        return
228
229class StudentBaseDisplayFormPage(WAeUPDisplayFormPage):
230    """ Page to display student base data
231    """
232    grok.context(IStudent)
233    grok.name('index')
234    grok.require('waeup.viewStudent')
235    grok.template('basepage')
236    form_fields = grok.AutoFields(IStudentBase).omit('password')
237    pnav = 4
238    title = 'Base Data'
239
240    @property
241    def label(self):
242        return '%s: Base Data' % self.context.name
243
244class StudentBaseManageActionButton(ManageActionButton):
245    grok.order(1)
246    grok.context(IStudent)
247    grok.view(StudentBaseDisplayFormPage)
248    grok.require('waeup.manageStudents')
249    text = 'Manage'
250    target = 'edit_base'
251
252class StudentBaseManageFormPage(WAeUPEditFormPage):
253    """ View to edit student base data
254    """
255    grok.context(IStudent)
256    grok.name('edit_base')
257    grok.require('waeup.manageStudents')
258    form_fields = grok.AutoFields(IStudentBase).omit('student_id')
259    grok.template('basemanagepage')
260    label = 'Manage base data'
261    title = 'Base Data'
262    pnav = 4
263
264    def update(self):
265        datepicker.need() # Enable jQuery datepicker in date fields.
266        super(StudentBaseManageFormPage, self).update()
267        self.wf_info = IWorkflowInfo(self.context)
268        return
269
270    def getTransitions(self):
271        """Return a list of dicts of allowed transition ids and titles.
272
273        Each list entry provides keys ``name`` and ``title`` for
274        internal name and (human readable) title of a single
275        transition.
276        """
277        allowed_transitions = self.wf_info.getManualTransitions()
278        return [dict(name='', title='No transition')] +[
279            dict(name=x, title=y) for x, y in allowed_transitions]
280
281    @grok.action('Save')
282    def save(self, **data):
283        changed_fields = self.applyData(self.context, **data)
284        changed_fields = changed_fields.values()
285        fields_string = '+'.join(' + '.join(str(i) for i in b) for b in changed_fields)
286        self.context._p_changed = True
287        form = self.request.form
288        if form.has_key('transition') and form['transition']:
289            transition_id = form['transition']
290            self.wf_info.fireTransition(transition_id)
291        self.flash('Form has been saved.')
292        ob_class = self.__implemented__.__name__.replace('waeup.sirp.','')
293        if fields_string:
294            self.context.loggerInfo(ob_class, 'saved: % s' % fields_string)
295        if 'password' in fields_string:
296            IUserAccount(self.context).setPassword(form['form.password'])
297        return
298
299class StudentClearanceDisplayFormPage(WAeUPDisplayFormPage):
300    """ Page to display student clearance data
301    """
302    grok.context(IStudent)
303    grok.name('view_clearance')
304    grok.require('waeup.viewStudent')
305    form_fields = grok.AutoFields(IStudentClearance).omit('clearance_locked')
306    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
307    title = 'Clearance Data'
308    pnav = 4
309
310    @property
311    def label(self):
312        return '%s: Clearance Data' % self.context.name
313
314class StudentClearanceManageActionButton(ManageActionButton):
315    grok.order(1)
316    grok.context(IStudent)
317    grok.view(StudentClearanceDisplayFormPage)
318    grok.require('waeup.manageStudents')
319    text = 'Manage'
320    target = 'edit_clearance'
321
322class StudentClearanceManageFormPage(WAeUPEditFormPage):
323    """ Page to edit student clearance data
324    """
325    grok.context(IStudent)
326    grok.name('edit_clearance')
327    grok.require('waeup.manageStudents')
328    form_fields = grok.AutoFields(IStudentClearance)
329    label = 'Manage clearance data'
330    title = 'Clearance Data'
331    pnav = 4
332
333    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
334
335    def update(self):
336        datepicker.need() # Enable jQuery datepicker in date fields.
337        return super(StudentClearanceManageFormPage, self).update()
338
339    @grok.action('Save')
340    def save(self, **data):
341        changed_fields = self.applyData(self.context, **data)
342        changed_fields = changed_fields.values()
343        fields_string = '+'.join(' + '.join(str(i) for i in b) for b in changed_fields)
344        self.context._p_changed = True
345        form = self.request.form
346        self.flash('Form has been saved.')
347        ob_class = self.__implemented__.__name__.replace('waeup.sirp.','')
348        if fields_string:
349            self.context.loggerInfo(ob_class, 'saved: % s' % fields_string)
350        return
351
352class StudentPersonalDisplayFormPage(WAeUPDisplayFormPage):
353    """ Page to display student personal data
354    """
355    grok.context(IStudent)
356    grok.name('view_personal')
357    grok.require('waeup.viewStudent')
358    form_fields = grok.AutoFields(IStudentPersonal)
359    title = 'Personal Data'
360    pnav = 4
361
362    @property
363    def label(self):
364        return '%s: Personal Data' % self.context.name
365
366class StudentPersonalManageActionButton(ManageActionButton):
367    grok.order(1)
368    grok.context(IStudent)
369    grok.view(StudentPersonalDisplayFormPage)
370    grok.require('waeup.manageStudents')
371    text = 'Manage'
372    target = 'edit_personal'
373
374class StudentPersonalManageFormPage(WAeUPEditFormPage):
375    """ Page to edit student clearance data
376    """
377    grok.context(IStudent)
378    grok.name('edit_personal')
379    grok.require('waeup.viewStudent')
380    form_fields = grok.AutoFields(IStudentPersonal)
381    label = 'Manage personal data'
382    title = 'Personal Data'
383    pnav = 4
384
385class StudyCourseDisplayFormPage(WAeUPDisplayFormPage):
386    """ Page to display the student study course data
387    """
388    grok.context(IStudentStudyCourse)
389    grok.name('index')
390    grok.require('waeup.viewStudent')
391    form_fields = grok.AutoFields(IStudentStudyCourse)
392    #grok.template('studycoursepage')
393    title = 'Study Course'
394    pnav = 4
395
396    @property
397    def label(self):
398        return '%s: Study Course' % self.context.__parent__.name
399
400class StudyCourseManageActionButton(ManageActionButton):
401    grok.order(1)
402    grok.context(IStudentStudyCourse)
403    grok.view(StudyCourseDisplayFormPage)
404    grok.require('waeup.manageStudents')
405    text = 'Manage'
406    target = 'edit'
407
408class StudyCourseManageFormPage(WAeUPEditFormPage):
409    """ Page to edit the student study course data
410    """
411    grok.context(IStudentStudyCourse)
412    grok.name('edit')
413    grok.require('waeup.manageStudents')
414    form_fields = grok.AutoFields(IStudentStudyCourse)
415    title = 'Study Course'
416    label = 'Manage study course'
417    pnav = 4
418
419class PaymentsDisplayFormPage(WAeUPDisplayFormPage):
420    """ Page to display the student payments
421    """
422    grok.context(IStudentPayments)
423    grok.name('index')
424    grok.require('waeup.viewStudent')
425    form_fields = grok.AutoFields(IStudentPayments)
426    #grok.template('paymentspage')
427    title = 'Payments'
428    pnav = 4
429
430    @property
431    def label(self):
432        return '%s: Payments' % self.context.__parent__.name
433
434class AccommodationDisplayFormPage(WAeUPDisplayFormPage):
435    """ Page to display the student accommodation data
436    """
437    grok.context(IStudentAccommodation)
438    grok.name('index')
439    grok.require('waeup.viewStudent')
440    form_fields = grok.AutoFields(IStudentAccommodation)
441    #grok.template('accommodationpage')
442    title = 'Accommodation'
443    pnav = 4
444
445    @property
446    def label(self):
447        return '%s: Accommodation Data' % self.context.__parent__.name
448
449class StudentHistoryPage(WAeUPPage):
450    """ Page to display student clearance data
451    """
452    grok.context(IStudent)
453    grok.name('history')
454    grok.require('waeup.viewStudent')
455    grok.template('studenthistory')
456    title = 'History'
457    pnav = 4
458
459    @property
460    def label(self):
461        return '%s: History' % self.context.name
462
463# Pages for students only
464
465class StudentBaseEditActionButton(ManageActionButton):
466    grok.order(1)
467    grok.context(IStudent)
468    grok.view(StudentBaseDisplayFormPage)
469    grok.require('waeup.handleStudent')
470    text = 'Change password'
471    target = 'bedit'
472
473class StudentBaseEditFormPage(WAeUPEditFormPage):
474    """ View to edit student base data by student
475    """
476    grok.context(IStudent)
477    grok.name('bedit')
478    grok.require('waeup.handleStudent')
479    form_fields = grok.AutoFields(IStudentBaseEdit).omit(
480        'student_id', 'reg_number')
481    grok.template('baseeditpage')
482    label = 'Change password'
483    title = 'Base Data'
484    pnav = 4
485
486    def update(self):
487        datepicker.need() # Enable jQuery datepicker in date fields.
488        super(StudentBaseEditFormPage, self).update()
489        self.wf_info = IWorkflowInfo(self.context)
490        return
491
492    @grok.action('Save')
493    def save(self, **data):
494        changed_fields = self.applyData(self.context, **data)
495        changed_fields = changed_fields.values()
496        fields_string = '+'.join(' + '.join(str(i) for i in b) for b in changed_fields)
497        self.context._p_changed = True
498        self.flash('Form has been saved.')
499        form = self.request.form
500        ob_class = self.__implemented__.__name__.replace('waeup.sirp.','')
501        if fields_string:
502            self.context.loggerInfo(ob_class, 'saved: % s' % fields_string)
503        if 'password' in fields_string:
504            IUserAccount(self.context).setPassword(form['form.password'])
505        return
506
507class StudentClearanceEditActionButton(ManageActionButton):
508    grok.order(1)
509    grok.context(IStudent)
510    grok.view(StudentClearanceDisplayFormPage)
511    grok.require('waeup.handleStudent')
512    text = 'Edit and submit'
513    target = 'cedit'
514
515class StudentClearanceEditFormPage(StudentClearanceManageFormPage):
516    """ View to edit student clearance data by student
517    """
518    grok.context(IStudent)
519    grok.name('cedit')
520    grok.require('waeup.handleStudent')
521    form_fields = grok.AutoFields(IStudentClearanceEdit).omit('clearance_locked')
522    #grok.template('clearanceeditpage')
523    label = 'Edit clerance data'
524    title = 'Clearance Data'
525    pnav = 4
526    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
Note: See TracBrowser for help on using the repository browser.