ADR 0025 — A level on the contribution decides rights over a core record#
Status: accepted
Decision#
What a person may do on a project, dataset, sample or measurement is one stored level on their contribution to it: view, edit or manage, each including the one before. A level on a dataset applies to its samples and measurements, and a level on a project applies to its datasets. The higher of two applies.
One permission backend, RecordLevelBackend, answers every object-level question about these
records from that level. Each permission the four models declare is mapped to the level it needs,
and a permission the map does not know is refused.
Permissions stored per person per record by django-guardian are not read for these records. An upgrade migration converts the ones that exist into levels. The backends that passed a dataset’s stored permissions down to its samples and measurements are removed. django-guardian stays for organizations and for any model a portal defines.
Holders of a portal role are answered as before, by PortalRolePermissionBackend.
Why#
Before this, rights over a record were several permission rows per person per record, granted to the creator and otherwise only in the administration interface. A research team could not let a colleague into its own private dataset. Three backends each knew part of the rule, none reached a project, and several lists read the rows directly without asking any backend.
The Contributors tab had to show and set what each person may do. A level is something a person can read and choose. A set of independent permissions is not: it allows combinations nobody can reason about, such as being able to delete a dataset and not open it.
Leaving the stored rows in force beside the levels would have kept a second way into a private record that the tab does not show.
Consequences#
Code that asks
user.has_perm("dataset.change_dataset", dataset)keeps working and is answered from the level.Code that grants rights with
assign_permon a core record no longer grants anything. It credits the person throughCreditingat the level it means.A list of the records a user may see or change uses
with_level(user, level)on the model’s queryset. A lookup of stored rows finds nothing.No level gives the right to delete without the right to change.
Deleting a sample needs the manage level on it or above. The right to change its dataset used to be enough.
Rights cannot be given over a core record to a whole group. If that is needed, it is a feature of its own, with the group shown on the tab, and this record would be amended.
A new permission on a core model has to be added to the map, or it is refused for everyone but holders of a portal role.