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

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

Use the setPassword method when saving a password.

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