diff --git a/audit/src/org/labkey/audit/AuditController.java b/audit/src/org/labkey/audit/AuditController.java index acd22a9e9b5..9778cd7dbbb 100644 --- a/audit/src/org/labkey/audit/AuditController.java +++ b/audit/src/org/labkey/audit/AuditController.java @@ -53,6 +53,7 @@ import org.labkey.api.settings.AdminConsole; import org.labkey.api.settings.LookAndFeelProperties; import org.labkey.api.util.DateUtil; +import org.labkey.api.util.Pair; import org.labkey.api.view.ActionURL; import org.labkey.api.view.HttpView; import org.labkey.api.view.JspView; @@ -382,17 +383,18 @@ public void validateForm(AuditTransactionForm form, Errors errors) @Override public Object execute(AuditTransactionForm form, BindException errors) { - List rowIds; + Pair, Map> results; User elevatedUser = ElevatedUser.ensureCanSeeAuditLogRole(getContainer(), getUser()); ContainerFilter cf = ContainerFilter.getContainerFilterByName(form.getContainerFilter(), getContainer(), elevatedUser); if (form.isSampleType()) - rowIds = AuditLogImpl.get().getTransactionSampleIds(form.getTransactionAuditId(), elevatedUser, getContainer(), cf); + results = AuditLogImpl.get().getTransactionSampleIds(form.getTransactionAuditId(), elevatedUser, getContainer(), cf); else - rowIds = AuditLogImpl.get().getTransactionSourceIds(form.getTransactionAuditId(), elevatedUser, getContainer(), cf); + results = AuditLogImpl.get().getTransactionSourceIds(form.getTransactionAuditId(), elevatedUser, getContainer(), cf); ApiSimpleResponse response = new ApiSimpleResponse(); response.put("success", true); - response.put("rowIds", rowIds); + response.put("rowIds", results.first); + response.put("dataTypeIds", results.second); return response; } diff --git a/audit/src/org/labkey/audit/AuditLogImpl.java b/audit/src/org/labkey/audit/AuditLogImpl.java index dd38dba1fbe..ce488afbde7 100644 --- a/audit/src/org/labkey/audit/AuditLogImpl.java +++ b/audit/src/org/labkey/audit/AuditLogImpl.java @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -247,63 +248,61 @@ public ActionURL getAuditUrl() return new ActionURL(AuditController.ShowAuditLogAction.class, ContainerManager.getRoot()); } - public List getTransactionSampleIds(long transactionAuditId, User user, Container container, @Nullable ContainerFilter containerFilter) + public Pair, Map> getTransactionSampleIds(long transactionAuditId, User user, Container container, @Nullable ContainerFilter containerFilter) { List transactionEvents = TRANSACTION_EVENT_CACHE.get(transactionAuditId).second; - if (!transactionEvents.isEmpty()) + List events; + if (transactionEvents.isEmpty()) { - List ids = new ArrayList<>(); - transactionEvents.forEach(event -> { - if (event instanceof SampleTimelineAuditEvent stEvent) - ids.add(stEvent.getSampleId()); - }); - return ids; + SimpleFilter filter = new SimpleFilter(); + filter.addCondition(FieldKey.fromParts("TransactionID"), transactionAuditId); + events = AuditLogService.get().getAuditEvents(container, user, SampleTimelineAuditEvent.EVENT_TYPE, filter, null, containerFilter); } - - SimpleFilter filter = new SimpleFilter(); - filter.addCondition(FieldKey.fromParts("TransactionID"), transactionAuditId); - - List events = AuditLogService.get().getAuditEvents(container, user, SampleTimelineAuditEvent.EVENT_TYPE, filter, null, containerFilter); - return events.stream().map(SampleTimelineAuditEvent::getSampleId).collect(Collectors.toList()); + else + { + events = transactionEvents.stream() + .filter(SampleTimelineAuditEvent.class::isInstance) + .map(SampleTimelineAuditEvent.class::cast) + .toList(); + } + Map dataTypeRowCounts = new HashMap<>(); + List sampleIds = new ArrayList<>(); + events.forEach(event -> { + dataTypeRowCounts.merge(event.getSampleTypeId(), 1L, Long::sum); + sampleIds.add(event.getSampleId()); + }); + return Pair.of(sampleIds, dataTypeRowCounts); } - public List getTransactionSourceIds(long transactionAuditId, User user, Container container, @Nullable ContainerFilter containerFilter) + public Pair, Map> getTransactionSourceIds(long transactionAuditId, User user, Container container, @Nullable ContainerFilter containerFilter) { List lsids = new ArrayList<>(); List sourceIds = new ArrayList<>(); + Map dataTypeRowCounts = new HashMap<>(); List transactionEvents = TRANSACTION_EVENT_CACHE.get(transactionAuditId).second; - if (!transactionEvents.isEmpty()) - { - transactionEvents.forEach(event -> { - if (event instanceof DetailedAuditTypeEvent detailedEvent) - { - if (detailedEvent.getNewRecordMap() != null) - { - Map newRecord = new CaseInsensitiveHashMap<>(AbstractAuditTypeProvider.decodeFromDataMap(detailedEvent.getNewRecordMap())); - if (newRecord.containsKey("RowId") && !StringUtils.isEmpty(newRecord.get("RowId"))) - sourceIds.add(Long.valueOf(newRecord.get("RowId"))); - else if (newRecord.containsKey("LSID") && !StringUtils.isEmpty(newRecord.get("LSID"))) - lsids.add(newRecord.get("LSID")); - } - } - }); - } - else - { - List events = QueryService.get().getQueryUpdateAuditRecords(user, container, transactionAuditId, containerFilter); + List detailedEvents = transactionEvents.isEmpty() + ? QueryService.get().getQueryUpdateAuditRecords(user, container, transactionAuditId, containerFilter) + : transactionEvents.stream() + .filter(DetailedAuditTypeEvent.class::isInstance) + .map(DetailedAuditTypeEvent.class::cast) + .toList(); + + detailedEvents.forEach(event -> { + if (event.getNewRecordMap() != null) + { + Map newRecord = new CaseInsensitiveHashMap<>(AbstractAuditTypeProvider.decodeFromDataMap(event.getNewRecordMap())); + if (newRecord.containsKey("RowId") && !StringUtils.isEmpty(newRecord.get("RowId"))) + sourceIds.add(Long.valueOf(newRecord.get("RowId"))); + else if (newRecord.containsKey("LSID") && !StringUtils.isEmpty(newRecord.get("LSID"))) + lsids.add(newRecord.get("LSID")); - events.forEach((event) -> { - if (event.getNewRecordMap() != null) + if (newRecord.containsKey("ClassId") && !StringUtils.isEmpty(newRecord.get("ClassId"))) { - Map newRecord = new CaseInsensitiveHashMap<>(AbstractAuditTypeProvider.decodeFromDataMap(event.getNewRecordMap())); - if (newRecord.containsKey("RowId") && !StringUtils.isEmpty(newRecord.get("RowId"))) - sourceIds.add(Long.valueOf(newRecord.get("RowId"))); - else if (newRecord.containsKey("LSID") && !StringUtils.isEmpty(newRecord.get("LSID"))) - lsids.add(newRecord.get("LSID")); - + Long classId = Long.valueOf(newRecord.get("ClassId")); + dataTypeRowCounts.merge(classId, 1L, Long::sum); } - }); - } + } + }); if (!lsids.isEmpty()) { SimpleFilter filter = SimpleFilter.createContainerFilter(container); @@ -311,6 +310,6 @@ else if (newRecord.containsKey("LSID") && !StringUtils.isEmpty(newRecord.get("LS TableSelector selector = new TableSelector(ExperimentService.get().getTinfoData(), Collections.singleton("RowId"), filter, null); sourceIds.addAll(selector.getArrayList(Long.class)); } - return sourceIds; + return Pair.of(sourceIds, dataTypeRowCounts); } } diff --git a/experiment/src/org/labkey/experiment/ExpDataIterators.java b/experiment/src/org/labkey/experiment/ExpDataIterators.java index 108fdb61148..faa50bd4fa2 100644 --- a/experiment/src/org/labkey/experiment/ExpDataIterators.java +++ b/experiment/src/org/labkey/experiment/ExpDataIterators.java @@ -96,6 +96,7 @@ import org.labkey.api.exp.query.SamplesSchema; import org.labkey.api.qc.DataState; import org.labkey.api.qc.SampleStatusService; +import org.labkey.api.query.AbstractQueryImportAction; import org.labkey.api.query.BatchValidationException; import org.labkey.api.query.FieldKey; import org.labkey.api.query.FileColumnValueMapper; @@ -2379,7 +2380,10 @@ public DataIterator getDataIterator(DataIteratorContext context) // useTransactionAuditCache already set for import and merge in AbstractQueryImportAction.createDataIteratorContext if (context.getInsertOption() == QueryUpdateService.InsertOption.INSERT) - context.setUseTransactionAuditCache(true); + { + if (context.getConfigParameters().isEmpty() || context.getConfigParameterBoolean(AbstractQueryImportAction.Params.useTransactionAuditCache)) + context.setUseTransactionAuditCache(true); + } // add FileLink DataIterator if any input columns are of type FILE_LINK if (null != _fileLinkDirectory)