11. Access as code¶
The bundles and roles a project always has can live in a file, reviewed like code and the same on every machine. The shop's:
"""
Who may do what in the shop, as code - applied by ``clearance_sync``, and by
every ``migrate`` (``SYNC_ON_MIGRATE``).
The file owns what it names: the admin site shows these bundles and roles
read only. Who is given a bundle or a role is not the file's to say - that is
done in the admin site, or by ``python manage.py example_data``.
"""
ACCESS = {
'bundles': {
# The orders of their own branch: read, edited and approved - never the price.
'Branch managers': {
'shop.order_view': 'branch',
'shop.order_edit': 'branch',
'shop.order_approve': 'branch',
'shop.order_print_invoice': 'branch',
},
# Every order, with its price, and nothing changed.
'Accountants': {
'shop.order_view': 'all',
'shop.order_view_price': None,
'shop.order_print_invoice': 'all',
},
# Their own orders: read, and new ones placed for themselves.
'Customers': {
'shop.order_view': 'own',
'shop.order_create': 'own',
},
},
'roles': {
# A customer starts with "Customers", and can never hold more than this.
'customer': {
'name': 'Customer',
'ceiling': ['shop.order_view', 'shop.order_create'],
'bundles': ['Customers'],
},
'manager': {
'name': 'Branch manager',
'ceiling': None,
'bundles': ['Branch managers'],
},
},
}
The settings name it, and every migrate applies it:
Or by hand:
python manage.py clearance_sync --dry-run # what would change, writing nothing
python manage.py clearance_sync --check # in CI: fail when the database differs
python manage.py clearance_sync # apply it, and say what changed
Who owns what¶
The file owns what it names, and nothing else. A bundle or a role the file names is shown read only in the admin site, with a note saying so - see the role page in step 10. A bundle an administrator makes is theirs, and the file never touches it.
Who is given a bundle or a role is not the file's to say. That stays in
the admin site - or, in the shop, in example_data.
A status action of a model that keeps Django's permissions goes in the file
too, under status_actions:
ACCESS = {
'status_actions': {
'shop.Payment': {'refund': {'field': 'state', 'to': ['refunded'], 'from': ['paid']}},
},
}
Start-up refuses a file naming something that cannot be - a permission not
written app_label.codename, a model not installed, a field or a value its
model does not have (E001).