mirror of
https://github.com/sartography/cr-connect-workflow.git
synced 2025-02-23 13:18:35 +00:00
Merge branch 'dev' into chore/log-changes-661
This commit is contained in:
commit
6ec01a0a85
@ -74,7 +74,6 @@ def update_datastore(id, body):
|
|||||||
def add_datastore(body):
|
def add_datastore(body):
|
||||||
""" add a new datastore item """
|
""" add a new datastore item """
|
||||||
|
|
||||||
print(body)
|
|
||||||
if body.get(id, None):
|
if body.get(id, None):
|
||||||
raise ApiError('id_specified', 'You may not specify an id for a new datastore item')
|
raise ApiError('id_specified', 'You may not specify an id for a new datastore item')
|
||||||
|
|
||||||
|
@ -33,8 +33,6 @@ 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()
|
||||||
field = self.find_field(task_name, field_name, spiff_task.workflow)
|
field = self.find_field(task_name, field_name, spiff_task.workflow)
|
||||||
print(field)
|
|
||||||
|
|
||||||
if field.type == Task.FIELD_TYPE_AUTO_COMPLETE:
|
if field.type == Task.FIELD_TYPE_AUTO_COMPLETE:
|
||||||
return self.lookup_label(workflow_model, task_name, field, value)
|
return self.lookup_label(workflow_model, task_name, field, value)
|
||||||
elif field.has_property(Task.FIELD_PROP_SPREADSHEET_NAME):
|
elif field.has_property(Task.FIELD_PROP_SPREADSHEET_NAME):
|
||||||
|
@ -24,7 +24,6 @@ class FactService(Script):
|
|||||||
self.do_task(task, study_id, workflow_id, **kwargs)
|
self.do_task(task, study_id, workflow_id, **kwargs)
|
||||||
|
|
||||||
def do_task(self, task, study_id, workflow_id, **kwargs):
|
def do_task(self, task, study_id, workflow_id, **kwargs):
|
||||||
print(task.data)
|
|
||||||
|
|
||||||
if "type" not in task.data:
|
if "type" not in task.data:
|
||||||
raise Exception("No Fact Provided.")
|
raise Exception("No Fact Provided.")
|
||||||
@ -41,6 +40,4 @@ class FactService(Script):
|
|||||||
details = "unknown fact type."
|
details = "unknown fact type."
|
||||||
|
|
||||||
#self.add_data_to_task(task, details)
|
#self.add_data_to_task(task, details)
|
||||||
|
|
||||||
print(details)
|
|
||||||
return details
|
return details
|
||||||
|
@ -66,7 +66,6 @@ class GitService(object):
|
|||||||
repo = self.setup_repo(remote_path, directory)
|
repo = self.setup_repo(remote_path, directory)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
|
||||||
app.logger.error(e)
|
app.logger.error(e)
|
||||||
raise ApiError(code='unknown_exception',
|
raise ApiError(code='unknown_exception',
|
||||||
message=f'There was an unknown exception. Original message is: {e}')
|
message=f'There was an unknown exception. Original message is: {e}')
|
||||||
@ -118,11 +117,11 @@ class GitService(object):
|
|||||||
try:
|
try:
|
||||||
repo.remotes.origin.pull()
|
repo.remotes.origin.pull()
|
||||||
except GitCommandError as ce:
|
except GitCommandError as ce:
|
||||||
print(ce)
|
raise ApiError(code='git_command_error',
|
||||||
|
message='Error Running Git Command:' + str(ce))
|
||||||
else:
|
else:
|
||||||
raise ApiError(code='dirty_repo',
|
raise ApiError(code='dirty_repo',
|
||||||
message='You have modified or untracked files. Please fix this before attempting to pull.')
|
message='You have modified or untracked files. Please fix this before attempting to pull.')
|
||||||
print(repo)
|
|
||||||
return repo
|
return repo
|
||||||
|
|
||||||
def merge_with_branch(self, branch):
|
def merge_with_branch(self, branch):
|
||||||
|
@ -31,17 +31,36 @@ Please Introduce yourself.
|
|||||||
Hi Dan, This is a jinja template too!
|
Hi Dan, This is a jinja template too!
|
||||||
Cool Right?
|
Cool Right?
|
||||||
"""
|
"""
|
||||||
|
template_pattern = re.compile('{ ?% ?include\s*[\'\"](\w+)[\'\"]\s*?-?%}', re.DOTALL)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_content(input_template, data):
|
def get_content(input_template, data):
|
||||||
templates = data
|
templates = {}
|
||||||
|
references = JinjaService.template_references(input_template)
|
||||||
|
for ref in references:
|
||||||
|
if ref in data.keys():
|
||||||
|
templates[ref] = data[ref]
|
||||||
|
else:
|
||||||
|
raise ApiError("missing_template", f"Your documentation imports a template that doest not exist: {ref}")
|
||||||
templates['main_template'] = input_template
|
templates['main_template'] = input_template
|
||||||
jinja2_env = Environment(loader=DictLoader(templates))
|
jinja2_env = Environment(loader=DictLoader(templates))
|
||||||
|
|
||||||
# We just make a call here and let any errors percolate up to the calling method
|
# We just make a call here and let any errors percolate up to the calling method
|
||||||
template = jinja2_env.get_template('main_template')
|
template = jinja2_env.get_template('main_template')
|
||||||
return template.render(**data)
|
try:
|
||||||
|
result = template.render(**data)
|
||||||
|
except AttributeError as ae:
|
||||||
|
if str(ae) == '\'NoneType\' object has no attribute \'splitlines\'':
|
||||||
|
raise ApiError("template_error", "Error processing template. You may be using a wordwrap "
|
||||||
|
"with a field that has no value.")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def template_references(input_template):
|
||||||
|
"""Using regex, determine what other templates are included, and return a list of those names."""
|
||||||
|
matches = JinjaService.template_pattern.findall(input_template)
|
||||||
|
return matches
|
||||||
#
|
#
|
||||||
# The rest of this is for using Word documents as Jinja templates
|
# The rest of this is for using Word documents as Jinja templates
|
||||||
#
|
#
|
||||||
|
@ -84,7 +84,6 @@ class LookupService(object):
|
|||||||
# to rebuild.
|
# to rebuild.
|
||||||
workflow_spec = WorkflowSpecService().get_spec(workflow.workflow_spec_id)
|
workflow_spec = WorkflowSpecService().get_spec(workflow.workflow_spec_id)
|
||||||
timestamp = SpecFileService.timestamp(workflow_spec, lookup_model.file_name)
|
timestamp = SpecFileService.timestamp(workflow_spec, lookup_model.file_name)
|
||||||
print(f"*** Comparing {timestamp} and {lookup_model.file_timestamp}")
|
|
||||||
# Assures we have the same timestamp, as storage in the database might create slight variations in
|
# Assures we have the same timestamp, as storage in the database might create slight variations in
|
||||||
# the floating point values, just assure they values match to within a second.
|
# the floating point values, just assure they values match to within a second.
|
||||||
is_current = int(timestamp - lookup_model.file_timestamp) == 0
|
is_current = int(timestamp - lookup_model.file_timestamp) == 0
|
||||||
|
@ -31,7 +31,6 @@ SPEC_SCHEMA = WorkflowSpecModelSchema()
|
|||||||
|
|
||||||
def remove_all_json_files(path):
|
def remove_all_json_files(path):
|
||||||
for json_file in pathlib.Path(path).glob('*.json'):
|
for json_file in pathlib.Path(path).glob('*.json'):
|
||||||
print("removing ", json_file)
|
|
||||||
os.remove(json_file)
|
os.remove(json_file)
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +40,6 @@ def update_workflows_for_category(path, schemas, category_id):
|
|||||||
new_path = os.path.join(path, schema.id)
|
new_path = os.path.join(path, schema.id)
|
||||||
if (os.path.exists(orig_path)):
|
if (os.path.exists(orig_path)):
|
||||||
os.rename(orig_path, new_path)
|
os.rename(orig_path, new_path)
|
||||||
print(new_path)
|
|
||||||
update_spec(new_path, schema, category_id)
|
update_spec(new_path, schema, category_id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ from SpiffWorkflow.dmn.specs.BusinessRuleTask import BusinessRuleTask
|
|||||||
from SpiffWorkflow.exceptions import WorkflowTaskExecException
|
from SpiffWorkflow.exceptions import WorkflowTaskExecException
|
||||||
from SpiffWorkflow.specs import CancelTask, StartTask
|
from SpiffWorkflow.specs import CancelTask, StartTask
|
||||||
from SpiffWorkflow.util.deep_merge import DeepMerge
|
from SpiffWorkflow.util.deep_merge import DeepMerge
|
||||||
from SpiffWorkflow.util.metrics import timeit, firsttime, sincetime
|
from sentry_sdk import capture_message, push_scope
|
||||||
from sqlalchemy.exc import InvalidRequestError
|
from sqlalchemy.exc import InvalidRequestError
|
||||||
|
|
||||||
from crc import db, app, session
|
from crc import db, app, session
|
||||||
@ -32,7 +31,6 @@ from crc.models.task_event import TaskEventModel
|
|||||||
from crc.models.user import UserModel
|
from crc.models.user import UserModel
|
||||||
from crc.models.workflow import WorkflowModel, WorkflowStatus
|
from crc.models.workflow import WorkflowModel, WorkflowStatus
|
||||||
from crc.services.data_store_service import DataStoreBase
|
from crc.services.data_store_service import DataStoreBase
|
||||||
|
|
||||||
from crc.services.document_service import DocumentService
|
from crc.services.document_service import DocumentService
|
||||||
from crc.services.jinja_service import JinjaService
|
from crc.services.jinja_service import JinjaService
|
||||||
from crc.services.lookup_service import LookupService
|
from crc.services.lookup_service import LookupService
|
||||||
@ -42,8 +40,6 @@ from crc.services.user_service import UserService
|
|||||||
from crc.services.workflow_processor import WorkflowProcessor
|
from crc.services.workflow_processor import WorkflowProcessor
|
||||||
from crc.services.workflow_spec_service import WorkflowSpecService
|
from crc.services.workflow_spec_service import WorkflowSpecService
|
||||||
|
|
||||||
from sentry_sdk import capture_message, push_scope
|
|
||||||
|
|
||||||
|
|
||||||
class WorkflowService(object):
|
class WorkflowService(object):
|
||||||
TASK_ACTION_COMPLETE = "COMPLETE"
|
TASK_ACTION_COMPLETE = "COMPLETE"
|
||||||
@ -203,12 +199,19 @@ class WorkflowService(object):
|
|||||||
task,
|
task,
|
||||||
add_docs_and_forms=True) # Assure we try to process the documentation, and raise those errors.
|
add_docs_and_forms=True) # Assure we try to process the documentation, and raise those errors.
|
||||||
# make sure forms have a form key
|
# make sure forms have a form key
|
||||||
if hasattr(task_api, 'form') and task_api.form is not None and task_api.form.key == '':
|
if hasattr(task_api, 'form') and task_api.form is not None:
|
||||||
|
if task_api.form.key == '':
|
||||||
raise ApiError(code='missing_form_key',
|
raise ApiError(code='missing_form_key',
|
||||||
message='Forms must include a Form Key.',
|
message='Forms must include a Form Key.',
|
||||||
task_id=task.id,
|
task_id=task.id,
|
||||||
task_name=task.get_name())
|
task_name=task.get_name())
|
||||||
WorkflowService.populate_form_with_random_data(task, task_api, required_only)
|
WorkflowService.populate_form_with_random_data(task, task_api, required_only)
|
||||||
|
if not WorkflowService.validate_form(task, task_api):
|
||||||
|
# In the process of completing the form, it is possible for fields to become required
|
||||||
|
# based on later fields. If the form has incomplete, but required fields (validate_form)
|
||||||
|
# then try to populate the form again, with this new information.
|
||||||
|
WorkflowService.populate_form_with_random_data(task, task_api, required_only)
|
||||||
|
|
||||||
processor.complete_task(task)
|
processor.complete_task(task)
|
||||||
if test_until == task.task_spec.name:
|
if test_until == task.task_spec.name:
|
||||||
raise ApiError.from_task(
|
raise ApiError.from_task(
|
||||||
@ -238,6 +241,26 @@ class WorkflowService(object):
|
|||||||
WorkflowService.delete_test_data(workflow_model)
|
WorkflowService.delete_test_data(workflow_model)
|
||||||
return processor.bpmn_workflow.last_task.data
|
return processor.bpmn_workflow.last_task.data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validate_form(task, task_api):
|
||||||
|
for field in task_api.form.fields:
|
||||||
|
if WorkflowService.is_required_field(field, task):
|
||||||
|
if not field.id in task.data or task.data[field.id] is None:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_required_field(field, task):
|
||||||
|
# Get Required State
|
||||||
|
is_required = False
|
||||||
|
if (field.has_validation(Task.FIELD_CONSTRAINT_REQUIRED) and
|
||||||
|
field.get_validation(Task.FIELD_CONSTRAINT_REQUIRED)):
|
||||||
|
is_required = True
|
||||||
|
if (field.has_property(Task.FIELD_PROP_REQUIRED_EXPRESSION) and
|
||||||
|
WorkflowService.evaluate_property(Task.FIELD_PROP_REQUIRED_EXPRESSION, field, task)):
|
||||||
|
is_required = True
|
||||||
|
return is_required
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def populate_form_with_random_data(task, task_api, required_only):
|
def populate_form_with_random_data(task, task_api, required_only):
|
||||||
"""populates a task with random data - useful for testing a spec."""
|
"""populates a task with random data - useful for testing a spec."""
|
||||||
@ -256,6 +279,8 @@ class WorkflowService(object):
|
|||||||
form_data[field.id] = None
|
form_data[field.id] = None
|
||||||
|
|
||||||
for field in task_api.form.fields:
|
for field in task_api.form.fields:
|
||||||
|
is_required = WorkflowService.is_required_field(field, task)
|
||||||
|
|
||||||
# Assure we have a field type
|
# Assure we have a field type
|
||||||
if field.type is None:
|
if field.type is None:
|
||||||
raise ApiError(code='invalid_form_data',
|
raise ApiError(code='invalid_form_data',
|
||||||
@ -284,19 +309,13 @@ class WorkflowService(object):
|
|||||||
task=task)
|
task=task)
|
||||||
|
|
||||||
# If a field is hidden and required, it must have a default value
|
# If a field is hidden and required, it must have a default value
|
||||||
if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION) and field.has_validation(
|
# if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION) and field.has_validation(
|
||||||
Task.FIELD_CONSTRAINT_REQUIRED):
|
# Task.FIELD_CONSTRAINT_REQUIRED):
|
||||||
if field.default_value is None:
|
# if field.default_value is None:
|
||||||
raise ApiError(code='hidden and required field missing default',
|
# raise ApiError(code='hidden and required field missing default',
|
||||||
message=f'Field "{field.id}" is required but can be hidden. It must have a default value.',
|
# message=f'Field "{field.id}" is required but can be hidden. It must have a def1ault value.',
|
||||||
task_id='task.id',
|
# task_id='task.id',
|
||||||
task_name=task.get_name())
|
# task_name=task.get_name())
|
||||||
|
|
||||||
# If the field is hidden and not required, it should not produce a value.
|
|
||||||
if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION) and not field.has_validation(
|
|
||||||
Task.FIELD_CONSTRAINT_REQUIRED):
|
|
||||||
if WorkflowService.evaluate_property(Task.FIELD_PROP_HIDE_EXPRESSION, field, task):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# If we have a default_value, try to set the default
|
# If we have a default_value, try to set the default
|
||||||
if field.default_value:
|
if field.default_value:
|
||||||
@ -306,21 +325,21 @@ class WorkflowService(object):
|
|||||||
raise ApiError.from_task("bad default value", f'The default value "{field.default_value}" in field {field.id} '
|
raise ApiError.from_task("bad default value", f'The default value "{field.default_value}" in field {field.id} '
|
||||||
f'could not be understood or evaluated. ',
|
f'could not be understood or evaluated. ',
|
||||||
task=task)
|
task=task)
|
||||||
if not field.has_property(Task.FIELD_PROP_REPEAT):
|
# If we have a good default value, and we aren't dealing with a repeat, we can stop here.
|
||||||
|
if form_data[field.id] is not None and not field.has_property(Task.FIELD_PROP_REPEAT):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
form_data[field.id] = None
|
form_data[field.id] = None
|
||||||
|
|
||||||
|
# If the field is hidden we can leave it as none.
|
||||||
|
if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION):
|
||||||
|
if WorkflowService.evaluate_property(Task.FIELD_PROP_HIDE_EXPRESSION, field, task):
|
||||||
|
continue
|
||||||
|
|
||||||
# If we are only populating required fields, and this isn't required. stop here.
|
# If we are only populating required fields, and this isn't required. stop here.
|
||||||
if required_only:
|
if required_only:
|
||||||
if (not field.has_validation(Task.FIELD_CONSTRAINT_REQUIRED) or
|
if not is_required:
|
||||||
field.get_validation(Task.FIELD_CONSTRAINT_REQUIRED).lower().strip() != "true"):
|
|
||||||
continue # Don't include any fields that aren't specifically marked as required.
|
continue # Don't include any fields that aren't specifically marked as required.
|
||||||
if field.has_property(Task.FIELD_PROP_REQUIRED_EXPRESSION):
|
|
||||||
result = WorkflowService.evaluate_property(Task.FIELD_PROP_REQUIRED_EXPRESSION, field, task)
|
|
||||||
if not result and required_only:
|
|
||||||
continue # Don't complete fields that are not required.
|
|
||||||
|
|
||||||
# If it is read only, stop here.
|
# If it is read only, stop here.
|
||||||
if field.has_property("read_only") and field.get_property(
|
if field.has_property("read_only") and field.get_property(
|
||||||
@ -1083,14 +1102,6 @@ class WorkflowService(object):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
return workflow_model
|
return workflow_model
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_standalone_workflow_specs():
|
|
||||||
return spec_service.standalone.values()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_library_workflow_specs():
|
|
||||||
return spec_service.libraries.values()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_workflow_spec_task_events(spec_id):
|
def delete_workflow_spec_task_events(spec_id):
|
||||||
session.query(TaskEventModel).filter(TaskEventModel.workflow_spec_id == spec_id).delete()
|
session.query(TaskEventModel).filter(TaskEventModel.workflow_spec_id == spec_id).delete()
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
from crc.api.file import get_document_directory
|
|
||||||
|
|
||||||
|
|
||||||
def render_files(study_id,irb_codes):
|
|
||||||
files = get_document_directory(study_id)
|
|
||||||
print(files)
|
|
83
tests/data/required_expressions/required_expressions.bpmn
Normal file
83
tests/data/required_expressions/required_expressions.bpmn
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1v1rp1q" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.10.0">
|
||||||
|
<bpmn:process id="Required" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>SequenceFlow_0lvudp8</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="SequenceFlow_0lvudp8" sourceRef="StartEvent_1" targetRef="Task_Required_Fields" />
|
||||||
|
<bpmn:endEvent id="EndEvent_0q4qzl9">
|
||||||
|
<bpmn:incoming>Flow_0payrur</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="SequenceFlow_02vev7n" sourceRef="Task_Required_Fields" targetRef="Activity_0kbvgue" />
|
||||||
|
<bpmn:userTask id="Task_Required_Fields" name="Required fields" camunda:formKey="RequiredForm">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:formData>
|
||||||
|
<camunda:formField id="required_if_true" label="'String'" type="string" defaultValue="'some string'">
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property id="required_expression" value="boolean_field" />
|
||||||
|
</camunda:properties>
|
||||||
|
</camunda:formField>
|
||||||
|
<camunda:formField id="boolean_field" label="'My Boolean'" type="boolean" defaultValue="True" />
|
||||||
|
<camunda:formField id="required_if_false" label="'some label'" type="string">
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property id="required_expression" value="not boolean_field" />
|
||||||
|
</camunda:properties>
|
||||||
|
</camunda:formField>
|
||||||
|
<camunda:formField id="always_set" type="string" defaultValue=""always"">
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property id="hide_expression" value="True" />
|
||||||
|
</camunda:properties>
|
||||||
|
</camunda:formField>
|
||||||
|
</camunda:formData>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>SequenceFlow_0lvudp8</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>SequenceFlow_02vev7n</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0payrur" sourceRef="Activity_0kbvgue" targetRef="EndEvent_0q4qzl9" />
|
||||||
|
<bpmn:scriptTask id="Activity_0kbvgue" name="Verify Script">
|
||||||
|
<bpmn:incoming>SequenceFlow_02vev7n</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0payrur</bpmn:outgoing>
|
||||||
|
<bpmn:script># By directly referencing the variables
|
||||||
|
# we can assure that whatever happens in
|
||||||
|
# validation, we won't have an error.
|
||||||
|
if boolean_field:
|
||||||
|
result = required_if_true
|
||||||
|
else:
|
||||||
|
result = required_if_false
|
||||||
|
|
||||||
|
# Note that hidden fields with a default
|
||||||
|
# value should always exist.
|
||||||
|
if not always_set == "always":
|
||||||
|
should_never_get_here
|
||||||
|
</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Required">
|
||||||
|
<bpmndi:BPMNEdge id="SequenceFlow_02vev7n_di" bpmnElement="SequenceFlow_02vev7n">
|
||||||
|
<di:waypoint x="370" y="117" />
|
||||||
|
<di:waypoint x="440" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="SequenceFlow_0lvudp8_di" bpmnElement="SequenceFlow_0lvudp8">
|
||||||
|
<di:waypoint x="215" y="117" />
|
||||||
|
<di:waypoint x="270" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0payrur_di" bpmnElement="Flow_0payrur">
|
||||||
|
<di:waypoint x="540" y="117" />
|
||||||
|
<di:waypoint x="592" 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="UserTask_18ly1yq_di" bpmnElement="Task_Required_Fields">
|
||||||
|
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="EndEvent_0q4qzl9_di" bpmnElement="EndEvent_0q4qzl9">
|
||||||
|
<dc:Bounds x="592" y="99" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0ks06ox_di" bpmnElement="Activity_0kbvgue">
|
||||||
|
<dc:Bounds x="440" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
@ -76,7 +76,26 @@ class TestJinjaService(BaseTest):
|
|||||||
self.assertEquals("Word Document creation error : unexpected '%'", ae.exception.message)
|
self.assertEquals("Word Document creation error : unexpected '%'", ae.exception.message)
|
||||||
self.assertEquals(14, ae.exception.line_number)
|
self.assertEquals(14, ae.exception.line_number)
|
||||||
|
|
||||||
|
def test_find_template_references(self):
|
||||||
|
test_string = """
|
||||||
|
{ % include 'template_1' %}
|
||||||
|
|
||||||
|
{ % include
|
||||||
|
'template_2' %}
|
||||||
|
|
||||||
|
{ % include 'template_3' -%}
|
||||||
|
{% include 'template_4'%}
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.assertEqual(['template_1', 'template_2', 'template_3', 'template_4'], JinjaService().template_references(test_string))
|
||||||
|
|
||||||
|
def test_better_error_message_for_wordwrap(self):
|
||||||
|
data = {"my_val": None}
|
||||||
|
my_tempate = "{{my_val | wordwrap(70)}}"
|
||||||
|
with self.assertRaises(ApiError) as e:
|
||||||
|
result = JinjaService().get_content(my_tempate, data)
|
||||||
|
self.assertEqual(e.exception.message, 'Error processing template. You may be using a wordwrap '
|
||||||
|
'with a field that has no value.')
|
||||||
|
|
||||||
def test_jinja_service_properties(self):
|
def test_jinja_service_properties(self):
|
||||||
pass
|
pass
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
from unittest import skip
|
||||||
|
|
||||||
from tests.base_test import BaseTest
|
from tests.base_test import BaseTest
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
class TestWorkflowHiddenRequiredField(BaseTest):
|
class TestWorkflowHiddenRequiredField(BaseTest):
|
||||||
|
|
||||||
|
@skip("Maybe we don't need to require a default for required hidden fields after all.")
|
||||||
def test_require_default(self):
|
def test_require_default(self):
|
||||||
# We have a field that can be hidden and required.
|
# We have a field that can be hidden and required.
|
||||||
# Validation should fail if we don't have a default value.
|
# Validation should fail if we don't have a default value.
|
||||||
|
@ -173,3 +173,17 @@ class TestWorkflowSpecValidation(BaseTest):
|
|||||||
self.create_reference_document()
|
self.create_reference_document()
|
||||||
errors = self.validate_workflow("date_value_expression")
|
errors = self.validate_workflow("date_value_expression")
|
||||||
self.assertEqual(0, len(errors))
|
self.assertEqual(0, len(errors))
|
||||||
|
|
||||||
|
def test_fields_required_based_on_later_fields_correctly_populates(self):
|
||||||
|
"""Say you have a form, where the first field is required only if the
|
||||||
|
SECOND field is checked true. This assures such a case will validate and
|
||||||
|
that the variables that should exist (because they are required) do exist.
|
||||||
|
|
||||||
|
As a bonus test, we also assert that a field with a default value is always present
|
||||||
|
regardless of it's hidden status.
|
||||||
|
"""
|
||||||
|
self.load_test_spec('empty_workflow', master_spec=True)
|
||||||
|
self.create_reference_document()
|
||||||
|
errors = self.validate_workflow("required_expressions")
|
||||||
|
self.assertEqual(0, len(errors))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user