Changeset 14934


Ignore:
Timestamp:
10 Jan 2018, 14:44:49 (7 years ago)
Author:
Henrik Bettermann
Message:

Do no longer hide the 'Create students' buttons but switch the portal to
maintenance mode to ensure that nobody can enter the portal during
record creation except for user 'admin'. This guarantees that record
creation is only started once.

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

Legend:

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

    r14915 r14934  
    441.6.dev0 (unreleased)
    55=======================
     6
     7* Do no longer hide the 'Create students' buttons but switch the portal to
     8  maintenance mode to ensure that nobody can enter the portal during
     9  record creation except for user 'admin'. This guarantees that record
     10  creation is only started once.
    611
    712* Replace `gpa_boundaries` utility attribute by `GPABoundaries` method
  • main/waeup.kofa/trunk/docs/source/userdocs/applicants/create_students.rst

    r14683 r14934  
    2525  applicants will be skipped without further notice.
    2626
    27 3. Last but not least, the portal manager with user id ``admin``
    28    does see a link button:
     273. Last but not least, the portal managers do see a link button:
    2928
    3029  |create_students_button|
     
    3231  on the `ApplicantsContainerPage` and on the `ApplicantsRootPage`
    3332  which creates student records from applicants inside a single
    34   applicants container or even portal-wide respectively.
     33  applicants container or even portal-wide respectively. A warning
     34  message appears before the process is started. After start the
     35  portal is immediately switched into maintenance mode to ensure that
     36  nobody can enter the portal during record creation except for user
     37  'admin'. Maintenance mode is switched off as soon as the process has
     38  finished.
    3539
    36   The reader may wonder: Why only user ``admin``?
     40.. note::
    3741
    3842  Batch creation of thousands or even tenthousands of student records
    3943  is very computation intensive and takes quite a long time, even with
    4044  powerful computers. Experience has shown that the portal must be
    41   disconnected from the Internet in order to avoid database write
    42   conflict errors, which cannot be resolved if also students access
    43   the portal. Usually conflict errrors are not serious. Unresolved
    44   conflicts just lead to an error message and the database remains
    45   unchanged. Unfortunataly, student creation does not only alter the
    46   object database. As we will see below, also folders and files in the
    47   filesystem are added. These filesystem changes are not being
    48   reverted after unresolved conflicts, a fact which can cause serious
    49   problems.
    50 
    51   So the answer to the question is trivial: We expect that the admin
    52   user knows what s/he is doing and is careful enough to start the
    53   creation process in maintenance mode, which means when the portal is
    54   disconnected from a public network.
     45  switched to maintenance mode (or even disconnected from the Internet)
     46  in order to avoid database write conflict errors, which cannot be
     47  resolved if also students access the portal. Usually conflict
     48  errrors are not serious. Unresolved conflicts just lead to an error
     49  message and the database remains unchanged. Unfortunataly, student
     50  creation does not only alter the object database. As we will see
     51  below, also folders and files in the filesystem are added. These
     52  filesystem changes are not being reverted after unresolved conflicts,
     53  a fact which can cause serious problems.
    5554
    5655
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py

    r14682 r14934  
    2424from urllib import urlencode
    2525from datetime import datetime, date
    26 from time import time
     26from time import time, sleep
    2727from zope.event import notify
    2828from zope.component import getUtility, queryUtility, createObject, getAdapter
     
    680680class CreateAllStudentsPage(UtilityView, grok.View):
    681681    """Create all student objects from applicant data
    682     in the root container or in a specific  applicants container only.
     682    in the root container or in a specific applicants container only.
    683683    Only PortalManagers can do this.
    684684    """
     
    688688
    689689    def update(self):
     690        grok.getSite()['configuration'].maintmode_enabled_by = u'admin'
     691        transaction.commit()
     692        # Wait 10 seconds for all transactions to be finished.
     693        # Do not wait in tests.
     694        if not self.request.principal.id == 'zope.mgr':
     695            sleep(10)
    690696        cat = getUtility(ICatalog, name='applicants_catalog')
    691697        results = list(cat.searchResults(state=(ADMITTED, ADMITTED)))
     
    706712                applicants_root.logger.info(
    707713                    '%s - %s - %s' % (ob_class, result.applicant_id, msg))
     714        grok.getSite()['configuration'].maintmode_enabled_by = None
    708715        if len(created):
    709716            self.flash(_('${a} students successfully created.',
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_applicantcopier.py

    r12565 r14934  
    2626from zope.component import getUtility
    2727from zope.i18n import translate
     28from zope.securitypolicy.interfaces import IPrincipalRoleManager
    2829from waeup.kofa.testing import FunctionalLayer
    2930from waeup.kofa.interfaces import IExtFileStore, IFileStoreNameChooser
     
    4243
    4344    def prepare_applicant(self):
    44         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    4545        self.browser.open(self.manage_path)
    4646        self.fill_correct_values()
     
    5656
    5757    def test_copier(self):
     58        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    5859        self.prepare_applicant()
    5960        storage = getUtility(IExtFileStore)
     
    140141
    141142    def test_batch_copying(self):
     143        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    142144        self.prepare_applicant()
    143145        IWorkflowState(self.applicant).setState('admitted')
     
    155157        logfile = os.path.join(
    156158            self.app['datacenter'].storage, 'logs', 'applicants.log')
     159        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    157160        self.prepare_applicant()
    158161        self.browser.open(self.container_path + '/createallstudents')
     
    182185        logfile = os.path.join(
    183186            self.app['datacenter'].storage, 'logs', 'applicants.log')
     187        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    184188        self.prepare_applicant()
    185189        self.browser.open(self.manage_path)
     
    238242        logcontent = open(logfile).read()
    239243        self.assertTrue('IOError: Application Slip could not be created.' in logcontent)
     244
     245    def disabled_test_delay(self):
     246        # Create portalmanager manager
     247        self.app['users'].addUser('mrportalmanager', 'mrportalmanagersecret')
     248        self.app['users']['mrportalmanager'].email = 'mrportalmanager@foo.ng'
     249        self.app['users']['mrportalmanager'].title = 'Carlos Portales'
     250        prmglobal = IPrincipalRoleManager(self.app)
     251        prmglobal.assignRoleToPrincipal(
     252            'waeup.PortalManager', 'mrportalmanager')
     253        # Login as portal manager
     254        self.browser.open(self.login_path)
     255        self.browser.getControl(name="form.login").value = 'mrportalmanager'
     256        self.browser.getControl(name="form.password").value = 'mrportalmanagersecret'
     257        self.browser.getControl("Login").click()
     258        self.prepare_applicant()
     259        self.browser.open(self.manage_path)
     260        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
     261        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
     262        self.browser.getControl("Save").click()
     263        IWorkflowState(self.applicant).setState('admitted')
     264        notify(grok.ObjectModifiedEvent(self.applicant))
     265        start = datetime.now()
     266        self.browser.open(self.root_path + '/createallstudents')
     267        self.assertTrue('1 students successfully created' in self.browser.contents)
     268        self.assertTrue((datetime.now() - start).seconds >= 10)
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/viewlets.py

    r13951 r14934  
    167167    grok.order(4)
    168168
     169creation_warning = _(
     170    "'The creation process may take a considerably long time "
     171    "depending on the number of student records to be created "
     172    "(appr. 0.5s per student). "
     173    "All users will be logged out and the portal will be in "
     174    "maintenance mode during record creation. You have to login again after "
     175    "creation process has finished. "
     176    "Do you really want to start the process now?'")
     177
    169178class ApplicantsRootCreateStudentsActionButton(ManageActionButton):
    170179    grok.order(3)
     
    177186
    178187    @property
    179     def target_url(self):
    180         if self.target and self.request.principal.id == 'admin':
    181             return self.view.url(self.view.context, self.target)
    182         return
     188    def onclick(self):
     189        return "return window.confirm(%s);" % creation_warning
    183190
    184191class ApplicantsContainerCreateStudentsActionButton(ManageActionButton):
     
    192199
    193200    @property
    194     def target_url(self):
    195         if self.target and self.request.principal.id == 'admin':
    196             return self.view.url(self.view.context, self.target)
    197         return
     201    def onclick(self):
     202        return "return window.confirm(%s);" % creation_warning
    198203
    199204class ApplicantViewActionButton(ManageActionButton):
Note: See TracChangeset for help on using the changeset viewer.