Monday, June 29, 2015¶
Uff! Adapting the permissions system of Lino Welfare to the new class-based paradigm took me a whole day!
Nevertheless it is clear that this was a good and important step for Lino. I am glad to have test cases like General overview of Lino Welfare.
Old content of setup_user_profiles()
:
from django.utils.translation import ugettext_lazy as _
from lino.modlib.users.choicelists import UserProfiles
UserProfiles.reset(
'* office coaching integ courses cbss newcomers debts '
'reception beid')
add = UserProfiles.add_item
add('000', _("Anonymous"), '_ _ _ _ _ _ _ _ _ _',
name='anonymous',
readonly=True,
authenticated=False)
add('100', _("Integration Agent"), 'U U U U U U _ _ _ U')
add('110', _("Integration Agent (Manager)"), 'U M M M M U _ _ _ U')
add('200', _("Newcomers consultant"), 'U U U _ _ U U _ _ U')
add('210', _("Reception clerk"), 'U U _ _ _ _ _ _ U U')
add('300', _("Debts consultant"), 'U U U _ _ _ U U _ U')
add('400', _("Social agent"), 'U U U _ U U _ _ _ U')
add('410', _("Social agent (Manager)"), 'U M M _ M U _ _ _ U')
add('900', _("Administrator"), 'A A A A A A A A A U',
name='admin')
Basically this code does not change much… except that we replaced
the system of “U M A _” strings by classes, and that we define these
classes in a separate module lino_welfare.modlib.welfare.roles
:
from lino.modlib.users.choicelists import UserProfiles
from lino_welfare.modlib.welfare.roles import *
UserProfiles.clear()
add = UserProfiles.add_item
add('000', _("Anonymous"), Anonymous, name='anonymous',
readonly=True, authenticated=False)
add('100', _("Integration Agent"), IntegrationAgent)
add('110', _("Integration Agent (Manager)"), IntegrationStaff)
add('200', _("Newcomers consultant"), NewcomersAgent)
add('210', _("Reception clerk"), ReceptionOperator)
add('300', _("Debts consultant"), DebtsUser)
add('400', _("Social agent"), SocialAgent)
add('410', _("Social agent (Manager)"), SocialStaff)
add('900', _("Administrator"), SiteAdmin, name='admin')
Maybe an inheritance-diagram can help to visualize the complexity:
Cannot create a consistent method resolution order¶
Here is a side effect of having class-based permissions: since we use a rather complex form of multiple inheritance, I needed to learn how to analyze error messages like this one:
$ python -m lino_welfare.modlib.welfare.roles
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/luc/hgwork/welfare/lino_welfare/modlib/welfare/roles.py", line 29, in <module>
class IntegrationStaff(IntegrationAgent, IntegrationStaff):
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases CBSSUser, OfficeOperator
This error comes when I specify a “nonsense” or “illegal” inheritence line. But in above case I did not see immediately where exactly the problem was. So I tried to write out the full genealogic tree:
Thanks to Sixty North for writing a good blog entry about it.
A disadvantage of the class-based permission system is (or was) the
fact that e.g. watch – Watching database changes which uses
lino.modlib.contacts
was now forced to define user
roles. Even though the example does not care about them. Because
otherwise even the site manager has no access to the contacts
menu.
The new attribute lino.core.site.Site.disable_user_roles
is a
workaround for this, or maybe even a cool thing: setting this to
True will “disable” all
lino.core.utils.Permittable.required_roles
.