Saturday, September 2, 2017¶
Avanti¶
I verified that there is still no fix for #1989. See Monday, July 31, 2017.
Courses
(All courses) is no longer visible for teachers.Idem for
ActivityPlanning
Custom permissions for the detail action¶
Lino has a subtle new feature: a DetailLayout
can now have a
required_roles
attribute. If this
is given, then it overrides the default value which until now was
always the required_roles of the actor.
This was needed because otherwise after above change (make
Courses
hidden for teachers), MyCoursesGiven
had no
detail action as well (for teacher). Also e.g. as_summary_item()
calls
get_default_table()
which, for a course, is customized because
the detail of a course can be different depending on what we call the
“course area”. E.g. in Lino Voga we have “courses”, “hikes” and
“travels”. They all are activities, but their detail layouts defer.
This new feature required a few internal changes. Don’t try to understand the following snippets in detail (I just used them in order to understand myself)
>>> from lino import startup
>>> startup('lino_book.projects.adg.settings.demo')
>>> from lino.api.doctest import *
>>> ses = rt.login('laura')
>>> user_type = ses.get_user().user_type
>>> user_type
<users.UserTypes.teacher:100>
>>> user_type.role
...
<lino_avanti.lib.avanti.user_types.Teacher object at ...>
>>> obj = rt.models.courses.Course.objects.get(pk=1)
>>> obj.get_detail_action(None)
<BoundAction(courses.Activities, <lino.core.actions.ShowDetail detail ('Detail')>)>
- Note this returned before::
<BoundAction(courses.Courses, <lino.core.actions.ShowDetail detail (‘Detail’)>)>
Problem: When a session with a user is given, then get_detail_action(ses) returned None because the default table was (and is) Courses, not Activities. But here we want Lino to understand that we actually do allow to open the detail window because that detail window has been inherited from Activities.
>>> obj.get_detail_action(ses)
<BoundAction(courses.Activities, <lino.core.actions.ShowDetail detail ('Detail')>)>
>>> obj.line.course_area.courses_table
u'courses.Courses'
>>> table = rt.models.resolve('courses.Courses')
>>> table
lino_xl.lib.courses.desktop.Courses
>>> table.detail_action
<BoundAction(courses.Courses, <lino.core.actions.ShowDetail detail ('Detail')>)>
Teachers have no permission to see the Courses table:
>>> table.default_action.get_view_permission(user_type)
False
>>> actor = table.detail_action.action.defining_actor
>>> actor
lino_xl.lib.courses.desktop.Activities
>>> actor.get_view_permission(user_type)
True
>>> actor.detail_action.action.get_view_permission(user_type)
True
>>> actor.detail_action.allow_view(user_type)
True
But now we have the following problem:
>>> ba = rt.models.users.MySettings.detail_action
>>> ba
<BoundAction(users.MySettings, <lino.core.actions.ShowDetail detail ('Detail')>)>
The detail on MySettings now can be viewed only by those who can view the Users table:
>>> ba.actor.get_view_permission(ses.user.user_type)
True
>>> ba.action.get_view_permission(ses.user.user_type)
True
>>> ba.action.owner.required_roles is None
True
>>> ba.required
set([<class 'lino.core.roles.SiteUser'>])
>>> user_type.has_required_roles(ba.required)
True
>>> ba.allow_view(ses.user.user_type)
True
>>> ba.get_view_permission(ses.user.user_type)
True
MySettings does allow a detail, but Lino
>>> #dl = rt.models.courses.MyCoursesGiven.get_detail_layout()
>>> ba = rt.models.courses.MyCoursesGiven.detail_action
>>> ba.actor
lino_xl.lib.courses.desktop.MyCoursesGiven
>>> ba.action
<lino.core.actions.ShowDetail detail ('Detail')>
>>> ba.get_view_permission(ses.user.user_type)
True
>>> rt.models.courses.Courses.detail_action.action
<lino.core.actions.ShowDetail detail ('Detail')>
>>> rt.models.courses.Courses.detail_action.action.defining_actor
lino_xl.lib.courses.desktop.Activities
>>> rt.models.courses.Courses.detail_action.action.owner
...
<lino_xl.lib.courses.desktop.CourseDetail object at ...>
>>> rt.models.courses.MyCoursesGiven.detail_action.action.defining_actor
lino_xl.lib.courses.desktop.Activities
Aha. Course defines a custom get_detail_action()
because the
detail_layout to use when displaying a course depends on the
course_area (given by the course’s line
). And this is
Courses in our case. And yes I told Lino that teachers don’t have
permission to see Courses.
We don’t want teachers to see all courses, but we do want them to see the detail of a course for which they are author or instructor.
The library actions (default_action, detail_action, submit_detail, insert_action, delete_action and update_action) had their defining_actor to None.
The defining_actor of an action is the actor on which it has been instantiated for the first time. Subclasses of the defining actor can use the same action instance. That differentiation is used by the extjs renderer: for actions that cause some JS code to be rendered it makes no sense to generate that code several times.
A side effect is that I probably discovered and fixed a bug: teachers had no permission to edit their own settings.