Skip to content

Commit 7ea4342

Browse files
Merge 26.3 to 26.7
2 parents d217704 + c5baffb commit 7ea4342

2 files changed

Lines changed: 117 additions & 24 deletions

File tree

laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,19 @@
2020
import org.apache.commons.beanutils.ConversionException;
2121
import org.apache.commons.lang3.StringUtils;
2222
import org.apache.logging.log4j.Level;
23-
import org.apache.logging.log4j.Logger;
2423
import org.apache.logging.log4j.LogManager;
24+
import org.apache.logging.log4j.Logger;
2525
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
2626
import org.json.JSONArray;
2727
import org.json.JSONObject;
28+
import org.labkey.api.assay.AssayProvider;
29+
import org.labkey.api.assay.AssayService;
2830
import org.labkey.api.collections.CaseInsensitiveHashMap;
2931
import org.labkey.api.data.Container;
32+
import org.labkey.api.data.ContainerManager;
33+
import org.labkey.api.data.ContainerType;
3034
import org.labkey.api.data.ConvertHelper;
31-
import org.labkey.api.data.DbSchema;
32-
import org.labkey.api.data.RuntimeSQLException;
3335
import org.labkey.api.data.SimpleFilter;
34-
import org.labkey.api.data.Table;
3536
import org.labkey.api.data.TableInfo;
3637
import org.labkey.api.data.TableSelector;
3738
import org.labkey.api.exp.PropertyDescriptor;
@@ -44,14 +45,14 @@
4445
import org.labkey.api.laboratory.LaboratoryService;
4546
import org.labkey.api.query.BatchValidationException;
4647
import org.labkey.api.query.FieldKey;
48+
import org.labkey.api.query.QueryService;
49+
import org.labkey.api.query.UserSchema;
4750
import org.labkey.api.query.ValidationException;
4851
import org.labkey.api.reader.ColumnDescriptor;
4952
import org.labkey.api.reader.ExcelFactory;
5053
import org.labkey.api.reader.Readers;
5154
import org.labkey.api.reader.TabLoader;
5255
import org.labkey.api.security.User;
53-
import org.labkey.api.assay.AssayProvider;
54-
import org.labkey.api.assay.AssayService;
5556
import org.labkey.api.util.FileType;
5657
import org.labkey.api.util.JsonUtil;
5758
import org.labkey.api.util.Pair;
@@ -461,10 +462,16 @@ protected void saveTemplate(ViewContext ctx, int templateId, long runId) throws
461462
{
462463
try
463464
{
464-
//validate the template exists
465-
TableInfo ti = DbSchema.get("laboratory").getTable("assay_run_templates");
465+
//validate the template exists. Note: this should always act against the current container, even if the container is a workbook (e.g., it should not allow cross-workbook actions)
466+
UserSchema us = QueryService.get().getUserSchema(ctx.getUser(), ctx.getContainer(), "laboratory");
467+
if (us == null)
468+
{
469+
throw new IllegalStateException("The laboratory schema is not available in container: " + ctx.getContainer().getPath());
470+
}
471+
472+
TableInfo ti = us.getTable("assay_run_templates");
466473
TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), templateId), null);
467-
if (ts.getRowCount() == 0)
474+
if (!ts.exists())
468475
{
469476
throw new BatchValidationException(Collections.singletonList(new ValidationException("Unknown template: " + templateId)), null);
470477
}
@@ -473,11 +480,15 @@ protected void saveTemplate(ViewContext ctx, int templateId, long runId) throws
473480
row.put("runid", runId);
474481
row.put("status", "Complete");
475482

476-
Table.update(ctx.getUser(), ti, row, templateId);
483+
ti.getUpdateService().updateRows(ctx.getUser(), ctx.getContainer(), Arrays.asList(row), Arrays.asList(Map.of("rowid", templateId)), null, null);
484+
}
485+
catch (BatchValidationException e)
486+
{
487+
throw e;
477488
}
478-
catch (RuntimeSQLException e)
489+
catch (Exception e)
479490
{
480-
throw new BatchValidationException(Collections.singletonList(new ValidationException(e.getSQLException().getMessage())), null);
491+
throw new BatchValidationException(Collections.singletonList(new ValidationException(e.getMessage())), null);
481492
}
482493
}
483494

