add an enum_label script that will return the label given a value selection.

This commit is contained in:
Dan 2021-10-21 13:57:49 -04:00
parent 1c84bd9f1b
commit 84ce24243f
6 changed files with 286 additions and 5 deletions

85
crc/scripts/enum_label.py Normal file
View File

@ -0,0 +1,85 @@
from crc import db
from crc.api.common import ApiError
from crc.models.api_models import Task
from crc.models.workflow import WorkflowModel
from crc.scripts.script import Script
from crc.services.lookup_service import LookupService
from crc.services.workflow_processor import WorkflowProcessor
class EnumLabel(Script):
UNKNOWN = "unknown"
def get_description(self):
return """In a form, when doing a select list, multi-select, autocomplete, etc... you are left with a single
value. You may want to know the label that was displayed to the user as well. This will return the label, given
enough information to do so, which requires the name of the user task, the name of the form field, and the value
of the selected item.
Example:
pet_label = enum_label('task_pet_form', 'pet', '1') // might return 'Dog' which has the value of 1
"""
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
return self.do_task(task, study_id, workflow_id, *args, **kwargs)
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
self.validate_arguments(**kwargs)
task_name = kwargs['task_name']
field_name = kwargs['field']
value = kwargs['value']
# get the field information for the provided task_name (NOT the current task)
workflow_model = db.session.query(WorkflowModel).filter(WorkflowModel.id == workflow_id).first()
processor = WorkflowProcessor(workflow_model)
spec, field = processor.find_spec_and_field(task_name, field_name)
print(spec)
print(field)
if field.type == Task.FIELD_TYPE_AUTO_COMPLETE:
return self.autocomplete_label(workflow_model, task_name, field, value)
elif field.type == Task.FIELD_TYPE_ENUM and hasattr(field, 'options'):
return self.enum_with_options_label(field, value)
elif field.has_property(Task.FIELD_PROP_DATA_NAME):
return self.enum_from_task_data_label(task, field, value)
def autocomplete_label(self, workflow_model, task_name, field, value):
label_column = field.get_property(Task.FIELD_PROP_LABEL_COLUMN)
result = LookupService().lookup(workflow_model, task_name, field.id, '', value=value, limit=1)
if len(result) > 0:
return result[0][label_column]
else:
return self.UNKNOWN
def enum_with_options_label(self, field, value):
for option in field.options:
if option.id == value:
return option.name
return self.UNKNOWN
def enum_from_task_data_label(self, task, field, value):
data_name = field.get_property(Task.FIELD_PROP_DATA_NAME)
value_column = field.get_property(Task.FIELD_PROP_VALUE_COLUMN)
label_column = field.get_property(Task.FIELD_PROP_LABEL_COLUMN)
if data_name in task.data:
for d in task.data[data_name]:
if d[value_column] == value:
return d[label_column]
return self.UNKNOWN
def validate_arguments(self, **kwargs):
if len(kwargs) != 3:
raise ApiError(code="invalid_argument",
message="enum_label requires three arguments: Task id, Field id, and the selected value.")
if not 'task_name' in kwargs:
raise ApiError(code="invalid_argument",
message="you must specify the 'task_name', that is the name of the task with a form and field")
if not 'field' in kwargs:
raise ApiError(code="invalid_argument",
message="you must specify the 'field', that is the name of the field with an enum.")
if not 'value' in kwargs:
raise ApiError(code="invalid_argument",
message="you must specify the 'value', that is the value of the enum you wish to get a label for.")

View File

@ -85,7 +85,7 @@ class LookupService(object):
@staticmethod
def lookup(workflow, task_spec_id, field_id, query, value=None, limit=10):
# Returns a list of dictionaries
lookup_model = LookupService.__get_lookup_model(workflow, task_spec_id, field_id)
if lookup_model.is_ldap:

View File

