Add detailed auditing of domain changes & comment ability#6655
Add detailed auditing of domain changes & comment ability#6655
Conversation
labkey-nicka
left a comment
There was a problem hiding this comment.
In general, this approach of being very explicit about each change and generating the audit message snippet wherever a changes is made is fine but I don't think it is ideal. The amount of checking for changes and the ease with which future changes could miss adding these details makes this cumbersome and fragile.
Seems like there is potential for a way to have domains retain a difference so that when auditing occurs it can be computed what the auditing should record.
That said, I'm not going to hold up this work on this account.
| if (domain == null) | ||
| return; | ||
|
|
||
| DomainAuditProvider.DomainAuditEvent event = new DomainAuditProvider.DomainAuditEvent(study.getContainer(), String.format("The domain %s was deleted", domain.getName())); |
There was a problem hiding this comment.
I see that you tried to call domain.delete(user, auditUserComment). Why did you move away from that? Did you run into deletion problems / lock-up? Seems that would be much preferred to wiring up our own audit event here.
There was a problem hiding this comment.
It was causing a failure on TC https://teamcity.labkey.org/buildConfiguration/LabkeyTrunk_Bvt/3508494, consistently. I cannot repro the failure locally (the problematic dataset is created in ClientAPITest), nor understand it. It might has to do with study container vs definition container vs domain container, but not sure why no repro for me.
# Conflicts: # biologics/package-lock.json # biologics/package.json # inventory/package-lock.json # inventory/package.json # sampleManagement/package-lock.json # sampleManagement/package.json
The implementation has been updated to be a bit more aligned with this comment. |
# Conflicts: # api/src/org/labkey/api/exp/PropertyDescriptor.java
| } | ||
|
|
||
| public static String encodeForDataMap(Container c, Map<String, ?> properties) | ||
| public static String encodeForDataMap(@Nullable Container c, Map<String, ?> properties) |
There was a problem hiding this comment.
nit: Looks like the Container parameter is not actually used by this method and can be factored out.
|
|
||
| public String toStringVal() | ||
| { | ||
| if (columnNames == null) |
There was a problem hiding this comment.
nit: Should this check for empty as well? Seems a bit incongruent to return when null, but then join and display the unique flag setting when columnNames is empty.
|
|
||
| @Override | ||
| public ValidationException setValidationAndAnalysisScripts(ExpProtocol protocol, @NotNull List<AnalysisScript> scripts) throws ExperimentException | ||
| public Pair<ValidationException, Pair<String, String>> setValidationAndAnalysisScripts(ExpProtocol protocol, @NotNull List<AnalysisScript> scripts) throws ExperimentException |
There was a problem hiding this comment.
nit: A typed record would provide more context than type Pair<String, String> about what these strings are.
|
|
||
| public Map<String, Object> getAuditRecordMap(@Nullable String validatorStr, @Nullable String conditionalFormatStr) | ||
| { | ||
| Map<String, Object> map = new LinkedHashMap<>(); |
There was a problem hiding this comment.
Should this include any of the following:
- getContainer()
- getPropertyId()
- getDatabaseDefaultValue()
| void save(User user, boolean auditComment) throws ChangePropertyDescriptorException; | ||
| void save(User user, @Nullable String allowAddBaseProperty) throws ChangePropertyDescriptorException; | ||
| void save(User user, @Nullable Map<String, Object> newRecordMap) throws ChangePropertyDescriptorException; | ||
| void save(User user, @Nullable String auditComment, @Nullable String auditUserComment, @Nullable Map<String, Object> oldRecordMap, @Nullable Map<String, Object> newRecordMap) throws ChangePropertyDescriptorException; |
There was a problem hiding this comment.
nit: A comment here about the difference between auditComment and auditUserComment could be useful.
|
|
||
| appendValueMapColumns(table); | ||
|
|
||
| DetailsURL url = DetailsURL.fromString("audit-detailedAuditChanges.view?auditRowId=${rowId}&auditEventType=" + EVENT_NAME); |
| } | ||
|
|
||
| @Override | ||
| public Map<String, Object> getAuditRecordMap(AssayProvider provider, Container container) |
There was a problem hiding this comment.
Container parameter is unused
| public static List<String> toStringVals(List<GWTIndex> indices, Set<PropertyStorageSpec.Index> excludeBaseIndices) | ||
| { | ||
| if (indices == null || indices.isEmpty()) | ||
| return null; |
There was a problem hiding this comment.
nit: Can just return Collections.emptyList() then callers do not need to worry about null values (and could be annotated @NotNull.
| return super.toString() + _pd.getPropertyURI(); | ||
| } | ||
|
|
||
| public Map<String, Object> getAuditRecordMap(@Nullable String validatorStr, @Nullable String conditionalFormatStr) |
There was a problem hiding this comment.
Since DomainPropertyImpl wraps a PropertyDescriptor should this somehow utilize the audit record of the underlying property descriptor and then extend with whatever additional properties are desired?
Much improved! |
… Pattern and can be hit quickly with unicode characters
# Conflicts: # core/package-lock.json # core/package.json # experiment/package-lock.json # experiment/package.json
# Conflicts: # biologics/package-lock.json # biologics/package.json # inventory/package-lock.json # inventory/package.json # sampleManagement/package-lock.json # sampleManagement/package.json
# Conflicts: # biologics/package-lock.json # biologics/package.json # inventory/package-lock.json # inventory/package.json # sampleManagement/package-lock.json # sampleManagement/package.json Merge branch 'develop' into fb_domainAudit # Conflicts: # core/package-lock.json # core/package.json # experiment/package-lock.json # experiment/package.json

Rationale
There is currently an App only setting that "requires users provide a reason before completing certain actions", which forces user to enter an audit comment before update/delete a data in the App. Certain update and delete actions of data are wired up to accept
auditUserCommentbut so far no enforcement is in place to ensure this comment is provided. This PR extends the actions that acceptauditUserCommentto updateDomain, deleteDomain and assay protocol update actions. There is a future story to enforce "required" comment.This PR also records more details about what's updated during a domain create/update. The domain event and domain property event will now have newRecordMap and oldRecordMap columns, that record all domain or property settings during update/create. Pomain property event will now report more changes, including regex, conditional formatting, text choices, etc.
Related Pull Requests
Changes
auditUserCommenttoupdateDomain,deleteDomainand assay protocol actions and utils