@@ -579,8 +590,12 @@ protected Map<String, Map<String, Object>> getTemplateRowMap(ImportContext conte
579590
if (templateId == null)
580591
return ret;
581592

582-
TableInfo ti = DbSchema.get("laboratory").getTable("assay_run_templates");
583-
593+
UserSchema us = QueryService.get().getUserSchema(context.getViewContext().getUser(), context.getViewContext().getContainer().getContainerFor(ContainerType.DataType.tabParent), "laboratory");
594+
if (us == null)
595+
{
596+
throw new IllegalStateException("Could not find the laboratory schema in container: " + context.getViewContext().getContainer().getContainerFor(ContainerType.DataType.tabParent).getPath());
597+
}
598+
TableInfo ti = us.getTable("assay_run_templates");
584599
TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), templateId), null);
585600
Map<String, Object>[] maps = ts.getMapArray();
586601
if (maps.length == 0)
@@ -590,6 +605,18 @@ protected Map<String, Map<String, Object>> getTemplateRowMap(ImportContext conte
590605

591606
Map<String, Object> map = maps[0];
592607
JSONObject templateJson = new JSONObject((String)map.get("json"));
608+
609+
// This enforces that the request and existing record are from the same container, including for workbook/parents:
610+
Container rowContainer = ContainerManager.getForId(String.valueOf(map.get("container")));
611+
if (rowContainer == null)
612+
{
613+
throw new IllegalStateException("Unable to determine the container for template: " + templateId);
614+
}
615+
else if (!rowContainer.equals(context.getViewContext().getContainer()))
616+
{
617+
throw new IllegalStateException("Template is from the wrong container: " + templateId);
618+
}
619+
593620
JSONArray rows = templateJson.getJSONArray("ResultRows");
594621
for (JSONObject row : JsonUtil.toJSONObjectList(rows))
595622
{

laboratory/src/org/labkey/laboratory/assay/AssayHelper.java

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232
import org.labkey.api.collections.CollectionUtils;
3333
import org.labkey.api.data.Container;
3434
import org.labkey.api.data.ContainerManager;
35-
import org.labkey.api.data.RuntimeSQLException;
35+
import org.labkey.api.data.ContainerType;
36+
import org.labkey.api.data.SimpleFilter;
3637
import org.labkey.api.data.TSVMapWriter;
37-
import org.labkey.api.data.Table;
3838
import org.labkey.api.data.TableInfo;
3939
import org.labkey.api.data.TableSelector;
4040
import org.labkey.api.exp.ChangePropertyDescriptorException;
@@ -51,9 +51,14 @@
5151
import org.labkey.api.laboratory.assay.AssayDataProvider;
5252
import org.labkey.api.laboratory.assay.AssayImportMethod;
5353
import org.labkey.api.query.BatchValidationException;
54+
import org.labkey.api.query.FieldKey;
55+
import org.labkey.api.query.QueryService;
56+
import org.labkey.api.query.UserSchema;
5457
import org.labkey.api.query.ValidationException;
5558
import org.labkey.api.security.User;
59+
import org.labkey.api.security.permissions.UpdatePermission;
5660
import org.labkey.api.util.FileUtil;
61+
import org.labkey.api.util.PageFlowUtil;
5762
import org.labkey.api.util.Pair;
5863
import org.labkey.api.view.ActionURL;
5964
import org.labkey.api.view.ViewContext;
@@ -66,6 +71,7 @@
6671
import java.io.File;
6772
import java.io.IOException;
6873
import java.util.ArrayList;
74+
import java.util.Arrays;
6975
import java.util.Collections;
7076
import java.util.HashMap;
7177
import java.util.List;
@@ -120,35 +126,52 @@ public Map<String, Object> saveTemplate(User u, Container c, ExpProtocol protoco
120126
{
121127
validateTemplate(u, c, protocol, templateId, title, importMethod, json);
122128

123-
TableInfo ti = LaboratorySchema.getInstance().getSchema().getTable(LaboratorySchema.TABLE_ASSAY_RUN_TEMPLATES);
129+
UserSchema us = QueryService.get().getUserSchema(u, c, "laboratory");
130+
if (us == null)
131+
{
132+
throw new IllegalStateException("Could not find the laboratory schema in container: " + c.getPath());
133+
}
134+
135+
TableInfo ti = us.getTable(LaboratorySchema.TABLE_ASSAY_RUN_TEMPLATES);
124136
Map<String, Object> row = new HashMap<>();
125137
row.put("assayId", protocol.getRowId());
126138
row.put("title", title);
127139
row.put("importMethod", importMethod);
128140
row.put("json", json.toString());
129-
row.put("container", c.getId());
130141

131142
if (templateId == null)
132143
{
133-
row = Table.insert(u, ti, row);
144+
BatchValidationException bve = new BatchValidationException();
145+
List<Map<String, Object>> rows = ti.getUpdateService().insertRows(u, c, Arrays.asList(row), bve, null, null);
146+
if (bve.hasErrors())
147+
{
148+
throw bve;
149+
}
150+
151+
return rows.get(0);
134152
}
135153
else
136154
{
137155
row.put("rowid", templateId);
138-
row = Table.update(u, ti, row, templateId);
156+
List<Map<String, Object>> rows = ti.getUpdateService().updateRows(u, c, Arrays.asList(row), Arrays.asList(Map.of("rowid", templateId)), null, null);
157+
return rows.get(0);
139158
}
140-
141-
return row;
142159
}
143-
catch (RuntimeSQLException e)
160+
catch (BatchValidationException e)
161+
{
162+
// Expected validation failures (e.g. from validateTemplate() or insertRows()) should propagate to the
163+
// client as-is, not be logged as server errors.
164+
throw e;
165+
}
166+
catch (Exception e)
144167
{
145168
_log.error(e.getMessage(), e);
146169
errors.addRowError(new ValidationException(e.getMessage()));
147170
throw errors;
148171
}
149172
}
150173

151-
public void validateTemplate(User u, Container c, ExpProtocol protocol, Integer templateId, String title, String importMethod, JSONObject json) throws BatchValidationException
174+
public void validateTemplate(User u, Container c, ExpProtocol protocol, @Nullable Integer templateId, String title, String importMethod, JSONObject json) throws BatchValidationException
152175
{
153176
BatchValidationException errors = new BatchValidationException();
154177

@@ -173,6 +196,49 @@ public void validateTemplate(User u, Container c, ExpProtocol protocol, Integer
173196
throw errors;
174197
}
175198

199+
// Verify if this template exists and permissions. This expects any existing row to be present in the current container:
200+
if (templateId != null)
201+
{
202+
// This queries the current container+workbooks to identify the existence of rows in other reasonable containers:
203+
UserSchema us = QueryService.get().getUserSchema(u, c.getContainerFor(ContainerType.DataType.tabParent), "laboratory");
204+
TableInfo ti = us.getTable("assay_run_templates");
205+
TableSelector ts = new TableSelector(ti, PageFlowUtil.set("container"), new SimpleFilter(FieldKey.fromString("rowId"), templateId), null);
206+
if (ts.exists())
207+
{
208+
Container rowContainer = ContainerManager.getForId(ts.getObject(String.class));
209+
if (rowContainer == null)
210+
{
211+
errors.addRowError(new ValidationException("Unable to determine the container for template: " + templateId));
212+
throw errors;
213+
}
214+
215+
if (!rowContainer.hasPermission("AssayHelper.validateTemplate()", u, UpdatePermission.class))
216+
{
217+
errors.addRowError(new ValidationException("The current user does not have permission to edit template: " + templateId));
218+
throw errors;
219+
}
220+
221+
if (!c.equals(rowContainer))
222+
{
223+
errors.addRowError(new ValidationException("Template " + templateId + " is not from this folder"));
224+
throw errors;
225+
}
226+
}
227+
else
228+
{
229+
errors.addRowError(new ValidationException("Unable to find template with ID: " + templateId));
230+
throw errors;
231+
}
232+
}
233+
else
234+
{
235+
if (!c.hasPermission("AssayHelper.validateTemplate()", u, UpdatePermission.class))
236+
{
237+
errors.addRowError(new ValidationException("The current user does not have permission to creates templates in folder: " + c.getName()));
238+
throw errors;
239+
}
240+
}
241+
176242
method.validateTemplate(u, c, protocol, templateId, title, json, errors);
177243

178244
if (errors.hasErrors())

0 commit comments

Comments
 (0)