diff --git a/api/src/org/labkey/api/action/QueryViewAction.java b/api/src/org/labkey/api/action/QueryViewAction.java index 9ebb9540eac..42a02c7bae6 100644 --- a/api/src/org/labkey/api/action/QueryViewAction.java +++ b/api/src/org/labkey/api/action/QueryViewAction.java @@ -16,6 +16,7 @@ package org.labkey.api.action; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.labkey.api.data.ColumnHeaderType; import org.labkey.api.data.ExcelWriter; @@ -135,7 +136,9 @@ protected ModelAndView getHtmlView(Form form, BindException errors) throws Excep /** * Correctly configures the QueryView to use the QueryViewAction for export purposes * @param dataRegion null as a convenience when only a single QueryView is being used + * @throws NotFoundException if passed a dataRegion name that doesn't exist */ + @NotNull protected final ViewType createInitializedQueryView(Form form, BindException errors, boolean forExport, @Nullable String dataRegion) throws Exception { ViewType result = createQueryView(form, errors, forExport, dataRegion); @@ -164,6 +167,7 @@ protected final ViewType createInitializedQueryView(Form form, BindException err * Create the specially configured query view. * @param dataRegion null as a convenience when only a single QueryView is being used */ + @Nullable protected abstract ViewType createQueryView(Form form, BindException errors, boolean forExport, @Nullable String dataRegion) throws Exception; public static class QueryExportForm extends QueryForm diff --git a/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java b/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java index c750658316f..f6e52614f42 100644 --- a/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java +++ b/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java @@ -23,6 +23,7 @@ import org.labkey.api.util.ContainerContext; import org.labkey.api.util.DOM; import org.labkey.api.util.GUID; +import org.labkey.api.util.HtmlString; import org.labkey.api.util.JavaScriptFragment; import org.labkey.api.util.StringExpression; import org.labkey.api.view.ActionURL; @@ -38,6 +39,7 @@ import static org.labkey.api.util.DOM.SPAN; import static org.labkey.api.util.DOM.id; +import static org.labkey.api.util.DOM.Attribute.style; /** * Uses LABKEY.Ext.CalloutTip to provide additional details, summoned via AJAX @@ -106,7 +108,7 @@ public void renderGridCellContents(RenderContext ctx, HtmlWriter out) props.put("target", divId); SPAN( - id(divId), + id(divId).at(style, "display:inline-flex;flex-wrap:nowrap"), (DOM.Renderable) ret -> { super.renderGridCellContents(ctx, out); return ret; diff --git a/api/src/org/labkey/api/dataiterator/SimpleTranslator.java b/api/src/org/labkey/api/dataiterator/SimpleTranslator.java index 5dcd3249d5c..eafe66196cd 100644 --- a/api/src/org/labkey/api/dataiterator/SimpleTranslator.java +++ b/api/src/org/labkey/api/dataiterator/SimpleTranslator.java @@ -485,20 +485,16 @@ protected class DerivationScopedConvertColumn extends SimpleConvertColumn final int derivationDataColInd; final int index; final boolean isDerivation; - final String presentDerivationWarning; - final String presentNonDerivationWarning; final SimpleConvertColumn _convertCol; - public DerivationScopedConvertColumn(int index, SimpleConvertColumn convertCol, int derivationDataColInd, boolean isDerivation, @Nullable String presentDerivationWarning, @Nullable String presentNonDerivationWarning) + public DerivationScopedConvertColumn(int index, SimpleConvertColumn convertCol, int derivationDataColInd, boolean isDerivation) { super(convertCol.fieldName, convertCol.index, convertCol.type, convertCol.defaultUnit); _convertCol = convertCol; this.index = index; this.derivationDataColInd = derivationDataColInd; this.isDerivation = isDerivation; - this.presentDerivationWarning = presentDerivationWarning; - this.presentNonDerivationWarning = presentNonDerivationWarning; } @Override @@ -506,7 +502,7 @@ protected Object convert(Object o) { Object thisValue = _convertCol.convert(o); - return getDerivationData(thisValue, derivationDataColInd, isDerivation, presentDerivationWarning, presentNonDerivationWarning); + return getDerivationData(thisValue, derivationDataColInd, isDerivation); } } @@ -519,23 +515,18 @@ protected class DerivationScopedColumn implements Supplier final int index; final boolean isDerivation; - final String presentDerivationWarning; - final String presentNonDerivationWarning; - - public DerivationScopedColumn(int index, int derivationDataColInd, boolean isDerivation, @Nullable String presentDerivationWarning, @Nullable String presentNonDerivationWarning) + public DerivationScopedColumn(int index, int derivationDataColInd, boolean isDerivation) { this.index = index; this.derivationDataColInd = derivationDataColInd; this.isDerivation = isDerivation; - this.presentDerivationWarning = presentDerivationWarning; - this.presentNonDerivationWarning = presentNonDerivationWarning; } @Override public Object get() { Object thisValue = _data.get(index); - return getDerivationData(thisValue, derivationDataColInd, isDerivation, presentDerivationWarning, presentNonDerivationWarning); + return getDerivationData(thisValue, derivationDataColInd, isDerivation); } } @@ -543,24 +534,14 @@ public Object get() * @param thisValue the original field value * @param derivationDataColInd the col index for the field used to determine if a record is child or parent * @param isDerivationField if this field is a child only field - * @param presentDerivationWarning the warning msg to log if a child field is present for a parent record - * @param presentNonDerivationWarning the warning msg to log if a parent field is present for a child record */ - private Object getDerivationData(Object thisValue, int derivationDataColInd, boolean isDerivationField, @Nullable String presentDerivationWarning, @Nullable String presentNonDerivationWarning) + private Object getDerivationData(Object thisValue, int derivationDataColInd, boolean isDerivationField) { Object derivationData = derivationDataColInd < 0 ? null : _data.get(derivationDataColInd); if ((isDerivationField && derivationData != null) || (!isDerivationField && derivationData == null)) return thisValue; - if (thisValue != null) - { - if (isDerivationField && presentDerivationWarning != null) - LOG.warn(presentDerivationWarning); - else if (!isDerivationField && presentNonDerivationWarning != null) - LOG.warn(presentNonDerivationWarning); - } - return null; } diff --git a/api/webapp/WEB-INF/web.xml b/api/webapp/WEB-INF/web.xml index 3dbc079f803..450a46349cd 100755 --- a/api/webapp/WEB-INF/web.xml +++ b/api/webapp/WEB-INF/web.xml @@ -58,6 +58,11 @@ *.post + + + COOKIE + + / diff --git a/audit/src/org/labkey/audit/AuditModule.java b/audit/src/org/labkey/audit/AuditModule.java index 5be6326ee39..ac6788c32d2 100644 --- a/audit/src/org/labkey/audit/AuditModule.java +++ b/audit/src/org/labkey/audit/AuditModule.java @@ -19,6 +19,13 @@ import org.jetbrains.annotations.NotNull; import org.labkey.api.audit.AuditLogService; import org.labkey.api.audit.provider.SiteSettingsAuditProvider; +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.JdbcType; +import org.labkey.api.data.SQLFragment; +import org.labkey.api.data.TableInfo; +import org.labkey.api.data.WrappedColumn; +import org.labkey.api.migration.DatabaseMigrationService; +import org.labkey.api.migration.MigrationTableHandler; import org.labkey.api.module.DefaultModule; import org.labkey.api.module.ModuleContext; import org.labkey.api.view.WebPartFactory; @@ -27,6 +34,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Set; +import java.util.TreeSet; public class AuditModule extends DefaultModule { @@ -89,4 +97,57 @@ public Set getProvisionedSchemaNames() { return Collections.singleton(AuditSchema.SCHEMA_NAME); } + + private final Set _registeredMigrationTables = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + + @Override + public void registerMigrationHandlers(@NotNull DatabaseMigrationService service) + { + service.registerSchemaContributor(AuditSchema.SCHEMA_NAME, schema -> + schema.getTableNames().stream() + .map(schema::getTable) + .filter(table -> table != null && _registeredMigrationTables.add(table.getSelectName())) + .forEach(table -> service.registerTableHandler(new MigrationTableHandler() + { + @Override + public TableInfo getTableInfo() + { + return table; + } + + @Override + public ColumnInfo handleColumn(ColumnInfo col) + { + if ("hasdetails".equalsIgnoreCase(col.getName())) + return new HasDetailsCastColumn(col); + return col; + } + }))); + } + + // Some legacy source databases store the DatasetAuditDomain "HasDetails" column as varchar + // while the target was provisioned as boolean. CAST to BIT in the source SELECT and report + // BOOLEAN as the JdbcType so the migration's INSERT parameter binds cleanly into the + // target's boolean column (otherwise the parameter inherits the source column's VARCHAR + // type and PG rejects the bound value). + private static final class HasDetailsCastColumn extends WrappedColumn + { + private HasDetailsCastColumn(ColumnInfo col) + { + super(col, col.getName()); + } + + @Override + @NotNull + public JdbcType getJdbcType() + { + return JdbcType.BOOLEAN; + } + + @Override + public SQLFragment getValueSql(String tableAlias) + { + return new SQLFragment("CAST(").append(super.getValueSql(tableAlias)).append(" AS BIT)"); + } + } } diff --git a/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java b/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java index 92510061fc5..13774614ac3 100644 --- a/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java +++ b/experiment/src/org/labkey/experiment/api/SampleTypeUpdateServiceDI.java @@ -1607,9 +1607,6 @@ private boolean rowExists(String name) static class _SamplesCoerceDataIterator extends SimpleTranslator { - private static final String INVALID_ALIQUOT_PROPERTY = "An aliquot-specific property [%1$s] value has been ignored for a non-aliquot sample."; - private static final String INVALID_NON_ALIQUOT_PROPERTY = "A sample property [%1$s] value has been ignored for an aliquot."; - private final ExpSampleTypeImpl _sampleType; private final Unit _sampleTypeBaseUnit; @@ -1664,14 +1661,12 @@ else if (amountImportAliasSet.contains(from.getName())) String name = to.getName(); boolean isScopedField = scopedFields.containsKey(name); - String ignoredAliquotPropValue = String.format(INVALID_ALIQUOT_PROPERTY, name); - String ignoredMetaPropValue = String.format(INVALID_NON_ALIQUOT_PROPERTY, name); if (to.getPropertyType() == PropertyType.ATTACHMENT || to.getPropertyType() == PropertyType.FILE_LINK) { if (isScopedField) { ColumnInfo clone = new BaseColumnInfo(to); - addColumn(clone, new DerivationScopedColumn(i, aliquotedFromDataColInd, scopedFields.get(name), ignoredAliquotPropValue, ignoredMetaPropValue)); + addColumn(clone, new DerivationScopedColumn(i, aliquotedFromDataColInd, scopedFields.get(name))); } else addColumn(to, i); @@ -1683,7 +1678,7 @@ else if (to.isMultiValued() || to.getFk() instanceof MultiValuedForeignKey) { var col = new BaseColumnInfo(getInput().getColumnInfo(i)); col.setName(name); - addColumn(col, new DerivationScopedColumn(i, aliquotedFromDataColInd, scopedFields.get(name), ignoredAliquotPropValue, ignoredMetaPropValue)); + addColumn(col, new DerivationScopedColumn(i, aliquotedFromDataColInd, scopedFields.get(name))); } else addColumn(to.getName(), i); @@ -1754,7 +1749,7 @@ private void _addConvertColumn(String name, int fromIndex, JdbcType toType, @Nul private void _addConvertColumn(ColumnInfo col, int fromIndex, int derivationDataColInd, boolean isAliquotField) { SimpleConvertColumn c = createConvertColumn(col, fromIndex, RemapMissingBehavior.Error); - c = new DerivationScopedConvertColumn(fromIndex, c, derivationDataColInd, isAliquotField, String.format(INVALID_ALIQUOT_PROPERTY, col.getName()), String.format(INVALID_NON_ALIQUOT_PROPERTY, col.getName())); + c = new DerivationScopedConvertColumn(fromIndex, c, derivationDataColInd, isAliquotField); addColumn(col, c); }