Changeset 13394


Ignore:
Timestamp:
6 Nov 2015, 05:43:37 (9 years ago)
Author:
Henrik Bettermann
Message:

Implement portal maintenance mode.

Location:
main/waeup.kofa/trunk
Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/CHANGES.txt

    r13363 r13394  
    441.3.4.dev0 (unreleased)
    55=======================
     6
     7* Add portal maintenance mode.
    68
    79* Allow also reg_number on public page to check application status
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/authentication.py

    r9335 r13394  
    4848    def checkPassword(self, password):
    4949        """Check whether the given `password` matches the one stored by
    50         students.
    51 
    52         We additionally check if student account has been suspended.
     50        students. We additionally check if applicant account has been suspended
     51        or if the portal is blocked.
    5352        """
     53        try:
     54            blocker = grok.getSite()['configuration'].maintmode_enabled_by
     55            if blocker:
     56                return False
     57        except TypeError:  # in unit tests
     58            pass
    5459        if not isinstance(password, basestring):
    5560            return False
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py

    r13365 r13394  
    11991199        if self.context.expired:
    12001200            self.flash(_('Outside application period.'), type='warning')
     1201            self.redirect(self.url(self.context))
     1202            return
     1203        blocker = grok.getSite()['configuration'].maintmode_enabled_by
     1204        if blocker:
     1205            self.flash(_('The portal is in maintenance mode '
     1206                        'and registration temporarily disabled.'),
     1207                       type='warning')
    12011208            self.redirect(self.url(self.context))
    12021209            return
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py

    r13365 r13394  
    609609        self.assertTrue(
    610610            'You logged in.' in self.browser.contents)
     611
     612    def test_maintenance_mode(self):
     613        config = grok.getSite()['configuration']
     614        self.login()
     615        # Applicant  logged in.
     616        self.assertTrue('You logged in' in self.browser.contents)
     617        self.assertTrue("Joan None" in self.browser.contents)
     618        # If maintenance mode is enabled, applicant is immediately logged out.
     619        config.maintmode_enabled_by = u'any_user'
     620        self.assertRaises(
     621            Unauthorized, self.browser.open, 'http://localhost/app/faculties')
     622        self.browser.open('http://localhost/app/login')
     623        self.assertTrue('The portal is in maintenance mode' in self.browser.contents)
     624        # Applicant really can't login if maintenance mode is enabled.
     625        self.login()
     626        # A second warning is raised.
     627        self.assertTrue(
     628            'The portal is in maintenance mode. You can\'t login!'
     629            in self.browser.contents)
     630        return
    611631
    612632    def test_applicant_access(self):
     
    12501270
    12511271    def test_register_applicant_create(self):
     1272        config = grok.getSite()['configuration']
     1273        config.maintmode_enabled_by = u'any_user'
    12521274        self.assertEqual(len(self.app['applicants'][container_name_1]), 1)
    12531275        # An applicant can register himself.
    12541276        self.browser.open(self.container_path)
    12551277        self.browser.getLink("Register for application").click()
    1256         # Fill the edit form with suitable values
     1278        self.assertTrue(
     1279            'The portal is in maintenance mode' in self.browser.contents)
     1280        config.maintmode_enabled_by = None
     1281        self.browser.getLink("Register for application").click()
     1282        # The edit form now opens and can be filled with suitable values
    12571283        self.browser.getControl(name="form.firstname").value = 'Anna'
    12581284        self.browser.getControl(name="form.lastname").value = 'Kurios'
  • main/waeup.kofa/trunk/src/waeup/kofa/authentication.py

    r13182 r13394  
    223223
    224224    def checkPassword(self, password):
     225        try:
     226            blocker = grok.getSite()['configuration'].maintmode_enabled_by
     227            if blocker and blocker != self.name:
     228                return False
     229        except (TypeError, KeyError):  # in unit tests
     230            pass
    225231        if not isinstance(password, basestring):
    226232            return False
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py

    r13354 r13394  
    337337
    338338    def update(self, SUBMIT=None, camefrom=None):
     339        blocker = grok.getSite()['configuration'].maintmode_enabled_by
     340        if blocker:
     341            self.flash(_('The portal is in maintenance mode '
     342                        'and authentication (login) temporarily disabled.'),
     343                       type='warning')
    339344        self.camefrom = camefrom
    340345        if SUBMIT is not None:
     
    363368                    return
    364369                self.redirect(self.camefrom)
     370                return
     371            # Display second warning message and remind user that
     372            # s/he can't login.
     373            if blocker:
     374                self.flash(_('The portal is in maintenance mode. '
     375                            'You can\'t login!'),
     376                           type='danger')
    365377                return
    366378            # Display appropriate flash message if credentials are correct
     
    10011013    form_fields = grok.AutoFields(IConfigurationContainer).omit(
    10021014        'frontpage_dict', 'next_matric_integer', 'next_matric_integer_2')
     1015    form_fields['maintmode_enabled_by'].for_display = True
    10031016
    10041017    @action(_('Save'), style='primary')
     
    13541367
    13551368    def update(self, filename=None, select=None, cancel=None):
     1369        if not grok.getSite()['configuration'].maintmode_enabled_by and \
     1370            not self.request.principal.id == 'admin':
     1371            self.flash(
     1372                _('Portal must be in maintenance mode for data import.'),
     1373                type='warning')
     1374            self.redirect(self.url(self.context))
     1375            return
    13561376        if cancel is not None:
    13571377            self.redirect(self.url(self.context))
     
    13621382            session['import_filename'] = select
    13631383            self.redirect(self.url(self.context, '@@import2'))
     1384        return
    13641385
    13651386class DatacenterImportStep2(KofaPage):
     
    16391660            self.mode)
    16401661
     1662        # Disable maintenance mode if set.
     1663        if grok.getSite()['configuration'].maintmode_enabled_by:
     1664            grok.getSite()['configuration'].maintmode_enabled_by = None
     1665            self.flash(_('Maintenance mode disabled.'))
     1666
    16411667        if self.warn_num:
    16421668            self.flash(_('Processing of ${a} rows failed.',
     
    18231849            '%s - downloaded: %s, job_id=%s' % (ob_class, filename, job_id))
    18241850        return result
     1851
     1852class SwitchMaintModePage(UtilityView, grok.View):
     1853    """Import managers must disable authentication for all other users
     1854    before starting an import. This pages switches maintenance mode
     1855    on and off.
     1856    """
     1857    grok.context(IDataCenter)
     1858    grok.name('switchmaintmode')
     1859    grok.require('waeup.importData')
     1860
     1861    def update(self):
     1862        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
     1863        if grok.getSite()['configuration'].maintmode_enabled_by:
     1864            grok.getSite()['configuration'].maintmode_enabled_by = None
     1865            self.context.logger.info('%s - maintmode disabled' % ob_class)
     1866            self.flash(_('Maintenance mode disabled.'))
     1867        else:
     1868            grok.getSite()['configuration'].maintmode_enabled_by = unicode(
     1869                self.request.principal.id)
     1870            self.context.logger.info('%s - maintmode enabled' % ob_class)
     1871            self.flash(_('Maintenance mode enabled.'), type='warning')
     1872        self.redirect(self.url(self.context))
     1873        return
     1874
     1875    def render(self):
     1876        return
    18251877
    18261878#
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/configurationmanagepage.pt

    r11254 r13394  
    1818        </tbody>
    1919      </table>
     20      <br />
    2021      <div tal:condition="view/availableActions">
    2122        <span tal:repeat="action view/actions" tal:omit-tag="">
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py

    r13199 r13394  
    2222import tempfile
    2323import os
     24import grok
    2425from zc.async.testing import wait_for_result
    2526from zope.component import createObject, getUtility
     
    506507        self.browser.getControl(name="form.password").value = 'secret'
    507508        self.browser.getControl("Login").click()
    508         # Yeah, office logged in.
     509        # Yeah, officer logged in.
    509510        self.assertMatches(
    510511            '...You logged in...', self.browser.contents)
     
    531532        return
    532533
     534    def test_maintenance_mode(self):
     535        config = grok.getSite()['configuration']
     536        self.app['users'].addUser(
     537            'officer', 'secret', title='Bob Officer', email='bob@abcd.ng')
     538        self.browser.open('http://localhost/app/login')
     539        self.browser.getControl(name="form.login").value = 'officer'
     540        self.browser.getControl(name="form.password").value = 'secret'
     541        self.browser.getControl("Login").click()
     542        # Officer logged in.
     543        self.assertMatches('...You logged in...', self.browser.contents)
     544        self.assertTrue("Bob Officer" in self.browser.contents)
     545        # If maintenance mode is enabled, officer is immediately logged out.
     546        config.maintmode_enabled_by = u'any_user'
     547        self.assertRaises(
     548            Unauthorized, self.browser.open, 'http://localhost/app/faculties')
     549        self.browser.open('http://localhost/app/login')
     550        self.assertMatches(
     551            '...The portal is in maintenance mode...',
     552            self.browser.contents)
     553        # Officers really can't login if maintenance mode is enabled.
     554        self.browser.getControl(name="form.login").value = 'officer'
     555        self.browser.getControl(name="form.password").value = 'secret'
     556        self.browser.getControl("Login").click()
     557        # A second warning is raised.
     558        self.assertMatches(
     559            '...The portal is in maintenance mode. You can\'t login!...',
     560            self.browser.contents)
     561        # Offficer can login if s/he is the blocker.
     562        config.maintmode_enabled_by = u'officer'
     563        self.browser.getControl(name="form.login").value = 'officer'
     564        self.browser.getControl(name="form.password").value = 'secret'
     565        self.browser.getControl("Login").click()
     566        self.assertTrue('You logged in' in self.browser.contents)
     567        self.assertTrue('Logout' in self.browser.contents)
     568        return
     569
    533570    def test_sources_overview(self):
    534571        self.browser.open('http://localhost/app/sources')
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/viewlets.py

    r13119 r13394  
    628628    text = _('View processed files')
    629629
     630class SwitchMaintMode(ActionButton):
     631    grok.context(IDataCenter)
     632    grok.require('waeup.importData')
     633    grok.view(DatacenterPage)
     634    grok.order(7)
     635    icon = 'actionicon_stop.png'
     636    target = 'switchmaintmode'
     637    text = _('Switch maintenance mode')
     638
     639    @property
     640    def onclick(self):
     641        if grok.getSite()['configuration'].maintmode_enabled_by:
     642            return
     643        return "return window.confirm(%s);" % _(
     644            "'In maintenance mode no other user can login, and "
     645            "already logged-in users will be automatically logged out. "
     646            "You will be the only logged-in user and you can safely start "
     647            "any import. Please wait a few seconds before starting the import "
     648            "so that all running processes are finished. "
     649            "If the import is done, maintenance mode will "
     650            "be automatically disabled. \\n\\n"
     651            "You really want to enable maintenance mode?'")
     652
    630653#
    631654# Primary navigation tabs (in upper left navigation bar)...
  • main/waeup.kofa/trunk/src/waeup/kofa/doctests/batchprocessing_browser.txt

    r12981 r13394  
    8686Step 1: start batch processing:
    8787
     88    >>> browser.getLink('Switch maintenance mode').click()
    8889    >>> browser.getLink('Process data').click()
    8990    >>> button = lookup_submit_value(
     
    191192Step 1: start batch processing:
    192193
     194    >>> browser.getLink('Switch maintenance mode').click()
    193195    >>> browser.getLink('Process data').click()
    194196    >>> button = lookup_submit_value(
     
    256258Step 1: start batch processing:
    257259
     260    >>> browser.getLink('Switch maintenance mode').click()
    258261    >>> browser.getLink('Process data').click()
    259262    >>> button = lookup_submit_value(
     
    321324Step 1: start batch processing:
    322325
     326    >>> browser.getLink('Switch maintenance mode').click()
    323327    >>> browser.getLink('Process data').click()
    324328    >>> button = lookup_submit_value(
     
    387391Step 1: start batch processing:
    388392
     393    >>> browser.getLink('Switch maintenance mode').click()
    389394    >>> browser.getLink('Process data').click()
    390395    >>> button = lookup_submit_value(
     
    453458Step 1: start batch processing:
    454459
     460    >>> browser.getLink('Switch maintenance mode').click()
    455461    >>> browser.getLink('Process data').click()
    456462    >>> button = lookup_submit_value(
     
    539545Step 1: start batch processing:
    540546
     547    >>> browser.getLink('Switch maintenance mode').click()
    541548    >>> browser.getLink('Process data').click()
    542549    >>> button = lookup_submit_value(
     
    602609
    603610    >>> browser.open('http://localhost/app/datacenter')
     611    >>> browser.getLink('Switch maintenance mode').click()
    604612    >>> browser.getLink('Process data').click()
    605613    >>> button = lookup_submit_value(
  • main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py

    r13354 r13394  
    741741        )
    742742
     743    maintmode_enabled_by = schema.TextLine(
     744        title = _(u'Maintenance Mode enabled by'),
     745        default = None,
     746        required = False,
     747        )
    743748
    744749    def addSessionConfiguration(sessionconfiguration):
  • main/waeup.kofa/trunk/src/waeup/kofa/students/authentication.py

    r12926 r13394  
    113113        """Check whether the given `password` matches the one stored by
    114114        students or the temporary password set by officers.
    115 
    116         We additionally check if student account has been suspended.
    117         """
     115        We additionally check if student account has been suspended
     116        or if the portal is blocked.
     117        """
     118        try:
     119            blocker = grok.getSite()['configuration'].maintmode_enabled_by
     120            if blocker:
     121                return False
     122        except TypeError:  # in unit tests
     123            pass
    118124        if not isinstance(password, basestring):
    119125            return False
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py

    r13349 r13394  
    13871387        filewidget.add_file(filecontents, 'text/plain', 'students.csv')
    13881388        self.browser.getControl(name='SUBMIT').click()
     1389        self.browser.getLink("Switch maintenance mode").click()
    13891390        self.browser.getLink('Process data').click()
    13901391        button = lookup_submit_value(
     
    14131414        filewidget.add_file(filecontents, 'text/plain', 'studycourses.csv')
    14141415        self.browser.getControl(name='SUBMIT').click()
     1416        # Meanwhile maintenance mode is disabled again.
     1417        self.browser.getLink("Switch maintenance mode").click()
    14151418        self.browser.getLink('Process data').click()
    14161419        button = lookup_submit_value(
     
    23762379            '...You logged in...', self.browser.contents)
    23772380
     2381    def test_maintenance_mode(self):
     2382        config = grok.getSite()['configuration']
     2383        self.browser.open(self.login_path)
     2384        self.browser.getControl(name="form.login").value = self.student_id
     2385        self.browser.getControl(name="form.password").value = 'spwd'
     2386        self.browser.getControl("Login").click()
     2387        # Student logged in.
     2388        self.assertTrue('You logged in' in self.browser.contents)
     2389        self.assertTrue("Anna Tester" in self.browser.contents)
     2390        # If maintenance mode is enabled, student is immediately logged out.
     2391        config.maintmode_enabled_by = u'any_user'
     2392        self.assertRaises(
     2393            Unauthorized, self.browser.open, 'http://localhost/app/faculties')
     2394        self.browser.open('http://localhost/app/login')
     2395        self.assertTrue('The portal is in maintenance mode' in self.browser.contents)
     2396        # Student really can't login if maintenance mode is enabled.
     2397        self.browser.open(self.login_path)
     2398        self.browser.getControl(name="form.login").value = self.student_id
     2399        self.browser.getControl(name="form.password").value = 'spwd'
     2400        self.browser.getControl("Login").click()
     2401        # A second warning is raised.
     2402        self.assertTrue(
     2403            'The portal is in maintenance mode. You can\'t login!'
     2404            in self.browser.contents)
     2405        return
     2406
    23782407    def test_student_clearance(self):
    23792408        # Student cant login if their password is not set
  • main/waeup.kofa/trunk/src/waeup/kofa/university/tests/test_batching.py

    r12868 r13394  
    351351        self.browser.getControl('Upload').click()
    352352        self.browser.getLink('Process data').click()
     353        self.assertTrue('Portal must be in maintenance mode for data import.'
     354            in self.browser.contents)
     355        self.browser.getLink("Switch").click()
     356        self.assertTrue('Maintenance mode enabled' in self.browser.contents)
     357        # Maintenance mode is now set.
     358        self.assertEqual(
     359            self.app['configuration'].maintmode_enabled_by, 'zope.mgr')
     360        self.browser.getLink('Process data').click()
    353361        self.browser.getControl(name="select").click()
    354362        importerselect = self.browser.getControl(name='importer')
     
    360368        self.browser.getControl('Perform import').click()
    361369        self.assertTrue('Successfully processed 1 rows' in self.browser.contents)
     370        self.assertTrue('Maintenance mode disabled' in self.browser.contents)
     371        # Maintenance mode is really disabled.
     372        self.assertEqual(
     373            self.app['configuration'].maintmode_enabled_by, None)
    362374        # We import the same file a second time.
    363375        self.browser.open(self.datacenter_path)
Note: See TracChangeset for help on using the changeset viewer.