Welcome | Get started | Dive into Lino | Contribute | Reference
users
: user management¶
This document describes the lino.modlib.users
plugin, which in Lino
replaces django.contrib.auth
. See also User management à la Lino for getting
started with user management. If you wonder why Lino replaces Django's user
management and permission system, see Lino has its own user management.
This is a tested document. The following instructions are used for initialization:
>>> from lino import startup
>>> startup('lino_book.projects.noi1r.settings')
>>> from lino.api.doctest import *
Users¶
- class lino.modlib.users.AllUsers¶
Shows the list of all users on this site.
- class lino.modlib.users.UsersOverview¶
A variant of
Users
showing only active users and only some fields. This is used on demo sites inadmin_main.html
to display the list of available users.
- class lino.modlib.users.User¶
The Django model used to represent a user account.
Database fields that must be edited by a site manager:
- username¶
Must be either unique or empty. Users with an empty username cannot sign in.
- user_type¶
The user type assigned to this user. User accounts having this field empty cannot be used to sign in.
See also Introduction to permissions.
- partner¶
The partner record with additional contact information about this user account.
This field is used to optionally link a user account to a partner. Some applications provide functionalities that aren't available unless this field is given.
A same partner can have more than one user accounts.
This is a pointer to
lino_xl.lib.contacts.Partner
. This is aDummyField
whenlino_xl.lib.contacts
is not installed or when User is a subclass ofPartner
.
Database fields that are considered user preferences:
- initials¶
The nickname or initials of this user. This does not need to be unique but should be reasonably identifying.
- date_format¶
The date format to use when parsing or displaying dates.
See
lino.modlib.about.DateFormats
.
Database fields that aren't directly editable:
- verification_code¶
A random string set for every new user. Used for online registration. When this is non empty,
is_verified()
returns False and theverify
action is available.When
allow_online_registration
is False, this is a dummy field.
- person¶
A virtual read-only field that returns the
Person
MTI child of thepartner
(if it exists) and otherwise None.
- company¶
A virtual read-only field that returns the
Company
MTI child of thepartner
(if it exists) and otherwise None.
- last_login¶
Not used in Lino.
- __str__(self)¶
Returns either the initials or
get_full_name()
.
- get_full_name(self)¶
Return the first_name plus the last_name, with a space in between. If both fields are empty, return the
initials
or theusername
.
- get_row_permission(self, ar, state, ba)¶
Only system managers may edit other users. See also
disabled_fields()
.One exception is when AnonymousUser is not readonly. This means that we want to enable online registration. In this case everybody can modify an unsaved user.
- end_date¶
- start_date¶
If
start_date
is given, then the user cannot sign in before that date. Ifend_date
is given, then the user cannot sign in after that date.These fields are also used for userstats: User statistics.
Instance attributes:
- authenticated¶
No longer used. See as
is_authenticated
.
- is_authenticated¶
This is always True. Compare with
AnonymousUser.is_authenticated
.
Querying users:
- classmethod get_active_users(cls, required_roles=None)¶
Return a queryset of users that satisfy the specified criteria.
Usage examples see Querying users below.
User types¶
>>> rt.show('users.UserTypes', language="en")
======= =============== ===============
value name text
------- --------------- ---------------
000 anonymous Anonymous
100 customer user Customer
200 contributor Contributor
400 developer Developer
900 admin Administrator
======= =============== ===============
- class lino.modlib.users.UserTypes¶
The list of user types available in this application.
Every application should define at least three named user types:
- anonymous¶
- user¶
- admin¶
- class lino.modlib.users.UserType¶
Base class for all user types. Any instance if this represents a possible user type.
- readonly¶
Whether users of this type get only write-proteced access.
A subset of
languages
which should be hidden for users of this type. Default value ishidden_languages
. This is used on multilingual sites with more than 4 or 5 languages.
- context(self)¶
Return a context manager so you can write code to be run with this as the current user type:
with UserTypes.admin.context(): # some code
User roles and their usage¶
- class lino.modlib.users.UserRoles¶
Shows a list of the user roles used in this application together with the user type that have them.
This table can help when designing the list of user types and what permissions each of them should have.
Example:
>>> rt.show(users.UserRoles)
...
================================ ===== ===== ===== ===== =====
Name 000 100 200 400 900
-------------------------------- ----- ----- ----- ----- -----
cal.CalendarReader ☑
comments.CommentsReader ☑ ☑ ☑ ☑ ☑
comments.CommentsStaff ☑ ☑
comments.CommentsUser ☑ ☑ ☑ ☑
comments.PrivateCommentsReader ☑ ☑
contacts.ContactsStaff ☑
contacts.ContactsUser ☑ ☑
core.DataExporter ☑ ☑ ☑ ☑
core.Expert ☑ ☑
core.SiteUser ☑ ☑ ☑ ☑
courses.CoursesUser ☑ ☑ ☑
excerpts.ExcerptsStaff ☑ ☑
excerpts.ExcerptsUser ☑ ☑ ☑
invoicing.InvoicingStaff ☑
invoicing.InvoicingUser ☑
ledger.LedgerStaff ☑
noi.Anonymous ☑
noi.Contributor ☑ ☑ ☑
noi.Customer ☑ ☑ ☑ ☑
noi.Developer ☑ ☑
noi.SiteAdmin ☑
office.OfficeStaff ☑
office.OfficeUser ☑ ☑ ☑ ☑
products.ProductsStaff ☑
storage.StorageStaff ☑
storage.StorageUser ☑
tickets.Reporter ☑ ☑ ☑ ☑
tickets.Searcher ☑ ☑ ☑ ☑ ☑
tickets.TicketsStaff ☑ ☑
tickets.Triager ☑ ☑
users.Helper ☑ ☑ ☑
votes.VotesStaff ☑
votes.VotesUser ☑ ☑ ☑ ☑
working.Worker ☑ ☑ ☑
================================ ===== ===== ===== ===== =====
The table doesn't show all user roles, only those that are "meaningful".
Where meaningful means: those which are mentioned (either imported or defined)
in the global context of the user_types_module
. We tried more "intelligent"
approaches, but it is not trivial for Lino to guess which roles are
"meaningful".
Querying users¶
All users:
>>> users.User.get_active_users()
<QuerySet [User #7 ('Jean'), User #6 ('Luc'), User #4 ('Marc'), User #5 ('Mathieu'), User #3 ('Romain Raffault'), User #2 ('Rolf Rompen'), User #1 ('Robin Rood')]>
Only site administrators:
>>> from lino.core.roles import SiteAdmin
>>> users.User.get_active_users([SiteAdmin])
<QuerySet [User #3 ('Romain Raffault'), User #2 ('Rolf Rompen'), User #1 ('Robin Rood')]>
All except site administrators:
>>> users.User.get_active_users(unwanted_roles=[SiteAdmin])
<QuerySet [User #7 ('Jean'), User #6 ('Luc'), User #4 ('Marc'), User #5 ('Mathieu')]>
All who speak English:
>>> users.User.get_active_users(language="en")
<QuerySet [User #7 ('Jean'), User #6 ('Luc'), User #4 ('Marc'), User #5 ('Mathieu'), User #1 ('Robin Rood')]>
User sessions¶
- class lino.modlib.users.Sessions¶
Show a list of all user sessions.
See User sessions.
The current user type¶
This is used by lino.utils.jsgen
, i.e. when generating the
linoweb.js
file for a given user type.
Site configuration¶
This plugin adds the following site features:
- third_party_authentication¶
Whether this site provides third party authentication.
This should be activated only when there is at least one authentication provider.
This plugin has the following site settings:
- allow_online_registration¶
Whether users can register online. When this is set to True, a create_account action will be available under
About
actor. This also activates the verification system, and on account creation new users are asked to enter a verification code to verify their email address.
- active_sessions_limit¶
The sessions limit for this site. The default value -1 means that there is no limitation. Setting this to 0 will prevent any new login attempt and might be useful as a temporary value before shutting down a site.
Roles¶
This plugin defines the following user roles.
- class lino.modlib.users.Helper¶
Somebody who can help others by running
AssignToMe
action.
- class lino.modlib.users.AuthorshipTaker¶
Somebody who can help others by running
TakeAuthorship
action.
Actions¶
- class lino.modlib.users.SendWelcomeMail¶
Send a welcome mail to this user.
- class lino.modlib.users.ChangePassword¶
Change the password of this user.
- current¶
The current password. Leave empty if the user has no password yet. A site manager doesn't need to specify this at all.
- new1¶
The new password.
- new2¶
The new password a second time. Both passwords must match.
- class lino.modlib.users.SignIn¶
Open a window that asks for username and password and authenticates as this user when submitted.
- class lino.modlib.users.SignOut¶
Sign out the current user and return to the welcome screen for anonymous visitors.
Model mixins¶
- class lino.modlib.users.Authored¶
- manager_roles_required¶
The list of required roles for getting permission to edit other users' work.
By default, only
SiteStaff
users can edit other users' work.An application can set
manager_roles_required
to some other user role class or a tuple of such classes.Setting
manager_roles_required
to[]
will disable this behaviour (i.e. everybody can edit the work of other users).This is going to be passed to
has_required_roles
of the requesting user's profile.Usage examples see
lino_xl.lib.notes.models.Note
orlino_xl.lib.cal.Component
.
- author_field_name¶
No longer used. The name of the field that defines the author of this object.
- class lino.modlib.users.UserAuthored¶
Inherits from
Authored
.Mixin for models with a
user
field that points to the "author" of this object. The default user of new instances is automatically set to the requesting user.- user¶
The author of this database object.
A pointer to
lino.modlib.users.models.User
.
- class lino.modlib.users.StartPlan¶
- update_after_start¶
Whether to run
Plan.update_plan()
after starting the plan.
- class lino.modlib.users.UserPlan¶
Mixin for anything that represents a "plan" of a given user on a given day.
What a "plan" means, depends on the inheriting child. Usage examples are an invoicing plan (
lino_xl.lib.invoicing.Plan
) or an accounting report ():class:lino_xl.ledger.Report).The mixin makes sure that there is only one database instance per user. A plan is considered a low value database object to be reused frequently.
Inherits from
UserAuthored
.- user¶
The user who owns and uses this plan.
- today¶
This date of this plan. This is automatically set to today each time the plan is called or updated.
- update_plan_button¶
- run_start_plan(self, user)¶
Return the database object for this plan and user. or create
- update_plan(self, ar)¶
Implementing models should provide this method.
- class lino.modlib.users.UpdatePlan¶
Build a new list of suggestions. This will remove all current suggestions.
doctests¶
Verify whether the help_text of the change_password action is set:
>>> ba = rt.models.users.AllUsers.get_action_by_name('change_password')
>>> print(ba.action.help_text)
Change the password of this user.
Verify whether #3766 is fixed:
>>> show_choices('robin', '/choices/users/Users/partner')
...
Altenberg Hans
Arens Andreas
...
Ärgerlich Erna
Õunapuu Õie
Östges Otto
>>> show_choices('robin', '/choices/users/Users/user_type')
000 (000 (Anonymous))
100 (100 (Customer))
200 (200 (Contributor))
400 (400 (Developer))
900 (900 (Administrator))
User types module¶
The default value for Site.user_types_module
is None, meaning that
permission control is inactive: everything is permitted. But note that
Site.set_user_model()
sets it to lino.core.user_types
.
This must be set if you want to enable permission control based on
user roles defined in Permittable.required_roles
and
UserType.role
.
If set, Lino will import the named module during site startup. It is expected to
define application-specific user roles (if necessary) and to populate the
UserTypes
choicelist.
Examples of such user types modules are
lino.core.user_types
and
lino_noi.lib.noi.user_types
.
The welcome message¶
- users/welcome_email.eml¶
The template used to generate the welcome email to new users.
Here are several ways for generating the verify link in the
users/welcome_email.eml
.
A first series used the instance action:
>>> ar = rt.login("robin", renderer=settings.SITE.kernel.default_renderer)
>>> obj = ar.get_user()
>>> ar.permalink_uris = True
>>> print(tostring(ar.instance_action_button(
... obj.verify, request_kwargs=dict(action_param_values=dict(
... email="foo@example.com", verification_code="123")))))
<a style="text-decoration:none" href="/api/users/AllUsers/1?fv=foo%40example.com&fv=123&an=verify">Verify</a>
>>> # ba = users.Users.get_action_by_name('verify')
>>> url = ar.get_permalink(obj.verify.bound_action, obj, email="foo@example.com", verification_code="123")
>>> print(url)
/api/users/AllUsers/1?fv=foo%40example.com&fv=123&an=verify
>>> # test_client.force_login(obj)
>>> # test_client.get(url)
But this wasn't good because it uses the lino.modlib.users.AllUsers
data view, which is visible only to SiteAdmin
.
>>> ba = users.Me.get_action_by_name('verify')
>>> pv = dict(email="foo@example.com", verification_code="123")
>>> from lino.api import _
>>> print(tostring(ar.row_action_button(
... obj, ba, _("Click here to verify"),
... request_kwargs=dict(action_param_values=pv))))
<a style="text-decoration:none" href="/api/users/Me/1?fv=foo%40example.com&fv=123&an=verify">Click here to verify</a>
TODO: Is there a more intuitive syntax for rendering our button? Here is an attempt:
>>> sar = obj.verify.request_from(ar, action_param_values=dict(
... email="foo@example.com", verification_code="123"), permalink_uris=True)
>>> sar.permalink_uris = True
>>> print(tostring(sar.row_action_button_ar(obj)))
<a style="text-decoration:none" href="javascript:window.App.runAction({ "actorId": "users.AllUsers", "an": "verify", "onMain": true, "rp": null, "sr": 1, "status": { "base_params": { }, "field_values": { "email": "", "verification_code": "" }, "fv": [ "", "" ], "param_values": { "end_date": null, "start_date": null, "user_type": null, "user_typeHidden": null }, "record_id": 1 } })">Verify</a>
In the body of the welcome_message.eml
, we use
lino.core.site.Site.server_url
as a base href
header field:
<html><head><base href="{{settings.SITE.server_url}}" target="_blank"></head><body>
>>> print(settings.SITE.server_url)
http://127.0.0.1:8000/