users in Lino Prima

The lino_prima.lib.users plugin extends lino.modlib.users.

A tested document

This is a tested document. The following instructions are used for initialization:

>>> import lino
>>> lino.startup('lino_prima.projects.prima1.settings')
>>> from lino.api.doctest import *

Available user types

Lino Prima knows the following user types:

>>> rt.show(rt.models.users.UserTypes, language="en")
======= =========== ===============
 value   name        text
------- ----------- ---------------
 000     anonymous   Anonymous
 100     user        User
 200     teacher     Teacher
 300     pupil       Pupil
 500     staff       Staff
 900     admin       Administrator
======= =========== ===============

A demo site has the following users:

>>> rt.show(rt.models.users.UsersOverview, language="en")
... 
====================== ===================== ==========
 Username               User type             Language
---------------------- --------------------- ----------
 abel.adam              200 (Teacher)         en
 achille.adriaen        200 (Teacher)         en
 adèle.adami            200 (Teacher)         en
 adélaïde.adriaensen    200 (Teacher)         en
 aglaé.adriaenssens     200 (Teacher)         en
 agnès.adriensence      200 (Teacher)         en
 aimé.adriaenssen       200 (Teacher)         en
 aimée.aelter           200 (Teacher)         en
 alfred.adriencense     200 (Teacher)         en
 alphonse.adrienssens   200 (Teacher)         en
 robin                  900 (Administrator)   en
 rolf                   900 (Administrator)   de
====================== ===================== ==========

The site manager

Robin is a site manager, he has a complete menu.

>>> show_menu('robin')
... 
- School : My groups, My Upload files, Data problem messages assigned to me
- Configure :
  - System : Site configuration, Pupils, Teachers, Users, System tasks
  - School : Groups, Subjects, Roles, Grades, Library volumes, Upload types, Academic years, Periods
  - Projects : Project templates
  - Certificates : Final challenges, Certificate templates
- Explorer :
  - System : Authorities, User types, User roles, Data checkers, Data problem messages, content types, Background procedures
  - School : Skills, Enrolments, Casts, Courses, Upload files, Upload areas
  - Projects : Project sections, General ratings
  - Certificates : Exams, Challenges, Challenge ratings, Rating summaries, Final exams, Final exam ratings, Exam responses, Certificate section templates, Certificate element templates, Certificates, Certificate sections, Certificate elements
  - Office : Mentions
- Site : User sessions, About

Our pilot customer uses Lino Prima mainly in German:

>>> show_menu('rolf')
... 
- Schule : Meine Klassen, Meine Upload-Dateien, Meine Datenkontrollliste
- Konfigurierung :
  - System : Site-Konfiguration, Schüler, Lehrer, Benutzer, Systemaufgaben
  - Schule : Klassen, Fächer, Rollen, Jahrgänge, Dateibibliotheken, Upload-Arten, Schuljahre, Perioden
  - Bausteine : Bausteinvorlagen
  - Zeugnisse : Prüfungsleistungen, Zeugnisvorlagen
- Explorer :
  - System : Vollmachten, Benutzerarten, Benutzerrollen, Datentests, Datenproblemmeldungen, Datenbankmodelle, Background procedures
  - Schule : Kompetenzen, Einschreibungen, Lehrerrollen, Kurse, Upload-Dateien, Upload-Bereiche
  - Bausteine : Bausteinabschnitte, Allgemeinbewertungen
  - Zeugnisse : Tests, Leistungen, Leistungsbewertungen, Bewertungsübersichten, Prüfungen, Prüfungsbewertungen, Test-Antworten, Zeugnisabschnittvorlagen, Zeugniselementvorlagen, Zeugnisse, Zeugnisabschnitte, Zeugniselemente
  - Büro : Erwähnungen
- Site : Benutzersitzungen, Info

Normal teachers have a reduced menu:

>>> rt.login('abel.adam').get_user().user_type
<users.UserTypes.teacher:200>
>>> show_menu('abel.adam')
... 
- School : My groups
- Site : About

Don’t read me

20251120

The following snippet verifies #6486 (TypeError at /api/users/Me/myself):

>>> test_client.force_login(rt.login('abel.adam').get_user())
>>> url = "/api/users/Me/myself?dm=detail&fmt=json&ul=de&wt=d"
>>> resp = test_client.get(url)
>>> pprint(json.loads(resp.content.decode()))  
{'data': {'created': '...',
          'disable_editing': False,
          'disabled_fields': {'created': True,
                              'export_excel': True,
                              'id': True,
                              'merge_row': True,
                              'modified': True,
                              'partner': True,
                              'send_email': True,
                              'user_type': True},
          'email': '',
          'end_date': None,
          'first_name': 'Abel',
          'id': 3,
          'initials': '',
          'language': 'Englisch',
          'languageHidden': 'en',
          'last_name': 'Adam',
          'modified': '...',
          'nickname': '',
          'school.CastsByUser1': {'delayed_value_url': 'values/users/Me/3/school.CastsByUser1'},
          'school.EnrolmentsByPupil1': {'delayed_value_url': 'values/users/Me/3/school.EnrolmentsByPupil1'},
          'start_date': None,
          'user_type': '200 (Lehrer)',
          'user_typeHidden': '200',
          'username': 'abel.adam',
          'users.AuthoritiesGiven1': {'delayed_value_url': 'values/users/Me/3/users.AuthoritiesGiven1'},
          'users.AuthoritiesGiven2': {'delayed_value_url': 'values/users/Me/3/users.AuthoritiesGiven2'},
          'users.AuthoritiesTaken1': {'delayed_value_url': 'values/users/Me/3/users.AuthoritiesTaken1'},
          'users.AuthoritiesTaken2': {'delayed_value_url': 'values/users/Me/3/users.AuthoritiesTaken2'}},
 'disable_delete': 'No delete_action',
 'id': 3,
 'navinfo': {'first': 107,
             'last': 138,
             'message': 'Record  35 von 156',
             'next': 5,
             'next_page': 22,
             'offset': 30,
             'prev': 155,
             'prev_page': 152,
             'recno': 35},
 'param_values': {'end_date': None,
                  'show_active': None,
                  'show_activeHidden': None,
                  'start_date': None,
                  'user_type': None,
                  'user_typeHidden': None},
 'title': 'Meine Einstellungen &raquo; Abel Adam'}

Side effect of #6486: Forgetting the “fmt=json” in above url lead to a confusing error message. Now it is less confusing:

>>> url = "/api/users/Me/myself"
>>> resp = test_client.get(url)  
<lino_react.react.renderer.Renderer object at ...> has no html_page_template: /api/users/Me/myself
Traceback (most recent call last):
...
django.core.exceptions.BadRequest: <lino_react.react.renderer.Renderer object at ...> has no html_page_template