diff --git a/api/src/org/labkey/api/assay/AssayFileWriter.java b/api/src/org/labkey/api/assay/AssayFileWriter.java index 087a2378f05..26e6011d4f5 100644 --- a/api/src/org/labkey/api/assay/AssayFileWriter.java +++ b/api/src/org/labkey/api/assay/AssayFileWriter.java @@ -262,7 +262,11 @@ public Map savePostedFiles(ContextType context, @NotNull Set pending = context.getPendingFileAuditEvents(); + if (pending != null) + pending.add(event); + else + AuditLogService.get().addEvent(context.getUser(), event); } if (!isAfterFirstFile) // first file gets stored with multipartFile's name { diff --git a/api/src/org/labkey/api/assay/AssayRunUploadContext.java b/api/src/org/labkey/api/assay/AssayRunUploadContext.java index 4ac118c772c..7b681bddc01 100644 --- a/api/src/org/labkey/api/assay/AssayRunUploadContext.java +++ b/api/src/org/labkey/api/assay/AssayRunUploadContext.java @@ -20,6 +20,7 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.labkey.api.audit.provider.FileSystemAuditProvider; import org.labkey.api.collections.CollectionUtils; import org.labkey.api.data.Container; import org.labkey.api.data.ExpDataFileConverter; @@ -37,6 +38,7 @@ import org.labkey.api.writer.ContainerUser; import org.labkey.vfs.FileLike; +import java.util.List; import java.util.Map; import java.util.Set; @@ -188,6 +190,17 @@ default void setPreparedTransform(@Nullable PreparedTransform prepared) throw new UnsupportedOperationException(getClass().getName() + " can't carry a prepared transform"); } + /** File audit events held until the import transaction opens, or null to add them as they're created. */ + default @Nullable List getPendingFileAuditEvents() + { + return null; + } + + default void setPendingFileAuditEvents(@Nullable List events) + { + throw new UnsupportedOperationException(getClass().getName() + " can't hold file audit events"); + } + /** The RowId for the run that is being deleted and reuploaded, or null if this is a new run */ Long getReRunId(); diff --git a/api/src/org/labkey/api/assay/AssayRunUploadContextImpl.java b/api/src/org/labkey/api/assay/AssayRunUploadContextImpl.java index 35351036bfe..acb2080c7f5 100644 --- a/api/src/org/labkey/api/assay/AssayRunUploadContextImpl.java +++ b/api/src/org/labkey/api/assay/AssayRunUploadContextImpl.java @@ -34,6 +34,7 @@ import org.labkey.api.assay.transform.DefaultTransformResult; import org.labkey.api.assay.transform.PreparedTransform; import org.labkey.api.assay.transform.TransformResult; +import org.labkey.api.audit.provider.FileSystemAuditProvider; import org.labkey.api.security.User; import org.labkey.api.util.URIUtil; import org.labkey.api.view.ActionURL; @@ -95,6 +96,7 @@ public class AssayRunUploadContextImpl imple // Mutable fields private TransformResult _transformResult; private @Nullable PreparedTransform _preparedTransform; + private @Nullable List _pendingFileAuditEvents; // async fields protected String _jobDescription; @@ -453,6 +455,18 @@ public void setPreparedTransform(@Nullable PreparedTransform prepared) _preparedTransform = prepared; } + @Override + public @Nullable List getPendingFileAuditEvents() + { + return _pendingFileAuditEvents; + } + + @Override + public void setPendingFileAuditEvents(@Nullable List events) + { + _pendingFileAuditEvents = events; + } + @Override public void uploadComplete(ExpRun run) { diff --git a/api/src/org/labkey/api/assay/DefaultAssayRunCreator.java b/api/src/org/labkey/api/assay/DefaultAssayRunCreator.java index bda56e87bdd..2639620e4ed 100644 --- a/api/src/org/labkey/api/assay/DefaultAssayRunCreator.java +++ b/api/src/org/labkey/api/assay/DefaultAssayRunCreator.java @@ -33,7 +33,9 @@ import org.labkey.api.assay.transform.TransformDataHandler; import org.labkey.api.assay.transform.TransformResult; import org.labkey.api.collections.LongHashMap; +import org.labkey.api.audit.AuditLogService; import org.labkey.api.audit.TransactionAuditProvider; +import org.labkey.api.audit.provider.FileSystemAuditProvider; import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; @@ -148,6 +150,8 @@ private PreparedTransform prepareTransformAfterInit(AssayRunUploadContext allProperties = new HashMap<>(context.getRunProperties()); allProperties.putAll(context.getBatchProperties()); + // Collecting the inputs saves the primary file, whose audit event belongs to the import transaction that isn't open yet + context.setPendingFileAuditEvents(new ArrayList<>()); Map inputDatas = new HashMap<>(); addRunDataInputs(context, null, findResolverType(allProperties), inputDatas); PreparedTransform prepared = runTransformBeforeRun(context, inputDatas.keySet()); @@ -206,6 +210,19 @@ private PreparedTransform runTransformBeforeRun(AssayRunUploadContext context, TransactionAuditProvider.TransactionAuditEvent auditEvent) + { + List pending = context.getPendingFileAuditEvents(); + if (pending == null) + return; + context.setPendingFileAuditEvents(null); + for (FileSystemAuditProvider.FileSystemAuditEvent event : pending) + { + event.setTransactionEvent(auditEvent, FileSystemAuditProvider.EVENT_TYPE); + AuditLogService.get().addEvent(context.getUser(), event); + } + } + /** Issue 26811: If we don't have a view, assume that we are on a background job thread already. */ public static boolean isBackgroundImport(AssayProvider provider, ExpProtocol protocol, boolean forceAsync) { @@ -263,6 +280,7 @@ public Pair saveExperimentRun( auditEvent = AbstractQueryUpdateService.createTransactionAuditEvent(context.getContainer(), context.getReRunId() == null ? QueryService.AuditAction.UPDATE : QueryService.AuditAction.INSERT, transactionDetails); AbstractQueryUpdateService.addTransactionAuditEvent(transaction, context.getUser(), auditEvent); } + addPendingFileAuditEvents(context, auditEvent); if (!importInBackground) { if ((Object) context.getUploadedData().get(AssayDataCollector.PRIMARY_FILE) instanceof File errFile) diff --git a/api/src/org/labkey/api/assay/actions/AssayRunUploadForm.java b/api/src/org/labkey/api/assay/actions/AssayRunUploadForm.java index f0cb8551789..64056c3f271 100644 --- a/api/src/org/labkey/api/assay/actions/AssayRunUploadForm.java +++ b/api/src/org/labkey/api/assay/actions/AssayRunUploadForm.java @@ -51,6 +51,7 @@ import org.labkey.api.assay.transform.DefaultTransformResult; import org.labkey.api.assay.transform.PreparedTransform; import org.labkey.api.assay.transform.TransformResult; +import org.labkey.api.audit.provider.FileSystemAuditProvider; import org.labkey.api.qc.TsvDataExchangeHandler; import org.labkey.api.query.DefaultSchema; import org.labkey.api.query.PdLookupForeignKey; @@ -108,6 +109,7 @@ public class AssayRunUploadForm extends Prot private List _collectors; private TransformResult _transformResult = DefaultTransformResult.createEmptyResult(); private @Nullable PreparedTransform _preparedTransform; + private @Nullable List _pendingFileAuditEvents; private ExpRun _reRun; private boolean _allowCrossRunFileInputs; @@ -727,6 +729,18 @@ public void setPreparedTransform(@Nullable PreparedTransform prepared) _preparedTransform = prepared; } + @Override + public @Nullable List getPendingFileAuditEvents() + { + return _pendingFileAuditEvents; + } + + @Override + public void setPendingFileAuditEvents(@Nullable List events) + { + _pendingFileAuditEvents = events; + } + @Override public Long getReRunId() { diff --git a/api/src/org/labkey/api/assay/pipeline/AssayRunAsyncContext.java b/api/src/org/labkey/api/assay/pipeline/AssayRunAsyncContext.java index c9231495574..a3c46d9111f 100644 --- a/api/src/org/labkey/api/assay/pipeline/AssayRunAsyncContext.java +++ b/api/src/org/labkey/api/assay/pipeline/AssayRunAsyncContext.java @@ -36,6 +36,7 @@ import org.labkey.api.assay.transform.DefaultTransformResult; import org.labkey.api.assay.transform.PreparedTransform; import org.labkey.api.assay.transform.TransformResult; +import org.labkey.api.audit.provider.FileSystemAuditProvider; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; import org.labkey.api.view.ActionURL; @@ -47,6 +48,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -90,6 +92,7 @@ public class AssayRunAsyncContext implements private transient Set _domains; private transient TransformResult _transformResult; private transient @Nullable PreparedTransform _preparedTransform; + private transient @Nullable List _pendingFileAuditEvents; private transient Logger _logger; // async fields @@ -404,6 +407,18 @@ public void setPreparedTransform(@Nullable PreparedTransform prepared) _preparedTransform = prepared; } + @Override + public @Nullable List getPendingFileAuditEvents() + { + return _pendingFileAuditEvents; + } + + @Override + public void setPendingFileAuditEvents(@Nullable List events) + { + _pendingFileAuditEvents = events; + } + @Override public Long getReRunId() {