From 389b21cf67c7b09dc308a5a0cc053cfdc201ff2b Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 12 Aug 2026 14:43:42 -0700 Subject: [PATCH 1/5] Add transaction ID to domain events audit table --- .../org/labkey/api/exp/property/DomainAuditProvider.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/src/org/labkey/api/exp/property/DomainAuditProvider.java b/api/src/org/labkey/api/exp/property/DomainAuditProvider.java index daef4c61259..b20a72495db 100644 --- a/api/src/org/labkey/api/exp/property/DomainAuditProvider.java +++ b/api/src/org/labkey/api/exp/property/DomainAuditProvider.java @@ -20,6 +20,7 @@ import org.labkey.api.audit.AuditTypeEvent; import org.labkey.api.audit.AuditTypeProvider; import org.labkey.api.audit.DetailedAuditTypeEvent; +import org.labkey.api.audit.TransactionAuditProvider; import org.labkey.api.audit.query.AbstractAuditDomainKind; import org.labkey.api.audit.query.DefaultAuditTypeTable; import org.labkey.api.data.ColumnInfo; @@ -104,6 +105,8 @@ protected void initColumn(MutableColumnInfo col) } else if (COLUMN_NAME_USER_COMMENT.equalsIgnoreCase(col.getName())) col.setLabel("User Comment"); + else if (COLUMN_NAME_TRANSACTION_ID.equalsIgnoreCase(col.getName())) + col.setLabel("Transaction ID"); } }; @@ -132,11 +135,13 @@ public static class DomainAuditEvent extends DetailedAuditTypeEvent public DomainAuditEvent() { super(); + setTransactionEvent(TransactionAuditProvider.getCurrentTransactionAuditEvent(), EVENT_TYPE); } public DomainAuditEvent(Container container, String comment) { super(EVENT_TYPE, container, comment); + setTransactionEvent(TransactionAuditProvider.getCurrentTransactionAuditEvent(), EVENT_TYPE); } public String getDomainUri() @@ -166,6 +171,7 @@ public Map getAuditLogMessageElements() elements.put("domainUri", getDomainUri()); elements.put("domainName", getDomainName()); elements.putAll(super.getAuditLogMessageElements()); + elements.put("transactionId", getTransactionId()); return elements; } } @@ -187,6 +193,7 @@ public DomainAuditDomainKind() fields.add(createOldDataMapPropertyDescriptor()); fields.add(createNewDataMapPropertyDescriptor()); fields.add(createPropertyDescriptor(COLUMN_NAME_USER_COMMENT, PropertyType.STRING)); + fields.add(createPropertyDescriptor(COLUMN_NAME_TRANSACTION_ID, PropertyType.BIGINT)); _fields = Collections.unmodifiableSet(fields); } From 2e473accf15a8ff20798df772ef4f4cf3bfcff1e Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 12 Aug 2026 14:46:17 -0700 Subject: [PATCH 2/5] Pass through optional auditUserComment to beforeMaterialDelete and beforeDataDelete methods --- .../api/exp/api/ExperimentListener.java | 5 ++- .../org/labkey/assay/plate/PlateManager.java | 2 +- .../api/ExpDataClassDataTableImpl.java | 4 +- .../api/ExpDataClassDataTestCase.jsp | 2 +- .../labkey/experiment/api/ExpDataImpl.java | 2 +- .../org/labkey/experiment/api/ExpRunImpl.java | 2 +- .../experiment/api/ExperimentServiceImpl.java | 41 +++++++++++-------- .../experiment/api/SampleTypeServiceImpl.java | 11 +++-- .../api/SampleTypeUpdateServiceDI.java | 2 +- .../labkey/list/PicklistMaterialListener.java | 3 +- .../study/assay/ExperimentListenerImpl.java | 3 +- 11 files changed, 45 insertions(+), 32 deletions(-) diff --git a/api/src/org/labkey/api/exp/api/ExperimentListener.java b/api/src/org/labkey/api/exp/api/ExperimentListener.java index c1c38421fff..ce7d130a0fb 100644 --- a/api/src/org/labkey/api/exp/api/ExperimentListener.java +++ b/api/src/org/labkey/api/exp/api/ExperimentListener.java @@ -15,6 +15,7 @@ */ package org.labkey.api.exp.api; +import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; import org.labkey.api.query.BatchValidationException; import org.labkey.api.security.User; @@ -51,13 +52,13 @@ default void afterResultDataCreated(Container container, User user, ExpRun run, default void beforeRunDelete(ExpProtocol protocol, ExpRun run, User user) { } /** Called before deleting the datas. */ - default void beforeDataDelete(Container c, User user, List data) { } + default void beforeDataDelete(Container c, User user, List data, @Nullable String auditUserComment) { } /** Called after deleting the datas. */ default void afterDataDelete(Container c, User user, List data) { } /** Called before deleting experiment materials (in-transaction). */ - default void beforeMaterialDelete(List materials, Container container, User user) { } + default void beforeMaterialDelete(List materials, Container container, User user, @Nullable String auditUserComment) { } /** Called after a material has been created (and saved). NOTE: This is not currently implemented. */ default void afterMaterialCreated(List materials, Container container, User user) { } diff --git a/assay/src/org/labkey/assay/plate/PlateManager.java b/assay/src/org/labkey/assay/plate/PlateManager.java index 8c125bb95f5..502cde71a82 100644 --- a/assay/src/org/labkey/assay/plate/PlateManager.java +++ b/assay/src/org/labkey/assay/plate/PlateManager.java @@ -5125,7 +5125,7 @@ private record HydratedResult(List plateData, @Nullable Integer plate } @Override - public void beforeMaterialDelete(List materials, Container container, User user) + public void beforeMaterialDelete(List materials, Container container, User user, @Nullable String auditUserComment) { if (materials == null || materials.isEmpty()) return; diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java index db15c9d080a..df8429a912b 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java @@ -32,7 +32,6 @@ import org.labkey.api.data.BaseColumnInfo; import org.labkey.api.data.ColumnHeaderType; import org.labkey.api.data.ColumnInfo; -import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerFilter; import org.labkey.api.data.ContainerManager; @@ -145,7 +144,6 @@ import java.util.Map; import java.util.Set; import java.util.function.Supplier; -import java.util.function.UnaryOperator; import java.util.stream.Collectors; import static org.labkey.api.dataiterator.DataIteratorUtil.DUPLICATE_COLUMN_IN_DATA_ERROR; @@ -1513,7 +1511,7 @@ protected void _delete(Container c, Map row) throws InvalidKeyEx @Override protected int truncateRows(User user, Container container) { - return ExperimentServiceImpl.get().truncateDataClass(_dataClass, user, container); + return ExperimentServiceImpl.get().truncateDataClass(_dataClass, user, container, null); } @Override diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index f82c663c0d0..52d436bd9de 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -329,7 +329,7 @@ private void testTruncateRows(ExpDataClassImpl dataClass, TableInfo table, Strin { // TODO: truncate rows API doesn't support truncating from all containers //count = table.getUpdateService().truncateRows(user, c, null, null); - count = ExperimentServiceImpl.get().truncateDataClass(dataClass, _user, null); + count = ExperimentServiceImpl.get().truncateDataClass(dataClass, _user, null, null); tx.commit(); } diff --git a/experiment/src/org/labkey/experiment/api/ExpDataImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataImpl.java index a0e259f5dbc..eb38273ddc2 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataImpl.java @@ -351,7 +351,7 @@ public void delete(User user) @Override public void delete(User user, boolean deleteRunsUsingData) { - ExperimentServiceImpl.get().deleteDataByRowIds(user, getContainer(), Collections.singleton(getRowId()), deleteRunsUsingData); + ExperimentServiceImpl.get().deleteDataByRowIds(user, getContainer(), Collections.singleton(getRowId()), deleteRunsUsingData, null); } public String getMimeType() diff --git a/experiment/src/org/labkey/experiment/api/ExpRunImpl.java b/experiment/src/org/labkey/experiment/api/ExpRunImpl.java index 45bc2eb621c..f7fe2a5e0fb 100644 --- a/experiment/src/org/labkey/experiment/api/ExpRunImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpRunImpl.java @@ -548,7 +548,7 @@ public void deleteProtocolApplications(List datasToDelete, User use deleteProtocolApplicationProvenance(); - svc.beforeDeleteData(user, getContainer(), datasToDelete); + svc.beforeDeleteData(user, getContainer(), datasToDelete, null); deleteInputObjects(svc, dialect); diff --git a/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java b/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java index ee0f5f867ef..03d8a02cfce 100644 --- a/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java @@ -4883,7 +4883,7 @@ public int deleteMaterialByRowIds( { SQLFragment rowIdSQL = new SQLFragment("RowId "); rowIdSQL.appendInClause(selectedMaterialIds, getSchema().getSqlDialect()); - return deleteMaterialBySqlFilter(user, container, rowIdSQL, deleteRunsUsingMaterials, false, stDeleteFrom, ignoreStatus, truncateContainer); + return deleteMaterialBySqlFilter(user, container, rowIdSQL, deleteRunsUsingMaterials, false, stDeleteFrom, ignoreStatus, truncateContainer, null); } /** @@ -4892,7 +4892,9 @@ public int deleteMaterialByRowIds( * null, the samples must have cpasType of {@link ExpMaterial#DEFAULT_CPAS_TYPE} unless * the deleteFromAllSampleTypes flag is true. * Deleting from multiple SampleTypes is only needed when cleaning an entire container. + * * @param truncateContainer delete all rows for this container. Not a real DB truncate because there may be rows in other containers. + * @param auditUserComment */ public int deleteMaterialBySqlFilter( User user, @@ -4902,8 +4904,8 @@ public int deleteMaterialBySqlFilter( boolean deleteFromAllSampleTypes, @Nullable ExpSampleType stDeleteFrom, boolean ignoreStatus, - boolean truncateContainer - ) + boolean truncateContainer, + @Nullable String auditUserComment) { if (stDeleteFrom != null && deleteFromAllSampleTypes) throw new IllegalArgumentException("Can only delete from multiple sample types when no sample type is provided"); @@ -4983,7 +4985,7 @@ public int deleteMaterialBySqlFilter( try (Timing ignored = MiniProfiler.step("beforeDelete")) { - beforeDeleteMaterials(user, container, materials); + beforeDeleteMaterials(user, container, materials, auditUserComment); } try (Timing ignored = MiniProfiler.step("deleteRunsUsingInput")) @@ -5393,12 +5395,12 @@ AND pa.cpastype IN ('ProtocolApplication', 'ExperimentRun') } - public void deleteDataByRowIds(User user, Container container, Collection selectedDataIds) + public void deleteDataByRowIds(User user, Container container, Collection selectedDataIds, @Nullable String auditUserComment) { - deleteDataByRowIds(user, container, selectedDataIds, true); + deleteDataByRowIds(user, container, selectedDataIds, true, auditUserComment); } - public void deleteDataByRowIds(User user, Container container, Collection selectedDataIds, boolean deleteRunsUsingData) + public void deleteDataByRowIds(User user, Container container, Collection selectedDataIds, boolean deleteRunsUsingData, @Nullable String auditUserComment) { if (selectedDataIds.isEmpty()) return; @@ -5424,7 +5426,7 @@ public void deleteDataByRowIds(User user, Container container, Collection } List expDatas = ExpDataImpl.fromDatas(datas); - beforeDeleteData(user, container, expDatas); + beforeDeleteData(user, container, expDatas, auditUserComment); // Delete any runs using the data if the ProtocolImplementation allows it if (deleteRunsUsingData) @@ -5655,13 +5657,13 @@ public void deleteAllExpObjInContainer(Container c, User user) throws Experiment // now delete starting materials that were not associated with a MaterialSource upload. // we get this list now so that it doesn't include all the run-scoped Materials that were // deleted already - deleteMaterialBySqlFilter(user, c, new SQLFragment("Container = ?", c), true, true, null, true, true); + deleteMaterialBySqlFilter(user, c, new SQLFragment("Container = ?", c), true, true, null, true, true, null); // same drill for data objects sql = "SELECT RowId FROM exp.Data WHERE Container = ?"; Collection dataIds = new SqlSelector(getExpSchema(), sql, c).getCollection(Long.class); LOG.debug("Deleting {} dataIds {} ", dataIds.size(), dataIds); - deleteDataByRowIds(user, c, dataIds); + deleteDataByRowIds(user, c, dataIds, null); LOG.debug("Deleting objects from container {}", c); OntologyManager.deleteAllObjects(c, user); @@ -5728,7 +5730,7 @@ public void moveRuns(ViewBackgroundInfo info, Container sourceContainer, List datas) + public void beforeDeleteData(User user, Container container, List datas, @Nullable String auditUserComment) { try { @@ -5751,7 +5753,7 @@ public void beforeDeleteData(User user, Container container, List d for (ExperimentListener listener : _listeners) { - listener.beforeDataDelete(container, user, datas); + listener.beforeDataDelete(container, user, datas, auditUserComment); } } @@ -5763,12 +5765,12 @@ public void afterDeleteData(User user, Container container, List da } } - public void beforeDeleteMaterials(User user, Container container, List materials) + public void beforeDeleteMaterials(User user, Container container, List materials, @Nullable String auditUserComment) { // Notify that a deletion is about to happen for (ExperimentListener materialListener : _listeners) { - materialListener.beforeMaterialDelete(materials, container, user); + materialListener.beforeMaterialDelete(materials, container, user, auditUserComment); } } @@ -6204,7 +6206,7 @@ void deleteDomainObjects(Container c, String lsid) throws ExperimentException * Delete all exp.Data from the DataClass. If container is not provided, * all rows from the DataClass will be deleted regardless of container. */ - public int truncateDataClass(ExpDataClassImpl dataClass, User user, @Nullable Container c) + public int truncateDataClass(ExpDataClassImpl dataClass, User user, @Nullable Container c, @Nullable String auditUserComment) { assert getExpSchema().getScope().isTransactionActive(); @@ -6221,7 +6223,7 @@ public int truncateDataClass(ExpDataClassImpl dataClass, User user, @Nullable Co for (Map.Entry> entry : byContainer.asMap().entrySet()) { Container container = ContainerManager.getForId(entry.getKey()); - deleteDataByRowIds(user, container, entry.getValue()); + deleteDataByRowIds(user, container, entry.getValue(), auditUserComment); count += entry.getValue().size(); } return count; @@ -6249,7 +6251,12 @@ public void deleteDataClass(long rowId, Container c, User user, @Nullable final try (DbScope.Transaction transaction = ensureTransaction()) { - truncateDataClass(dataClass, user, null); + if (transaction.getAuditEvent() == null) + { + TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(c, QueryService.AuditAction.DELETE, null); + AbstractQueryUpdateService.addTransactionAuditEvent(transaction, user, auditEvent); + } + truncateDataClass(dataClass, user, null, auditUserComment); d.delete(user, auditUserComment); diff --git a/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java b/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java index 1ae70f5b04c..2a4328807d1 100644 --- a/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java @@ -625,7 +625,7 @@ public Pair getSampleTypeSamplePrefixLsids(Container container) * Delete all exp.Material from the SampleType. If container is not provided, * all rows from the SampleType will be deleted regardless of container. */ - public int truncateSampleType(ExpSampleTypeImpl source, User user, @Nullable Container c) + public int truncateSampleType(ExpSampleTypeImpl source, User user, @Nullable Container c, @Nullable String auditUserComment) { assert getExpSchema().getScope().isTransactionActive(); @@ -649,7 +649,7 @@ public int truncateSampleType(ExpSampleTypeImpl source, User user, @Nullable Con SQLFragment sqlFilter = new SQLFragment("CpasType = ? AND Container = ?"); sqlFilter.add(source.getLSID()); sqlFilter.add(toDelete); - count += ExperimentServiceImpl.get().deleteMaterialBySqlFilter(user, toDelete, sqlFilter, true, false, source, true, true); + count += ExperimentServiceImpl.get().deleteMaterialBySqlFilter(user, toDelete, sqlFilter, true, false, source, true, true, auditUserComment); } return count; } @@ -668,9 +668,14 @@ public void deleteSampleType(long rowId, Container c, User user, @Nullable Strin try (DbScope.Transaction transaction = ensureTransaction()) { + if (transaction.getAuditEvent() == null) + { + TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(c, QueryService.AuditAction.DELETE, null); + AbstractQueryUpdateService.addTransactionAuditEvent(transaction, user, auditEvent); + } // TODO: option to skip deleting rows from the materialized table since we're about to delete it anyway // TODO do we need both truncateSampleType() and deleteDomainObjects()? - truncateSampleType(source, user, null); + truncateSampleType(source, user, null, auditUserComment); StudyService studyService = StudyService.get(); if (studyService != null) diff --git a/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java b/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java index a5e5074bd9f..cf2ceacead6 100644 --- a/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java +++ b/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java @@ -759,7 +759,7 @@ protected int truncateRows(User user, Container container) if (_sampleType == null) return 0; - int ret = SampleTypeServiceImpl.get().truncateSampleType(_sampleType, user, container); + int ret = SampleTypeServiceImpl.get().truncateSampleType(_sampleType, user, container, null); if (ret > 0) { // NOTE: Not necessary to call onSamplesChanged -- already called by truncateSampleSet diff --git a/list/src/org/labkey/list/PicklistMaterialListener.java b/list/src/org/labkey/list/PicklistMaterialListener.java index ca6edbb28dd..fd166553338 100644 --- a/list/src/org/labkey/list/PicklistMaterialListener.java +++ b/list/src/org/labkey/list/PicklistMaterialListener.java @@ -15,6 +15,7 @@ */ package org.labkey.list; +import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.Table; @@ -35,7 +36,7 @@ public class PicklistMaterialListener implements ExperimentListener { @Override - public void beforeMaterialDelete(List materials, Container container, User user) + public void beforeMaterialDelete(List materials, Container container, User user, @Nullable String auditUserComment) { Collection picklists = ListManager.get().getPicklists(container); List materialIds = materials.stream().map(ExpMaterial::getRowId).collect(Collectors.toList()); diff --git a/study/src/org/labkey/study/assay/ExperimentListenerImpl.java b/study/src/org/labkey/study/assay/ExperimentListenerImpl.java index 86f6ea74d20..e680651d503 100644 --- a/study/src/org/labkey/study/assay/ExperimentListenerImpl.java +++ b/study/src/org/labkey/study/assay/ExperimentListenerImpl.java @@ -15,6 +15,7 @@ */ package org.labkey.study.assay; +import org.jetbrains.annotations.Nullable; import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.SimpleFilter; @@ -68,7 +69,7 @@ public void afterResultDataCreated(Container container, User user, ExpRun run, E } @Override - public void beforeMaterialDelete(List materials, Container container, User user) + public void beforeMaterialDelete(List materials, Container container, User user, @Nullable String auditUserComment) { // Check for datasets that need rows deleted due to a linked Sample Type row-level deletion From 5b921e839bd3fea90fbf0e7e958c8a2e28eb7f63 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 12 Aug 2026 17:27:30 -0700 Subject: [PATCH 3/5] Don't set transaction id from default constructor --- api/src/org/labkey/api/exp/property/DomainAuditProvider.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/org/labkey/api/exp/property/DomainAuditProvider.java b/api/src/org/labkey/api/exp/property/DomainAuditProvider.java index b20a72495db..3c2a4fcd71e 100644 --- a/api/src/org/labkey/api/exp/property/DomainAuditProvider.java +++ b/api/src/org/labkey/api/exp/property/DomainAuditProvider.java @@ -135,7 +135,6 @@ public static class DomainAuditEvent extends DetailedAuditTypeEvent public DomainAuditEvent() { super(); - setTransactionEvent(TransactionAuditProvider.getCurrentTransactionAuditEvent(), EVENT_TYPE); } public DomainAuditEvent(Container container, String comment) From 5876a008bc1f9098737eae137d1088ac28eb4f2e Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Thu, 13 Aug 2026 16:51:04 -0700 Subject: [PATCH 4/5] Move adding of the transaction audit event to AbstractDeleteAction --- .../org/labkey/experiment/api/ExperimentServiceImpl.java | 5 ----- .../org/labkey/experiment/api/SampleTypeServiceImpl.java | 5 ----- .../experiment/controllers/exp/ExperimentController.java | 6 ++++++ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java b/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java index 03d8a02cfce..cfbc1415bfa 100644 --- a/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java @@ -6251,11 +6251,6 @@ public void deleteDataClass(long rowId, Container c, User user, @Nullable final try (DbScope.Transaction transaction = ensureTransaction()) { - if (transaction.getAuditEvent() == null) - { - TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(c, QueryService.AuditAction.DELETE, null); - AbstractQueryUpdateService.addTransactionAuditEvent(transaction, user, auditEvent); - } truncateDataClass(dataClass, user, null, auditUserComment); d.delete(user, auditUserComment); diff --git a/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java b/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java index 2a4328807d1..e1aeec93ab5 100644 --- a/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java @@ -668,11 +668,6 @@ public void deleteSampleType(long rowId, Container c, User user, @Nullable Strin try (DbScope.Transaction transaction = ensureTransaction()) { - if (transaction.getAuditEvent() == null) - { - TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(c, QueryService.AuditAction.DELETE, null); - AbstractQueryUpdateService.addTransactionAuditEvent(transaction, user, auditEvent); - } // TODO: option to skip deleting rows from the materialized table since we're about to delete it anyway // TODO do we need both truncateSampleType() and deleteDomainObjects()? truncateSampleType(source, user, null, auditUserComment); diff --git a/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java b/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java index bb8d487ee41..9e7db9c5e23 100644 --- a/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java +++ b/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java @@ -165,6 +165,7 @@ import org.labkey.api.pipeline.PipelineValidationException; import org.labkey.api.qc.SampleStatusService; import org.labkey.api.query.AbstractQueryImportAction; +import org.labkey.api.query.AbstractQueryUpdateService; import org.labkey.api.query.BatchValidationException; import org.labkey.api.query.DetailsURL; import org.labkey.api.query.DuplicateKeyException; @@ -3589,6 +3590,11 @@ public boolean handlePost(DeleteForm deleteForm, BindException errors) throws Ex { try (DbScope.Transaction tx = ExperimentService.get().ensureTransaction()) { + if (tx.getAuditEvent() == null) + { + TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(getContainer(), QueryService.AuditAction.DELETE, null); + AbstractQueryUpdateService.addTransactionAuditEvent(tx, getUser(), auditEvent); + } tx.addCommitTask(deleteForm::clearSelected, POSTCOMMIT); deleteObjects(deleteForm); From a99865421ab97ce051378ad23901f691bb49ce9b Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Thu, 13 Aug 2026 16:54:12 -0700 Subject: [PATCH 5/5] Add call to getTransactionAuditDetails --- .../labkey/experiment/controllers/exp/ExperimentController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java b/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java index 9e7db9c5e23..5d790088af3 100644 --- a/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java +++ b/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java @@ -3592,7 +3592,7 @@ public boolean handlePost(DeleteForm deleteForm, BindException errors) throws Ex { if (tx.getAuditEvent() == null) { - TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(getContainer(), QueryService.AuditAction.DELETE, null); + TransactionAuditProvider.TransactionAuditEvent auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(getContainer(), QueryService.AuditAction.DELETE, getTransactionAuditDetails()); AbstractQueryUpdateService.addTransactionAuditEvent(tx, getUser(), auditEvent); } tx.addCommitTask(deleteForm::clearSelected, POSTCOMMIT);