Changeset 13806 for main


Ignore:
Timestamp:
6 Apr 2016, 10:27:11 (8 years ago)
Author:
Henrik Bettermann
Message:

Add portal maintenance mode.

See r13394, r13396, r13468.

Location:
main/waeup.ikoba/trunk
Files:
1 added
10 edited

Legend:

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

    r13804 r13806  
    440.2.dev0 (unreleased)
    55=====================
     6
     7* Add portal maintenance mode.
     8
     9* Forbid style and script elements in html fields.
    610
    711* Rearrange datacenter upload page. Provide modal windows to view all
  • main/waeup.ikoba/trunk/src/waeup/ikoba/authentication.py

    r13803 r13806  
    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.ikoba/trunk/src/waeup/ikoba/browser/pages.py

    r13804 r13806  
    308308
    309309    def update(self, SUBMIT=None, camefrom=None):
     310        blocker = grok.getSite()['configuration'].maintmode_enabled_by
     311        if blocker:
     312            self.flash(_('The portal is in maintenance mode '
     313                        'and authentication (login) temporarily disabled.'),
     314                       type='warning')
    310315        self.camefrom = camefrom
    311316        if SUBMIT is not None:
     
    335340                    return
    336341                self.redirect(self.camefrom)
     342                return
     343            # Display second warning message and remind user that
     344            # s/he can't login.
     345            if blocker:
     346                self.flash(_('The portal is in maintenance mode. '
     347                            'You can\'t login!'),
     348                           type='danger')
    337349                return
    338350            # Display appropriate flash message if credentials are correct
     
    638650
    639651    def render(self):
    640         #ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
     652        #ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
    641653        #self.context.logger.info(
    642654        #    '%s - skeleton downloaded: %s' % (ob_class, self.filename))
     
    921933    form_fields = grok.AutoFields(IConfigurationContainer).omit(
    922934        'frontpage_dict')
     935    form_fields['maintmode_enabled_by'].for_display = True
    923936
    924937    @action(_('Save'), style='primary')
     
    11931206
    11941207    def update(self, filename=None, select=None, cancel=None):
     1208        if not grok.getSite()['configuration'].maintmode_enabled_by and \
     1209            not self.request.principal.id == 'admin':
     1210            self.flash(
     1211                _('Portal must be in maintenance mode for data import.'),
     1212                type='warning')
     1213            self.redirect(self.url(self.context))
     1214            return
    11951215        if cancel is not None:
    11961216            self.redirect(self.url(self.context))
     
    12011221            session['import_filename'] = select
    12021222            self.redirect(self.url(self.context, '@@import2'))
     1223        return
    12031224
    12041225class DatacenterImportStep2(IkobaPage):
     
    14401461            self.redirect(self.url(self.context, '@@import1'))
    14411462            return
     1463        if not grok.getSite()['configuration'].maintmode_enabled_by and \
     1464            not self.request.principal.id == 'admin':
     1465            self.flash(
     1466                _('File has not been imported. '
     1467                  'Portal must be in maintenance mode for data import.'),
     1468                type='danger')
     1469            self.redirect(self.url(self.context))
     1470            return
    14421471        session = ISession(self.request)['waeup.ikoba']
    14431472        self.filename = session.get('import_filename', None)
     
    14761505            self.warn_num == 0, self.fullpath, fin_path, pending_path,
    14771506            self.mode)
     1507        # Disable maintenance mode if set.
     1508        if grok.getSite()['configuration'].maintmode_enabled_by:
     1509            grok.getSite()['configuration'].maintmode_enabled_by = None
     1510            self.flash(_('Maintenance mode disabled.'))
    14781511
    14791512        if self.warn_num:
     
    16591692        return result
    16601693
     1694class SwitchMaintModePage(UtilityView, grok.View):
     1695    """Import managers must disable authentication for all other users
     1696    before starting an import. This pages switches maintenance mode
     1697    on and off.
     1698    """
     1699    grok.context(IDataCenter)
     1700    grok.name('switchmaintmode')
     1701    grok.require('waeup.importData')
     1702
     1703    def update(self):
     1704        ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
     1705        if grok.getSite()['configuration'].maintmode_enabled_by:
     1706            grok.getSite()['configuration'].maintmode_enabled_by = None
     1707            self.context.logger.info('%s - maintmode disabled' % ob_class)
     1708            self.flash(_('Maintenance mode disabled.'))
     1709            self.redirect(self.url(self.context))
     1710        else:
     1711            grok.getSite()['configuration'].maintmode_enabled_by = unicode(
     1712                self.request.principal.id)
     1713            self.context.logger.info('%s - maintmode enabled' % ob_class)
     1714            self.flash(_('Maintenance mode enabled.'), type='warning')
     1715            self.redirect(self.url(self.context, 'import1'))
     1716        return
     1717
     1718    def render(self):
     1719        return
     1720
     1721
    16611722class ChangePasswordRequestPage(IkobaFormPage):
    16621723    """Captcha'd page for all kind of users to request a password change.
  • main/waeup.ikoba/trunk/src/waeup/ikoba/browser/tests/test_browser.py

    r13804 r13806  
    2222import tempfile
    2323import os
     24import grok
    2425from zc.async.testing import wait_for_result
    2526from zope.component import createObject, getUtility
     
    215216        return
    216217
     218    def test_maintenance_mode(self):
     219        config = grok.getSite()['configuration']
     220        self.app['users'].addUser(
     221            'officer', 'secret', title='Bob Officer', email='bob@abcd.ng')
     222        self.browser.open('http://localhost/app/login')
     223        self.browser.getControl(name="form.login").value = 'officer'
     224        self.browser.getControl(name="form.password").value = 'secret'
     225        self.browser.getControl("Login").click()
     226        # Officer logged in.
     227        self.assertMatches('...You logged in...', self.browser.contents)
     228        self.assertTrue("Bob Officer" in self.browser.contents)
     229        # If maintenance mode is enabled, officer is immediately logged out.
     230        config.maintmode_enabled_by = u'any_user'
     231        self.assertRaises(
     232            Unauthorized, self.browser.open, 'http://localhost/app/customers')
     233        self.browser.open('http://localhost/app/login')
     234        self.assertMatches(
     235            '...The portal is in maintenance mode...',
     236            self.browser.contents)
     237        # Officers really can't login if maintenance mode is enabled.
     238        self.browser.getControl(name="form.login").value = 'officer'
     239        self.browser.getControl(name="form.password").value = 'secret'
     240        self.browser.getControl("Login").click()
     241        # A second warning is raised.
     242        self.assertMatches(
     243            '...The portal is in maintenance mode. You can\'t login!...',
     244            self.browser.contents)
     245        # Offficer can login if s/he is the blocker.
     246        config.maintmode_enabled_by = u'officer'
     247        self.browser.getControl(name="form.login").value = 'officer'
     248        self.browser.getControl(name="form.password").value = 'secret'
     249        self.browser.getControl("Login").click()
     250        self.assertTrue('You logged in' in self.browser.contents)
     251        self.assertTrue('Logout' in self.browser.contents)
     252        return
     253
    217254    def test_sources_overview(self):
    218255        self.browser.open('http://localhost/app/sources')
  • main/waeup.ikoba/trunk/src/waeup/ikoba/browser/viewlets.py

    r13804 r13806  
    454454    text = _('View processed files')
    455455
     456class SwitchMaintMode(ActionButton):
     457    grok.context(IDataCenter)
     458    grok.require('waeup.importData')
     459    #grok.view(DatacenterImportStep1)
     460    grok.order(7)
     461    icon = 'actionicon_stop.png'
     462    target = 'switchmaintmode'
     463    text = _('Switch maintenance mode')
     464
     465    @property
     466    def onclick(self):
     467        if grok.getSite()['configuration'].maintmode_enabled_by:
     468            return
     469        return "return window.confirm(%s);" % _(
     470            "'In maintenance mode no other user can login, and "
     471            "already logged-in users will be automatically logged out. "
     472            "You will be the only logged-in user and you can safely start "
     473            "any import. Please wait a few seconds before starting the import "
     474            "so that all running processes are finished. "
     475            "If the import is done, maintenance mode will "
     476            "be automatically disabled. \\n\\n"
     477            "You really want to enable maintenance mode?'")
     478
    456479#
    457480# Primary navigation tabs (in upper left navigation bar)...
  • main/waeup.ikoba/trunk/src/waeup/ikoba/customers/authentication.py

    r13803 r13806  
    116116        customers or the temporary password set by the system.
    117117
    118         We additionally check if customer account has been suspended.
    119         """
     118        We additionally check if customer account has been suspended
     119        or maintenance mode is on.
     120        """
     121        try:
     122            blocker = grok.getSite()['configuration'].maintmode_enabled_by
     123            if blocker and blocker != self.name:
     124                return False
     125        except (TypeError, KeyError):  # in unit tests
     126            pass
    120127        if not isinstance(password, basestring):
    121128            return False
  • main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py

    r13066 r13806  
    492492        self.browser.getControl(name='SUBMIT').click()
    493493        self.browser.getLink('Process data').click()
     494        self.browser.getLink("Switch maintenance mode").click()
    494495        button = lookup_submit_value(
    495496            'select', 'customers_zope.mgr.csv', self.browser)
  • main/waeup.ikoba/trunk/src/waeup/ikoba/doctests/batchprocessing_browser.txt

    r12993 r13806  
    8484
    8585    >>> browser.getLink('Process data').click()
     86    >>> browser.getLink('Switch maintenance mode').click()
    8687    >>> button = lookup_submit_value(
    8788    ...   'select', 'users_zope.mgr.csv', browser)
     
    170171
    171172    >>> browser.getLink('Process data').click()
     173    >>> browser.getLink('Switch maintenance mode').click()
    172174    >>> button = lookup_submit_value(
    173175    ...   'select', 'newusers_zope.mgr.csv', browser)
     
    232234    >>> browser.open('http://localhost/app/datacenter')
    233235    >>> browser.getLink('Process data').click()
     236    >>> browser.getLink('Switch maintenance mode').click()
    234237    >>> button = lookup_submit_value(
    235238    ...   'select', 'newusers_zope.mgr.create.pending.csv', browser)
  • main/waeup.ikoba/trunk/src/waeup/ikoba/interfaces.py

    r13805 r13806  
    650650        )
    651651
     652    maintmode_enabled_by = schema.TextLine(
     653        title = _(u'Maintenance Mode enabled by'),
     654        default = None,
     655        required = False,
     656        )
     657
    652658
    653659class IDataCenter(IIkobaObject):
  • main/waeup.ikoba/trunk/src/waeup/ikoba/products/tests/test_batching.py

    r12490 r13806  
    3333from zope.interface.verify import verifyClass, verifyObject
    3434from zope.securitypolicy.interfaces import IPrincipalRoleManager
     35from zope.testbrowser.testing import Browser
    3536
    3637from waeup.ikoba.app import Company
     
    6465        self.workdir = tempfile.mkdtemp()
    6566        app = Company()
     67        self.browser = Browser()
     68        self.browser.handleErrors = False
     69        self.datacenter_path = 'http://localhost/app/datacenter'
    6670        app['datacenter'].setStoragePath(self.dc_root)
    6771        self.getRootFolder()['app'] = app
     
    202206            in failcontent)
    203207        shutil.rmtree(os.path.dirname(fin_file))
     208
     209
     210    def test_upload_import_reupload(self):
     211        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
     212        self.browser.open(self.datacenter_path)
     213        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     214        self.assertEqual(self.browser.url, self.datacenter_path)
     215        self.browser.getLink("Upload data").click()
     216        file = open(self.csv_file)
     217        ctrl = self.browser.getControl(name='uploadfile:file')
     218        file_ctrl = ctrl.mech_control
     219        file_ctrl.add_file(file, filename='sample_product_data.csv')
     220        self.browser.getControl('Upload').click()
     221        self.browser.getLink('Process data').click()
     222        self.assertTrue('Portal must be in maintenance mode for data import.'
     223            in self.browser.contents)
     224        self.browser.getLink("Switch").click()
     225        self.assertTrue('Maintenance mode enabled' in self.browser.contents)
     226        # Maintenance mode is now set.
     227        self.assertEqual(
     228            self.app['configuration'].maintmode_enabled_by, 'zope.mgr')
     229        self.browser.getControl(name="select").click()
     230        importerselect = self.browser.getControl(name='importer')
     231        importerselect.getControl('Product Processor').selected = True
     232        modeselect = self.browser.getControl(name='mode')
     233        modeselect.getControl(value='create').selected = True
     234        self.browser.getControl('Proceed to step 3').click()
     235        self.assertTrue('Header fields OK' in self.browser.contents)
     236        self.browser.getControl('Perform import').click()
     237        self.assertTrue('Successfully processed 3 rows' in self.browser.contents)
     238        self.assertTrue('Maintenance mode disabled' in self.browser.contents)
     239        # Maintenance mode is really disabled.
     240        self.assertEqual(
     241            self.app['configuration'].maintmode_enabled_by, None)
     242        # We import the same file a second time.
     243        self.browser.open(self.datacenter_path)
     244        self.browser.getLink("Upload data").click()
     245        file = open(self.csv_file)
     246        ctrl = self.browser.getControl(name='uploadfile:file')
     247        file_ctrl = ctrl.mech_control
     248        file_ctrl.add_file(file, filename='sample_product_data.csv')
     249        self.browser.getControl('Upload').click()
     250        self.assertTrue(
     251            'File with same name was uploaded earlier' in self.browser.contents)
     252        return
Note: See TracChangeset for help on using the changeset viewer.