Merge pull request #421 from sartography/bug/validation_of_enum_label_failing_in_sub_workflows

Validation was failing for enum_label() expressions when called withi…
This commit is contained in:
Dan Funk 2021-11-10 15:26:03 -05:00 committed by GitHub
commit e764bf937d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 14 deletions

View File

@ -7,6 +7,7 @@ import sentry_sdk
import connexion import connexion
from SpiffWorkflow import WorkflowException from SpiffWorkflow import WorkflowException
from SpiffWorkflow.exceptions import WorkflowTaskExecException
from connexion import ProblemException from connexion import ProblemException
from flask import Response from flask import Response
from flask_cors import CORS from flask_cors import CORS
@ -139,8 +140,8 @@ def sync_with_testing():
@app.cli.command() @app.cli.command()
@click.argument("study_id") @click.argument("study_id")
@click.argument("category") @click.argument("category", required=False)
@click.argument("spec_id") @click.argument("spec_id", required=False)
def validate_all(study_id, category=None, spec_id=None): def validate_all(study_id, category=None, spec_id=None):
"""Step through all the local workflows and validate them, returning any errors. This make take forever. """Step through all the local workflows and validate them, returning any errors. This make take forever.
Please provide a real study id to use for validation, an optional category can be specified to only validate Please provide a real study id to use for validation, an optional category can be specified to only validate
@ -148,7 +149,13 @@ def validate_all(study_id, category=None, spec_id=None):
from crc.models.workflow import WorkflowSpecModel from crc.models.workflow import WorkflowSpecModel
from crc.services.workflow_service import WorkflowService from crc.services.workflow_service import WorkflowService
from crc.api.common import ApiError from crc.api.common import ApiError
from crc.models.study import StudyModel
from crc.models.user import UserModel
from flask import g
study = session.query(StudyModel).filter(StudyModel.id == study_id).first()
g.user = session.query(UserModel).filter(UserModel.uid == study.user_uid).first()
g.token = "anything_is_fine_just_need_something."
specs = session.query(WorkflowSpecModel).all() specs = session.query(WorkflowSpecModel).all()
for spec in specs: for spec in specs:
if spec_id and spec_id != spec.id: if spec_id and spec_id != spec.id:
@ -158,10 +165,15 @@ def validate_all(study_id, category=None, spec_id=None):
try: try:
WorkflowService.test_spec(spec.id, validate_study_id=study_id) WorkflowService.test_spec(spec.id, validate_study_id=study_id)
except ApiError as e: except ApiError as e:
print("Failed to validate workflow " + spec.id) if e.code == 'disabled_workflow':
print(e) print(f"Skipping {spec.id} in category {spec.category.display_name}, it is disabled for this study.")
return else:
except WorkflowException as e: print(f"API Error {e.code}, validate workflow {spec.id} in Category {spec.category.display_name}")
print("Failed to validate workflow " + spec.id) return
except WorkflowTaskExecException as e:
print(f"Workflow Error, {e}, in Task {e.task.name} validate workflow {spec.id} in Category {spec.category.display_name}")
return
except Exception as e:
print(f"Unexpected Error, {e} validate workflow {spec.id} in Category {spec.category.display_name}")
print(e) print(e)
return return

View File

@ -32,9 +32,7 @@ pet_label = enum_label(task='task_pet_form',field='pet',value='1') // might r
# get the field information for the provided task_name (NOT the current task) # 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() workflow_model = db.session.query(WorkflowModel).filter(WorkflowModel.id == workflow_id).first()
processor = WorkflowProcessor(workflow_model) field = self.find_field(task_name, field_name, spiff_task.workflow)
spec, field = processor.find_spec_and_field(task_name, field_name)
print(spec)
print(field) print(field)
if field.type == Task.FIELD_TYPE_AUTO_COMPLETE: if field.type == Task.FIELD_TYPE_AUTO_COMPLETE:
@ -44,6 +42,18 @@ pet_label = enum_label(task='task_pet_form',field='pet',value='1') // might r
elif field.has_property(Task.FIELD_PROP_DATA_NAME): elif field.has_property(Task.FIELD_PROP_DATA_NAME):
return self.enum_from_task_data_label(spiff_task, field, value) return self.enum_from_task_data_label(spiff_task, field, value)
def find_field(self, task_name, field_name, workflow):
for spec in workflow.spec.task_specs.values():
if spec.name == task_name:
for field in spec.form.fields:
if field.id == field_name:
return field
raise ApiError("invalid_field",
f"The task '{task_name}' has no field named '{field_name}'")
raise ApiError("invalid_spec",
f"Unable to find a task in the workflow called '{task_name}'")
def autocomplete_label(self, workflow_model, task_name, field, value): def autocomplete_label(self, workflow_model, task_name, field, value):
label_column = field.get_property(Task.FIELD_PROP_LABEL_COLUMN) label_column = field.get_property(Task.FIELD_PROP_LABEL_COLUMN)
result = LookupService().lookup(workflow_model, task_name, field.id, '', value=value, limit=1) result = LookupService().lookup(workflow_model, task_name, field.id, '', value=value, limit=1)

View File

@ -199,7 +199,7 @@ class LookupService(object):
def _run_lookup_query(lookup_file_model, query, value, limit): def _run_lookup_query(lookup_file_model, query, value, limit):
db_query = LookupDataModel.query.filter(LookupDataModel.lookup_file_model == lookup_file_model) db_query = LookupDataModel.query.filter(LookupDataModel.lookup_file_model == lookup_file_model)
if value is not None: # Then just find the model with that value if value is not None: # Then just find the model with that value
db_query = db_query.filter(LookupDataModel.value == value) db_query = db_query.filter(LookupDataModel.value == str(value))
else: else:
# Build a full text query that takes all the terms provided and executes each term as a prefix query, and # Build a full text query that takes all the terms provided and executes each term as a prefix query, and
# OR's those queries together. The order of the results is handled as a standard "Like" on the original # OR's those queries together. The order of the results is handled as a standard "Like" on the original

View File

@ -433,7 +433,7 @@ class WorkflowService(object):
elif lookup_model: elif lookup_model:
data = db.session.query(LookupDataModel).\ data = db.session.query(LookupDataModel).\
filter(LookupDataModel.lookup_file_model == lookup_model). \ filter(LookupDataModel.lookup_file_model == lookup_model). \
filter(LookupDataModel.value == default).\ filter(LookupDataModel.value == str(default)).\
first() first()
if not data: if not data:
raise ApiError.from_task("invalid_default", "You specified a default value that does not exist in " raise ApiError.from_task("invalid_default", "You specified a default value that does not exist in "

View File

@ -2,6 +2,7 @@ from tests.base_test import BaseTest
from crc.scripts.enum_label import EnumLabel from crc.scripts.enum_label import EnumLabel
from crc.api.common import ApiError from crc.api.common import ApiError
from crc.services.workflow_processor import WorkflowProcessor
class TestGetEnumLabel(BaseTest): class TestGetEnumLabel(BaseTest):
@ -12,8 +13,10 @@ class TestGetEnumLabel(BaseTest):
self.workflow_api = self.get_workflow_api(self.workflow) self.workflow_api = self.get_workflow_api(self.workflow)
# Assure the form has been loaded at least once. # Assure the form has been loaded at least once.
self.task = self.workflow_api.next_task processor = WorkflowProcessor(self.workflow)
self.assertEqual(self.task.name, 'myFormTask') processor.do_engine_steps()
self.task = processor.next_task()
self.assertEqual(self.task.get_name(), 'myFormTask')
self.labelScript = EnumLabel() self.labelScript = EnumLabel()