Changeset 12926


Ignore:
Timestamp:
12 May 2015, 15:19:10 (10 years ago)
Author:
Henrik Bettermann
Message:

Enable temporary suspension of officer accounts. Plugins must be updated after restart.

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

Legend:

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

    r12912 r12926  
    441.3.2.dev0 (unreleased)
    55=======================
     6
     7* Enable temporary suspension of officer accounts. Plugins must be
     8  updated after restart.
    69
    710* Rename 'Portal Users' 'Officers'.
  • main/waeup.kofa/trunk/docs/source/userdocs/testing.rst

    r12925 r12926  
    1717functionality. Why *automated* testing? Simply because no developer
    1818likes to click around the user interface to check tons of
    19 functionality. In Kofa more than 1100 tests, with dozens of actions
     19functionality. In Kofa more than 1300 tests, with dozens of actions
    2020per test, are being executed each time when the testrunner is
    2121started. This job can't be done manually.
     
    3030interacting with the portal as a user would. That implies that
    3131functional testing has to make use of a test browser. A test browser
    32 does the same job as normal web browser do, except for visualizing
     32does the same job as normal web browser does, except for visualizing
    3333the rendered html code.
    3434
  • main/waeup.kofa/trunk/docs/source/userdocs/users.rst

    r12922 r12926  
    5252   :ref:`Officers Doctests <userscontainer_txt>`
    5353
    54 Officers are users with a dedicated user account object stored in
    55 the ``users`` container (of type :py:class:`UsersContainer
    56 <waeup.kofa.userscontainer.UsersContainer>`) which is located in
    57 Kofa's root container. The officer account object has two more
    58 attributes than the principal instance which is created from the
    59 account data: (1) a `roles` attribute which is a list of global role
    60 names assigned to the officer, and (2) a private `_local_roles`
    61 attribute. The latter maps local role names to lists of objects the
    62 respective local role applies to. This information is important
    63 because local role assignment is originally stored only with the
    64 objects the role applies to and not with the user who got the role.
    65 When removing a user, Kofa iterates over the mapping and the list of
    66 objects in order to remove all these local role assignments denoted
    67 in the mapping.
     54Officers are users with a dedicated user account object stored in the
     55``users`` container (of type :py:class:`UsersContainer
     56<waeup.kofa.userscontainer.UsersContainer>`) which is located in Kofa's root
     57container. The account object has three more attributes than the principal
     58instance which is created from the account data: (1) a `suspended` attribute
     59which allows to deactivate an account, (2) a `roles` attribute which is a list
     60of global role names assigned to the officer, and (3) a private `_local_roles`
     61attribute which maps local role names to lists of objects the respective local
     62role applies to. This information is important because local role assignment
     63is originally stored only with the objects the role applies to and not with
     64the user who got the role. When removing an officer, Kofa iterates over the
     65mapping and the list of objects in order to remove all these local role
     66assignments denoted in the mapping.
    6867
    6968The management of portal officers is done in the 'Officers' section
    70 of Kofa. The management page shoes all officers registered in the
     69of Kofa. The management page shows all officers registered in the
    7170portal together with their global and local roles. The table can be
    72 easily sorted or filtered.
     71easily sorted or filtered. Deactivated officer accounst are marked
     72``(suspended)``.
    7373
    7474
  • main/waeup.kofa/trunk/src/waeup/kofa/app.py

    r12476 r12926  
    8181        """Lookup all plugins and call their `update()` method.
    8282        """
    83         # XXX: TBD: Remove update() in all plugins but documents
     83        # XXX: TBD: Remove update() in all plugins but documents and users
    8484        getUtility(IKofaPluggable, name='documents').update(
     85            self, 'documents', self.logger)
     86        getUtility(IKofaPluggable, name='users').update(
    8587            self, 'documents', self.logger)
    8688        return
  • main/waeup.kofa/trunk/src/waeup/kofa/authentication.py

    r12869 r12926  
    210210        self.phone = phone
    211211        self.public_name = public_name
     212        self.suspended = False
    212213        self.setPassword(password)
    213214        self.setSiteRolesForPrincipal(roles)
     
    226227        if not self.password:
    227228            # unset/empty passwords do never match
     229            return False
     230        if self.suspended == True:
    228231            return False
    229232        passwordmanager = getUtility(IPasswordManager, 'SSHA')
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py

    r12919 r12926  
    333333                                   type='warning')
    334334                    return
     335            # Display appropriate flash message if credentials are correct
     336            # but officer has been deactivated.
     337            login = self.request.form['form.login']
     338            if login in grok.getSite()['users']:
     339                user = grok.getSite()['users'][login]
     340                password = self.request.form['form.password']
     341                passwordmanager = getUtility(IPasswordManager, 'SSHA')
     342                if user.password is not None and \
     343                    passwordmanager.checkPassword(user.password, password):
     344                    self.flash(_('Your user name and password are correct '
     345                                 'but yor account has been temporarily '
     346                                 'deactivated.'),
     347                               type='warning')
     348                    return
    335349            self.flash(_('You entered invalid credentials.'), type='danger')
    336350            return
     
    578592    grok.name('add')
    579593    grok.template('usereditformpage')
    580     form_fields = grok.AutoFields(IUserAccount)
     594    form_fields = grok.AutoFields(IUserAccount).omit('suspended')
    581595    label = _('Add officer')
    582596
     
    624638
    625639    def label(self):
    626         return _("Edit user ${a}", mapping = {'a':self.context.__name__})
     640        return _("Edit officer ${a}", mapping = {'a':self.context.__name__})
    627641
    628642    def setUpWidgets(self, ignore_request=False):
     
    703717    grok.require('waeup.editUser')
    704718    form_fields = grok.AutoFields(IUserAccount).omit(
    705         'name', 'description', 'roles')
     719        'name', 'description', 'roles', 'suspended')
    706720    label = _(u"My Preferences")
    707721
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/usereditformpage.pt

    r11254 r12926  
     1<p class="alert alert-danger"  i18n:domain="waeup.kofa"
     2   i18n:translate="officer_suspended_warning"
     3   tal:condition="python: getattr(context, 'suspended', False)">
     4  <strong>ATTENTION:</strong>
     5  This account has been suspended. The officer can't login.
     6</p>
     7
    18<form action="." tal:attributes="action request/URL" method="post"
    29      i18n:domain="waeup.kofa" enctype="multipart/form-data"
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/userscontainerpage.pt

    r11254 r12926  
    1212    <tr tal:repeat="account context/values">
    1313      <td tal:content="account/name">USERNAME</td>
    14       <td tal:content="account/title">TITLE</td>
     14      <td>
     15        <span tal:content="account/title">TITLE</span>
     16        <span style="color:red" tal:condition="account/suspended">(suspended)</span>
     17      </td>
    1518      <td nowrap tal:content="structure python:view.getSiteRoles(account)">SITE ROLES</td>
    1619      <td tal:content="structure python:view.getLocalRoles(account)">LOCAL ROLES</td>
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py

    r12841 r12926  
    3030from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
    3131from waeup.kofa.app import University
    32 from waeup.kofa.interfaces import IJobManager
     32from waeup.kofa.interfaces import IJobManager, IUserAccount
    3333from waeup.kofa.tests.test_async import FunctionalAsyncTestCase
    3434from waeup.kofa.university.faculty import Faculty
     
    445445            'faculties']['fac1']['dep1'].certificates['CERT1'])
    446446        return
     447
     448    def test_suspended_officer(self):
     449        self.app['users'].addUser(
     450            'officer', 'secret', title='Bob Officer', email='aa@aa.ng')
     451        # Officer can't login if their password is not set
     452        self.app['users']['officer'].password = None
     453        self.browser.open('http://localhost/app/login')
     454        self.browser.getControl(name="form.login").value = 'officer'
     455        self.browser.getControl(name="form.password").value = 'secret'
     456        self.browser.getControl("Login").click()
     457        self.assertTrue(
     458            'You entered invalid credentials.' in self.browser.contents)
     459        # We set the password again
     460        IUserAccount(
     461            self.app['users']['officer']).setPassword('secret')
     462        # Officers can't login if their account is suspended/deactivated
     463        self.app['users']['officer'].suspended = True
     464        self.browser.open('http://localhost/app/login')
     465        self.browser.getControl(name="form.login").value = 'officer'
     466        self.browser.getControl(name="form.password").value = 'secret'
     467        self.browser.getControl("Login").click()
     468        self.assertMatches(
     469            '...but yor account has been temporarily deactivated...',
     470            self.browser.contents)
     471        self.assertFalse("Bob Officer" in self.browser.contents)
     472        self.app['users']['officer'].suspended = False
     473        self.browser.open('http://localhost/app/login')
     474        self.browser.getControl(name="form.login").value = 'officer'
     475        self.browser.getControl(name="form.password").value = 'secret'
     476        self.browser.getControl("Login").click()
     477        self.assertMatches(
     478            '...You logged in...', self.browser.contents)
     479        self.assertTrue("Bob Officer" in self.browser.contents)
     480        self.browser.getLink("Logout").click()
     481        # Suspended accounts are marked
     482        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
     483        self.browser.open('http://localhost/app/users')
     484        self.assertFalse('(suspended)' in self.browser.contents)
     485        self.app['users']['officer'].suspended = True
     486        self.browser.open('http://localhost/app/users')
     487        self.assertTrue(
     488            '<span style="color:red">(suspended)</span>'
     489            in self.browser.contents)
     490        self.browser.open('http://localhost/app/users/officer')
     491        self.assertTrue(
     492            'This account has been suspended.' in self.browser.contents)
     493        self.app['users']['officer'].suspended = False
     494        self.browser.open('http://localhost/app/users/officer')
     495        self.assertFalse(
     496            'This account has been suspended.' in self.browser.contents)
     497        return
  • main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py

    r12915 r12926  
    549549    """
    550550
    551     failed_logins = Attribute("""FailedLoginInfo for this account""")
     551    failed_logins = Attribute('FailedLoginInfo for this account')
    552552
    553553    name = schema.TextLine(
    554554        title = _(u'User Id'),
    555         description = u'Login name of user',
     555        description = _(u'Login name of user'),
    556556        required = True,)
    557557
     
    562562    public_name = schema.TextLine(
    563563        title = _(u'Public Name'),
    564         description = u"Substitute for officer's real name "
    565                        "in student object histories.",
     564        description = _(u"Substitute for officer's real name "
     565                       "in student object histories."),
    566566        required = False,)
    567567
     
    589589        )
    590590
     591    suspended = schema.Bool(
     592        title = _(u'Account suspended'),
     593        description = _(u'If set, the account is immediately blocked.'),
     594        default = False,
     595        required = False,
     596        )
    591597
    592598
  • main/waeup.kofa/trunk/src/waeup/kofa/students/authentication.py

    r10055 r12926  
    7171        return self.title
    7272
     73    def suspended(self):
     74        return self.context.suspended
     75
    7376    @property
    7477    def failed_logins(self):
Note: See TracChangeset for help on using the changeset viewer.