## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## """UI components for students and related components. """ import sys import grok from datetime import datetime from zope.formlib.widget import CustomWidgetFactory from zope.formlib.form import setUpEditWidgets from zope.securitypolicy.interfaces import IPrincipalRoleManager from zope.traversing.browser import absoluteURL from zope.component import ( createObject,) from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState from reportlab.pdfgen import canvas from reportlab.lib.units import cm from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet from reportlab.platypus import (Frame, Paragraph, Image, Table, Spacer) from reportlab.platypus.tables import TableStyle from waeup.sirp.accesscodes import invalidate_accesscode, get_access_code from waeup.sirp.accesscodes.workflow import USED from waeup.sirp.browser import ( WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage) from waeup.sirp.browser.breadcrumbs import Breadcrumb from waeup.sirp.browser.layout import NullValidator from waeup.sirp.browser.pages import add_local_role, del_local_roles from waeup.sirp.browser.resources import datepicker, tabs, datatable from waeup.sirp.browser.viewlets import ( ManageActionButton, PrimaryNavTab, AddActionButton, ActionButton, PlainActionButton, ) from waeup.sirp.image.browser.widget import ( ThumbnailWidget, EncodingImageFileWidget, ) from waeup.sirp.image.image import createWAeUPImageFile from waeup.sirp.interfaces import IWAeUPObject, ILocalRolesAssignable from waeup.sirp.permissions import get_users_with_local_roles from waeup.sirp.university.interfaces import ICertificate from waeup.sirp.widgets.datewidget import ( FriendlyDateWidget, FriendlyDateDisplayWidget) from waeup.sirp.widgets.restwidget import ReSTDisplayWidget from waeup.sirp.widgets.objectwidget import ( WAeUPObjectWidget, WAeUPObjectDisplayWidget) from waeup.sirp.widgets.multilistwidget import ( MultiListWidget, MultiListDisplayWidget) from waeup.sirp.students.interfaces import ( IStudentsContainer, IStudent, IStudentClearance, IStudentPersonal, IStudentBase, IStudentStudyCourse, IStudentPayments, IStudentAccommodation, IStudentNavigation ) from waeup.sirp.students.student import ( Student, ) from waeup.sirp.students.catalog import search class StudentsTab(PrimaryNavTab): """Students tab in primary navigation. """ grok.context(IWAeUPObject) grok.order(3) grok.require('waeup.viewStudents') grok.template('primarynavtab') pnav = 4 tab_title = u'Students' @property def link_target(self): return self.view.application_url('students') class StudentsBreadcrumb(Breadcrumb): """A breadcrumb for the students container. """ grok.context(IStudentsContainer) title = u'Students' class SudyCourseBreadcrumb(Breadcrumb): """A breadcrumb for the student study course. """ grok.context(IStudentStudyCourse) title = u'Study Course' class PaymentsBreadcrumb(Breadcrumb): """A breadcrumb for the student payments folder. """ grok.context(IStudentPayments) title = u'Payments' class AccommodationBreadcrumb(Breadcrumb): """A breadcrumb for the student accommodation folder. """ grok.context(IStudentAccommodation) title = u'Accommodation' class StudentsContainerPage(WAeUPPage): """The standard view for student containers. """ grok.context(IStudentsContainer) grok.name('index') grok.require('waeup.viewStudents') grok.template('studentscontainerpage') pnav = 4 @property def title(self): return "Students" @property def label(self): return self.title def update(self, *args, **kw): datatable.need() form = self.request.form self.hitlist = [] if 'searchterm' in form and form['searchterm']: self.searchterm = form['searchterm'] self.searchtype = form['searchtype'] elif 'old_searchterm' in form: self.searchterm = form['old_searchterm'] self.searchtype = form['old_searchtype'] else: if 'search' in form: self.flash('Empty search string.') return self.hitlist = search(query=self.searchterm, searchtype=self.searchtype, view=self) if not self.hitlist: self.flash('No student found.') return class StudentsContainerManageActionButton(ManageActionButton): grok.order(1) grok.context(IStudentsContainer) grok.view(StudentsContainerPage) grok.require('waeup.manageStudents') text = 'Manage students' class StudentsContainerManagePage(WAeUPPage): """The manage page for student containers. """ grok.context(IStudentsContainer) grok.name('manage') grok.require('waeup.manageStudents') grok.template('studentscontainermanagepage') pnav = 4 @property def title(self): return "Students" @property def label(self): return self.title def update(self, *args, **kw): datatable.need() form = self.request.form self.hitlist = [] if 'searchterm' in form and form['searchterm']: self.searchterm = form['searchterm'] self.searchtype = form['searchtype'] elif 'old_searchterm' in form: self.searchterm = form['old_searchterm'] self.searchtype = form['old_searchtype'] else: if 'search' in form: self.flash('Empty search string.') return #import pdb; pdb.set_trace() if not 'entries' in form: self.hitlist = search(query=self.searchterm, searchtype=self.searchtype, view=self) if not self.hitlist: self.flash('No student found.') return entries = form['entries'] if isinstance(entries, basestring): entries = [entries] deleted = [] for entry in entries: if 'remove' in form: del self.context[entry] deleted.append(entry) self.hitlist = search(query=self.searchterm, searchtype=self.searchtype, view=self) if len(deleted): self.flash('Successfully removed: %s' % ', '.join(deleted)) return class StudentsContainerAddActionButton(AddActionButton): grok.order(1) grok.context(IStudentsContainer) grok.view(StudentsContainerManagePage) grok.require('waeup.manageStudents') text = 'Add student' target = 'addstudent' class StudentAddFormPage(WAeUPAddFormPage): """Add-form to add a student. """ grok.context(IStudentsContainer) grok.require('waeup.manageStudents') grok.name('addstudent') grok.template('studentaddpage') form_fields = grok.AutoFields(IStudent) title = 'Students' label = 'Add student' pnav = 4 @grok.action('Create student record') def addStudent(self, **data): student_id = self.request.form.get('form.student_id') student = createObject(u'waeup.Student') student.student_id = student_id self.applyData(student, **data) #import pdb; pdb.set_trace() try: self.context.addStudent(student) except KeyError: self.flash('The student id chosen already exists.') return self.flash('Student record created.') self.redirect(self.url(self.context[student_id], 'index')) return class StudentBaseDisplayFormPage(WAeUPDisplayFormPage): """ Page to display student base data """ grok.context(IStudent) grok.name('index') grok.require('waeup.viewStudents') grok.template('studentpage') form_fields = grok.AutoFields(IStudentBase) pnav = 4 title = 'Base Data' @property def label(self): return '%s: Base Data' % self.context.name class StudentBaseManageActionButton(ManageActionButton): grok.order(1) grok.context(IStudent) grok.view(StudentBaseDisplayFormPage) grok.require('waeup.manageStudents') text = 'Edit' target = 'edit_base' class StudentBaseManageFormPage(WAeUPEditFormPage): """ View to edit student base data """ grok.context(IStudent) grok.name('edit_base') grok.require('waeup.manageStudents') form_fields = grok.AutoFields(IStudentBase).omit('student_id') grok.template('studentbasemanagepage') label = 'Edit base data' title = 'Base Data' pnav = 4 def update(self): datepicker.need() # Enable jQuery datepicker in date fields. super(StudentBaseManageFormPage, self).update() self.wf_info = IWorkflowInfo(self.context) return def getTransitions(self): """Return a list of dicts of allowed transition ids and titles. Each list entry provides keys ``name`` and ``title`` for internal name and (human readable) title of a single transition. """ allowed_transitions = self.wf_info.getManualTransitions() return [dict(name='', title='No transition')] +[ dict(name=x, title=y) for x, y in allowed_transitions] @grok.action('Save') def save(self, **data): changed_fields = self.applyData(self.context, **data) changed_fields = changed_fields.values() fields_string = '+'.join(' + '.join(str(i) for i in b) for b in changed_fields) self.context._p_changed = True form = self.request.form if form.has_key('transition') and form['transition']: transition_id = form['transition'] self.wf_info.fireTransition(transition_id) self.flash('Form has been saved.') ob_class = self.__implemented__.__name__.replace('waeup.sirp.','') if fields_string: self.context.loggerInfo(ob_class, 'saved: % s' % fields_string) return class StudentClearanceDisplayFormPage(WAeUPDisplayFormPage): """ Page to display student clearance data """ grok.context(IStudent) grok.name('view_clearance') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentClearance) title = 'Clearance Data' pnav = 4 @property def label(self): return '%s: Clearance Data' % self.context.name class StudentClearanceManageActionButton(ManageActionButton): grok.order(1) grok.context(IStudent) grok.view(StudentClearanceDisplayFormPage) grok.require('waeup.manageStudents') text = 'Edit' target = 'edit_clearance' class StudentClearanceManageFormPage(WAeUPEditFormPage): """ Page to edit student clearance data """ grok.context(IStudent) grok.name('edit_clearance') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentClearance) label = 'Edit clearance data' title = 'Clearance Data' pnav = 4 class StudentPersonalDisplayFormPage(WAeUPDisplayFormPage): """ Page to display student personal data """ grok.context(IStudent) grok.name('view_personal') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentPersonal) title = 'Personal Data' pnav = 4 @property def label(self): return '%s: Personal Data' % self.context.name class StudentPersonalManageActionButton(ManageActionButton): grok.order(1) grok.context(IStudent) grok.view(StudentPersonalDisplayFormPage) grok.require('waeup.manageStudents') text = 'Edit' target = 'edit_personal' class StudentPersonalManageFormPage(WAeUPEditFormPage): """ Page to edit student clearance data """ grok.context(IStudent) grok.name('edit_personal') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentPersonal) label = 'Edit personal data' title = 'Personal Data' pnav = 4 class StudyCourseDisplayFormPage(WAeUPDisplayFormPage): """ Page to display the student study course data """ grok.context(IStudentStudyCourse) grok.name('index') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentStudyCourse) #grok.template('studycoursepage') title = 'Study Course' pnav = 4 @property def label(self): return '%s: Study Course' % self.context.__parent__.name class PaymentsDisplayFormPage(WAeUPDisplayFormPage): """ Page to display the student payments """ grok.context(IStudentPayments) grok.name('index') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentPayments) #grok.template('paymentspage') title = 'Payments' pnav = 4 @property def label(self): return '%s: Payments' % self.context.__parent__.name class AccommodationDisplayFormPage(WAeUPDisplayFormPage): """ Page to display the student accommodation data """ grok.context(IStudentAccommodation) grok.name('index') grok.require('waeup.viewStudents') form_fields = grok.AutoFields(IStudentAccommodation) #grok.template('accommodationpage') title = 'Accommodation' pnav = 4 @property def label(self): return '%s: Accommodation Data' % self.context.__parent__.name class StudentHistoryPage(WAeUPPage): """ Page to display student clearance data """ grok.context(IStudent) grok.name('history') grok.require('waeup.viewStudents') grok.template('studenthistory') title = 'History' pnav = 4 @property def label(self): return '%s: History' % self.context.name