|Version 4 (modified by 9 years ago) ( diff ),|
Table of Contents
The S3 Record Approval Framework hides records which have not yet been reviewed and approved by an authorized user.
Status: under construction
Whether a record is approved or not is encoded as
approved_by field in the record. The field is either None (unapproved record) or holds the user ID of the approving user (approved record).
For tables which require approval, this field is mandatory (field type "integer" or "reference auth_user"). The default value for this field is None, i.e. all new records are unapproved by default. This field should not be editable, i.e. writable=False.
The intended workflow for approval is:
- user creates a new record => record is unapproved by default (i.e. approved_by=None)
- unapproved records are treated as invalid and excluded from any kind of workflow (i.e. invisible) except for review/approval
- user with approval role reviews the record and either approves or rejects it
- approve sets the approved_by field of the record to the approving users ID
- reject deletes the record and all its dependencies
- approved records are now available for all workflows, except for review/approval
- it should not be possible to import pre-approved records, otherwise this would allow unauthorized users to circumvent the approval framework
- unapproved records should be disregarded in Sync, because otherwise this introduces the same hole as above: the user could approve the record in a remote instance where he is Admin and synchronize it back. Apart from that, circulation of unapproved records turns the purpose of approval somewhat upside down.
The Record Approval Framework can be turned on/off globally by a deployment setting:
settings.auth.record_approval = True
Default is False.
Whether record approval is required can be configured per table like:
Default is False.
For a deployment-specific approval configuration, you can override all table-specific settings with:
settings.auth.record_approval_required_for = [tablename, tablename]
Record approval will then only be applied to those tables in the list. If you set this to
None, it will fall back to the table-specific settings.
In addition to activating record approval for a table, you will also need to give user roles permission to review/approve/reject records in this table.
These permissions are encoded as auth.permission.REVIEW (permission to access unapproved records) and auth.permission.APPROVE (permission to approve or reject unapproved records).
acl = current.auth.permission acl.update_acl(ROLE_XY, t="some_table", uacl=acl.READ|acl.CREATE|acl.REVIEW|acl.APPROVE, oacl=acl.READ|acl.UPDATE|acl.REVIEW|acl.APPROVE)
Note: that users can have review permission (=permission to see unapproved records) without need to also have approve/reject permission.
Note: REVIEW permission alone doesn't give any access to unapproved records: it merely extends the READ/UPDATE permissions so they also apply for unapproved records. That means, if the user besides REVIEW has only READ permission in this table, then they can read unapproved records but not update them. To do that, they would need REVIEW+UPDATE permission.
The permission to review/approve/reject records of this role is realm-limited (see S3AAA/OrgAuth for more details).
Admin can always see all records, regardless whether they are approved or not. Other users can only see approved records, unless they have the approver role and use one of the approval methods "review", "approve", "reject".
Methods to Approve or Reject Records
S3Resource implements two low-level methods for record approval:
...to approve all records in a resource (and all its components), and
...to reject (=delete) all unapproved records in a resource.
S3CRUD shall implement the following methods:
...to see all unapproved records in a resource, or:
...to review a particular record, which then gives the user the option to either:
...approve the record, or:
NOTE: resource.reject() is much more radical about record deletion than delete() - it will try to bypass any RESTRICTs and rigirously delete any dependency of the rejected records so they can not leave any undesired legacy behind. However, that means that reject() must always be properly authorized and strictly limited to unapproved records in tables which require approval.
Developer note: GET to
rejectshall forward to
review(for REST compliance)
Developer note: If
rejectare called without record ID, they shall raise a "Record Not Found" error rather than to approve/reject all unapproved records as per the requirement that a record can only be approved/rejects after it has been reviewed (=no bulk approval/reject).
For both, resource.approve() and resource.reject(), there are hooks which will be called for each record that gets approved/rejected:
s3db.configure(tablename, onapprove=function) s3db.configure(tablename, onreject=function)
The hook function must table
(table, row) as parameter, and doesn't return anything.