diff --git a/audit/src/org/labkey/audit/AuditLogImpl.java b/audit/src/org/labkey/audit/AuditLogImpl.java index ac0364a9be8..9c7e82bea13 100644 --- a/audit/src/org/labkey/audit/AuditLogImpl.java +++ b/audit/src/org/labkey/audit/AuditLogImpl.java @@ -56,12 +56,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; public class AuditLogImpl implements AuditLogService, StartupListener { @@ -248,7 +249,7 @@ public ActionURL getAuditUrl() return new ActionURL(AuditController.ShowAuditLogAction.class, ContainerManager.getRoot()); } - public record TransactionRowIds(List rowIds, Map dataTypeRowCounts) {} + public record TransactionRowIds(Set rowIds, Map dataTypeRowCounts) {} public TransactionRowIds getTransactionSampleIds(long transactionAuditId, User user, Container container, @Nullable ContainerFilter containerFilter) { @@ -267,8 +268,15 @@ public TransactionRowIds getTransactionSampleIds(long transactionAuditId, User u .map(SampleTimelineAuditEvent.class::cast) .toList(); } + // Drop the secondary "added/removed sample to/from job" events; the same sample has a primary registration/update event in the transaction, so counting these would double-count it. + events = events.stream() + .filter(event -> SampleTimelineAuditEvent.SampleTimelineEventType.INSERT.getComment().equals(event.getComment()) || SampleTimelineAuditEvent.SampleTimelineEventType.MERGE.getComment().equals(event.getComment())) + .toList(); + Map dataTypeRowCounts = new HashMap<>(); - List sampleIds = new ArrayList<>(); + // Return distinct set of sampleIds, since there might be multiple events in transaction for the same sample + // For example: job derive action creates one registration event, one add to job event. + Set sampleIds = new HashSet<>(); events.forEach(event -> { dataTypeRowCounts.merge(event.getSampleTypeId(), 1L, Long::sum); sampleIds.add(event.getSampleId()); @@ -279,7 +287,7 @@ public TransactionRowIds getTransactionSampleIds(long transactionAuditId, User u public TransactionRowIds getTransactionSourceIds(long transactionAuditId, User user, Container container, @Nullable ContainerFilter containerFilter) { List lsids = new ArrayList<>(); - List sourceIds = new ArrayList<>(); + Set sourceIds = new HashSet<>(); Map dataTypeRowCounts = new HashMap<>(); List transactionEvents = TRANSACTION_EVENT_CACHE.get(transactionAuditId).second; List detailedEvents = transactionEvents.isEmpty() diff --git a/query/src/org/labkey/query/controllers/QueryController.java b/query/src/org/labkey/query/controllers/QueryController.java index 7bdffee8991..e1c9d69d2f5 100644 --- a/query/src/org/labkey/query/controllers/QueryController.java +++ b/query/src/org/labkey/query/controllers/QueryController.java @@ -4651,6 +4651,10 @@ protected JSONObject executeJson(JSONObject json, CommandType commandType, boole Map auditDetails = json.has("auditDetails") ? json.getJSONObject("auditDetails").toMap() : new CaseInsensitiveHashMap<>(); Map configParameters = new HashMap<>(); + + if (extraContext.containsKey(AbstractQueryImportAction.Params.useTransactionAuditCache.name())) + configParameters.put(AbstractQueryImportAction.Params.useTransactionAuditCache, extraContext.get(AbstractQueryImportAction.Params.useTransactionAuditCache.name())); + if (WorkflowService.get() != null) WorkflowService.get().populateConfigParams(extraContext, configParameters);