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

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

Fix tests.

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