diff --git a/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java b/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java index bbcd2ac4..a1a33f32 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java +++ b/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java @@ -26,6 +26,7 @@ import org.json.JSONArray; import org.json.JSONObject; import org.labkey.api.collections.CaseInsensitiveHashMap; +import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.ConvertHelper; import org.labkey.api.data.DbSchema; @@ -462,13 +463,30 @@ protected void validateRows(List> rows, ImportContext contex errors.confirmNoErrors(); } + /** + * Returns the set of container ids in which an assay run template for a request in the given container may + * legitimately live: the container itself, plus its parent when the request runs in a workbook (mirroring the + * run-template picker, which sources templates from Laboratory.Utils.getQueryContainerPath). Used to scope + * assay_run_templates lookups to the request's folder tree without reaching an unrelated container. + */ + public static List getTemplateContainerIds(Container c) + { + List ids = new ArrayList<>(); + ids.add(c.getId()); + if (c.isWorkbook()) + ids.add(c.getParent().getId()); + return ids; + } + protected void saveTemplate(ViewContext ctx, int templateId, int runId) throws BatchValidationException { try { - //validate the template exists + //validate the template exists in (or above) this container TableInfo ti = DbSchema.get("laboratory").getTable("assay_run_templates"); - TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), templateId), null); + SimpleFilter filter = new SimpleFilter(FieldKey.fromString("rowid"), templateId); + filter.addCondition(FieldKey.fromString("container"), getTemplateContainerIds(_container), CompareType.IN); + TableSelector ts = new TableSelector(ti, filter, null); if (ts.getRowCount() == 0) { throw new BatchValidationException(Collections.singletonList(new ValidationException("Unknown template: " + templateId)), null); @@ -586,7 +604,9 @@ protected Map> getTemplateRowMap(ImportContext conte TableInfo ti = DbSchema.get("laboratory").getTable("assay_run_templates"); - TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), templateId), null); + SimpleFilter filter = new SimpleFilter(FieldKey.fromString("rowid"), templateId); + filter.addCondition(FieldKey.fromString("container"), getTemplateContainerIds(_container), CompareType.IN); + TableSelector ts = new TableSelector(ti, filter, null); Map[] maps = ts.getMapArray(); if (maps.length == 0) { diff --git a/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java b/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java index ee4a9816..71086ff1 100644 --- a/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java +++ b/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java @@ -30,9 +30,11 @@ import org.labkey.api.cache.CacheManager; import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.api.collections.CollectionUtils; +import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; import org.labkey.api.data.RuntimeSQLException; +import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.TSVMapWriter; import org.labkey.api.data.Table; import org.labkey.api.data.TableInfo; @@ -50,7 +52,9 @@ import org.labkey.api.laboratory.LaboratoryService; import org.labkey.api.laboratory.assay.AssayDataProvider; import org.labkey.api.laboratory.assay.AssayImportMethod; +import org.labkey.api.laboratory.assay.DefaultAssayParser; import org.labkey.api.query.BatchValidationException; +import org.labkey.api.query.FieldKey; import org.labkey.api.query.ValidationException; import org.labkey.api.security.User; import org.labkey.api.util.FileUtil; @@ -131,16 +135,26 @@ public Map saveTemplate(User u, Container c, ExpProtocol protoco row.put("title", title); row.put("importMethod", importMethod); row.put("json", json.toString()); - row.put("container", c.getId()); if (templateId == null) { + row.put("container", c.getId()); row = Table.insert(u, ti, row); } else { + // Table.update operates by global PK; verify the template is reachable from this container + // (here, or the parent when in a workbook) before updating, and leave its container unchanged. + SimpleFilter filter = new SimpleFilter(FieldKey.fromString("rowid"), templateId); + filter.addCondition(FieldKey.fromString("container"), DefaultAssayParser.getTemplateContainerIds(c), CompareType.IN); + if (!new TableSelector(ti, filter, null).exists()) + { + errors.addRowError(new ValidationException("Unknown template: " + templateId)); + throw errors; + } + row.put("rowid", templateId); - row = Table.update(u, ti, row, templateId); + row = Table.update(u, ti, row, templateId); // "container" intentionally absent -> not moved } return row;