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

Last change on this file since 6638 was 6638, checked in by Henrik Bettermann, 13 years ago

Add studentbasemanagepage which allows performing transitions. Add tests.

  • Property svn:keywords set to Id
File size: 15.8 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, LeftSidebarLink,
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 IWAeUPObject, ILocalRolesAssignable
55from waeup.sirp.permissions import get_users_with_local_roles
56from waeup.sirp.university.interfaces import ICertificate
57from waeup.sirp.widgets.datewidget import (
58    FriendlyDateWidget, FriendlyDateDisplayWidget)
59from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
60from waeup.sirp.widgets.objectwidget import (
61    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
62from waeup.sirp.widgets.multilistwidget import (
63    MultiListWidget, MultiListDisplayWidget)
64from waeup.sirp.students.interfaces import (
65    IStudentsContainer, IStudent, IStudentClearance,
66    IStudentPersonal, IStudentBase, IStudentStudyCourse,
67    IStudentPayments, IStudentAccommodation
68    )
69from waeup.sirp.students.student import (
70    Student,
71    )
72from waeup.sirp.students.catalog import search
73
74class StudentsTab(PrimaryNavTab):
75    """Students tab in primary navigation.
76    """
77
78    grok.context(IWAeUPObject)
79    grok.order(3)
80    grok.require('waeup.viewStudents')
81    grok.template('primarynavtab')
82
83    pnav = 4
84    tab_title = u'Students'
85
86    @property
87    def link_target(self):
88        return self.view.application_url('students')
89
90class StudentsBreadcrumb(Breadcrumb):
91    """A breadcrumb for the students container.
92    """
93    grok.context(IStudentsContainer)
94    title = u'Students'
95
96class SudyCourseBreadcrumb(Breadcrumb):
97    """A breadcrumb for the student study course.
98    """
99    grok.context(IStudentStudyCourse)
100    title = u'Study Course'
101
102class PaymentsBreadcrumb(Breadcrumb):
103    """A breadcrumb for the student payments folder.
104    """
105    grok.context(IStudentPayments)
106    title = u'Payments'
107
108class AccommodationBreadcrumb(Breadcrumb):
109    """A breadcrumb for the student accommodation folder.
110    """
111    grok.context(IStudentAccommodation)
112    title = u'Accommodation'
113
114class StudentsContainerPage(WAeUPPage):
115    """The standard view for student containers.
116    """
117    grok.context(IStudentsContainer)
118    grok.name('index')
119    grok.require('waeup.viewStudents')
120    grok.template('studentscontainerpage')
121
122    @property
123    def title(self):
124        return "Students"
125
126    @property
127    def label(self):
128        return self.title
129
130    def update(self, *args, **kw):
131        datatable.need()
132        form = self.request.form
133        self.hitlist = []
134        if 'searchterm' in form and form['searchterm']:
135            self.searchterm = form['searchterm']
136            self.searchtype = form['searchtype']
137        elif 'old_searchterm' in form:
138            self.searchterm = form['old_searchterm']
139            self.searchtype = form['old_searchtype']
140        else:
141            if 'search' in form:
142                self.flash('Empty search string.')
143            return
144        self.hitlist = search(query=self.searchterm,
145            searchtype=self.searchtype, view=self)
146        if not self.hitlist:
147            self.flash('No student found.')
148        return
149
150class StudentsContainerManageActionButton(ManageActionButton):
151    grok.order(1)
152    grok.context(IStudentsContainer)
153    grok.view(StudentsContainerPage)
154    grok.require('waeup.manageStudents')
155    text = 'Manage students'
156
157
158class StudentsContainerManagePage(WAeUPPage):
159    """The manage page for student containers.
160    """
161    grok.context(IStudentsContainer)
162    grok.name('manage')
163    grok.require('waeup.manageStudents')
164    grok.template('studentscontainermanagepage')
165
166    @property
167    def title(self):
168        return "Students"
169
170    @property
171    def label(self):
172        return self.title
173
174    def update(self, *args, **kw):
175        datatable.need()
176        form = self.request.form
177        self.hitlist = []
178        if 'searchterm' in form and form['searchterm']:
179            self.searchterm = form['searchterm']
180            self.searchtype = form['searchtype']
181        elif 'old_searchterm' in form:
182            self.searchterm = form['old_searchterm']
183            self.searchtype = form['old_searchtype']
184        else:
185            if 'search' in form:
186                self.flash('Empty search string.')
187            return
188        #import pdb; pdb.set_trace()
189        if not 'entries' in form:
190            self.hitlist = search(query=self.searchterm,
191                searchtype=self.searchtype, view=self)
192            if not self.hitlist:
193                self.flash('No student found.')
194            return
195        entries = form['entries']
196        if isinstance(entries, basestring):
197            entries = [entries]
198        deleted = []
199        for entry in entries:
200            if 'remove' in form:
201                del self.context[entry]
202                deleted.append(entry)
203        self.hitlist = search(query=self.searchterm,
204            searchtype=self.searchtype, view=self)
205        if len(deleted):
206            self.flash('Successfully removed: %s' % ', '.join(deleted))
207        return
208
209class StudentsContainerAddActionButton(AddActionButton):
210    grok.order(1)
211    grok.context(IStudentsContainer)
212    grok.view(StudentsContainerManagePage)
213    grok.require('waeup.manageStudents')
214    text = 'Add student'
215    target = 'addstudent'
216
217class StudentAddFormPage(WAeUPAddFormPage):
218    """Add-form to add a student.
219    """
220    grok.context(IStudentsContainer)
221    grok.require('waeup.manageStudents')
222    grok.name('addstudent')
223    grok.template('studentaddpage')
224    form_fields = grok.AutoFields(IStudent)
225    title = 'Students'
226    label = 'Add student'
227
228    @grok.action('Create student record')
229    def addStudent(self, **data):
230        student_id = self.request.form.get('form.student_id')
231        student = createObject(u'waeup.Student')
232        student.student_id = student_id
233        self.applyData(student, **data)
234        #import pdb; pdb.set_trace()
235        try:
236            self.context.addStudent(student)
237        except KeyError:
238            self.flash('The student id chosen already exists.')
239            return
240        self.flash('Student record created.')
241        self.redirect(self.url(self.context[student_id], 'index'))
242        return
243
244class StudentBaseDisplayFormPage(WAeUPDisplayFormPage):
245    """ Page to display student base data
246    """
247    grok.context(IStudent)
248    grok.name('index')
249    grok.require('waeup.viewStudents')
250    grok.template('studentpage')
251    form_fields = grok.AutoFields(IStudentBase)
252
253    @property
254    def title(self):
255        return 'Student: %s' % self.context.name
256
257    @property
258    def label(self):
259        return '%s: Base Data' % self.context.name
260
261class StudentBaseManageActionButton(ManageActionButton):
262    grok.order(1)
263    grok.context(IStudent)
264    grok.view(StudentBaseDisplayFormPage)
265    grok.require('waeup.manageStudents')
266    text = 'Edit'
267    target = 'edit_base'
268
269class StudentClearanceViewActionButton(PlainActionButton):
270    grok.order(2)
271    grok.context(IStudent)
272    grok.view(StudentBaseDisplayFormPage)
273    grok.require('waeup.viewStudents')
274    text = 'Clearance Data'
275    target = 'view_clearance'
276
277class StudentPersonalViewActionButton(PlainActionButton):
278    grok.order(3)
279    grok.context(IStudent)
280    grok.view(StudentBaseDisplayFormPage)
281    grok.require('waeup.viewStudents')
282    text = 'Personal Data'
283    target = 'view_personal'
284
285class StudyCourseViewActionButton(PlainActionButton):
286    grok.order(4)
287    grok.context(IStudent)
288    grok.view(StudentBaseDisplayFormPage)
289    grok.require('waeup.viewStudents')
290    text = 'Study Course'
291    target = 'studycourse'
292
293class PaymentsViewActionButton(PlainActionButton):
294    grok.order(5)
295    grok.context(IStudent)
296    grok.view(StudentBaseDisplayFormPage)
297    grok.require('waeup.viewStudents')
298    text = 'Payments'
299    target = 'payments'
300
301class AccommodationViewActionButton(PlainActionButton):
302    grok.order(6)
303    grok.context(IStudent)
304    grok.view(StudentBaseDisplayFormPage)
305    grok.require('waeup.viewStudents')
306    text = 'Accommodation'
307    target = 'accommodation'
308
309class HistoryViewActionButton(PlainActionButton):
310    grok.order(7)
311    grok.context(IStudent)
312    grok.view(StudentBaseDisplayFormPage)
313    grok.require('waeup.viewStudents')
314    text = 'History'
315    target = 'history'
316
317class StudentBaseManageFormPage(WAeUPEditFormPage):
318    """ View to edit student base data
319    """
320    grok.context(IStudent)
321    grok.name('edit_base')
322    grok.require('waeup.manageStudents')
323    form_fields = grok.AutoFields(IStudentBase).omit('student_id')
324    grok.template('studentbasemanagepage')
325    label = 'Edit base data'
326
327    def update(self):
328        datepicker.need() # Enable jQuery datepicker in date fields.
329        super(StudentBaseManageFormPage, self).update()
330        self.wf_info = IWorkflowInfo(self.context)
331        return
332
333    @property
334    def title(self):
335        return 'Student: %s' % self.context.name
336
337    def getTransitions(self):
338        """Return a list of dicts of allowed transition ids and titles.
339
340        Each list entry provides keys ``name`` and ``title`` for
341        internal name and (human readable) title of a single
342        transition.
343        """
344        allowed_transitions = self.wf_info.getManualTransitions()
345        return [dict(name='', title='No transition')] +[
346            dict(name=x, title=y) for x, y in allowed_transitions]
347
348    @grok.action('Save')
349    def save(self, **data):
350        changed_fields = self.applyData(self.context, **data)
351        changed_fields = changed_fields.values()
352        fields_string = '+'.join(' + '.join(str(i) for i in b) for b in changed_fields)
353        self.context._p_changed = True
354        form = self.request.form
355        if form.has_key('transition') and form['transition']:
356            transition_id = form['transition']
357            self.wf_info.fireTransition(transition_id)
358        self.flash('Form has been saved.')
359        ob_class = self.__implemented__.__name__.replace('waeup.sirp.','')
360        self.context.loggerInfo(ob_class, 'saved: % s' % fields_string)
361        return
362
363class StudentClearanceDisplayFormPage(WAeUPDisplayFormPage):
364    """ Page to display student clearance data
365    """
366    grok.context(IStudent)
367    grok.name('view_clearance')
368    grok.require('waeup.viewStudents')
369    form_fields = grok.AutoFields(IStudentClearance)
370
371    @property
372    def title(self):
373        return 'Student: %s' % self.context.name
374
375    @property
376    def label(self):
377        return '%s: Clearance Data' % self.context.name
378
379class StudentClearanceManageActionButton(ManageActionButton):
380    grok.order(1)
381    grok.context(IStudent)
382    grok.view(StudentClearanceDisplayFormPage)
383    grok.require('waeup.manageStudents')
384    text = 'Edit'
385    target = 'edit_clearance'
386
387class StudentClearanceManageFormPage(WAeUPEditFormPage):
388    """ Page to edit student clearance data
389    """
390    grok.context(IStudent)
391    grok.name('edit_clearance')
392    grok.require('waeup.viewStudents')
393    form_fields = grok.AutoFields(IStudentClearance)
394    label = 'Edit clearance data'
395
396    @property
397    def title(self):
398        return 'Student: %s' % self.context.name
399
400class StudentPersonalDisplayFormPage(WAeUPDisplayFormPage):
401    """ Page to display student personal data
402    """
403    grok.context(IStudent)
404    grok.name('view_personal')
405    grok.require('waeup.viewStudents')
406    form_fields = grok.AutoFields(IStudentPersonal)
407
408    @property
409    def title(self):
410        return 'Student: %s' % self.context.name
411
412    @property
413    def label(self):
414        return '%s: Personal Data' % self.context.name
415
416class StudentPersonalManageActionButton(ManageActionButton):
417    grok.order(1)
418    grok.context(IStudent)
419    grok.view(StudentPersonalDisplayFormPage)
420    grok.require('waeup.manageStudents')
421    text = 'Edit'
422    target = 'edit_personal'
423
424class StudentPersonalManageFormPage(WAeUPEditFormPage):
425    """ Page to edit student clearance data
426    """
427    grok.context(IStudent)
428    grok.name('edit_personal')
429    grok.require('waeup.viewStudents')
430    form_fields = grok.AutoFields(IStudentPersonal)
431    label = 'Edit personal data'
432
433    @property
434    def title(self):
435        return 'Student: %s' % self.context.name
436
437class StudyCourseDisplayFormPage(WAeUPDisplayFormPage):
438    """ Page to display the student study course data
439    """
440    grok.context(IStudentStudyCourse)
441    grok.name('index')
442    grok.require('waeup.viewStudents')
443    form_fields = grok.AutoFields(IStudentStudyCourse)
444    #grok.template('studycoursepage')
445
446    @property
447    def title(self):
448        return 'Student: %s' % self.context.__parent__.name
449
450    @property
451    def label(self):
452        return '%s: Study Course Data' % self.context.__parent__.name
453
454class PaymentsDisplayFormPage(WAeUPDisplayFormPage):
455    """ Page to display the student payments
456    """
457    grok.context(IStudentPayments)
458    grok.name('index')
459    grok.require('waeup.viewStudents')
460    form_fields = grok.AutoFields(IStudentPayments)
461    #grok.template('paymentspage')
462
463    @property
464    def title(self):
465        return 'Student: %s' % self.context.__parent__.name
466
467    @property
468    def label(self):
469        return '%s: Payments' % self.context.__parent__.name
470
471class AccommodationDisplayFormPage(WAeUPDisplayFormPage):
472    """ Page to display the student accommodation data
473    """
474    grok.context(IStudentAccommodation)
475    grok.name('index')
476    grok.require('waeup.viewStudents')
477    form_fields = grok.AutoFields(IStudentAccommodation)
478    #grok.template('accommodationpage')
479
480    @property
481    def title(self):
482        return 'Student: %s' % self.context.__parent__.name
483
484    @property
485    def label(self):
486        return '%s: Accommodation Data' % self.context.__parent__.name
487
488class StudentHistoryPage(WAeUPPage):
489    """ Page to display student clearance data
490    """
491    grok.context(IStudent)
492    grok.name('history')
493    grok.require('waeup.viewStudents')
494    grok.template('studenthistory')
495
496    @property
497    def title(self):
498        return 'Student: %s' % self.context.name
499
500    @property
501    def label(self):
502        return '%s: History' % self.context.name
Note: See TracBrowser for help on using the repository browser.