Admin, member and guest roles per organisation, and roles the admins make
What someone may do in an organisation depends on their role there. Three roles are a column of the membership table; more can be made at run time by the organisation's admins.
authz
type org = app.orgs
admin : user = app.org_members(org_id -> user_id) where {role = 'admin'}
member : user = app.org_members(org_id -> user_id) where {role in ('admin', 'member')}
can manage_roles = admin
type document = app.documents
org : org = org_id
owner : user = owner_id
viewer : user shared by share
roles : user from org
can share = owner or org.admin
can edit = share or roles
can view = edit or viewer or org.member or roleswhere {role = 'admin'}makes a relation from some rows of a table. Admins and members see every document of the organisation; admins also edit and share them.- A guest is in the table with the role
guest, and no relation reads that: a guest holds only what is shared with them. roles : user from orglets users hold roles that the document's organisation defined. A permission writesroleswhere such a role may give it.can manage_roles = adminsays who makes them. An admin creates one withauthz.create_role('org', 1, 'document', 'reviewer', ARRAY['view']), which returns its id, and gives it like a relation:authz.share('document', 7, 'role:<id>', 'user', 4).
Tested
authz
test "admins, members and guests"
user $bo can edit document $mine
user $ann can edit document $mine
user $bo can view document $hers
user $bo cannot edit document $hers
user $cy cannot view document $hers
as user $ann allowed {SELECT authz.share('document', $hers, 'viewer', 'user', $cy)}
user $cy can view document $hers
user $cy cannot view document $mineThe second test makes a role and gives it in one statement, since giving it needs the id that making it returns:
authz
test "a role the admins make"
as user $bo refused {SELECT authz.create_role('org', $acme, 'document', 'reviewer', ARRAY['view'])}
as user $ann allowed {SELECT authz.share('document', $d, 'role:' || authz.create_role('org', $acme, 'document', 'reviewer', ARRAY['view']), 'user', $cy)}
user $cy can view document $d
user $cy cannot edit document $dTry it
Open it in the playground: the tables, the policy and the tests, in your browser, with nothing to install. Or take the files of docs/cookbook/roles-per-organization/ (schema.sql, policy.authz, tests.authz) and run rowstile dev. CI applies and tests them on every change (core/tests/cookbook.sh), and every line shown here is in those files.