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

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

Add permission waeup.handleStudent and local role StudentRecordOwner? for students.

Change permission name from waeup.viewStudents to waeup.viewStudent. This permission can be applied to one student (by assigning the role StudentRecordOwner?) in contrast to waeup.manageStudents which will only be applicable to a group of students.

  • Property svn:keywords set to Id
File size: 14.6 KB
RevLine 
[6621]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
[6622]26from zope.component import (
27    createObject,)
[6621]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 (
[6642]47    ManageActionButton, PrimaryNavTab,
[6635]48    AddActionButton, ActionButton, PlainActionButton,
[6621]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 (
[6631]65    IStudentsContainer, IStudent, IStudentClearance,
[6635]66    IStudentPersonal, IStudentBase, IStudentStudyCourse,
[6642]67    IStudentPayments, IStudentAccommodation, IStudentNavigation
[6621]68    )
[6651]69from waeup.sirp.students.student import Student
[6626]70from waeup.sirp.students.catalog import search
[6621]71
72class StudentsTab(PrimaryNavTab):
73    """Students tab in primary navigation.
74    """
75
76    grok.context(IWAeUPObject)
77    grok.order(3)
[6660]78    grok.require('waeup.viewStudent')
[6621]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
[6629]88class StudentsBreadcrumb(Breadcrumb):
89    """A breadcrumb for the students container.
90    """
91    grok.context(IStudentsContainer)
92    title = u'Students'
93
[6635]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
[6626]112class StudentsContainerPage(WAeUPPage):
113    """The standard view for student containers.
[6621]114    """
115    grok.context(IStudentsContainer)
116    grok.name('index')
[6660]117    grok.require('waeup.viewStudent')
[6621]118    grok.template('studentscontainerpage')
[6654]119    label = 'Student Section'
120    title = 'Students'
[6642]121    pnav = 4
[6621]122
[6626]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):
[6622]144    grok.order(1)
145    grok.context(IStudentsContainer)
146    grok.view(StudentsContainerPage)
147    grok.require('waeup.manageStudents')
[6647]148    text = 'Manage student section'
[6622]149
[6626]150
151class StudentsContainerManagePage(WAeUPPage):
152    """The manage page for student containers.
[6622]153    """
154    grok.context(IStudentsContainer)
155    grok.name('manage')
156    grok.require('waeup.manageStudents')
[6626]157    grok.template('studentscontainermanagepage')
[6642]158    pnav = 4
[6647]159    title = 'Manage student section'
[6622]160
161    @property
162    def label(self):
163        return self.title
164
[6626]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))
[6622]197        return
198
[6626]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
[6622]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'
[6642]217    pnav = 4
[6622]218
219    @grok.action('Create student record')
220    def addStudent(self, **data):
221        student = createObject(u'waeup.Student')
222        self.applyData(student, **data)
[6652]223        self.context.addStudent(student)
[6626]224        self.flash('Student record created.')
[6651]225        self.redirect(self.url(self.context[student.student_id], 'index'))
[6622]226        return
227
[6631]228class StudentBaseDisplayFormPage(WAeUPDisplayFormPage):
229    """ Page to display student base data
230    """
[6622]231    grok.context(IStudent)
232    grok.name('index')
[6660]233    grok.require('waeup.viewStudent')
[6635]234    grok.template('studentpage')
[6631]235    form_fields = grok.AutoFields(IStudentBase)
[6642]236    pnav = 4
237    title = 'Base Data'
[6622]238
239    @property
240    def label(self):
[6631]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')
[6635]248    text = 'Edit'
[6631]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')
[6638]258    grok.template('studentbasemanagepage')
[6631]259    label = 'Edit base data'
[6642]260    title = 'Base Data'
261    pnav = 4
[6631]262
[6638]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.','')
[6644]292        if fields_string:
293            self.context.loggerInfo(ob_class, 'saved: % s' % fields_string)
[6638]294        return
295
[6631]296class StudentClearanceDisplayFormPage(WAeUPDisplayFormPage):
297    """ Page to display student clearance data
298    """
299    grok.context(IStudent)
300    grok.name('view_clearance')
[6660]301    grok.require('waeup.viewStudent')
[6631]302    form_fields = grok.AutoFields(IStudentClearance)
[6650]303    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
[6642]304    title = 'Clearance Data'
305    pnav = 4
[6631]306
307    @property
308    def label(self):
309        return '%s: Clearance Data' % self.context.name
310
311class StudentClearanceManageActionButton(ManageActionButton):
312    grok.order(1)
313    grok.context(IStudent)
314    grok.view(StudentClearanceDisplayFormPage)
315    grok.require('waeup.manageStudents')
[6635]316    text = 'Edit'
[6631]317    target = 'edit_clearance'
318
319class StudentClearanceManageFormPage(WAeUPEditFormPage):
320    """ Page to edit student clearance data
321    """
322    grok.context(IStudent)
323    grok.name('edit_clearance')
[6649]324    grok.require('waeup.manageStudents')
[6631]325    form_fields = grok.AutoFields(IStudentClearance)
326    label = 'Edit clearance data'
[6642]327    title = 'Clearance Data'
328    pnav = 4
[6631]329
[6650]330    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
331
332    def update(self):
333        datepicker.need() # Enable jQuery datepicker in date fields.
334        return super(StudentClearanceManageFormPage, self).update()
335
[6631]336class StudentPersonalDisplayFormPage(WAeUPDisplayFormPage):
337    """ Page to display student personal data
338    """
339    grok.context(IStudent)
340    grok.name('view_personal')
[6660]341    grok.require('waeup.viewStudent')
[6631]342    form_fields = grok.AutoFields(IStudentPersonal)
[6642]343    title = 'Personal Data'
344    pnav = 4
[6631]345
346    @property
347    def label(self):
348        return '%s: Personal Data' % self.context.name
349
350class StudentPersonalManageActionButton(ManageActionButton):
351    grok.order(1)
352    grok.context(IStudent)
353    grok.view(StudentPersonalDisplayFormPage)
354    grok.require('waeup.manageStudents')
[6635]355    text = 'Edit'
[6631]356    target = 'edit_personal'
357
358class StudentPersonalManageFormPage(WAeUPEditFormPage):
359    """ Page to edit student clearance data
360    """
361    grok.context(IStudent)
362    grok.name('edit_personal')
[6660]363    grok.require('waeup.viewStudent')
[6631]364    form_fields = grok.AutoFields(IStudentPersonal)
365    label = 'Edit personal data'
[6642]366    title = 'Personal Data'
367    pnav = 4
[6631]368
[6635]369class StudyCourseDisplayFormPage(WAeUPDisplayFormPage):
370    """ Page to display the student study course data
371    """
372    grok.context(IStudentStudyCourse)
373    grok.name('index')
[6660]374    grok.require('waeup.viewStudent')
[6635]375    form_fields = grok.AutoFields(IStudentStudyCourse)
376    #grok.template('studycoursepage')
[6642]377    title = 'Study Course'
378    pnav = 4
[6635]379
380    @property
381    def label(self):
[6642]382        return '%s: Study Course' % self.context.__parent__.name
[6635]383
[6649]384class StudyCourseManageActionButton(ManageActionButton):
385    grok.order(1)
386    grok.context(IStudentStudyCourse)
387    grok.view(StudyCourseDisplayFormPage)
388    grok.require('waeup.manageStudents')
389    text = 'Edit'
390    target = 'edit'
391
392class StudyCourseManageFormPage(WAeUPEditFormPage):
393    """ Page to edit the student study course data
394    """
395    grok.context(IStudentStudyCourse)
396    grok.name('edit')
397    grok.require('waeup.manageStudents')
398    form_fields = grok.AutoFields(IStudentStudyCourse)
399    label = 'Edit clearance data'
400    title = 'Study Course'
401    label = 'Edit study course'
402    pnav = 4
403
[6635]404class PaymentsDisplayFormPage(WAeUPDisplayFormPage):
405    """ Page to display the student payments
406    """
407    grok.context(IStudentPayments)
408    grok.name('index')
[6660]409    grok.require('waeup.viewStudent')
[6635]410    form_fields = grok.AutoFields(IStudentPayments)
411    #grok.template('paymentspage')
[6642]412    title = 'Payments'
413    pnav = 4
[6635]414
415    @property
416    def label(self):
417        return '%s: Payments' % self.context.__parent__.name
418
419class AccommodationDisplayFormPage(WAeUPDisplayFormPage):
420    """ Page to display the student accommodation data
421    """
422    grok.context(IStudentAccommodation)
423    grok.name('index')
[6660]424    grok.require('waeup.viewStudent')
[6635]425    form_fields = grok.AutoFields(IStudentAccommodation)
426    #grok.template('accommodationpage')
[6642]427    title = 'Accommodation'
428    pnav = 4
[6635]429
430    @property
431    def label(self):
432        return '%s: Accommodation Data' % self.context.__parent__.name
[6637]433
434class StudentHistoryPage(WAeUPPage):
435    """ Page to display student clearance data
436    """
437    grok.context(IStudent)
438    grok.name('history')
[6660]439    grok.require('waeup.viewStudent')
[6637]440    grok.template('studenthistory')
[6642]441    title = 'History'
442    pnav = 4
[6637]443
444    @property
445    def label(self):
446        return '%s: History' % self.context.name
Note: See TracBrowser for help on using the repository browser.