Ignore:
Timestamp:
14 Jun 2016, 01:38:12 (8 years ago)
Author:
uli
Message:

Merge changes from uli-scores-upload back into trunk.

Location:
main/waeup.kofa/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk

  • main/waeup.kofa/trunk/src/waeup/kofa

  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py

    r13908 r13935  
    1818"""UI components for students and related components.
    1919"""
    20 import sys
     20import csv
    2121import grok
    2222import pytz
     23import sys
     24from cStringIO import StringIO
     25from datetime import datetime
     26from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
    2327from urllib import urlencode
    24 from datetime import datetime
    25 from zope.event import notify
    26 from zope.i18n import translate
    2728from zope.catalog.interfaces import ICatalog
    2829from zope.component import queryUtility, getUtility, createObject
     30from zope.event import notify
     31from zope.formlib.textwidgets import BytesDisplayWidget
     32from zope.i18n import translate
    2933from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing
    30 from zope.formlib.textwidgets import BytesDisplayWidget
    3134from zope.security import checkPermission
    32 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
    33 from waeup.kofa.accesscodes import (
    34     invalidate_accesscode, get_access_code)
     35from waeup.kofa.accesscodes import invalidate_accesscode, get_access_code
    3536from waeup.kofa.accesscodes.workflow import USED
     37from waeup.kofa.browser.breadcrumbs import Breadcrumb
     38from waeup.kofa.browser.interfaces import ICaptchaManager
    3639from waeup.kofa.browser.layout import (
    3740    KofaPage, KofaEditFormPage, KofaAddFormPage, KofaDisplayFormPage,
    3841    NullValidator, jsaction, action, UtilityView)
    39 from waeup.kofa.browser.breadcrumbs import Breadcrumb
    4042from waeup.kofa.browser.pages import (
    4143    ContactAdminFormPage, ExportCSVView, doll_up, exports_not_allowed,
    4244    LocalRoleAssignmentUtilityView)
    43 from waeup.kofa.browser.interfaces import ICaptchaManager
    4445from waeup.kofa.hostels.hostel import NOT_OCCUPIED
    4546from waeup.kofa.interfaces import (
    4647    IKofaObject, IUserAccount, IExtFileStore, IPasswordValidator, IContactForm,
    47     IKofaUtils, IUniversity, IObjectHistory, academic_sessions, ICSVExporter,
    48     academic_sessions_vocab, IJobManager, IDataCenter, DOCLINK)
     48    IKofaUtils, IObjectHistory, academic_sessions, ICSVExporter,
     49    academic_sessions_vocab, IDataCenter, DOCLINK)
    4950from waeup.kofa.interfaces import MessageFactory as _
    50 from waeup.kofa.widgets.datewidget import (
    51     FriendlyDateWidget, FriendlyDateDisplayWidget,
    52     FriendlyDatetimeDisplayWidget)
    5351from waeup.kofa.mandates.mandate import PasswordMandate
    5452from waeup.kofa.university.interfaces import (
    5553    IDepartment, ICertificate, ICourse)
     54from waeup.kofa.university.certificate import (
     55    VirtualCertificateExportJobContainer)
     56from waeup.kofa.university.department import (
     57    VirtualDepartmentExportJobContainer)
    5658from waeup.kofa.university.faculty import VirtualFacultyExportJobContainer
    57 from waeup.kofa.university.department import VirtualDepartmentExportJobContainer
    5859from waeup.kofa.university.facultiescontainer import (
    59     VirtualFacultiesExportJobContainer, FacultiesContainer)
    60 from waeup.kofa.university.certificate import (
    61     VirtualCertificateExportJobContainer,)
     60    VirtualFacultiesExportJobContainer)
    6261from waeup.kofa.university.course import (
    6362    VirtualCourseExportJobContainer,)
    6463from waeup.kofa.university.vocabularies import course_levels
    6564from waeup.kofa.utils.batching import VirtualExportJobContainer
    66 from waeup.kofa.utils.helpers import get_current_principal, to_timezone, now
     65from waeup.kofa.utils.helpers import get_current_principal, now
     66from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
    6767from waeup.kofa.students.interfaces import (
    68     IStudentsContainer, IStudent,
    69     IUGStudentClearance,IPGStudentClearance,
     68    IStudentsContainer, IStudent, IUGStudentClearance, IPGStudentClearance,
    7069    IStudentPersonal, IStudentPersonalEdit, IStudentBase, IStudentStudyCourse,
    7170    IStudentStudyCourseTransfer, IStudentStudyCourseTranscript,
    72     IStudentAccommodation, IStudentStudyLevel,
    73     ICourseTicket, ICourseTicketAdd, IStudentPaymentsContainer,
    74     IStudentOnlinePayment, IStudentPreviousPayment, IStudentBalancePayment,
    75     IBedTicket, IStudentsUtils, IStudentRequestPW, IStudentTranscript
     71    IStudentAccommodation, IStudentStudyLevel, ICourseTicket, ICourseTicketAdd,
     72    IStudentPaymentsContainer, IStudentOnlinePayment, IStudentPreviousPayment,
     73    IStudentBalancePayment, IBedTicket, IStudentsUtils, IStudentRequestPW,
     74    IStudentTranscript
    7675    )
    7776from waeup.kofa.students.catalog import search, StudentQueryResultItem
    78 from waeup.kofa.students.studylevel import StudentStudyLevel, CourseTicket
    7977from waeup.kofa.students.vocabularies import StudyLevelSource
    80 from waeup.kofa.students.workflow import (CREATED, ADMITTED, PAID,
    81     CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED,
    82     GRADUATED, TRANSCRIPT, FORBIDDEN_POSTGRAD_TRANS)
    83 
    84 
    85 grok.context(IKofaObject) # Make IKofaObject the default context
     78from waeup.kofa.students.workflow import (
     79    ADMITTED, PAID, CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED,
     80    VALIDATED, GRADUATED, TRANSCRIPT, FORBIDDEN_POSTGRAD_TRANS
     81    )
     82
     83
     84grok.context(IKofaObject)  # Make IKofaObject the default context
     85
    8686
    8787# Save function used for save methods in pages
     
    9090    # Turn list of lists into single list
    9191    if changed_fields:
    92         changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
     92        changed_fields = reduce(lambda x, y: x+y, changed_fields.values())
    9393    # Inform catalog if certificate has changed
    9494    # (applyData does this only for the context)
     
    11991199    def label(self):
    12001200        # Here we know that the cookie has been set
    1201         lang = self.request.cookies.get('kofa.language')
    12021201        return _('${a}: Transcript Data', mapping = {
    12031202            'a':self.context.student.display_fullname})
     
    13971396    def render(self):
    13981397        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    1399         Term = translate(_('Term'), 'waeup.kofa', target_language=portal_language)
    14001398        Code = translate(_('Code'), 'waeup.kofa', target_language=portal_language)
    14011399        Title = translate(_('Title'), 'waeup.kofa', target_language=portal_language)
     
    31043102        return list(coursetickets)
    31053103
     3104    def _extract_uploadfile(self, uploadfile):
     3105        """Get a mapping of student-ids to scores.
     3106
     3107        The mapping is constructed by reading contents from `uploadfile`.
     3108
     3109        We expect uploadfile to be a regular CSV file with columns
     3110        ``student_id`` and ``score`` (other cols are ignored).
     3111        """
     3112        result = dict()
     3113        data = StringIO(uploadfile.read())  # ensure we have something seekable
     3114        reader = csv.DictReader(data)
     3115        for row in reader:
     3116            if not 'student_id' in row or not 'score' in row:
     3117                continue
     3118            result[row['student_id']] = row['score']
     3119        return result
     3120
    31063121    def update(self,  *args, **kw):
    31073122        form = self.request.form
    3108         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
     3123        ob_class = self.__implemented__.__name__.replace('waeup.kofa.', '')
    31093124        self.current_academic_session = grok.getSite()[
    31103125            'configuration'].current_academic_session
     
    31243139            self.redirect(self.url(self.context))
    31253140            return
    3126         if 'UPDATE' in form:
    3127             error = ''
    3128             if not editable_tickets:
    3129                 return
    3130             scores = form['scores']
    3131             sids = form['sids']
    3132             if isinstance(scores, basestring):
    3133                 scores = [scores]
    3134             if isinstance(sids, basestring):
    3135                 sids = [sids]
    3136             formvals = dict([(sids[i], scores[i]) for i in range(len(sids))])
    3137             for ticket in editable_tickets:
    3138                 score = ticket.score
    3139                 sid = ticket.student.student_id
    3140                 if formvals[sid] == '':
    3141                     score = None
    3142                 else:
    3143                     try:
    3144                         score = int(formvals[sid])
    3145                     except ValueError:
    3146                         error += '%s, ' % ticket.student.display_fullname
    3147                 if ticket.score != score:
    3148                     ticket.score = score
    3149                     ticket.student.__parent__.logger.info(
    3150                         '%s - %s %s/%s score updated (%s)' %
    3151                         (ob_class, ticket.student.student_id,
    3152                          ticket.level, ticket.code, score))
    3153                     #notify(grok.ObjectModifiedEvent(ticket))
    3154             if error:
    3155                 self.flash(_('Error: Score(s) of %s have not be updated. '
    3156                   'Only integers are allowed.' % error.strip(', ')),
    3157                   type="danger")
    3158         return
     3141        if not 'UPDATE' in form:
     3142            return
     3143        error = ''
     3144        if not editable_tickets:
     3145            return
     3146        formvals = dict(zip(form['sids'], form['scores']))
     3147        if form['uploadfile']:
     3148            try:
     3149                formvals = self._extract_uploadfile(form['uploadfile'])
     3150            except:
     3151                self.flash(
     3152                    _('Uploaded file contains illegal data. Ignored'),
     3153                    type="danger")
     3154        for ticket in editable_tickets:
     3155            score = ticket.score
     3156            sid = ticket.student.student_id
     3157            if sid not in formvals:
     3158                continue
     3159            if formvals[sid] == '':
     3160                score = None
     3161            else:
     3162                try:
     3163                    score = int(formvals[sid])
     3164                except ValueError:
     3165                    error += '%s, ' % ticket.student.display_fullname
     3166            if ticket.score != score:
     3167                ticket.score = score
     3168                ticket.student.__parent__.logger.info(
     3169                    '%s - %s %s/%s score updated (%s)' % (
     3170                        ob_class, ticket.student.student_id,
     3171                        ticket.level, ticket.code, score)
     3172                    )
     3173        if error:
     3174            self.flash(
     3175                _('Error: Score(s) of following students have not been '
     3176                    'updated (only integers are allowed): %s.' % error.strip(', ')),
     3177                type="danger")
     3178        return
     3179
    31593180
    31603181class DownloadScoresView(UtilityView, grok.View):
     
    31663187
    31673188    def update(self):
    3168         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
    31693189        self.current_academic_session = grok.getSite()[
    31703190            'configuration'].current_academic_session
     
    33503370            date_format = '%d/%m/%Y'
    33513371            try:
    3352                 dummy = datetime.strptime(payments_start, date_format)
    3353                 dummy = datetime.strptime(payments_end, date_format)
     3372                datetime.strptime(payments_start, date_format)
     3373                datetime.strptime(payments_end, date_format)
    33543374            except ValueError:
    33553375                self.flash(_('Payment dates do not match format d/m/Y.'),
Note: See TracChangeset for help on using the changeset viewer.