Let's say the "ownership" or "visibility" information for a data model (table) is not present as a column in the table, but in a different related table. In this case, let's say there is an ``article`` table and a ``collaborator`` table that has ``article_id, collaborator_id`` columns.
- Create a relationship called ``collaborators`` from the article table.
- Array relationship (article has array of collaborators): ``article :: id → collaborator :: article_id``.
- Create a role called ``collaborator``.
- Create a select permission on the ``article`` table, which has the condition:
If you have the information about roles and how they map to your data in the same database as the one configured with the GraphQL engine, you can leverage relationships to define permissions that effectively control access to data and the operations each role is allowed to perform.
*``author``: Users with this role can submit **their own** articles.
*``reviewer``: Users with this role can review **articles assigned to them** and add a review comment to each article. A mapping of articles to reviewers is maintained in the ``reviewers`` table.
*``editor``: Users with this role can edit and publish **any article**. They can also leave a private rating for each article. However, they cannot overwrite a reviewer's notes. A list of editors is maintained in the ``editors`` table.
Database Schema
^^^^^^^^^^^^^^^
The following is a reference database schema for our example:
:sup:`*`*Additional restriction required to ensure that a user with the role*``author``*can submit only their own article i.e.*``author_id``*should be the same as the user's id*.
We'll create permission rules for the roles and actions listed above (*you can easily extend them for the actions not documented here*) .
Permissions for role ``author``
"""""""""""""""""""""""""""""""
***Allow users with the role**``author``**to insert only their own articles**
a) :ref:`Column-level permissions<col-level-permissions>`: Restrict access to certain columns only.
b) :doc:`Column presets <../../schema/default-values/column-presets>`: Session-variable-based column preset for the ``author_id`` column to automatically insert the user's ID i.e. the ``X-Hasura-User-Id`` session-variable's value. It also helps us avoid explicitly passing the user's ID in the insert mutation.
Notice how we don't need to have an explicit row-level permission (*a custom check*) as only authenticated users with the role ``author`` can perform this action. As we have a column preset for the ``author_id`` column that automatically takes the author's ID (*and the*``id``*column is an auto-increment integer field*), we only need to allow access to the ``title`` column.
***Allow users with the role**``author``**to select certain columns only**
Again, we'll use **column-level** permissions to restrict access to certain columns. Additionally, we need to define row-level permissions (*a custom check*) to restrict access to only those articles authored by the current user:
The row-level permission rule shown here translates to "*if the value in the*``author_id``*column of this row is equal to the user's ID i.e. the*``X-Hasura-User-Id``*session-variable's value, allow access to it*".
Permissions for role ``reviewer``
"""""""""""""""""""""""""""""""""
***Allow users with the role**``reviewer``**to update articles assigned to them for reviews**
For this use-case, we'll use :ref:`relationship or nested-object permissions<relationships-in-permissions>` based on the array relationship ``reviewers`` to restrict access to assigned articles only.
The array-relationship based permission rule in the above image reads as "*if the ID of any reviewer assigned to this article is equal to the user's ID i.e. the*``X-Hasura-User-Id``*session-variable's value, allow access to it*". The columns' access is restricted using the column-level permissions highlighted above.