|Version 1 (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.
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.
In addition to activating record approval, you will also need to set the role which is permitted to review/approve/reject records:
settings.auth.record_approver_role = <role_uid>
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".
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.
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 rigorous about record deletion than delete() - it will try to ignore any RESTRICTs and rigirously delete any dependency, because otherwise unapproved records could still leave a legacy behind which is not desirable. 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.