Skip to content

Commit 7ae6f55

Browse files
Merge remote-tracking branch 'origin/develop' into fb_urlProvider
2 parents 7b6cc78 + 163973e commit 7ae6f55

18 files changed

Lines changed: 3598 additions & 1152 deletions

File tree

api/src/org/labkey/api/study/actions/ParticipantVisitResolverChooser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value)
168168
return ret2;
169169
}
170170
),
171-
disabledInput ? InputBuilder.hidden().name(_typeInputName).value(finalSelected.getName()).appendTo(out) : null
171+
disabledInput ? InputBuilder.hidden().name(_typeInputName).value(finalSelected.getName()).getHtmlString() : null
172172
)
173173
).appendTo(out);
174174
}
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
package org.labkey.api.workflow;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.json.JSONArray;
6+
import org.json.JSONObject;
7+
import org.labkey.api.data.Container;
8+
import org.labkey.api.data.ContainerManager;
9+
import org.labkey.api.data.CreatedModified;
10+
import org.labkey.api.exp.api.ExpProtocol;
11+
import org.labkey.api.exp.api.ExperimentService;
12+
import org.labkey.api.exp.api.SampleTypeService;
13+
import org.labkey.api.qc.SampleStatusService;
14+
import org.labkey.api.util.GUID;
15+
16+
import java.util.ArrayList;
17+
import java.util.Collections;
18+
import java.util.HashSet;
19+
import java.util.LinkedHashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
24+
public abstract class Action extends CreatedModified
25+
{
26+
public static final String ASSAY_TYPES_KEY = "assayTypes";
27+
public static final String NUM_PER_PARENT_KEY = "numPerParent";
28+
public static final String UPDATE_STATUS_KEY = "updateStatus";
29+
public static final String STATUS_KEY = "sampleStatus";
30+
protected Long _rowId;
31+
protected int _ordinal;
32+
protected GUID _containerId;
33+
private Container _container;
34+
protected String _name;
35+
protected boolean _isUpdatable = false;
36+
protected Long _taskId;
37+
protected WorkflowService.ActionType _type;
38+
protected JSONObject _inputParameters;
39+
40+
41+
public Long getRowId()
42+
{
43+
return _rowId;
44+
}
45+
46+
public void setRowId(Long rowId)
47+
{
48+
_rowId = rowId;
49+
}
50+
51+
public GUID getContainerId()
52+
{
53+
return _containerId;
54+
}
55+
56+
public void setContainerId(GUID containerId)
57+
{
58+
_containerId = containerId;
59+
}
60+
61+
@JsonIgnore
62+
public Container getContainer()
63+
{
64+
if (_container == null && _containerId != null)
65+
_container = ContainerManager.getForId(_containerId);
66+
return _container;
67+
}
68+
69+
public String getName()
70+
{
71+
return _name;
72+
}
73+
74+
public void setName(String name)
75+
{
76+
_name = name;
77+
}
78+
79+
public int getOrdinal()
80+
{
81+
return _ordinal;
82+
}
83+
84+
public void setOrdinal(int ordinal)
85+
{
86+
_ordinal = ordinal;
87+
}
88+
89+
public boolean getIsUpdatable()
90+
{
91+
return _isUpdatable;
92+
}
93+
94+
public void setIsUpdatable(boolean updatable)
95+
{
96+
_isUpdatable = updatable;
97+
}
98+
99+
public Long getTaskId()
100+
{
101+
return _taskId;
102+
}
103+
104+
public void setTaskId(Long taskId)
105+
{
106+
_taskId = taskId;
107+
}
108+
109+
public WorkflowService.ActionType getType()
110+
{
111+
return _type;
112+
}
113+
114+
public void setType(WorkflowService.ActionType type)
115+
{
116+
_type = type;
117+
}
118+
119+
public JSONObject getInputParameters()
120+
{
121+
return _inputParameters;
122+
}
123+
124+
public void setInputParameters(JSONObject inputParameters)
125+
{
126+
_inputParameters = inputParameters;
127+
}
128+
129+
@JsonIgnore
130+
public List<String> validateInputParameters(int ordinal, Container container)
131+
{
132+
String prefix = "Action #" + ordinal + ": ";
133+
if (_type == WorkflowService.ActionType.AssayImport)
134+
{
135+
if (_inputParameters != null && _inputParameters.has(ASSAY_TYPES_KEY))
136+
{
137+
try
138+
{
139+
JSONArray assayTypes = _inputParameters.getJSONArray(ASSAY_TYPES_KEY);
140+
// When assay types are updatable, there may be none provided. Usually that means the inputParameters will
141+
// be empty or null, but it also works if the assay types array is empty.
142+
if (assayTypes.isEmpty())
143+
return Collections.emptyList();
144+
145+
Set<Object> invalidAssayIds = new HashSet<>();
146+
assayTypes.toList().forEach(assayId ->
147+
{
148+
try
149+
{
150+
int protocolId = (assayId instanceof String) ? Integer.valueOf((String) assayId) : (Integer) assayId;
151+
ExpProtocol assay = ExperimentService.get().getExpProtocol(protocolId);
152+
if (null == assay)
153+
invalidAssayIds.add(protocolId);
154+
}
155+
catch (Exception e)
156+
{
157+
invalidAssayIds.add(assayId);
158+
}
159+
});
160+
if (!invalidAssayIds.isEmpty())
161+
return List.of(prefix + "invalid assay IDs " + invalidAssayIds + ".");
162+
}
163+
catch (Exception e)
164+
{
165+
return List.of(prefix + ASSAY_TYPES_KEY + " must be an array.");
166+
}
167+
}
168+
169+
}
170+
else if (_type == WorkflowService.ActionType.AliquotSamples)
171+
{
172+
if (_inputParameters == null || !_inputParameters.has(NUM_PER_PARENT_KEY))
173+
return List.of(prefix + NUM_PER_PARENT_KEY + " is required for action of type " + _type + ".");
174+
else
175+
{
176+
try {
177+
int numPerParent = _inputParameters.getInt(NUM_PER_PARENT_KEY);
178+
if (numPerParent < 0)
179+
return List.of(prefix + NUM_PER_PARENT_KEY + " cannot be negative.");
180+
}
181+
catch (Exception e) {
182+
return List.of(prefix + NUM_PER_PARENT_KEY + " must be an integer.");
183+
}
184+
}
185+
}
186+
else if (_type == WorkflowService.ActionType.DeriveSamples || _type == WorkflowService.ActionType.PoolSamples)
187+
{
188+
if (_inputParameters == null || _inputParameters.isEmpty())
189+
return List.of(prefix + "data about sample types and sample counts per parent is required for action of type " + _type + ".");
190+
if (_type == WorkflowService.ActionType.PoolSamples && _inputParameters.length() > 1)
191+
return List.of(prefix + "only one sample type can be specified for action of type " + _type + ".");
192+
SampleTypeService sampleTypeService = SampleTypeService.get();
193+
Set<String> invalidSampleTypeIds = new HashSet<>();
194+
List<Object> invalidCounts = new ArrayList<>();
195+
196+
_inputParameters.keys().forEachRemaining(id -> {
197+
try
198+
{
199+
if (sampleTypeService.getSampleType(Long.valueOf(id)) == null)
200+
invalidSampleTypeIds.add(id);
201+
}
202+
catch (NumberFormatException e)
203+
{
204+
invalidSampleTypeIds.add(id);
205+
}
206+
Object countObj = _inputParameters.get(id);
207+
if ((countObj instanceof String))
208+
try
209+
{
210+
if (Integer.parseInt((String) countObj) < 0)
211+
invalidCounts.add(countObj);
212+
}
213+
catch (NumberFormatException e)
214+
{
215+
invalidCounts.add(countObj);
216+
}
217+
else if (countObj instanceof Integer)
218+
{
219+
if (((Integer) countObj) < 0)
220+
invalidCounts.add(countObj);
221+
}
222+
else
223+
invalidCounts.add(countObj);
224+
});
225+
List<String> messages = new ArrayList<>();
226+
if (!invalidSampleTypeIds.isEmpty())
227+
messages.add(prefix + "invalid sample type IDs " + invalidSampleTypeIds + ".");
228+
if (!invalidCounts.isEmpty())
229+
messages.add(prefix + "invalid sample count values " + invalidCounts + ".");
230+
return messages;
231+
}
232+
else if (_type == WorkflowService.ActionType.RemoveFromStorage)
233+
{
234+
if (_inputParameters == null || _inputParameters.isEmpty())
235+
return Collections.emptyList();
236+
boolean updateStatus = _inputParameters.getBoolean(UPDATE_STATUS_KEY);
237+
if (updateStatus && !_inputParameters.has(STATUS_KEY))
238+
return List.of(prefix + STATUS_KEY + " is required for action of type " + _type + " when " + UPDATE_STATUS_KEY + " is true.");
239+
if (!updateStatus && _inputParameters.has(STATUS_KEY))
240+
return List.of(prefix + STATUS_KEY + " is not allowed for action of type " + _type + " when " + UPDATE_STATUS_KEY + " is false.");
241+
if (updateStatus && container != null)
242+
{
243+
try
244+
{
245+
long statusId = _inputParameters.getLong(STATUS_KEY);
246+
SampleStatusService sampleStatusService = SampleStatusService.get();
247+
if (sampleStatusService.getStateForRowId(container, statusId) == null)
248+
return List.of(prefix + "Invalid " + STATUS_KEY + " (" + statusId + ").");
249+
}
250+
catch (Exception e)
251+
{
252+
return List.of(prefix + "Invalid " + STATUS_KEY + ".");
253+
}
254+
}
255+
} else {
256+
if (_inputParameters != null && !_inputParameters.isEmpty())
257+
return List.of(prefix + "input parameters are not allowed for action of type " + _type + ".");
258+
}
259+
return Collections.emptyList();
260+
}
261+
262+
@Override
263+
public boolean equals(Object o)
264+
{
265+
if (this == o) return true;
266+
if (o == null || getClass() != o.getClass()) return false;
267+
Action action = (Action) o;
268+
269+
// GitHub Issue 799: Workflow Automation: Attempting to add a sample filter on an existing template errors
270+
// Migration script generated action.name, but they are currently not used. Allow name to be changed to null or empty string.
271+
if (!java.util.Objects.equals(_name, action._name) && !StringUtils.isEmpty(action.getName()))
272+
return false;
273+
274+
return _isUpdatable == action._isUpdatable &&
275+
_ordinal == action._ordinal &&
276+
java.util.Objects.equals(_rowId, action._rowId) &&
277+
java.util.Objects.equals(_taskId, action._taskId) &&
278+
java.util.Objects.equals(_type, action._type) &&
279+
java.util.Objects.equals(
280+
_inputParameters == null ? null : _inputParameters.toString(),
281+
action._inputParameters == null ? null : action._inputParameters.toString()
282+
);
283+
}
284+
285+
public Map<String, Object> toAuditDetailMap()
286+
{
287+
Map<String, Object> map = new LinkedHashMap<>();
288+
map.put("rowId", _rowId);
289+
map.put("name", _name);
290+
map.put("ordinal", _ordinal);
291+
map.put("isUpdatable", _isUpdatable);
292+
map.put("taskId", _taskId);
293+
if (_type != null)
294+
map.put("type", _type.name());
295+
if (_inputParameters != null)
296+
map.put("inputParameters", _inputParameters.toString());
297+
return map;
298+
}
299+
300+
public abstract Task getTask();
301+
}

0 commit comments

Comments
 (0)