-
Notifications
You must be signed in to change notification settings - Fork 3
User Lab Assignment
Classification records are created under a lab.
Lab membership is not a direct user↔lab table — a user belongs to a lab by being in a Django group
whose name matches the lab's group_name field. Lab.valid_labs_qs(user) is literally
"labs whose group_name is one of this user's group names".
This was primarily done for being able to assign users to labs via OIDC/Keycloak
(see oidc_auth/backend.py), where the identity provider sends group membership.
Lab groups are
<institution>/<lab>
Rather than pre-define the groups, if we define the Labs via the admin tool, the groups will be
automatically created. If you create a Lab with a "group_name" field of
sa_pathology/familial_cancer_frome, saving it auto-creates (if they don't already exist):
-
sa_pathology— the parent institution group -
sa_pathology/familial_cancer_frome— the lab group
then repeat for the other labs.
Now to assign people to a lab, assign them to the most specific relevant group, and each group below. e.g. if they're a lab member for Familial Cancer assign them to
-
sa_pathology/familial_cancer_fromeand sa_pathology
Note that the OIDC login automatically assigns to groups in the hierarchy, but for regular Django login you need to make sure you manually set it.
Keycloak sends lab membership as groups under a top-level /associations/ tree.
oidc_auth/backend.py strips the associations prefix and adds each level of nesting as its own
Django group, so /associations/sa_pathology/familial_cancer_frome produces:
sa_pathology/familial_cancer_fromesa_pathology
Groups are created on demand (we trust the OIDC connector, since it can already make admins), and
groups the user no longer has are removed on each login. auto_set_default_lab() runs at the end of
login, so the default lab is kept valid automatically. See Keycloak Setup.
Lab heads are not a group — there is a LabHead model (lab + user, unique together), managed via
Django admin. It is what Lab.can_write() and Organization.can_write() check, and what
lab.lab_users uses to label a member's role as "head" vs "user".
UserSettings.default_lab is a FK used as the default when a user belongs to more than one lab.
UserSettings.auto_set_default_lab() maintains it: if the current value is no longer valid for the user
(they've lost the matching group) it is cleared, and if unset it is populated with the user's first
valid lab. A valid existing value is left alone.
# requires "default_lab" be set if they have multiple labs. Raises ValueError if it can't decide
user_settings.get_lab()
# Same, but returns (lab, error_message) instead of raising
UserSettings.get_lab_and_error(user)
# Active users of a lab, each wrapped in a LabUser carrying .user and .role ('head' or 'user')
for lab_user in lab.lab_users:
print(lab_user.user, lab_user.role)
# Just the active Users as a queryset
lab.active_users
# Return labs for a user
for lab in Lab.valid_labs_qs(user):
pass
# Permission checks
lab.is_member(user)
lab.can_write(user) # superuser or LabHead
lab.check_can_write(user) # raises PermissionDenied