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

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

Don't add log message when no attribute has been changed, but log all transitions.

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