@ -481,12 +481,21 @@ class WorkflowProcessor(object):
for task in self.bpmn_workflow.get_ready_user_tasks():
if task.workflow not in workflows:
workflows.append(task.workflow)
spec_found = False
for workflow in workflows:
for spec in workflow.spec.task_specs.values():
if spec.name == spec_name and hasattr(spec, "form"):
if spec.name == spec_name:
spec_found = True
if not hasattr(spec, "form"):
raise ApiError("invalid_spec",
"The spec name you provided does not contain a form.")
for field in spec.form.fields:
if field.id == field_id:
return spec, field
raise ApiError("invalid_field",
"Unable to find a task in the workflow with a lookup field called: %s" % field_id)
raise ApiError("invalid_field",
f"The task '{spec_name}' has no field named '{field_id}'")
raise ApiError("invalid_spec",
f"Unable to find a task in the workflow called '{spec_name}'")

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_6e556e1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.10.0">
<bpmn:process id="Process_6e556e1" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_173zivg</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_173zivg" sourceRef="StartEvent_1" targetRef="CreateDataSetup" />
<bpmn:sequenceFlow id="Flow_1e3q669" sourceRef="CreateDataSetup" targetRef="myFormTask" />
<bpmn:endEvent id="Event_03y3h9u">
<bpmn:documentation># This is what was entered</bpmn:documentation>
<bpmn:incoming>Flow_0f9fac8</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0f9fac8" sourceRef="myFormTask" targetRef="Event_03y3h9u" />
<bpmn:scriptTask id="CreateDataSetup" name="Create Data Setup">
<bpmn:incoming>Flow_173zivg</bpmn:incoming>
<bpmn:outgoing>Flow_1e3q669</bpmn:outgoing>
<bpmn:script>dogs = [
{'label':'Ham','value':'ham'},
{'label':'Ginger','value':'ginger'},
{'label':'Etta','value':'etta'},
{'label':'Simo','value':'simo'},
]
</bpmn:script>
</bpmn:scriptTask>
<bpmn:userTask id="myFormTask" name="Render Form" camunda:formKey="my_form">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="ldap" label="LDAP Lookup" type="autocomplete">
<camunda:properties>
<camunda:property id="ldap.lookup" value="True" />
<camunda:property id="value.column" value="uid" />
<camunda:property id="label.column" value="display_name" />
<camunda:property id="autocomplete_num" value="20" />
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="standard_enum" label="Standard Enum" type="enum">
<camunda:properties>
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
<camunda:value id="one" name="1" />
<camunda:value id="two" name="2" />
<camunda:value id="three" name="3" />
<camunda:value id="four" name="4" />
<camunda:value id="five" name="5" />
</camunda:formField>
<camunda:formField id="spreadsheet" label="Spreadsheet" type="autocomplete">
<camunda:properties>
<camunda:property id="label.column" value="desc" />
<camunda:property id="value.column" value="code" />
<camunda:property id="spreadsheet.name" value="my_list.xlsx" />
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="data" label="My Data" type="enum">
<camunda:properties>
<camunda:property id="data.name" value="dogs" />
<camunda:property id="value.column" value="value" />
<camunda:property id="label.column" value="label" />
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="checkbox" label="My Checkbox" type="enum">
<camunda:properties>
<camunda:property id="enum_type" value="checkbox" />
<camunda:property id="data.name" value="dogs" />
<camunda:property id="value.column" value="value" />
<camunda:property id="label.column" value="label" />
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="standard" label="Simple" type="string">
<camunda:properties>
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="pets" label="Prefered Pet" type="enum">
<camunda:properties>
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
<camunda:value id="cats" name="Cats" />
<camunda:value id="dogs" name="Dogs" />
<camunda:value id="other" name="other" />
</camunda:formField>
<camunda:formField id="petsOther" label="Prefered Pet (Other)" type="string">
<camunda:properties>
<camunda:property id="hide_expression" value="pets != &#39;other&#39;" />
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="file" label="upload file" type="file">
<camunda:properties>
<camunda:property id="repeat" value="repeatme" />
</camunda:properties>
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1e3q669</bpmn:incoming>
<bpmn:outgoing>Flow_0f9fac8</bpmn:outgoing>
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_6e556e1">
<bpmndi:BPMNEdge id="Flow_0f9fac8_di" bpmnElement="Flow_0f9fac8">
<di:waypoint x="570" y="117" />
<di:waypoint x="712" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1e3q669_di" bpmnElement="Flow_1e3q669">
<di:waypoint x="370" y="117" />
<di:waypoint x="470" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_173zivg_di" bpmnElement="Flow_173zivg">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_03y3h9u_di" bpmnElement="Event_03y3h9u">
<dc:Bounds x="712" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_13epga6_di" bpmnElement="CreateDataSetup">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1g2ib52_di" bpmnElement="myFormTask">
<dc:Bounds x="470" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

Binary file not shown.

View File

@ -0,0 +1,56 @@
from tests.base_test import BaseTest
from crc.scripts.enum_label import EnumLabel
from crc.api.common import ApiError
class TestGetEnumLabel(BaseTest):
def setUp(self):
self.load_example_data()
self.workflow = self.create_workflow('enum_options_all')
self.workflow_api = self.get_workflow_api(self.workflow)
# Assure the form has been loaded at least once.
self.task = self.workflow_api.next_task
self.assertEqual(self.task.name, 'myFormTask')
self.labelScript = EnumLabel()
def test_get_enum_label_for_ldap(self):
result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myFormTask', field='ldap', value='dhf8r')
self.assertEqual("Dan Funk", result)
def test_get_enum_label_for_standard_enum(self):
result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myFormTask', field='standard_enum', value='one')
self.assertEqual('1', result)
def test_get_enum_label_for_spreadsheet(self):
result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myFormTask', field='spreadsheet', value='2')
self.assertEqual('T-shirts', result)
def test_get_enum_label_for_data(self):
result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myFormTask', field='data', value='simo')
self.assertEqual('Simo', result)
def test_get_enum_label_for_checkbox(self):
result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myFormTask', field='checkbox', value='simo')
self.assertEqual('Simo', result)
def test_get_invalid_spec_name(self):
with self.assertRaises(ApiError) as ctx:
ldap_result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myWrongFormTask', field='standard_enum', value='one')
self.assertEqual("ApiError: Unable to find a task in the workflow called 'myWrongFormTask'. ", str(ctx.exception))
def test_get_invalid_field_name(self):
with self.assertRaises(ApiError) as ctx:
ldap_result = self.labelScript.do_task(self.task, self.workflow_api.study_id, self.workflow_api.id,
task_name='myFormTask', field='made_up_enum', value='one')
self.assertEqual("ApiError: The task 'myFormTask' has no field named 'made_up_enum'. ", str(ctx.exception))