Merge pull request #327 from sartography/feature/file_refactor_2

modified the tools api to return the expression and data with the res…
This commit is contained in:
Dan Funk 2021-06-11 16:30:55 -04:00 committed by GitHub
commit 508c265952
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 14 deletions

2
Pipfile.lock generated
View File

@ -957,7 +957,7 @@
},
"spiffworkflow": {
"git": "https://github.com/sartography/SpiffWorkflow.git",
"ref": "ce939de158246e9d10e7e154c92230669354bc64"
"ref": "da79e8b0f66df1cb8372435bdff3b294e5f3a336"
},
"sqlalchemy": {
"hashes": [

View File

@ -1,3 +1,4 @@
import hashlib
import io
import json
@ -78,11 +79,13 @@ def send_email(subject, address, body, data=None):
def evaluate_python_expression(body):
"""Evaluate the given python expression, returning its result. This is useful if the
front end application needs to do real-time processing on task data. If for instance
there is a hide expression that is based on a previous value in the same form."""
there is a hide expression that is based on a previous value in the same form.
The response includes both the result, and a hash of the original query, subsequent calls
of the same hash are unnecessary. """
try:
script_engine = CustomBpmnScriptEngine()
result = script_engine.eval(body['expression'], body['data'])
return {"result": result}
return {"result": result, "expression": body['expression'], "data": body['data']}
except Exception as e:
raise ApiError("expression_error", f"Failed to evaluate the expression '%s'. %s" %
(body['expression'], str(e)),

View File

@ -259,19 +259,34 @@ class WorkflowService(object):
"""Looks through the fields in a submitted form, acting on any properties."""
if not hasattr(task.task_spec, 'form'): return
for field in task.task_spec.form.fields:
if field.has_property(Task.FIELD_PROP_DOC_CODE) and \
field.type == Task.FIELD_TYPE_FILE:
file_id = task.data[field.id]
file = db.session.query(FileModel).filter(FileModel.id == file_id).first()
doc_code = WorkflowService.evaluate_property(Task.FIELD_PROP_DOC_CODE, field, task)
data = task.data
if field.has_property(Task.FIELD_PROP_REPEAT):
repeat_array = task.data[field.get_property(Task.FIELD_PROP_REPEAT)]
for repeat_data in repeat_array:
WorkflowService.__post_process_field(task, field, repeat_data)
else:
WorkflowService.__post_process_field(task, field, data)
@staticmethod
def __post_process_field(task, field, data):
if field.has_property(Task.FIELD_PROP_DOC_CODE) and field.id in data:
# This is generally handled by the front end, but it is possible that the file was uploaded BEFORE
# the doc_code was correctly set, so this is a stop gap measure to assure we still hit it correctly.
file_id = data[field.id]
doc_code = task.workflow.script_engine.eval(field.get_property(Task.FIELD_PROP_DOC_CODE), data)
file = db.session.query(FileModel).filter(FileModel.id == file_id).first()
if(file):
file.irb_doc_code = doc_code
db.session.commit()
# Set the doc code on the file.
if field.has_property(Task.FIELD_PROP_FILE_DATA) and \
field.get_property(Task.FIELD_PROP_FILE_DATA) in task.data:
file_id = task.data[field.get_property(Task.FIELD_PROP_FILE_DATA)]
data_store = DataStoreModel(file_id=file_id, key=field.id, value=task.data[field.id])
db.session.add(data_store)
else:
# We have a problem, the file doesn't exist, and was removed, but it is still referenced in the data
# At least attempt to clear out the data.
data = {}
if field.has_property(Task.FIELD_PROP_FILE_DATA) and \
field.get_property(Task.FIELD_PROP_FILE_DATA) in data:
file_id = data[field.get_property(Task.FIELD_PROP_FILE_DATA)]
data_store = DataStoreModel(file_id=file_id, key=field.id, value=data[field.id])
db.session.add(data_store)
@staticmethod
def evaluate_property(property_name, field, task):

View File

@ -48,6 +48,20 @@ class TestStudyApi(BaseTest):
response = json.loads(rv.get_data(as_text=True))
self.assertEqual(True, response['result'])
def test_eval_returns_query(self):
"""Assures that along with the result, we get the original data and expression.
This can be useful if the calling client is caching results and needs to hash the expression and data
when it gets returned."""
data = '{"expression": "x.y==2", "data": {"x":{"y":2}}}'
rv = self.app.put('/v1.0/eval',
data=data, follow_redirects=True,
content_type='application/json',
headers=self.logged_in_headers())
self.assert_success(rv)
response = json.loads(rv.get_data(as_text=True))
self.assertEqual("x.y==2", response['expression'])
self.assertEqual({'x': {'y': 2}}, response['data'])
def test_eval_expression_with_strings(self):
"""Assures we can use python to process a value expression from the front end"""