Ignore:
Timestamp:
24 May 2019, 09:11:40 (6 years ago)
Author:
Henrik Bettermann
Message:

Implement course result validation workflow for lecturers.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/students
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py

    r15419 r15422  
    3333from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing
    3434from zope.security import checkPermission
     35from zope.securitypolicy.interfaces import IPrincipalRoleManager
    3536from waeup.kofa.accesscodes import invalidate_accesscode, get_access_code
    3637from waeup.kofa.accesscodes.workflow import USED
     
    33793380        return
    33803381
    3381 
    33823382class EditScoresPage(KofaPage):
    33833383    """Page that allows to edit batches of scores.
     
    34643464        return True
    34653465
     3466    def _validate_results(self, form):
     3467        ob_class = self.__implemented__.__name__.replace('waeup.kofa.', '')
     3468        user = get_current_principal()
     3469        if user is None:
     3470            usertitle = 'system'
     3471        else:
     3472            usertitle = getattr(user, 'public_name', None)
     3473            if not usertitle:
     3474                usertitle = user.title
     3475        self.context.results_validated_by = usertitle
     3476        self.context.results_validation_date = datetime.utcnow()
     3477        self.context.results_validation_session = self.current_academic_session
     3478        return
     3479
     3480    def _results_editable(self, results_validation_session,
     3481                         current_academic_session):
     3482        user = get_current_principal()
     3483        prm = IPrincipalRoleManager(self.context)
     3484        roles = [x[0] for x in prm.getRolesForPrincipal(user.id)]
     3485        if 'waeup.local.LocalStudentsManager' in roles:
     3486            return True
     3487        if results_validation_session \
     3488            and results_validation_session >= current_academic_session:
     3489            return False
     3490        return True
     3491
    34663492    def update(self,  *args, **kw):
    34673493        form = self.request.form
     
    34763502            self.redirect(self.url(self.context))
    34773503            return
     3504        vs = self.context.results_validation_session
     3505        if not self._results_editable(vs, self.current_academic_session):
     3506            self.flash(
     3507                _('Course results have already been '
     3508                  'validated and can no longer be changed.'),
     3509                type="danger")
     3510            self.redirect(self.url(self.context))
     3511            return
    34783512        self.session_title = academic_sessions_vocab.getTerm(
    34793513            self.current_academic_session).title
     
    34853519        self.editable_tickets = [
    34863520            ticket for ticket in self.tickets if ticket.editable_by_lecturer]
    3487         if not 'UPDATE_TABLE' in form and not 'UPDATE_FILE' in form:
     3521        if not 'UPDATE_TABLE' in form and not 'UPDATE_FILE' in form\
     3522            and not 'VALIDATE_RESULTS' in form:
     3523            return
     3524        if 'VALIDATE_RESULTS' in form:
     3525            if vs and vs >= self.current_academic_session:
     3526                self.flash(
     3527                    _('Course results have already been validated.'),
     3528                    type="danger")
     3529                return
     3530            self._validate_results(form)
     3531            self.flash(_('You successfully validated the course results.'))
     3532            self.redirect(self.url(self.context))
    34883533            return
    34893534        if not self.editable_tickets:
     
    34943539        return
    34953540
    3496 
    34973541class DownloadScoresView(UtilityView, grok.View):
    34983542    """View that exports scores.
     
    35013545    grok.require('waeup.editScores')
    35023546    grok.name('download_scores')
     3547
     3548    def _results_editable(self, results_validation_session,
     3549                         current_academic_session):
     3550        user = get_current_principal()
     3551        prm = IPrincipalRoleManager(self.context)
     3552        roles = [x[0] for x in prm.getRolesForPrincipal(user.id)]
     3553        if 'waeup.local.LocalStudentsManager' in roles:
     3554            return True
     3555        if results_validation_session \
     3556            and results_validation_session >= current_academic_session:
     3557            return False
     3558        return True
    35033559
    35043560    def update(self):
     
    35113567        if not self.current_academic_session:
    35123568            self.flash(_('Current academic session not set.'), type="warning")
     3569            self.redirect(self.url(self.context))
     3570            return
     3571        vs = self.context.results_validation_session
     3572        if not self._results_editable(vs, self.current_academic_session):
     3573            self.flash(
     3574                _('Course results have already been '
     3575                  'validated and can no longer be changed.'),
     3576                type="danger")
    35133577            self.redirect(self.url(self.context))
    35143578            return
     
    35373601    grok.context(ICourse)
    35383602    grok.name('coursetickets.pdf')
    3539     grok.require('waeup.editScores')
     3603    grok.require('waeup.showStudents')
    35403604
    35413605    @property
  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/editscorespage.pt

    r14287 r15422  
    108108         value="Update scores from table" class="btn btn-primary"
    109109         />
     110
     111  <input type="submit" name="VALIDATE_RESULTS" i18n:translate=""
     112         value="Validate course results" class="btn btn-primary"
     113         />
    110114</form>
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py

    r15421 r15422  
    44584458        self.assertTrue('COURSE1 score updated (None)' in logcontent)
    44594459
     4460    def test_lecturer_can_validate_courses(self):
     4461        # the form is locked after validation
     4462        self.login_as_lecturer()
     4463        self.student['studycourse']['100']['COURSE1'].score = None
     4464        self.browser.open(self.edit_scores_url)
     4465        self.browser.getControl(name="scores:list", index=0).value = ''
     4466        self.browser.getControl("Update scores").click()
     4467        self.browser.getControl("Validate").click()
     4468        self.assertTrue(
     4469            'You successfully validated the course results'
     4470            in self.browser.contents)
     4471        self.assertEqual(self.course.results_validation_session, 2004)
     4472        self.assertEqual(self.course.results_validated_by, 'Mercedes Benz')
     4473        self.assertEqual(self.browser.url, self.course_url)
     4474        # Lecturer can't open edit_scores again
     4475        self.browser.getLink("Update session 2004/2005 scores").click()
     4476        self.assertEqual(self.browser.url, self.course_url)
     4477        self.assertTrue(
     4478            'Course results have already been validated'
     4479            ' and can no longer be changed.'
     4480            in self.browser.contents)
     4481        # Also DownloadScoresView is blocked
     4482        self.browser.open(self.browser.url + '/download_scores')
     4483        self.assertEqual(self.browser.url, self.course_url)
     4484        self.assertTrue(
     4485            'Course results have already been validated'
     4486            ' and can no longer be changed.'
     4487            in self.browser.contents)
     4488        # Students Manager can open page ...
     4489        prmlocal = IPrincipalRoleManager(self.course)
     4490        prmlocal.assignRoleToPrincipal(
     4491            'waeup.local.LocalStudentsManager', 'mrslecturer')
     4492        self.browser.getLink("Update session 2004/2005 scores").click()
     4493        self.assertEqual(self.browser.url, self.edit_scores_url)
     4494        self.browser.getLink("Download csv file").click()
     4495        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     4496        self.assertEqual(self.browser.headers['Content-Type'],
     4497                         'text/csv; charset=UTF-8')
     4498        # ... but can't validate courses a second time
     4499        self.browser.open(self.edit_scores_url)
     4500        self.browser.getControl("Validate").click()
     4501        self.assertTrue(
     4502            'Course results have already been validated.'
     4503            in self.browser.contents)
     4504
    44604505    def test_lecturers_can_download_course_tickets(self):
    44614506        # A course ticket slip can be downloaded
  • main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py

    r15175 r15422  
    3232    OnlinePaymentDisplayFormPage, BedTicketDisplayFormPage,
    3333    StudentClearanceEditFormPage, StudentPersonalEditFormPage,
    34     PaymentsManageFormPage, StudyCourseTranscriptPage, EditScoresPage)
     34    PaymentsManageFormPage, StudyCourseTranscriptPage)
    3535from waeup.kofa.students.interfaces import (
    3636    IStudentsContainer, IStudent, IStudentStudyCourse, IStudentStudyLevel,
     
    4141    ADMITTED, PAID, REQUESTED, CLEARED, REGISTERED, VALIDATED, GRADUATED,
    4242    TRANSREQ, TRANSVAL, TRANSREL)
    43 from waeup.kofa.university.interfaces import ICourse
    4443
    4544
     
    922921            ]
    923922        return targets
    924 
    925 
    926 class DownloadCSVFileActionButton(ManageActionButton):
    927     """ 'Download csv file' button for courses.
    928     """
    929     grok.context(ICourse)
    930     grok.view(EditScoresPage)
    931     grok.name('downloadcsv')
    932     grok.require('waeup.editScores')
    933     icon = 'actionicon_down.png'
    934     text = _('Download csv file (editable scores only)')
    935     target = 'download_scores'
    936     grok.order(1)
    937 
    938 
    939 class DownloadTicketOverviewActionButton(ManageActionButton):
    940     """ 'Download ticket overview' button for courses.
    941     """
    942     grok.context(ICourse)
    943     grok.view(EditScoresPage)
    944     grok.name('coursetickets')
    945     grok.require('waeup.editScores')
    946     icon = 'actionicon_pdf.png'
    947     text = _('Download pdf file')
    948     target = 'coursetickets.pdf'
    949     grok.order(2)
Note: See TracChangeset for help on using the changeset viewer.