mirror of
https://github.com/sartography/cr-connect-workflow.git
synced 2025-02-22 20:58:28 +00:00
commit
bde43c07b4
51
Pipfile.lock
generated
51
Pipfile.lock
generated
@ -783,31 +783,40 @@
|
||||
"spiffworkflow": {
|
||||
"editable": true,
|
||||
"git": "https://github.com/sartography/SpiffWorkflow.git",
|
||||
"ref": "bb83497f5128f6221113b090d8de84401b0f108f"
|
||||
"ref": "661902387021f7130ae27fa35434eb3b2c138610"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:083e383a1dca8384d0ea6378bd182d83c600ed4ff4ec8247d3b2442cf70db1ad",
|
||||
"sha256:0a690a6486658d03cc6a73536d46e796b6570ac1f8a7ec133f9e28c448b69828",
|
||||
"sha256:114b6ace30001f056e944cebd46daef38fdb41ebb98f5e5940241a03ed6cad43",
|
||||
"sha256:128f6179325f7597a46403dde0bf148478f868df44841348dfc8d158e00db1f9",
|
||||
"sha256:13d48cd8b925b6893a4e59b2dfb3e59a5204fd8c98289aad353af78bd214db49",
|
||||
"sha256:211a1ce7e825f7142121144bac76f53ac28b12172716a710f4bf3eab477e730b",
|
||||
"sha256:2dc57ee80b76813759cccd1a7affedf9c4dbe5b065a91fb6092c9d8151d66078",
|
||||
"sha256:3e625e283eecc15aee5b1ef77203bfb542563fa4a9aa622c7643c7b55438ff49",
|
||||
"sha256:43078c7ec0457387c79b8d52fff90a7ad352ca4c7aa841c366238c3e2cf52fdf",
|
||||
"sha256:5b1bf3c2c2dca738235ce08079783ef04f1a7fc5b21cf24adaae77f2da4e73c3",
|
||||
"sha256:6056b671aeda3fc451382e52ab8a753c0d5f66ef2a5ccc8fa5ba7abd20988b4d",
|
||||
"sha256:68d78cf4a9dfade2e6cf57c4be19f7b82ed66e67dacf93b32bb390c9bed12749",
|
||||
"sha256:7025c639ce7e170db845e94006cf5f404e243e6fc00d6c86fa19e8ad8d411880",
|
||||
"sha256:7224e126c00b8178dfd227bc337ba5e754b197a3867d33b9f30dc0208f773d70",
|
||||
"sha256:7d98e0785c4cd7ae30b4a451416db71f5724a1839025544b4edbd92e00b91f0f",
|
||||
"sha256:8d8c21e9d4efef01351bf28513648ceb988031be4159745a7ad1b3e28c8ff68a",
|
||||
"sha256:bbb545da054e6297242a1bb1ba88e7a8ffb679f518258d66798ec712b82e4e07",
|
||||
"sha256:d00b393f05dbd4ecd65c989b7f5a81110eae4baea7a6a4cdd94c20a908d1456e",
|
||||
"sha256:e18752cecaef61031252ca72031d4d6247b3212ebb84748fc5d1a0d2029c23ea"
|
||||
"sha256:128bc917ed20d78143a45024455ff0aed7d3b96772eba13d5dbaf9cc57e5c41b",
|
||||
"sha256:156a27548ba4e1fed944ff9fcdc150633e61d350d673ae7baaf6c25c04ac1f71",
|
||||
"sha256:27e2efc8f77661c9af2681755974205e7462f1ae126f498f4fe12a8b24761d15",
|
||||
"sha256:2a12f8be25b9ea3d1d5b165202181f2b7da4b3395289000284e5bb86154ce87c",
|
||||
"sha256:31c043d5211aa0e0773821fcc318eb5cbe2ec916dfbc4c6eea0c5188971988eb",
|
||||
"sha256:65eb3b03229f684af0cf0ad3bcc771970c1260a82a791a8d07bffb63d8c95bcc",
|
||||
"sha256:6cd157ce74a911325e164441ff2d9b4e244659a25b3146310518d83202f15f7a",
|
||||
"sha256:703c002277f0fbc3c04d0ae4989a174753a7554b2963c584ce2ec0cddcf2bc53",
|
||||
"sha256:869bbb637de58ab0a912b7f20e9192132f9fbc47fc6b5111cd1e0f6cdf5cf9b0",
|
||||
"sha256:8a0e0cd21da047ea10267c37caf12add400a92f0620c8bc09e4a6531a765d6d7",
|
||||
"sha256:8d01e949a5d22e5c4800d59b50617c56125fc187fbeb8fa423e99858546de616",
|
||||
"sha256:925b4fe5e7c03ed76912b75a9a41dfd682d59c0be43bce88d3b27f7f5ba028fb",
|
||||
"sha256:9cb1819008f0225a7c066cac8bb0cf90847b2c4a6eb9ebb7431dbd00c56c06c5",
|
||||
"sha256:a87d496884f40c94c85a647c385f4fd5887941d2609f71043e2b73f2436d9c65",
|
||||
"sha256:a9030cd30caf848a13a192c5e45367e3c6f363726569a56e75dc1151ee26d859",
|
||||
"sha256:a9e75e49a0f1583eee0ce93270232b8e7bb4b1edc89cc70b07600d525aef4f43",
|
||||
"sha256:b50f45d0e82b4562f59f0e0ca511f65e412f2a97d790eea5f60e34e5f1aabc9a",
|
||||
"sha256:b7878e59ec31f12d54b3797689402ee3b5cfcb5598f2ebf26491732758751908",
|
||||
"sha256:ce1ddaadee913543ff0154021d31b134551f63428065168e756d90bdc4c686f5",
|
||||
"sha256:ce2646e4c0807f3461be0653502bb48c6e91a5171d6e450367082c79e12868bf",
|
||||
"sha256:ce6c3d18b2a8ce364013d47b9cad71db815df31d55918403f8db7d890c9d07ae",
|
||||
"sha256:e4e2664232005bd306f878b0f167a31f944a07c4de0152c444f8c61bbe3cfb38",
|
||||
"sha256:e8aa395482728de8bdcca9cc0faf3765ab483e81e01923aaa736b42f0294f570",
|
||||
"sha256:eb4fcf7105bf071c71068c6eee47499ab8d4b8f5a11fc35147c934f0faa60f23",
|
||||
"sha256:ed375a79f06cad285166e5be74745df1ed6845c5624aafadec4b7a29c25866ef",
|
||||
"sha256:f35248f7e0d63b234a109dd72fbfb4b5cb6cb6840b221d0df0ecbf54ab087654",
|
||||
"sha256:f502ef245c492b391e0e23e94cba030ab91722dcc56963c85bfd7f3441ea2bbe",
|
||||
"sha256:fe01bac7226499aedf472c62fa3b85b2c619365f3f14dd222ffe4f3aa91e5f98"
|
||||
],
|
||||
"version": "==1.3.16"
|
||||
"version": "==1.3.17"
|
||||
},
|
||||
"swagger-ui-bundle": {
|
||||
"hashes": [
|
||||
|
59
crc/api.yml
59
crc/api.yml
@ -939,12 +939,10 @@ components:
|
||||
status:
|
||||
type: enum
|
||||
enum: ['new','user_input_required','waiting','complete']
|
||||
user_tasks:
|
||||
navigation:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Task"
|
||||
last_task:
|
||||
$ref: "#/components/schemas/Task"
|
||||
$ref: "#/components/schemas/NavigationItem"
|
||||
next_task:
|
||||
$ref: "#/components/schemas/Task"
|
||||
workflow_spec_id:
|
||||
@ -990,6 +988,19 @@ components:
|
||||
$ref: "#/components/schemas/Form"
|
||||
documentation:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
multi_instance_type:
|
||||
type: enum
|
||||
enum: ['none', 'looping', 'parallel', 'sequential']
|
||||
multi_instance_count:
|
||||
type: number
|
||||
multi_instance_index:
|
||||
type: number
|
||||
process_name:
|
||||
type: string
|
||||
properties:
|
||||
type: object
|
||||
example:
|
||||
id: study_identification
|
||||
name: Study Identification
|
||||
@ -1160,5 +1171,45 @@ components:
|
||||
example: "Chuck Norris"
|
||||
data:
|
||||
type: any
|
||||
NavigationItem:
|
||||
properties:
|
||||
id:
|
||||
type: number
|
||||
format: integer
|
||||
example: 5
|
||||
task_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "1234123uuid1234"
|
||||
name:
|
||||
type: string
|
||||
example: "Task_Has_bananas"
|
||||
description:
|
||||
type: string
|
||||
example: "Has Bananas?"
|
||||
backtracks:
|
||||
type: boolean
|
||||
example: false
|
||||
level:
|
||||
type: integer
|
||||
example: 1
|
||||
indent:
|
||||
type: integer
|
||||
example: 2
|
||||
child_count:
|
||||
type: integer
|
||||
example: 4
|
||||
state:
|
||||
type: enum
|
||||
enum: ['FUTURE', 'WAITING', 'READY', 'CANCELLED', 'COMPLETED','LIKELY','MAYBE']
|
||||
readOnly: true
|
||||
is_decision:
|
||||
type: boolean
|
||||
example: False
|
||||
readOnly: true
|
||||
task:
|
||||
$ref: "#/components/schemas/Task"
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@ import uuid
|
||||
|
||||
from crc import session
|
||||
from crc.api.common import ApiError, ApiErrorSchema
|
||||
from crc.models.api_models import WorkflowApi, WorkflowApiSchema
|
||||
from crc.models.api_models import WorkflowApi, WorkflowApiSchema, NavigationItem, NavigationItemSchema
|
||||
from crc.models.file import FileModel, LookupDataSchema
|
||||
from crc.models.workflow import WorkflowModel, WorkflowSpecModelSchema, WorkflowSpecModel, WorkflowSpecCategoryModel, \
|
||||
WorkflowSpecCategoryModelSchema
|
||||
@ -83,16 +83,33 @@ def delete_workflow_specification(spec_id):
|
||||
session.commit()
|
||||
|
||||
|
||||
def __get_workflow_api_model(processor: WorkflowProcessor):
|
||||
spiff_tasks = processor.get_all_user_tasks()
|
||||
user_tasks = [WorkflowService.spiff_task_to_api_task(t, add_docs_and_forms=True) for t in spiff_tasks]
|
||||
def __get_workflow_api_model(processor: WorkflowProcessor, next_task = None):
|
||||
"""Returns an API model representing the state of the current workflow, if requested, and
|
||||
possible, next_task is set to the current_task."""
|
||||
|
||||
nav_dict = processor.bpmn_workflow.get_nav_list()
|
||||
navigation = []
|
||||
for nav_item in nav_dict:
|
||||
spiff_task = processor.bpmn_workflow.get_task(nav_item['task_id'])
|
||||
if 'description' in nav_item:
|
||||
nav_item['title'] = nav_item.pop('description')
|
||||
else:
|
||||
nav_item['title'] = ""
|
||||
if spiff_task:
|
||||
nav_item['task'] = WorkflowService.spiff_task_to_api_task(spiff_task, add_docs_and_forms=False)
|
||||
nav_item['title'] = nav_item['task'].title # Prefer the task title.
|
||||
else:
|
||||
nav_item['task'] = None
|
||||
if not 'is_decision' in nav_item:
|
||||
nav_item['is_decision'] = False
|
||||
|
||||
navigation.append(NavigationItem(**nav_item))
|
||||
NavigationItemSchema().dump(nav_item)
|
||||
workflow_api = WorkflowApi(
|
||||
id=processor.get_workflow_id(),
|
||||
status=processor.get_status(),
|
||||
last_task=WorkflowService.spiff_task_to_api_task(processor.bpmn_workflow.last_task),
|
||||
next_task=None,
|
||||
previous_task=processor.previous_task(),
|
||||
user_tasks=user_tasks,
|
||||
navigation=navigation,
|
||||
workflow_spec_id=processor.workflow_spec_id,
|
||||
spec_version=processor.get_spec_version(),
|
||||
is_latest_spec=processor.get_spec_version() == processor.get_latest_version_string(processor.workflow_spec_id),
|
||||
@ -100,7 +117,9 @@ def __get_workflow_api_model(processor: WorkflowProcessor):
|
||||
completed_tasks=processor.workflow_model.completed_tasks,
|
||||
last_updated=processor.workflow_model.last_updated
|
||||
)
|
||||
next_task = processor.next_task()
|
||||
if not next_task: # The Next Task can be requested to be a certain task, useful for parallel tasks.
|
||||
# This may or may not work, sometimes there is no next task to complete.
|
||||
next_task = processor.next_task()
|
||||
if next_task:
|
||||
workflow_api.next_task = WorkflowService.spiff_task_to_api_task(next_task, add_docs_and_forms=True)
|
||||
|
||||
@ -117,19 +136,20 @@ def get_workflow(workflow_id, soft_reset=False, hard_reset=False):
|
||||
def delete_workflow(workflow_id):
|
||||
StudyService.delete_workflow(workflow_id)
|
||||
|
||||
|
||||
def set_current_task(workflow_id, task_id):
|
||||
workflow_model = session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||
processor = WorkflowProcessor(workflow_model)
|
||||
task_id = uuid.UUID(task_id)
|
||||
task = processor.bpmn_workflow.get_task(task_id)
|
||||
if task.state != task.COMPLETED:
|
||||
if task.state != task.COMPLETED and task.state != task.READY:
|
||||
raise ApiError("invalid_state", "You may not move the token to a task who's state is not "
|
||||
"currently set to COMPLETE.")
|
||||
"currently set to COMPLETE or READY.")
|
||||
|
||||
task.reset_token(reset_data=False) # we could optionally clear the previous data.
|
||||
processor.save()
|
||||
WorkflowService.log_task_action(processor, task, WorkflowService.TASK_ACTION_TOKEN_RESET)
|
||||
workflow_api_model = __get_workflow_api_model(processor)
|
||||
workflow_api_model = __get_workflow_api_model(processor, task)
|
||||
return WorkflowApiSchema().dump(workflow_api_model)
|
||||
|
||||
|
||||
|
@ -15,6 +15,20 @@ class MultiInstanceType(enum.Enum):
|
||||
sequential = "sequential"
|
||||
|
||||
|
||||
class NavigationItem(object):
|
||||
def __init__(self, id, task_id, name, title, backtracks, level, indent, child_count, state, is_decision, task=None):
|
||||
self.id = id
|
||||
self.task_id = task_id
|
||||
self.name = name,
|
||||
self.title = title
|
||||
self.backtracks = backtracks
|
||||
self.level = level
|
||||
self.indent = indent
|
||||
self.child_count = child_count
|
||||
self.state = state
|
||||
self.is_decision = is_decision
|
||||
self.task = task
|
||||
|
||||
class Task(object):
|
||||
|
||||
ENUM_OPTIONS_FILE_PROP = "enum.options.file"
|
||||
@ -22,9 +36,8 @@ class Task(object):
|
||||
EMUM_OPTIONS_LABEL_COL_PROP = "enum.options.label.column"
|
||||
EMUM_OPTIONS_AS_LOOKUP = "enum.options.lookup"
|
||||
|
||||
|
||||
def __init__(self, id, name, title, type, state, form, documentation, data,
|
||||
mi_type, mi_count, mi_index, process_name, properties):
|
||||
multi_instance_type, multi_instance_count, multi_instance_index, process_name, properties):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.title = title
|
||||
@ -33,9 +46,9 @@ class Task(object):
|
||||
self.form = form
|
||||
self.documentation = documentation
|
||||
self.data = data
|
||||
self.mi_type = mi_type # Some tasks have a repeat behavior.
|
||||
self.mi_count = mi_count # This is the number of times the task could repeat.
|
||||
self.mi_index = mi_index # And the index of the currently repeating task.
|
||||
self.multi_instance_type = multi_instance_type # Some tasks have a repeat behavior.
|
||||
self.multi_instance_count = multi_instance_count # This is the number of times the task could repeat.
|
||||
self.multi_instance_index = multi_instance_index # And the index of the currently repeating task.
|
||||
self.process_name = process_name
|
||||
self.properties = properties # Arbitrary extension properties from BPMN editor.
|
||||
|
||||
@ -50,10 +63,11 @@ class ValidationSchema(ma.Schema):
|
||||
fields = ["name", "config"]
|
||||
|
||||
|
||||
class PropertiesSchema(ma.Schema):
|
||||
class FormFieldPropertySchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "value"]
|
||||
|
||||
fields = [
|
||||
"id", "value"
|
||||
]
|
||||
|
||||
class FormFieldSchema(ma.Schema):
|
||||
class Meta:
|
||||
@ -64,7 +78,7 @@ class FormFieldSchema(ma.Schema):
|
||||
default_value = marshmallow.fields.String(required=False, allow_none=True)
|
||||
options = marshmallow.fields.List(marshmallow.fields.Nested(OptionSchema))
|
||||
validation = marshmallow.fields.List(marshmallow.fields.Nested(ValidationSchema))
|
||||
properties = marshmallow.fields.List(marshmallow.fields.Nested(PropertiesSchema))
|
||||
properties = marshmallow.fields.List(marshmallow.fields.Nested(FormFieldPropertySchema))
|
||||
|
||||
|
||||
class FormSchema(ma.Schema):
|
||||
@ -74,14 +88,13 @@ class FormSchema(ma.Schema):
|
||||
|
||||
class TaskSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "name", "title", "type", "state", "form", "documentation", "data", "mi_type",
|
||||
"mi_count", "mi_index", "process_name", "properties"]
|
||||
fields = ["id", "name", "title", "type", "state", "form", "documentation", "data", "multi_instance_type",
|
||||
"multi_instance_count", "multi_instance_index", "process_name", "properties"]
|
||||
|
||||
mi_type = EnumField(MultiInstanceType)
|
||||
multi_instance_type = EnumField(MultiInstanceType)
|
||||
documentation = marshmallow.fields.String(required=False, allow_none=True)
|
||||
form = marshmallow.fields.Nested(FormSchema, required=False, allow_none=True)
|
||||
title = marshmallow.fields.String(required=False, allow_none=True)
|
||||
properties = marshmallow.fields.List(marshmallow.fields.Nested(PropertiesSchema))
|
||||
process_name = marshmallow.fields.String(required=False, allow_none=True)
|
||||
|
||||
@marshmallow.post_load
|
||||
@ -89,15 +102,24 @@ class TaskSchema(ma.Schema):
|
||||
return Task(**data)
|
||||
|
||||
|
||||
class NavigationItemSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "task_id", "name", "title", "backtracks", "level", "indent", "child_count", "state",
|
||||
"is_decision", "task"]
|
||||
unknown = INCLUDE
|
||||
task = marshmallow.fields.Nested(TaskSchema, dump_only=True, required=False, allow_none=True)
|
||||
backtracks = marshmallow.fields.String(required=False, allow_none=True)
|
||||
title = marshmallow.fields.String(required=False, allow_none=True)
|
||||
task_id = marshmallow.fields.String(required=False, allow_none=True)
|
||||
|
||||
|
||||
class WorkflowApi(object):
|
||||
def __init__(self, id, status, user_tasks, last_task, next_task, previous_task,
|
||||
def __init__(self, id, status, next_task, navigation,
|
||||
spec_version, is_latest_spec, workflow_spec_id, total_tasks, completed_tasks, last_updated):
|
||||
self.id = id
|
||||
self.status = status
|
||||
self.user_tasks = user_tasks
|
||||
self.last_task = last_task # The last task that was completed, may be different than previous.
|
||||
self.next_task = next_task # The next task that requires user input.
|
||||
self.previous_task = previous_task # The opposite of next task.
|
||||
self.navigation = navigation
|
||||
self.workflow_spec_id = workflow_spec_id
|
||||
self.spec_version = spec_version
|
||||
self.is_latest_spec = is_latest_spec
|
||||
@ -108,21 +130,20 @@ class WorkflowApi(object):
|
||||
class WorkflowApiSchema(ma.Schema):
|
||||
class Meta:
|
||||
model = WorkflowApi
|
||||
fields = ["id", "status", "user_tasks", "last_task", "next_task", "previous_task",
|
||||
fields = ["id", "status", "next_task", "navigation",
|
||||
"workflow_spec_id", "spec_version", "is_latest_spec", "total_tasks", "completed_tasks",
|
||||
"last_updated"]
|
||||
unknown = INCLUDE
|
||||
|
||||
status = EnumField(WorkflowStatus)
|
||||
user_tasks = marshmallow.fields.List(marshmallow.fields.Nested(TaskSchema, dump_only=True))
|
||||
last_task = marshmallow.fields.Nested(TaskSchema, dump_only=True, required=False)
|
||||
next_task = marshmallow.fields.Nested(TaskSchema, dump_only=True, required=False)
|
||||
previous_task = marshmallow.fields.Nested(TaskSchema, dump_only=True, required=False)
|
||||
navigation = marshmallow.fields.List(marshmallow.fields.Nested(NavigationItemSchema, dump_only=True))
|
||||
|
||||
@marshmallow.post_load
|
||||
def make_workflow(self, data, **kwargs):
|
||||
keys = ['id', 'status', 'user_tasks', 'last_task', 'next_task', 'previous_task',
|
||||
keys = ['id', 'status', 'next_task', 'navigation',
|
||||
'workflow_spec_id', 'spec_version', 'is_latest_spec', "total_tasks", "completed_tasks",
|
||||
"last_updated"]
|
||||
filtered_fields = {key: data[key] for key in keys}
|
||||
filtered_fields['next_task'] = TaskSchema().make_task(data['next_task'])
|
||||
return WorkflowApi(**filtered_fields)
|
||||
|
@ -392,6 +392,17 @@ class WorkflowProcessor(object):
|
||||
def get_ready_user_tasks(self):
|
||||
return self.bpmn_workflow.get_ready_user_tasks()
|
||||
|
||||
def get_current_user_tasks(self):
|
||||
"""Return a list of all user tasks that are READY or
|
||||
COMPLETE and are parallel to the READY Task."""
|
||||
ready_tasks = self.bpmn_workflow.get_ready_user_tasks()
|
||||
additional_tasks = []
|
||||
if len(ready_tasks) > 0:
|
||||
for child in ready_tasks[0].parent.children:
|
||||
if child.state == SpiffTask.COMPLETED:
|
||||
additional_tasks.append(child)
|
||||
return ready_tasks + additional_tasks
|
||||
|
||||
def get_all_user_tasks(self):
|
||||
all_tasks = self.bpmn_workflow.get_tasks(SpiffTask.ANY_MASK)
|
||||
return [t for t in all_tasks if not self.bpmn_workflow._is_engine_task(t.task_spec)]
|
||||
@ -425,5 +436,8 @@ class WorkflowProcessor(object):
|
||||
|
||||
return process_elements[0].attrib['id']
|
||||
|
||||
|
||||
def get_nav_item(self, task):
|
||||
for nav_item in self.bpmn_workflow.get_nav_list():
|
||||
if nav_item['task_id'] == task.id:
|
||||
return nav_item
|
||||
|
||||
|
@ -10,7 +10,7 @@ from flask import g
|
||||
from pandas import ExcelFile
|
||||
from sqlalchemy import func
|
||||
|
||||
from crc import db
|
||||
from crc import db, app
|
||||
from crc.api.common import ApiError
|
||||
from crc.models.api_models import Task, MultiInstanceType
|
||||
import jinja2
|
||||
@ -24,7 +24,6 @@ from SpiffWorkflow import Task as SpiffTask, WorkflowException
|
||||
|
||||
|
||||
class WorkflowService(object):
|
||||
|
||||
TASK_ACTION_COMPLETE = "Complete"
|
||||
TASK_ACTION_TOKEN_RESET = "Backwards Move"
|
||||
TASK_ACTION_HARD_RESET = "Restart (Hard)"
|
||||
@ -54,7 +53,8 @@ class WorkflowService(object):
|
||||
tasks = bpmn_workflow.get_tasks(SpiffTask.READY)
|
||||
for task in tasks:
|
||||
task_api = WorkflowService.spiff_task_to_api_task(
|
||||
task, add_docs_and_forms=True) # Assure we try to process the documenation, and raise those errors.
|
||||
task,
|
||||
add_docs_and_forms=True) # Assure we try to process the documenation, and raise those errors.
|
||||
WorkflowProcessor.populate_form_with_random_data(task, task_api)
|
||||
task.complete()
|
||||
except WorkflowException as we:
|
||||
@ -90,10 +90,10 @@ class WorkflowService(object):
|
||||
else:
|
||||
mi_type = MultiInstanceType.none
|
||||
|
||||
props = []
|
||||
props = {}
|
||||
if hasattr(spiff_task.task_spec, 'extensions'):
|
||||
for id, val in spiff_task.task_spec.extensions.items():
|
||||
props.append({"id": id, "value": val})
|
||||
props[id] = val
|
||||
|
||||
task = Task(spiff_task.id,
|
||||
spiff_task.task_spec.name,
|
||||
@ -102,25 +102,52 @@ class WorkflowService(object):
|
||||
spiff_task.get_state_name(),
|
||||
None,
|
||||
"",
|
||||
spiff_task.data,
|
||||
{},
|
||||
mi_type,
|
||||
info["mi_count"],
|
||||
info["mi_index"],
|
||||
process_name=spiff_task.task_spec._wf_spec.description,
|
||||
properties=props)
|
||||
properties=props
|
||||
)
|
||||
|
||||
# Only process the form and documentation if requested.
|
||||
# The task should be in a completed or a ready state, and should
|
||||
# not be a previously completed MI Task.
|
||||
if add_docs_and_forms:
|
||||
task.data = spiff_task.data
|
||||
if hasattr(spiff_task.task_spec, "form"):
|
||||
task.form = spiff_task.task_spec.form
|
||||
for field in task.form.fields:
|
||||
WorkflowService.process_options(spiff_task, field)
|
||||
|
||||
task.documentation = WorkflowService._process_documentation(spiff_task)
|
||||
|
||||
# All ready tasks should have a valid name, and this can be computed for
|
||||
# some tasks, particularly multi-instance tasks that all have the same spec
|
||||
# but need different labels.
|
||||
if spiff_task.state == SpiffTask.READY:
|
||||
task.properties = WorkflowService._process_properties(spiff_task, props)
|
||||
|
||||
# Replace the title with the display name if it is set in the task properties,
|
||||
# otherwise strip off the first word of the task, as that should be following
|
||||
# a BPMN standard, and should not be included in the display.
|
||||
if task.properties and "display_name" in task.properties:
|
||||
task.title = task.properties['display_name']
|
||||
elif task.title and ' ' in task.title:
|
||||
task.title = task.title.partition(' ')[2]
|
||||
|
||||
return task
|
||||
|
||||
@staticmethod
|
||||
def _process_properties(spiff_task, props):
|
||||
"""Runs all the property values through the Jinja2 processor to inject data."""
|
||||
for k, v in props.items():
|
||||
try:
|
||||
template = Template(v)
|
||||
props[k] = template.render(**spiff_task.data)
|
||||
except jinja2.exceptions.TemplateError as ue:
|
||||
app.logger.error("Failed to process task property %s " % str(ue))
|
||||
return props
|
||||
|
||||
@staticmethod
|
||||
def _process_documentation(spiff_task):
|
||||
"""Runs the given documentation string through the Jinja2 processor to inject data
|
||||
@ -144,7 +171,7 @@ class WorkflowService(object):
|
||||
return template.render(**spiff_task.data)
|
||||
except jinja2.exceptions.TemplateError as ue:
|
||||
|
||||
# return "Error processing template. %s" % ue.message
|
||||
# return "Error processing template. %s" % ue.message
|
||||
raise ApiError(code="template_error", message="Error processing template for task %s: %s" %
|
||||
(spiff_task.task_spec.name, str(ue)), status_code=500)
|
||||
# TODO: Catch additional errors and report back.
|
||||
@ -261,14 +288,11 @@ class WorkflowService(object):
|
||||
task_title=task.title,
|
||||
task_type=str(task.type),
|
||||
task_state=task.state,
|
||||
mi_type=task.mi_type.value, # Some tasks have a repeat behavior.
|
||||
mi_count=task.mi_count, # This is the number of times the task could repeat.
|
||||
mi_index=task.mi_index, # And the index of the currently repeating task.
|
||||
mi_type=task.multi_instance_type.value, # Some tasks have a repeat behavior.
|
||||
mi_count=task.multi_instance_count, # This is the number of times the task could repeat.
|
||||
mi_index=task.multi_instance_index, # And the index of the currently repeating task.
|
||||
process_name=task.process_name,
|
||||
date=datetime.now(),
|
||||
)
|
||||
db.session.add(task_event)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?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" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1wv9t3c" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.5.0">
|
||||
<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" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1wv9t3c" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.3">
|
||||
<bpmn:process id="Process_19ej1y2" name="Data Securty Plan" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1co48s3">
|
||||
<bpmn:outgoing>SequenceFlow_100w7co</bpmn:outgoing>
|
||||
@ -372,7 +372,7 @@
|
||||
<bpmn:incoming>SequenceFlow_0nc6lcs</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_0gp2pjm</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0gp2pjm" sourceRef="Task_EnterIndividualUseDevices" targetRef="Task_EnterOutsideUVA" />
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0gp2pjm" sourceRef="Task_EnterIndividualUseDevices" targetRef="Activity_1qbfs1w" />
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0mgwas4" sourceRef="Task_EnterOutsideUVA" targetRef="ExclusiveGateway_0pi0c2d" />
|
||||
<bpmn:sequenceFlow id="SequenceFlow_1i8e52t" sourceRef="ExclusiveGateway_0x3t2vl" targetRef="Task_EnterEmailMethods" />
|
||||
<bpmn:userTask id="Task_EnterOutsideUVA" name="Enter Outside of UVA" camunda:formKey="EnterOutsideUVa">
|
||||
@ -389,7 +389,7 @@ Indicate all the possible formats in which you will transmit your data outside o
|
||||
</camunda:formField>
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>SequenceFlow_0gp2pjm</bpmn:incoming>
|
||||
<bpmn:incoming>Flow_0cpwkms</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_0mgwas4</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:userTask id="Task_EnterEmailMethods" name="Enter Email Methods" camunda:formKey="EnterEmailMethods">
|
||||
@ -623,222 +623,339 @@ Indicate all the possible formats in which you will collect or receive your orig
|
||||
<bpmn:incoming>SequenceFlow_0blyor8</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_1oq4w2h</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:task id="Activity_1qbfs1w" name="Enter Device Details">
|
||||
<bpmn:incoming>SequenceFlow_0gp2pjm</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0cpwkms</bpmn:outgoing>
|
||||
<bpmn:multiInstanceLoopCharacteristics />
|
||||
</bpmn:task>
|
||||
<bpmn:sequenceFlow id="Flow_0cpwkms" sourceRef="Activity_1qbfs1w" targetRef="Task_EnterOutsideUVA" />
|
||||
<bpmn:textAnnotation id="TextAnnotation_190dbhy">
|
||||
<bpmn:text>> Instructions
|
||||
o Hippa Instructions
|
||||
o Hippa Indentifiers
|
||||
o Vuew Definitions and Instructions
|
||||
o Paper Documents
|
||||
o Emailed to UVA Personnel
|
||||
o EMC (EPIC)
|
||||
o UVA Approvled eCRF
|
||||
o UVA Servers
|
||||
o Web or Cloud Server
|
||||
o Individual Use Devices
|
||||
o Device Details
|
||||
0 Outside of UVA
|
||||
|
||||
o Outside of UVA?
|
||||
o Yes
|
||||
o Email Methods
|
||||
o Data Management
|
||||
o Transmission Method
|
||||
o Generate DSP
|
||||
o No
|
||||
o Generate DSP</bpmn:text>
|
||||
</bpmn:textAnnotation>
|
||||
<bpmn:association id="Association_1nrg5es" sourceRef="Task_0q6ir2l" targetRef="TextAnnotation_190dbhy" />
|
||||
<bpmn:textAnnotation id="TextAnnotation_0l6dohi">
|
||||
<bpmn:text>* Instructions
|
||||
* Hippa Instructions
|
||||
* Hippa Indentifiers
|
||||
o Vuew Definitions and Instructions
|
||||
>> Paper Documents
|
||||
> Emailed to UVA Personnel
|
||||
> EMC (EPIC)
|
||||
> UVA Approvled eCRF
|
||||
> UVA Servers
|
||||
> Web or Cloud Server
|
||||
o Individual Use Devices
|
||||
o Device Details
|
||||
o Outside of UVA
|
||||
|
||||
o Outside of UVA?
|
||||
o Yes
|
||||
o Email Methods
|
||||
o Data Management
|
||||
o Transmission Method
|
||||
o Generate DSP
|
||||
o No
|
||||
o Generate DSP</bpmn:text>
|
||||
</bpmn:textAnnotation>
|
||||
<bpmn:association id="Association_0ykpfju" sourceRef="Task_EnterPaperDocuments" targetRef="TextAnnotation_0l6dohi" />
|
||||
<bpmn:textAnnotation id="TextAnnotation_0tpe506">
|
||||
<bpmn:text>* Instructions
|
||||
* Hippa Instructions
|
||||
* Hippa Indentifiers
|
||||
* View Definitions and Instructions
|
||||
|
||||
|
||||
* Paper Documents (Parallel creates spaces)
|
||||
* Emailed to UVA Personnel
|
||||
* EMC (EPIC)
|
||||
* UVA Approvled eCRF
|
||||
* UVA Servers
|
||||
* Web or Cloud Server
|
||||
* Individual Use Devices
|
||||
|
||||
o Device Details (MultiInstance Indents, Parallel creates spaces))
|
||||
> Desktop
|
||||
>> Laptop
|
||||
> Cell Phone
|
||||
> Other
|
||||
|
||||
o Outside of UVA
|
||||
|
||||
o Outside of UVA?
|
||||
o Yes
|
||||
o Email Methods
|
||||
o Data Management
|
||||
o Transmission Method
|
||||
o Generate DSP
|
||||
o No
|
||||
o Generate DSP</bpmn:text>
|
||||
</bpmn:textAnnotation>
|
||||
<bpmn:association id="Association_01x19xx" sourceRef="Activity_1qbfs1w" targetRef="TextAnnotation_0tpe506" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_19ej1y2">
|
||||
<bpmndi:BPMNShape id="TextAnnotation_0l6dohi_di" bpmnElement="TextAnnotation_0l6dohi">
|
||||
<dc:Bounds x="1200" y="80" width="283.5273279352227" height="309.04183535762485" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="TextAnnotation_190dbhy_di" bpmnElement="TextAnnotation_190dbhy">
|
||||
<dc:Bounds x="190" y="150" width="237.9175101214575" height="309.04183535762485" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="TextAnnotation_0tpe506_di" bpmnElement="TextAnnotation_0tpe506">
|
||||
<dc:Bounds x="1240" y="820" width="370" height="442" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_16kyite_di" bpmnElement="SequenceFlow_16kyite">
|
||||
<di:waypoint x="2240" y="390" />
|
||||
<di:waypoint x="2322" y="390" />
|
||||
<di:waypoint x="2240" y="660" />
|
||||
<di:waypoint x="2322" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0t6xl9i_di" bpmnElement="SequenceFlow_0t6xl9i">
|
||||
<di:waypoint x="1620" y="415" />
|
||||
<di:waypoint x="1620" y="640" />
|
||||
<di:waypoint x="2190" y="640" />
|
||||
<di:waypoint x="2190" y="430" />
|
||||
<di:waypoint x="1620" y="685" />
|
||||
<di:waypoint x="1620" y="910" />
|
||||
<di:waypoint x="2190" y="910" />
|
||||
<di:waypoint x="2190" y="700" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0k2r83n_di" bpmnElement="SequenceFlow_0k2r83n">
|
||||
<di:waypoint x="2075" y="390" />
|
||||
<di:waypoint x="2140" y="390" />
|
||||
<di:waypoint x="2075" y="660" />
|
||||
<di:waypoint x="2140" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0blyor8_di" bpmnElement="SequenceFlow_0blyor8">
|
||||
<di:waypoint x="665" y="390" />
|
||||
<di:waypoint x="717" y="390" />
|
||||
<di:waypoint x="665" y="660" />
|
||||
<di:waypoint x="717" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0jyty9m_di" bpmnElement="SequenceFlow_0jyty9m">
|
||||
<di:waypoint x="498" y="390" />
|
||||
<di:waypoint x="565" y="390" />
|
||||
<di:waypoint x="498" y="660" />
|
||||
<di:waypoint x="565" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0m2op9s_di" bpmnElement="SequenceFlow_0m2op9s">
|
||||
<di:waypoint x="351" y="390" />
|
||||
<di:waypoint x="398" y="390" />
|
||||
<di:waypoint x="351" y="660" />
|
||||
<di:waypoint x="398" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1oq4w2h_di" bpmnElement="SequenceFlow_1oq4w2h">
|
||||
<di:waypoint x="817" y="390" />
|
||||
<di:waypoint x="875" y="390" />
|
||||
<di:waypoint x="817" y="660" />
|
||||
<di:waypoint x="875" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_100w7co_di" bpmnElement="SequenceFlow_100w7co">
|
||||
<di:waypoint x="191" y="390" />
|
||||
<di:waypoint x="251" y="390" />
|
||||
<di:waypoint x="191" y="660" />
|
||||
<di:waypoint x="251" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_01hl869_di" bpmnElement="SequenceFlow_01hl869">
|
||||
<di:waypoint x="1645" y="390" />
|
||||
<di:waypoint x="1725" y="390" />
|
||||
<di:waypoint x="1645" y="660" />
|
||||
<di:waypoint x="1725" y="660" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="1676" y="372" width="18" height="14" />
|
||||
<dc:Bounds x="1676" y="642" width="19" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0lere0k_di" bpmnElement="SequenceFlow_0lere0k">
|
||||
<di:waypoint x="1950" y="530" />
|
||||
<di:waypoint x="2050" y="530" />
|
||||
<di:waypoint x="2050" y="415" />
|
||||
<di:waypoint x="1950" y="800" />
|
||||
<di:waypoint x="2050" y="800" />
|
||||
<di:waypoint x="2050" y="685" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0uewki3_di" bpmnElement="SequenceFlow_0uewki3">
|
||||
<di:waypoint x="1950" y="250" />
|
||||
<di:waypoint x="2050" y="250" />
|
||||
<di:waypoint x="2050" y="365" />
|
||||
<di:waypoint x="1950" y="520" />
|
||||
<di:waypoint x="2050" y="520" />
|
||||
<di:waypoint x="2050" y="635" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_08rwbhm_di" bpmnElement="SequenceFlow_08rwbhm">
|
||||
<di:waypoint x="1950" y="390" />
|
||||
<di:waypoint x="2025" y="390" />
|
||||
<di:waypoint x="1950" y="660" />
|
||||
<di:waypoint x="2025" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1mnmo6p_di" bpmnElement="SequenceFlow_1mnmo6p">
|
||||
<di:waypoint x="1750" y="415" />
|
||||
<di:waypoint x="1750" y="530" />
|
||||
<di:waypoint x="1850" y="530" />
|
||||
<di:waypoint x="1750" y="685" />
|
||||
<di:waypoint x="1750" y="800" />
|
||||
<di:waypoint x="1850" y="800" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_12bv2i4_di" bpmnElement="SequenceFlow_12bv2i4">
|
||||
<di:waypoint x="1775" y="390" />
|
||||
<di:waypoint x="1850" y="390" />
|
||||
<di:waypoint x="1775" y="660" />
|
||||
<di:waypoint x="1850" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1i8e52t_di" bpmnElement="SequenceFlow_1i8e52t">
|
||||
<di:waypoint x="1750" y="365" />
|
||||
<di:waypoint x="1750" y="250" />
|
||||
<di:waypoint x="1850" y="250" />
|
||||
<di:waypoint x="1750" y="635" />
|
||||
<di:waypoint x="1750" y="520" />
|
||||
<di:waypoint x="1850" y="520" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0mgwas4_di" bpmnElement="SequenceFlow_0mgwas4">
|
||||
<di:waypoint x="1550" y="390" />
|
||||
<di:waypoint x="1595" y="390" />
|
||||
<di:waypoint x="1570" y="660" />
|
||||
<di:waypoint x="1595" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0gp2pjm_di" bpmnElement="SequenceFlow_0gp2pjm">
|
||||
<di:waypoint x="1380" y="390" />
|
||||
<di:waypoint x="1450" y="390" />
|
||||
<di:waypoint x="1300" y="660" />
|
||||
<di:waypoint x="1330" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0nc6lcs_di" bpmnElement="SequenceFlow_0nc6lcs">
|
||||
<di:waypoint x="1185" y="390" />
|
||||
<di:waypoint x="1280" y="390" />
|
||||
<di:waypoint x="1185" y="660" />
|
||||
<di:waypoint x="1200" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_10fsxk4_di" bpmnElement="SequenceFlow_10fsxk4">
|
||||
<di:waypoint x="1080" y="650" />
|
||||
<di:waypoint x="1160" y="650" />
|
||||
<di:waypoint x="1160" y="415" />
|
||||
<di:waypoint x="1080" y="910" />
|
||||
<di:waypoint x="1160" y="910" />
|
||||
<di:waypoint x="1160" y="685" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1xp62py_di" bpmnElement="SequenceFlow_1xp62py">
|
||||
<di:waypoint x="1080" y="550" />
|
||||
<di:waypoint x="1160" y="550" />
|
||||
<di:waypoint x="1160" y="415" />
|
||||
<di:waypoint x="1080" y="810" />
|
||||
<di:waypoint x="1160" y="810" />
|
||||
<di:waypoint x="1160" y="685" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1agmshr_di" bpmnElement="SequenceFlow_1agmshr">
|
||||
<di:waypoint x="1080" y="440" />
|
||||
<di:waypoint x="1160" y="440" />
|
||||
<di:waypoint x="1160" y="415" />
|
||||
<di:waypoint x="1080" y="710" />
|
||||
<di:waypoint x="1160" y="710" />
|
||||
<di:waypoint x="1160" y="685" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_12cos7w_di" bpmnElement="SequenceFlow_12cos7w">
|
||||
<di:waypoint x="1080" y="220" />
|
||||
<di:waypoint x="1160" y="220" />
|
||||
<di:waypoint x="1160" y="365" />
|
||||
<di:waypoint x="1080" y="490" />
|
||||
<di:waypoint x="1160" y="490" />
|
||||
<di:waypoint x="1160" y="635" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1q6gf6w_di" bpmnElement="SequenceFlow_1q6gf6w">
|
||||
<di:waypoint x="1080" y="120" />
|
||||
<di:waypoint x="1160" y="120" />
|
||||
<di:waypoint x="1160" y="365" />
|
||||
<di:waypoint x="1080" y="390" />
|
||||
<di:waypoint x="1160" y="390" />
|
||||
<di:waypoint x="1160" y="635" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0z10m1d_di" bpmnElement="SequenceFlow_0z10m1d">
|
||||
<di:waypoint x="1080" y="320" />
|
||||
<di:waypoint x="1160" y="320" />
|
||||
<di:waypoint x="1160" y="365" />
|
||||
<di:waypoint x="1080" y="590" />
|
||||
<di:waypoint x="1160" y="590" />
|
||||
<di:waypoint x="1160" y="635" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0obqjjx_di" bpmnElement="SequenceFlow_0obqjjx">
|
||||
<di:waypoint x="900" y="415" />
|
||||
<di:waypoint x="900" y="650" />
|
||||
<di:waypoint x="980" y="650" />
|
||||
<di:waypoint x="900" y="685" />
|
||||
<di:waypoint x="900" y="910" />
|
||||
<di:waypoint x="980" y="910" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0ng3fm8_di" bpmnElement="SequenceFlow_0ng3fm8">
|
||||
<di:waypoint x="900" y="415" />
|
||||
<di:waypoint x="900" y="550" />
|
||||
<di:waypoint x="980" y="550" />
|
||||
<di:waypoint x="900" y="685" />
|
||||
<di:waypoint x="900" y="810" />
|
||||
<di:waypoint x="980" y="810" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0pw57x9_di" bpmnElement="SequenceFlow_0pw57x9">
|
||||
<di:waypoint x="900" y="415" />
|
||||
<di:waypoint x="900" y="440" />
|
||||
<di:waypoint x="980" y="440" />
|
||||
<di:waypoint x="900" y="685" />
|
||||
<di:waypoint x="900" y="710" />
|
||||
<di:waypoint x="980" y="710" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_10g92nf_di" bpmnElement="SequenceFlow_10g92nf">
|
||||
<di:waypoint x="900" y="365" />
|
||||
<di:waypoint x="900" y="320" />
|
||||
<di:waypoint x="980" y="320" />
|
||||
<di:waypoint x="900" y="635" />
|
||||
<di:waypoint x="900" y="590" />
|
||||
<di:waypoint x="980" y="590" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_084dyht_di" bpmnElement="SequenceFlow_084dyht">
|
||||
<di:waypoint x="900" y="365" />
|
||||
<di:waypoint x="900" y="220" />
|
||||
<di:waypoint x="980" y="220" />
|
||||
<di:waypoint x="900" y="635" />
|
||||
<di:waypoint x="900" y="490" />
|
||||
<di:waypoint x="980" y="490" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1i6ac9a_di" bpmnElement="SequenceFlow_1i6ac9a">
|
||||
<di:waypoint x="900" y="365" />
|
||||
<di:waypoint x="900" y="120" />
|
||||
<di:waypoint x="980" y="120" />
|
||||
<di:waypoint x="900" y="635" />
|
||||
<di:waypoint x="900" y="390" />
|
||||
<di:waypoint x="980" y="390" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0cpwkms_di" bpmnElement="Flow_0cpwkms">
|
||||
<di:waypoint x="1430" y="660" />
|
||||
<di:waypoint x="1470" y="660" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="StartEvent_1co48s3_di" bpmnElement="StartEvent_1co48s3">
|
||||
<dc:Bounds x="155" y="372" width="36" height="36" />
|
||||
<dc:Bounds x="155" y="642" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_16imtaa_di" bpmnElement="Task_EnterHIPAAIdentifiers">
|
||||
<dc:Bounds x="565" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="565" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ParallelGateway_03qblyb_di" bpmnElement="ExclusiveGateway_0b16kmf">
|
||||
<dc:Bounds x="875" y="365" width="50" height="50" />
|
||||
<dc:Bounds x="875" y="635" width="50" height="50" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1wsga3m_di" bpmnElement="Task_EnterPaperDocuments">
|
||||
<dc:Bounds x="980" y="80" width="100" height="80" />
|
||||
<dc:Bounds x="980" y="350" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0o1xjub_di" bpmnElement="Task_EnterEmailedUVAPersonnel">
|
||||
<dc:Bounds x="980" y="180" width="100" height="80" />
|
||||
<dc:Bounds x="980" y="450" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1gnbchf_di" bpmnElement="Task_EnterEMR">
|
||||
<dc:Bounds x="980" y="280" width="100" height="80" />
|
||||
<dc:Bounds x="980" y="550" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0a4bj92_di" bpmnElement="Task_EnterUVAApprovedECRF">
|
||||
<dc:Bounds x="980" y="400" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1f2b80a_di" bpmnElement="Task_EnterUVaServersWebsites">
|
||||
<dc:Bounds x="980" y="510" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0n3jbd7_di" bpmnElement="Task_EnterWebCloudServer">
|
||||
<dc:Bounds x="980" y="610" width="100" height="80" />
|
||||
<dc:Bounds x="980" y="670" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ParallelGateway_0zl5t7b_di" bpmnElement="ExclusiveGateway_06kvl84">
|
||||
<dc:Bounds x="1135" y="365" width="50" height="50" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0q8o038_di" bpmnElement="Task_EnterIndividualUseDevices">
|
||||
<dc:Bounds x="1280" y="350" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_10x8kgc_di" bpmnElement="Task_EnterOutsideUVA">
|
||||
<dc:Bounds x="1450" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="1135" y="635" width="50" height="50" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1x8azom_di" bpmnElement="Task_EnterEmailMethods">
|
||||
<dc:Bounds x="1850" y="210" width="100" height="80" />
|
||||
<dc:Bounds x="1850" y="480" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1r640re_di" bpmnElement="Task_EnterDataManagement">
|
||||
<dc:Bounds x="1850" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="1850" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ParallelGateway_0cignbh_di" bpmnElement="ExclusiveGateway_1lpm3pa">
|
||||
<dc:Bounds x="2025" y="365" width="50" height="50" />
|
||||
<dc:Bounds x="2025" y="635" width="50" height="50" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0ns9m8t_di" bpmnElement="Task_EnterTransmissionMethod">
|
||||
<dc:Bounds x="1850" y="490" width="100" height="80" />
|
||||
<dc:Bounds x="1850" y="760" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="EndEvent_151cj59_di" bpmnElement="EndEvent_151cj59">
|
||||
<dc:Bounds x="2322" y="372" width="36" height="36" />
|
||||
<dc:Bounds x="2322" y="642" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ExclusiveGateway_0pi0c2d_di" bpmnElement="ExclusiveGateway_0pi0c2d" isMarkerVisible="true">
|
||||
<dc:Bounds x="1595" y="365" width="50" height="50" />
|
||||
<dc:Bounds x="1595" y="635" width="50" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="1580" y="341" width="80" height="14" />
|
||||
<dc:Bounds x="1580" y="611" width="80" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ParallelGateway_1284xgu_di" bpmnElement="ExclusiveGateway_0x3t2vl">
|
||||
<dc:Bounds x="1725" y="365" width="50" height="50" />
|
||||
<dc:Bounds x="1725" y="635" width="50" height="50" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ScriptTask_1616pnb_di" bpmnElement="Task_1ypw8ge">
|
||||
<dc:Bounds x="2140" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="2140" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1l6rjbr_di" bpmnElement="Task_0q6ir2l">
|
||||
<dc:Bounds x="251" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="251" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_11u7de2_di" bpmnElement="Task_0uotpzg">
|
||||
<dc:Bounds x="398" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="398" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0nfmn0k_di" bpmnElement="Task_196zozc">
|
||||
<dc:Bounds x="717" y="350" width="100" height="80" />
|
||||
<dc:Bounds x="717" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0q8o038_di" bpmnElement="Task_EnterIndividualUseDevices">
|
||||
<dc:Bounds x="1200" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_10x8kgc_di" bpmnElement="Task_EnterOutsideUVA">
|
||||
<dc:Bounds x="1470" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1qbfs1w_di" bpmnElement="Activity_1qbfs1w">
|
||||
<dc:Bounds x="1330" y="620" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1f2b80a_di" bpmnElement="Task_EnterUVaServersWebsites">
|
||||
<dc:Bounds x="980" y="770" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0n3jbd7_di" bpmnElement="Task_EnterWebCloudServer">
|
||||
<dc:Bounds x="980" y="870" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Association_0ykpfju_di" bpmnElement="Association_0ykpfju">
|
||||
<di:waypoint x="1080" y="365" />
|
||||
<di:waypoint x="1200" y="306" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Association_1nrg5es_di" bpmnElement="Association_1nrg5es">
|
||||
<di:waypoint x="302" y="620" />
|
||||
<di:waypoint x="306" y="459" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Association_01x19xx_di" bpmnElement="Association_01x19xx">
|
||||
<di:waypoint x="1385" y="700" />
|
||||
<di:waypoint x="1399" y="820" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
|
@ -1,16 +1,11 @@
|
||||
import datetime
|
||||
import glob
|
||||
import glob
|
||||
import os
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
|
||||
from crc import app, db, session
|
||||
from crc.models.file import FileType, FileModel, FileDataModel, CONTENT_TYPES
|
||||
from crc.models.study import StudyModel
|
||||
from crc.models.user import UserModel
|
||||
from crc.models.file import CONTENT_TYPES
|
||||
from crc.models.workflow import WorkflowSpecModel, WorkflowSpecCategoryModel
|
||||
from crc.services.file_service import FileService
|
||||
from crc.services.workflow_processor import WorkflowProcessor
|
||||
from crc.models.protocol_builder import ProtocolBuilderStatus
|
||||
|
||||
|
||||
class ExampleDataLoader:
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1j7idla" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.4.1">
|
||||
<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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1j7idla" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.3">
|
||||
<bpmn:process id="Process_18biih5" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>SequenceFlow_1pnq3kg</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_1pnq3kg" sourceRef="StartEvent_1" targetRef="Task_Has_Bananas" />
|
||||
<bpmn:userTask id="Task_Has_Bananas" name="Has Bananas?" camunda:formKey="bananas_form">
|
||||
<bpmn:userTask id="Task_Has_Bananas" name="Enter Do You Have Bananas" camunda:formKey="bananas_form">
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="has_bananas" label="Do you have bananas?" type="boolean" />
|
||||
@ -15,7 +15,7 @@
|
||||
<bpmn:outgoing>SequenceFlow_1lmkn99</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_1lmkn99" sourceRef="Task_Has_Bananas" targetRef="ExclusiveGateway_003amsm" />
|
||||
<bpmn:exclusiveGateway id="ExclusiveGateway_003amsm">
|
||||
<bpmn:exclusiveGateway id="ExclusiveGateway_003amsm" name="Has Bananas?">
|
||||
<bpmn:incoming>SequenceFlow_1lmkn99</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_Yes_Bananas</bpmn:outgoing>
|
||||
<bpmn:outgoing>SequenceFlow_No_Bananas</bpmn:outgoing>
|
||||
@ -55,29 +55,13 @@
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_18biih5">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1pnq3kg_di" bpmnElement="SequenceFlow_1pnq3kg">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_08djf6q_di" bpmnElement="SequenceFlow_08djf6q">
|
||||
<di:waypoint x="660" y="230" />
|
||||
<di:waypoint x="752" y="230" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="UserTask_0u8fjmw_di" bpmnElement="Task_Has_Bananas">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1lmkn99_di" bpmnElement="SequenceFlow_1lmkn99">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="425" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="ExclusiveGateway_14wqqsi_di" bpmnElement="ExclusiveGateway_003amsm" isMarkerVisible="true">
|
||||
<dc:Bounds x="425" y="92" width="50" height="50" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0f3vx1l_di" bpmnElement="SequenceFlow_Yes_Bananas">
|
||||
<di:waypoint x="475" y="117" />
|
||||
<di:waypoint x="560" y="117" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="509" y="99" width="18" height="40" />
|
||||
</bpmndi:BPMNLabel>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_02z84p5_di" bpmnElement="SequenceFlow_02z84p5">
|
||||
<di:waypoint x="660" y="117" />
|
||||
<di:waypoint x="752" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_12acevn_di" bpmnElement="SequenceFlow_No_Bananas">
|
||||
<di:waypoint x="450" y="142" />
|
||||
@ -87,6 +71,33 @@
|
||||
<dc:Bounds x="459" y="183" width="13" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0f3vx1l_di" bpmnElement="SequenceFlow_Yes_Bananas">
|
||||
<di:waypoint x="475" y="117" />
|
||||
<di:waypoint x="560" y="117" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="509" y="99" width="18" height="40" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1lmkn99_di" bpmnElement="SequenceFlow_1lmkn99">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="425" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1pnq3kg_di" bpmnElement="SequenceFlow_1pnq3kg">
|
||||
<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="UserTask_0u8fjmw_di" bpmnElement="Task_Has_Bananas">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ExclusiveGateway_14wqqsi_di" bpmnElement="ExclusiveGateway_003amsm" isMarkerVisible="true">
|
||||
<dc:Bounds x="425" y="92" width="50" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="415" y="62" width="73" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0ht939a_di" bpmnElement="Task_Num_Bananas">
|
||||
<dc:Bounds x="560" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
@ -96,17 +107,9 @@
|
||||
<bpmndi:BPMNShape id="EndEvent_063bpg6_di" bpmnElement="EndEvent_063bpg6">
|
||||
<dc:Bounds x="752" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_02z84p5_di" bpmnElement="SequenceFlow_02z84p5">
|
||||
<di:waypoint x="660" y="117" />
|
||||
<di:waypoint x="752" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="EndEvent_1hwtug4_di" bpmnElement="EndEvent_1hwtug4">
|
||||
<dc:Bounds x="752" y="212" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_08djf6q_di" bpmnElement="SequenceFlow_08djf6q">
|
||||
<di:waypoint x="660" y="230" />
|
||||
<di:waypoint x="752" y="230" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_17fwemw" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.4.1">
|
||||
<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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_17fwemw" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.3">
|
||||
<bpmn:process id="MultiInstance" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1" name="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0t6p1sb</bpmn:outgoing>
|
||||
@ -17,6 +17,9 @@
|
||||
<camunda:formData>
|
||||
<camunda:formField id="email" label="Email Address:" type="string" />
|
||||
</camunda:formData>
|
||||
<camunda:properties>
|
||||
<camunda:property name="display_name" value="{{investigator.label}}" />
|
||||
</camunda:properties>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>SequenceFlow_1p568pp</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0ugjw69</bpmn:outgoing>
|
||||
@ -31,33 +34,33 @@
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="MultiInstance">
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1p568pp_di" bpmnElement="SequenceFlow_1p568pp">
|
||||
<di:waypoint x="350" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0ugjw69_di" bpmnElement="Flow_0ugjw69">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="592" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0t6p1sb_di" bpmnElement="Flow_0t6p1sb">
|
||||
<di:waypoint x="178" y="117" />
|
||||
<di:waypoint x="250" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="142" y="99" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="129" y="142" width="64" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_0t6p1sb_di" bpmnElement="Flow_0t6p1sb">
|
||||
<di:waypoint x="178" y="117" />
|
||||
<di:waypoint x="250" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Event_1g0pmib_di" bpmnElement="Event_End">
|
||||
<dc:Bounds x="592" y="99" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="585" y="142" width="54" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_0ugjw69_di" bpmnElement="Flow_0ugjw69">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="592" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Activity_1iyilui_di" bpmnElement="MutiInstanceTask">
|
||||
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1p568pp_di" bpmnElement="SequenceFlow_1p568pp">
|
||||
<di:waypoint x="350" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="ScriptTask_0cbbirp_di" bpmnElement="Task_1v0e2zu">
|
||||
<dc:Bounds x="250" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
|
@ -66,9 +66,14 @@ class TestTasksApi(BaseTest):
|
||||
self.assertEquals(task_in.title, event.task_title)
|
||||
self.assertEquals(task_in.type, event.task_type)
|
||||
self.assertEquals("COMPLETED", event.task_state)
|
||||
self.assertEquals(task_in.mi_type.value, event.mi_type)
|
||||
self.assertEquals(task_in.mi_count, event.mi_count)
|
||||
self.assertEquals(task_in.mi_index, event.mi_index)
|
||||
# Not sure what vodoo is happening inside of marshmallow to get me in this state.
|
||||
if isinstance(task_in.multi_instance_type, MultiInstanceType):
|
||||
self.assertEquals(task_in.multi_instance_type.value, event.mi_type)
|
||||
else:
|
||||
self.assertEquals(task_in.multi_instance_type, event.mi_type)
|
||||
|
||||
self.assertEquals(task_in.multi_instance_count, event.mi_count)
|
||||
self.assertEquals(task_in.multi_instance_index, event.mi_index)
|
||||
self.assertEquals(task_in.process_name, event.process_name)
|
||||
self.assertIsNotNone(event.date)
|
||||
|
||||
@ -82,9 +87,9 @@ class TestTasksApi(BaseTest):
|
||||
workflow = self.create_workflow('random_fact')
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
task = workflow.next_task
|
||||
self.assertEqual("Task_User_Select_Type", task['name'])
|
||||
self.assertEqual(3, len(task['form']["fields"][0]["options"]))
|
||||
self.assertIsNotNone(task['documentation'])
|
||||
self.assertEqual("Task_User_Select_Type", task.name)
|
||||
self.assertEqual(3, len(task.form["fields"][0]["options"]))
|
||||
self.assertIsNotNone(task.documentation)
|
||||
expected_docs = """# h1 Heading 8-)
|
||||
## h2 Heading
|
||||
### h3 Heading
|
||||
@ -92,7 +97,7 @@ class TestTasksApi(BaseTest):
|
||||
##### h5 Heading
|
||||
###### h6 Heading
|
||||
"""
|
||||
self.assertTrue(str.startswith(task['documentation'], expected_docs))
|
||||
self.assertTrue(str.startswith(task.documentation, expected_docs))
|
||||
|
||||
def test_two_forms_task(self):
|
||||
# Set up a new workflow
|
||||
@ -101,67 +106,61 @@ class TestTasksApi(BaseTest):
|
||||
# get the first form in the two form workflow.
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.assertEqual('two_forms', workflow_api.workflow_spec_id)
|
||||
self.assertEqual(2, len(workflow_api.user_tasks))
|
||||
self.assertIsNotNone(workflow_api.next_task['form'])
|
||||
self.assertEqual("UserTask", workflow_api.next_task['type'])
|
||||
self.assertEqual("StepOne", workflow_api.next_task['name'])
|
||||
self.assertEqual(1, len(workflow_api.next_task['form']['fields']))
|
||||
self.assertEqual(2, len(workflow_api.navigation))
|
||||
self.assertIsNotNone(workflow_api.next_task.form)
|
||||
self.assertEqual("UserTask", workflow_api.next_task.type)
|
||||
self.assertEqual("StepOne", workflow_api.next_task.name)
|
||||
self.assertEqual(1, len(workflow_api.next_task.form['fields']))
|
||||
|
||||
# Complete the form for Step one and post it.
|
||||
self.complete_form(workflow, workflow_api.user_tasks[0], {"color": "blue"})
|
||||
self.complete_form(workflow, workflow_api.next_task, {"color": "blue"})
|
||||
|
||||
# Get the next Task
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.assertEqual("StepTwo", workflow_api.next_task['name'])
|
||||
self.assertEqual("StepTwo", workflow_api.next_task.name)
|
||||
|
||||
# Get all user Tasks and check that the data have been saved
|
||||
for task in workflow_api.user_tasks:
|
||||
self.assertIsNotNone(task.data)
|
||||
for val in task.data.values():
|
||||
self.assertIsNotNone(val)
|
||||
task = workflow_api.next_task
|
||||
self.assertIsNotNone(task.data)
|
||||
for val in task.data.values():
|
||||
self.assertIsNotNone(val)
|
||||
|
||||
def test_error_message_on_bad_gateway_expression(self):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('exclusive_gateway')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.complete_form(workflow, tasks[0], {"has_bananas": True})
|
||||
task = self.get_workflow_api(workflow).next_task
|
||||
self.complete_form(workflow, task, {"has_bananas": True})
|
||||
|
||||
def test_workflow_with_parallel_forms(self):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('exclusive_gateway')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.complete_form(workflow, tasks[0], {"has_bananas": True})
|
||||
task = self.get_workflow_api(workflow).next_task
|
||||
self.complete_form(workflow, task, {"has_bananas": True})
|
||||
|
||||
# Get the next Task
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.assertEqual("Task_Num_Bananas", workflow_api.next_task['name'])
|
||||
self.assertEqual("Task_Num_Bananas", workflow_api.next_task.name)
|
||||
|
||||
def test_get_workflow_contains_details_about_last_task_data(self):
|
||||
def test_navigation_with_parallel_forms(self):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('exclusive_gateway')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
workflow_api = self.complete_form(workflow, tasks[0], {"has_bananas": True})
|
||||
|
||||
self.assertIsNotNone(workflow_api.last_task)
|
||||
self.assertEqual({"has_bananas": True}, workflow_api.last_task['data'])
|
||||
|
||||
def test_get_workflow_contains_reference_to_last_task_and_next_task(self):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('exclusive_gateway')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.complete_form(workflow, tasks[0], {"has_bananas": True})
|
||||
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.assertIsNotNone(workflow_api.last_task)
|
||||
self.assertIsNotNone(workflow_api.next_task)
|
||||
|
||||
self.assertIsNotNone(workflow_api.navigation)
|
||||
nav = workflow_api.navigation
|
||||
self.assertEquals(5, len(nav))
|
||||
self.assertEquals("Do You Have Bananas", nav[0]['title'])
|
||||
self.assertEquals("READY", nav[0]['state'])
|
||||
self.assertEquals("Bananas?", nav[1]['title'])
|
||||
self.assertEquals("FUTURE", nav[1]['state'])
|
||||
self.assertEquals("yes", nav[2]['title'])
|
||||
self.assertEquals("NOOP", nav[2]['state'])
|
||||
|
||||
|
||||
def test_document_added_to_workflow_shows_up_in_file_list(self):
|
||||
@ -169,7 +168,7 @@ class TestTasksApi(BaseTest):
|
||||
self.create_reference_document()
|
||||
workflow = self.create_workflow('docx')
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
task = self.get_workflow_api(workflow).next_task
|
||||
data = {
|
||||
"full_name": "Buck of the Wild",
|
||||
"date": "5/1/2020",
|
||||
@ -177,9 +176,9 @@ class TestTasksApi(BaseTest):
|
||||
"company": "In the company of wolves",
|
||||
"last_name": "Mr. Wolf"
|
||||
}
|
||||
workflow_api = self.complete_form(workflow, tasks[0], data)
|
||||
workflow_api = self.complete_form(workflow, task, data)
|
||||
self.assertIsNotNone(workflow_api.next_task)
|
||||
self.assertEqual("EndEvent_0evb22x", workflow_api.next_task['name'])
|
||||
self.assertEqual("EndEvent_0evb22x", workflow_api.next_task.name)
|
||||
self.assertTrue(workflow_api.status == WorkflowStatus.complete)
|
||||
rv = self.app.get('/v1.0/file?workflow_id=%i' % workflow.id, headers=self.logged_in_headers())
|
||||
self.assert_success(rv)
|
||||
@ -197,14 +196,14 @@ class TestTasksApi(BaseTest):
|
||||
workflow = self.create_workflow('random_fact')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
self.assertEqual("Task_User_Select_Type", task['name'])
|
||||
self.assertEqual(3, len(task['form']["fields"][0]["options"]))
|
||||
self.assertIsNotNone(task['documentation'])
|
||||
self.complete_form(workflow, workflow_api.user_tasks[0], {"type": "norris"})
|
||||
self.assertEqual("Task_User_Select_Type", task.name)
|
||||
self.assertEqual(3, len(task.form["fields"][0]["options"]))
|
||||
self.assertIsNotNone(task.documentation)
|
||||
self.complete_form(workflow, workflow_api.next_task, {"type": "norris"})
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.assertEqual("EndEvent_0u1cgrf", workflow_api.next_task['name'])
|
||||
self.assertIsNotNone(workflow_api.next_task['documentation'])
|
||||
self.assertTrue("norris" in workflow_api.next_task['documentation'])
|
||||
self.assertEqual("EndEvent_0u1cgrf", workflow_api.next_task.name)
|
||||
self.assertIsNotNone(workflow_api.next_task.documentation)
|
||||
self.assertTrue("norris" in workflow_api.next_task.documentation)
|
||||
|
||||
def test_load_workflow_from_outdated_spec(self):
|
||||
|
||||
@ -212,7 +211,7 @@ class TestTasksApi(BaseTest):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('two_forms')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.complete_form(workflow, workflow_api.user_tasks[0], {"color": "blue"})
|
||||
self.complete_form(workflow, workflow_api.next_task, {"color": "blue"})
|
||||
self.assertTrue(workflow_api.is_latest_spec)
|
||||
|
||||
# Modify the specification, with a major change that alters the flow and can't be deserialized
|
||||
@ -239,7 +238,7 @@ class TestTasksApi(BaseTest):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('two_forms')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.complete_form(workflow, workflow_api.user_tasks[0], {"color": "blue"})
|
||||
self.complete_form(workflow, workflow_api.next_task, {"color": "blue"})
|
||||
self.assertTrue(workflow_api.is_latest_spec)
|
||||
|
||||
# Modify the specification, with a major change that alters the flow and can't be deserialized
|
||||
@ -265,23 +264,22 @@ class TestTasksApi(BaseTest):
|
||||
workflow = self.create_workflow('manual_task_with_external_documentation')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
workflow_api = self.complete_form(workflow, tasks[0], {"name": "Dan"})
|
||||
task = self.get_workflow_api(workflow).next_task
|
||||
workflow_api = self.complete_form(workflow, task, {"name": "Dan"})
|
||||
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
self.assertEquals('Task_Manual_One', workflow.next_task['name'])
|
||||
self.assertEquals('ManualTask', workflow_api.next_task['type'])
|
||||
self.assertTrue('Markdown' in workflow_api.next_task['documentation'])
|
||||
self.assertTrue('Dan' in workflow_api.next_task['documentation'])
|
||||
self.assertEquals('Task_Manual_One', workflow.next_task.name)
|
||||
self.assertEquals('ManualTask', workflow_api.next_task.type)
|
||||
self.assertTrue('Markdown' in workflow_api.next_task.documentation)
|
||||
self.assertTrue('Dan' in workflow_api.next_task.documentation)
|
||||
|
||||
def test_bpmn_extension_properties_are_populated(self):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('manual_task_with_external_documentation')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.assertEquals("JustAKey", tasks[0].properties[0]['id'])
|
||||
self.assertEquals("JustAValue", tasks[0].properties[0]['value'])
|
||||
task = self.get_workflow_api(workflow).next_task
|
||||
self.assertEquals("JustAValue", task.properties['JustAKey'])
|
||||
|
||||
|
||||
@patch('crc.services.protocol_builder.requests.get')
|
||||
@ -294,11 +292,15 @@ class TestTasksApi(BaseTest):
|
||||
workflow = self.create_workflow('multi_instance')
|
||||
|
||||
# get the first form in the two form workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.assertEquals(1, len(tasks))
|
||||
self.assertEquals("UserTask", tasks[0].type)
|
||||
self.assertEquals(MultiInstanceType.sequential, tasks[0].mi_type)
|
||||
self.assertEquals(9, tasks[0].mi_count)
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
navigation = self.get_workflow_api(workflow).navigation
|
||||
self.assertEquals(4, len(navigation)) # Start task, form_task, multi_task, end task
|
||||
self.assertEquals("UserTask", workflow.next_task.type)
|
||||
self.assertEquals(MultiInstanceType.sequential.value, workflow.next_task.multi_instance_type)
|
||||
self.assertEquals(9, workflow.next_task.multi_instance_count)
|
||||
|
||||
# Assure that the names for each task are properly updated, so they aren't all the same.
|
||||
self.assertEquals("Primary Investigator", workflow.next_task.properties['display_name'])
|
||||
|
||||
|
||||
def test_lookup_endpoint_for_task_field_enumerations(self):
|
||||
@ -307,9 +309,9 @@ class TestTasksApi(BaseTest):
|
||||
# get the first form in the two form workflow.
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
task = workflow.next_task
|
||||
field_id = task['form']['fields'][0]['id']
|
||||
field_id = task.form['fields'][0]['id']
|
||||
rv = self.app.get('/v1.0/workflow/%i/task/%s/lookup/%s?query=%s&limit=5' %
|
||||
(workflow.id, task['id'], field_id, 'c'), # All records with a word that starts with 'c'
|
||||
(workflow.id, task.id, field_id, 'c'), # All records with a word that starts with 'c'
|
||||
headers=self.logged_in_headers(),
|
||||
content_type="application/json")
|
||||
self.assert_success(rv)
|
||||
@ -321,13 +323,16 @@ class TestTasksApi(BaseTest):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('subprocess')
|
||||
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.assertEquals(2, len(tasks))
|
||||
self.assertEquals("UserTask", tasks[0].type)
|
||||
self.assertEquals("Activity_A", tasks[0].name)
|
||||
self.assertEquals("My Sub Process", tasks[0].process_name)
|
||||
workflow_api = self.complete_form(workflow, tasks[0], {"name": "Dan"})
|
||||
task = TaskSchema().load(workflow_api.next_task)
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
navigation = workflow_api.navigation
|
||||
task = workflow_api.next_task
|
||||
|
||||
self.assertEquals(2, len(navigation))
|
||||
self.assertEquals("UserTask", task.type)
|
||||
self.assertEquals("Activity_A", task.name)
|
||||
self.assertEquals("My Sub Process", task.process_name)
|
||||
workflow_api = self.complete_form(workflow, task, {"name": "Dan"})
|
||||
task = workflow_api.next_task
|
||||
self.assertIsNotNone(task)
|
||||
|
||||
self.assertEquals("Activity_B", task.name)
|
||||
@ -340,46 +345,42 @@ class TestTasksApi(BaseTest):
|
||||
workflow = self.create_workflow('exclusive_gateway')
|
||||
|
||||
# Start the workflow.
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.complete_form(workflow, tasks[0], {"has_bananas": True})
|
||||
first_task = self.get_workflow_api(workflow).next_task
|
||||
self.complete_form(workflow, first_task, {"has_bananas": True})
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
self.assertEquals('Task_Num_Bananas', workflow.next_task['name'])
|
||||
self.assertEquals('Task_Num_Bananas', workflow.next_task.name)
|
||||
|
||||
# Trying to re-submit the initial task, and answer differently, should result in an error.
|
||||
self.complete_form(workflow, tasks[0], {"has_bananas": False}, error_code="invalid_state")
|
||||
self.complete_form(workflow, first_task, {"has_bananas": False}, error_code="invalid_state")
|
||||
|
||||
# Go ahead and set the number of bananas.
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
task = TaskSchema().load(workflow.next_task)
|
||||
task = workflow.next_task
|
||||
|
||||
self.complete_form(workflow, task, {"num_bananas": 4})
|
||||
# We are now at the end of the workflow.
|
||||
|
||||
# Make the old task the current task.
|
||||
rv = self.app.put('/v1.0/workflow/%i/task/%s/set_token' % (workflow.id, tasks[0].id),
|
||||
rv = self.app.put('/v1.0/workflow/%i/task/%s/set_token' % (workflow.id, first_task.id),
|
||||
headers=self.logged_in_headers(),
|
||||
content_type="application/json")
|
||||
self.assert_success(rv)
|
||||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
workflow = WorkflowApiSchema().load(json_data)
|
||||
|
||||
# Assure the last task is the task we were on before the reset,
|
||||
# and the Next Task is the one we just reset the token to be on.
|
||||
self.assertEquals("Task_Has_Bananas", workflow.next_task['name'])
|
||||
self.assertEquals("End", workflow.last_task['name'])
|
||||
# Assure the Next Task is the one we just reset the token to be on.
|
||||
self.assertEquals("Task_Has_Bananas", workflow.next_task.name)
|
||||
|
||||
# Go ahead and get that workflow one more time, it should still be right.
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
|
||||
# Assure the last task is the task we were on before the reset,
|
||||
# and the Next Task is the one we just reset the token to be on.
|
||||
self.assertEquals("Task_Has_Bananas", workflow.next_task['name'])
|
||||
self.assertEquals("End", workflow.last_task['name'])
|
||||
# Assure the Next Task is the one we just reset the token to be on.
|
||||
self.assertEquals("Task_Has_Bananas", workflow.next_task.name)
|
||||
|
||||
# The next task should be a different value.
|
||||
self.complete_form(workflow, tasks[0], {"has_bananas": False})
|
||||
self.complete_form(workflow, workflow.next_task, {"has_bananas": False})
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
self.assertEquals('Task_Why_No_Bananas', workflow.next_task['name'])
|
||||
self.assertEquals('Task_Why_No_Bananas', workflow.next_task.name)
|
||||
|
||||
@patch('crc.services.protocol_builder.requests.get')
|
||||
def test_parallel_multi_instance(self, mock_get):
|
||||
@ -392,27 +393,20 @@ class TestTasksApi(BaseTest):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('multi_instance_parallel')
|
||||
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
self.assertEquals(9, len(tasks))
|
||||
self.assertEquals("UserTask", tasks[0].type)
|
||||
self.assertEquals("MutiInstanceTask", tasks[0].name)
|
||||
self.assertEquals("Gather more information", tasks[0].title)
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
self.assertEquals(12, len(workflow_api.navigation))
|
||||
ready_items = [nav for nav in workflow_api.navigation if nav['state'] == "READY"]
|
||||
self.assertEquals(9, len(ready_items))
|
||||
|
||||
self.assertEquals("UserTask", workflow_api.next_task.type)
|
||||
self.assertEquals("MutiInstanceTask",workflow_api.next_task.name)
|
||||
self.assertEquals("more information", workflow_api.next_task.title)
|
||||
|
||||
for i in random.sample(range(9), 9):
|
||||
self.complete_form(workflow, tasks[i], {"investigator":{"email": "dhf8r@virginia.edu"}})
|
||||
tasks = self.get_workflow_api(workflow).user_tasks
|
||||
task = TaskSchema().load(ready_items[i]['task'])
|
||||
self.complete_form(workflow, task, {"investigator":{"email": "dhf8r@virginia.edu"}})
|
||||
#tasks = self.get_workflow_api(workflow).user_tasks
|
||||
|
||||
workflow = self.get_workflow_api(workflow)
|
||||
self.assertEquals(WorkflowStatus.complete, workflow.status)
|
||||
|
||||
# def test_parent_task_set_on_tasks(self):
|
||||
# self.load_example_data()
|
||||
# workflow = self.create_workflow('exclusive_gateway')
|
||||
#
|
||||
# # Start the workflow.
|
||||
# workflow = self.get_workflow_api(workflow)
|
||||
# self.assertEquals(None, workflow.previous_task)
|
||||
# self.complete_form(workflow, workflow.next_task, {"has_bananas": True})
|
||||
# workflow = self.get_workflow_api(workflow)
|
||||
# self.assertEquals('Task_Num_Bananas', workflow.next_task['name'])
|
||||
# self.assertEquals('has_bananas', workflow.previous_task['name'])
|
||||
|
@ -61,9 +61,9 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||
|
||||
self.assertEqual("MutiInstanceTask", task.get_name())
|
||||
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||
self.assertEquals(MultiInstanceType.sequential, api_task.mi_type)
|
||||
self.assertEquals(3, api_task.mi_count)
|
||||
self.assertEquals(1, api_task.mi_index)
|
||||
self.assertEquals(MultiInstanceType.sequential, api_task.multi_instance_type)
|
||||
self.assertEquals(3, api_task.multi_instance_count)
|
||||
self.assertEquals(1, api_task.multi_instance_index)
|
||||
task.update_data({"investigator":{"email":"asd3v@virginia.edu"}})
|
||||
processor.complete_task(task)
|
||||
processor.do_engine_steps()
|
||||
@ -72,8 +72,8 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||
self.assertEqual("MutiInstanceTask", api_task.name)
|
||||
task.update_data({"investigator":{"email":"asdf32@virginia.edu"}})
|
||||
self.assertEquals(3, api_task.mi_count)
|
||||
self.assertEquals(2, api_task.mi_index)
|
||||
self.assertEquals(3, api_task.multi_instance_count)
|
||||
self.assertEquals(2, api_task.multi_instance_index)
|
||||
processor.complete_task(task)
|
||||
processor.do_engine_steps()
|
||||
|
||||
@ -81,8 +81,8 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||
self.assertEqual("MutiInstanceTask", task.get_name())
|
||||
task.update_data({"investigator":{"email":"dhf8r@virginia.edu"}})
|
||||
self.assertEquals(3, api_task.mi_count)
|
||||
self.assertEquals(3, api_task.mi_index)
|
||||
self.assertEquals(3, api_task.multi_instance_count)
|
||||
self.assertEquals(3, api_task.multi_instance_index)
|
||||
processor.complete_task(task)
|
||||
processor.do_engine_steps()
|
||||
task = processor.bpmn_workflow.last_task
|
||||
@ -120,7 +120,7 @@ class TestWorkflowProcessorMultiInstance(BaseTest):
|
||||
self.assertEquals("asd3v", task.data["investigator"]["user_id"]) # The last of the tasks
|
||||
|
||||
api_task = WorkflowService.spiff_task_to_api_task(task)
|
||||
self.assertEquals(MultiInstanceType.parallel, api_task.mi_type)
|
||||
self.assertEquals(MultiInstanceType.parallel, api_task.multi_instance_type)
|
||||
task.update_data({"investigator":{"email":"dhf8r@virginia.edu"}})
|
||||
processor.complete_task(task)
|
||||
processor.do_engine_steps()
|
||||
|
Loading…
x
Reference in New Issue
Block a user