| | 3 | |
| | 4 | S3Anonymize is a tool to remove sensitive information from a record (and related records) based on configurable rules. |
| | 5 | |
| | 6 | == Overview == |
| | 7 | |
| | 8 | S3Anonymize removes information from a record (and related records) based on rules. It is primarily intended for person data, but can be re-used for any type of record. |
| | 9 | |
| | 10 | == Configuring Rules == |
| | 11 | |
| | 12 | Rules are configured using {{{s3db.configure}}} for the target table. The rules format looks like this: |
| | 13 | |
| | 14 | {{{#!py |
| | 15 | s3db.configure("pr_person", |
| | 16 | anonymize = {# A name and title for the rule set: |
| | 17 | "name": "default", |
| | 18 | "title": "Names, IDs, Reference Numbers, Contact Information, Addresses", |
| | 19 | |
| | 20 | # Rules how to clean up fields in the master record: |
| | 21 | "fields": {"first_name": ("set", "-"), # Set field to this value |
| | 22 | "last_name": ("set", "-"), |
| | 23 | "pe_label": anonymous_id, # Callable returning a new field value |
| | 24 | "date_of_birth": obscure_dob, |
| | 25 | "comments": "remove", # Set field value to None |
| | 26 | }, |
| | 27 | |
| | 28 | # Rules for related records: |
| | 29 | "cascade": [("dvr_case", {"key": "person_id", # Foreign key in the related table |
| | 30 | "match": "id", # Match this key of the parent table |
| | 31 | |
| | 32 | # Field rules for the related table |
| | 33 | "fields": {"comments": "remove", |
| | 34 | }, |
| | 35 | }), |
| | 36 | |
| | 37 | ("pr_contact", {"key": "pe_id", |
| | 38 | "match": "pe_id", |
| | 39 | "fields": {"contact_description": "remove", |
| | 40 | "value": ("set", ""), |
| | 41 | "comments": "remove", |
| | 42 | }, |
| | 43 | |
| | 44 | "delete": True, # Delete the related records after cleanup (default False) |
| | 45 | }), |
| | 46 | ], |
| | 47 | }, |
| | 48 | ) |
| | 49 | }}} |
| | 50 | |
| | 51 | - in cascading rules, the {{{key}}}+{{{match}}} properties can be replaced by a {{{lookup}}} property to configure a callable with the signature {{{lookup(table, rows, tablename)}}} that returns a set of relevant record IDs in the related table |
| | 52 | |
| | 53 | - standard field rules are: |
| | 54 | - {{{"remove"}}} sets the field value to None |
| | 55 | - {{{"reset"}}} sets the field value to the field default |
| | 56 | - {{{("set", value)}}} sets the field value to the specified value |
| | 57 | - field rules can also be callables with the signature {{{rule(master_id, field, current_value)}}} that return the new value for the field |
| | 58 | - field rules must produce valid records (i.e. the resulting value must pass database constraints and validators) |
| | 59 | - after applying field rules, S3Anonymize will execute {{{update_super}}} and {{{onaccept}}} like any other CRUD method |
| | 60 | - records in related tables will additionally be deleted if {{{"delete": True}}} is specified (which makes sense if the field rules remove all useful information from those records anyway) |
| | 61 | - if cascading records are to be deleted, this will ''additionally'' execute {{{ondelete}}} (as last step) |
| | 62 | |
| | 63 | Instead of a single set of rules, it is possible to configure multiple rule sets as list: |
| | 64 | {{{ |
| | 65 | s3db.configure("pr_person", |
| | 66 | anonymize = [{...first rule set...}, {...second rule set...}], |
| | 67 | ) |
| | 68 | }}} |
| | 69 | |
| | 70 | ...each with its own {{{name}}} and {{{title}}}. These rule sets will later be selectable in the GUI, so that the user can choose to only remove some, but not other data from the record (see screenshot below). |
| | 71 | |
| | 72 | == GUI and REST Method == |
| | 73 | |
| | 74 | === S3AnonymizeWidget === |
| | 75 | |
| | 76 | To embed S3Anonymize in the GUI, it comes with a special widget class S3AnonymizeWidget and a UI script (s3.ui.anonymize.js). |
| | 77 | |
| | 78 | S3AnonymizeWidget produces an action button/link (with a hidden dialog) that can be embedded in the record view (e.g. in postp in place of the delete-button): |
| | 79 | {{{ |
| | 80 | def postp(r, output): |
| | 81 | |
| | 82 | if r.record and not r.component and r.method in (None, "update", "read") and isinstance(output, dict): |
| | 83 | |
| | 84 | buttons = output.get("buttons") or {} |
| | 85 | |
| | 86 | from s3 import S3AnonymizeWidget |
| | 87 | buttons["delete_btn"] = S3AnonymizeWidget.widget(r, _class="action-btn anonymize-btn") |
| | 88 | |
| | 89 | output["buttons"] = buttons |
| | 90 | |
| | 91 | return output |
| | 92 | }}} |
| | 93 | |
| | 94 | The {{{_class}}} parameter can be used to control the appearance of the link. The {{{widget}}} function will automatically embed the UI dialog and script, and authorize the link. |
| | 95 | |
| | 96 | Clicking on the link brings up a dialog like this: |
| | 97 | |
| | 98 | |
| | 99 | == Back-end Function == |