Merge branch 'dev' of github.com:sartography/cr-connect-workflow into dev
This commit is contained in:
commit
f7337f4e54
|
@ -1,7 +1,7 @@
|
||||||
sonar.organization=sartography
|
sonar.organization=sartography
|
||||||
sonar.projectKey=sartography_cr-connect-workflow
|
sonar.projectKey=sartography_cr-connect-workflow
|
||||||
sonar.host.url=https://sonarcloud.io
|
sonar.host.url=https://sonarcloud.io
|
||||||
sonar.exclusions=docs/**,config/**,instance/**,migrations/**,postgres/**,readme_images/**,schema/**,templates/**
|
sonar.exclusions=crc/templates/*.html,docs/**,config/**,instance/**,migrations/**,postgres/**,readme_images/**,schema/**,templates/**
|
||||||
sonar.sources=crc
|
sonar.sources=crc
|
||||||
sonar.test.inclusions=tests
|
sonar.test.inclusions=tests
|
||||||
sonar.python.coverage.reportPaths=coverage.xml
|
sonar.python.coverage.reportPaths=coverage.xml
|
||||||
|
|
|
@ -15,7 +15,8 @@ JSON_SORT_KEYS = False # CRITICAL. Do not sort the data when returning values
|
||||||
API_TOKEN = environ.get('API_TOKEN', default = 'af95596f327c9ecc007b60414fc84b61')
|
API_TOKEN = environ.get('API_TOKEN', default = 'af95596f327c9ecc007b60414fc84b61')
|
||||||
|
|
||||||
NAME = "CR Connect Workflow"
|
NAME = "CR Connect Workflow"
|
||||||
FLASK_PORT = environ.get('PORT0') or environ.get('FLASK_PORT', default="5000")
|
DEFAULT_PORT = "5000"
|
||||||
|
FLASK_PORT = environ.get('PORT0') or environ.get('FLASK_PORT', default=DEFAULT_PORT)
|
||||||
CORS_ALLOW_ORIGINS = re.split(r',\s*', environ.get('CORS_ALLOW_ORIGINS', default="localhost:4200, localhost:5002"))
|
CORS_ALLOW_ORIGINS = re.split(r',\s*', environ.get('CORS_ALLOW_ORIGINS', default="localhost:4200, localhost:5002"))
|
||||||
TESTING = environ.get('TESTING', default="false") == "true"
|
TESTING = environ.get('TESTING', default="false") == "true"
|
||||||
PRODUCTION = (environ.get('PRODUCTION', default="false") == "true")
|
PRODUCTION = (environ.get('PRODUCTION', default="false") == "true")
|
||||||
|
|
|
@ -31,3 +31,5 @@ print('TESTING = ', TESTING)
|
||||||
#Use the mock ldap.
|
#Use the mock ldap.
|
||||||
LDAP_URL = 'mock'
|
LDAP_URL = 'mock'
|
||||||
|
|
||||||
|
from config.default import DEFAULT_PORT
|
||||||
|
SERVER_NAME = f'localhost:{DEFAULT_PORT}'
|
||||||
|
|
|
@ -9,6 +9,7 @@ from crc.models.protocol_builder import ProtocolBuilderStatus
|
||||||
from crc.models.study import Study, StudyEvent, StudyEventType, StudyModel, StudySchema, StudyForUpdateSchema, StudyStatus
|
from crc.models.study import Study, StudyEvent, StudyEventType, StudyModel, StudySchema, StudyForUpdateSchema, StudyStatus
|
||||||
from crc.services.study_service import StudyService
|
from crc.services.study_service import StudyService
|
||||||
from crc.services.user_service import UserService
|
from crc.services.user_service import UserService
|
||||||
|
from crc.services.workflow_service import WorkflowService
|
||||||
|
|
||||||
|
|
||||||
def add_study(body):
|
def add_study(body):
|
||||||
|
@ -63,6 +64,10 @@ def update_study(study_id, body):
|
||||||
|
|
||||||
session.add(study_model)
|
session.add(study_model)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
if status == StudyStatus.abandoned or status == StudyStatus.hold:
|
||||||
|
WorkflowService.process_workflows_for_cancels(study_id)
|
||||||
|
|
||||||
# Need to reload the full study to return it to the frontend
|
# Need to reload the full study to return it to the frontend
|
||||||
study = StudyService.get_study(study_id)
|
study = StudyService.get_study(study_id)
|
||||||
return StudySchema().dump(study)
|
return StudySchema().dump(study)
|
||||||
|
|
|
@ -24,6 +24,8 @@ def all_specifications():
|
||||||
|
|
||||||
|
|
||||||
def add_workflow_specification(body):
|
def add_workflow_specification(body):
|
||||||
|
count = session.query(WorkflowSpecModel).filter_by(category_id=body['category_id']).count()
|
||||||
|
body['display_order'] = count
|
||||||
new_spec: WorkflowSpecModel = WorkflowSpecModelSchema().load(body, session=session)
|
new_spec: WorkflowSpecModel = WorkflowSpecModelSchema().load(body, session=session)
|
||||||
session.add(new_spec)
|
session.add(new_spec)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
@ -115,7 +117,7 @@ def restart_workflow(workflow_id, clear_data=False):
|
||||||
"""Restart a workflow with the latest spec.
|
"""Restart a workflow with the latest spec.
|
||||||
Clear data allows user to restart the workflow without previous data."""
|
Clear data allows user to restart the workflow without previous data."""
|
||||||
workflow_model: WorkflowModel = session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
workflow_model: WorkflowModel = session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||||
WorkflowProcessor.reset(workflow_model, clear_data=clear_data)
|
WorkflowProcessor(workflow_model).reset(workflow_model, clear_data=clear_data)
|
||||||
return get_workflow(workflow_model.id)
|
return get_workflow(workflow_model.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ from crc import app
|
||||||
from crc.api.common import ApiError
|
from crc.api.common import ApiError
|
||||||
from crc.scripts.script import Script
|
from crc.scripts.script import Script
|
||||||
from crc.services.ldap_service import LdapService
|
from crc.services.ldap_service import LdapService
|
||||||
from crc.services.mails import send_mail
|
from crc.services.email_service import EmailService
|
||||||
|
|
||||||
|
from flask import render_template, request
|
||||||
|
|
||||||
|
|
||||||
class Email(Script):
|
class Email(Script):
|
||||||
|
@ -25,25 +27,27 @@ email ("My Subject", "dhf8r@virginia.edu", pi.email)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def do_task_validate_only(self, task, *args, **kwargs):
|
def do_task_validate_only(self, task, *args, **kwargs):
|
||||||
self.get_subject(task, args)
|
self.get_subject(args)
|
||||||
self.get_email_recipients(task, args)
|
self.get_email_recipients(task, args)
|
||||||
self.get_content(task)
|
self.get_content(task)
|
||||||
|
|
||||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
|
|
||||||
if len(args) < 1:
|
if len(args) < 2:
|
||||||
raise ApiError(code="missing_argument",
|
raise ApiError(code="missing_argument",
|
||||||
message="Email script requires a subject and at least one email address as arguments")
|
message="Email script requires a subject and at least one email address as arguments")
|
||||||
subject = args[0]
|
subject = self.get_subject(args)
|
||||||
recipients = self.get_email_recipients(task, args)
|
recipients = self.get_email_recipients(task, args)
|
||||||
content, content_html = self.get_content(task)
|
|
||||||
if recipients:
|
if recipients:
|
||||||
send_mail(
|
content, content_html = self.get_content(task)
|
||||||
|
EmailService.add_email(
|
||||||
subject=subject,
|
subject=subject,
|
||||||
sender=app.config['DEFAULT_SENDER'],
|
sender=app.config['DEFAULT_SENDER'],
|
||||||
recipients=recipients,
|
recipients=recipients,
|
||||||
content=content,
|
content=content,
|
||||||
content_html=content_html
|
content_html=content_html,
|
||||||
|
study_id=study_id
|
||||||
)
|
)
|
||||||
|
|
||||||
def check_valid_email(self, email):
|
def check_valid_email(self, email):
|
||||||
|
@ -82,7 +86,8 @@ email ("My Subject", "dhf8r@virginia.edu", pi.email)
|
||||||
|
|
||||||
return emails
|
return emails
|
||||||
|
|
||||||
def get_subject(self, task, args):
|
@staticmethod
|
||||||
|
def get_subject(args):
|
||||||
# subject = ''
|
# subject = ''
|
||||||
if len(args[0]) < 1:
|
if len(args[0]) < 1:
|
||||||
raise ApiError(code="missing_argument",
|
raise ApiError(code="missing_argument",
|
||||||
|
@ -101,4 +106,10 @@ email ("My Subject", "dhf8r@virginia.edu", pi.email)
|
||||||
template = Template(content)
|
template = Template(content)
|
||||||
rendered = template.render(task.data)
|
rendered = template.render(task.data)
|
||||||
rendered_markdown = markdown.markdown(rendered).replace('\n', '<br>')
|
rendered_markdown = markdown.markdown(rendered).replace('\n', '<br>')
|
||||||
return rendered, rendered_markdown
|
wrapped = self.get_cr_connect_wrapper(rendered_markdown)
|
||||||
|
|
||||||
|
return rendered, wrapped
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_cr_connect_wrapper(email_body):
|
||||||
|
return render_template('mail_content_template.html', email_body=email_body, base_url=request.base_url)
|
||||||
|
|
|
@ -196,10 +196,10 @@ class WorkflowProcessor(object):
|
||||||
else:
|
else:
|
||||||
self.is_latest_spec = False
|
self.is_latest_spec = False
|
||||||
|
|
||||||
@classmethod
|
def reset(self, workflow_model, clear_data=False):
|
||||||
def reset(cls, workflow_model, clear_data=False):
|
|
||||||
print('WorkflowProcessor: reset: ')
|
print('WorkflowProcessor: reset: ')
|
||||||
|
|
||||||
|
self.cancel_notify()
|
||||||
workflow_model.bpmn_workflow_json = None
|
workflow_model.bpmn_workflow_json = None
|
||||||
if clear_data:
|
if clear_data:
|
||||||
# Clear form_data from task_events
|
# Clear form_data from task_events
|
||||||
|
@ -209,7 +209,7 @@ class WorkflowProcessor(object):
|
||||||
task_event.form_data = {}
|
task_event.form_data = {}
|
||||||
session.add(task_event)
|
session.add(task_event)
|
||||||
session.commit()
|
session.commit()
|
||||||
return cls(workflow_model)
|
return self.__init__(workflow_model)
|
||||||
|
|
||||||
def __get_bpmn_workflow(self, workflow_model: WorkflowModel, spec: WorkflowSpec, validate_only=False):
|
def __get_bpmn_workflow(self, workflow_model: WorkflowModel, spec: WorkflowSpec, validate_only=False):
|
||||||
if workflow_model.bpmn_workflow_json:
|
if workflow_model.bpmn_workflow_json:
|
||||||
|
|
|
@ -251,7 +251,9 @@ class WorkflowService(object):
|
||||||
default = result
|
default = result
|
||||||
|
|
||||||
# If no default exists, return None
|
# If no default exists, return None
|
||||||
if not default: return None
|
# Note: if default is False, we don't want to execute this code
|
||||||
|
if default is None:
|
||||||
|
return None
|
||||||
|
|
||||||
if field.type == "enum" and not has_lookup:
|
if field.type == "enum" and not has_lookup:
|
||||||
default_option = next((obj for obj in field.options if obj.id == default), None)
|
default_option = next((obj for obj in field.options if obj.id == default), None)
|
||||||
|
@ -278,7 +280,10 @@ class WorkflowService(object):
|
||||||
elif field.type == "long":
|
elif field.type == "long":
|
||||||
return int(default)
|
return int(default)
|
||||||
elif field.type == 'boolean':
|
elif field.type == 'boolean':
|
||||||
return bool(default)
|
default = str(default).lower()
|
||||||
|
if default == 'true' or default == 't':
|
||||||
|
return True
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
@ -704,5 +709,10 @@ class WorkflowService(object):
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process_workflows_for_cancels(study_id):
|
||||||
|
workflows = db.session.query(WorkflowModel).filter_by(study_id=study_id).all()
|
||||||
|
for workflow in workflows:
|
||||||
|
if workflow.status == WorkflowStatus.user_input_required or workflow.status == WorkflowStatus.waiting:
|
||||||
|
processor = WorkflowProcessor(workflow)
|
||||||
|
processor.reset(workflow)
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="43.79221"
|
||||||
|
width="43.330002"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 43.330002 43.79221"
|
||||||
|
data-name="Layer 1"
|
||||||
|
id="Layer_1"
|
||||||
|
sodipodi:docname="uva_rotunda.svg"
|
||||||
|
inkscape:version="0.92.4 (f8dce91, 2019-08-02)">
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="705"
|
||||||
|
inkscape:window-height="480"
|
||||||
|
id="namedview21"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="8"
|
||||||
|
fit-margin-left="8"
|
||||||
|
fit-margin-right="8"
|
||||||
|
fit-margin-bottom="8"
|
||||||
|
inkscape:zoom="7.9215345"
|
||||||
|
inkscape:cx="21.665"
|
||||||
|
inkscape:cy="21.896104"
|
||||||
|
inkscape:window-x="912"
|
||||||
|
inkscape:window-y="253"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Layer_1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata107">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>Artboard 1</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<style
|
||||||
|
id="style2">.cls-1,.cls-2{fill:#e57200;}.cls-2,.cls-3{fill-rule:evenodd;}.cls-3,.cls-4{fill:#232d4b;}</style>
|
||||||
|
</defs>
|
||||||
|
<title
|
||||||
|
id="title6">Artboard 1</title>
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon8"
|
||||||
|
points="22.87,30.46 22.87,19.25 25.23,19.25 25.23,30.46 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon10"
|
||||||
|
points="10.16,30.46 10.16,19.25 12.44,19.25 12.44,30.46 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon12"
|
||||||
|
points="13.23,30.46 13.23,19.25 15.66,19.25 15.66,30.46 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon14"
|
||||||
|
points="16.44,30.46 16.44,19.25 18.87,19.25 18.87,30.46 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon16"
|
||||||
|
points="22.09,19.25 22.09,30.46 19.66,30.46 19.66,19.25 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon18"
|
||||||
|
points="11.13,18.46 17.84,14.33 24.22,18.46 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon20"
|
||||||
|
points="9.62,18.46 4.01,18.46 4.01,14.29 16.41,14.29 "
|
||||||
|
class="cls-1" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="polygon22"
|
||||||
|
points="19.23,14.29 31.31,14.29 31.31,18.46 25.67,18.46 "
|
||||||
|
class="cls-1" />
|
||||||
|
<path
|
||||||
|
style="fill:#e57200"
|
||||||
|
id="path24"
|
||||||
|
d="M 33.58,15.052206 H 9.74 a 13.6,13.6 0 0 1 23.84,0 z"
|
||||||
|
class="cls-1"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#e57200;fill-rule:evenodd"
|
||||||
|
id="path26"
|
||||||
|
d="m 8,22.752206 v -0.65 l 0.16,0.11 -0.11,0.35 v 0.19 z m 4.64,9.27 H 11.6 l 0.53,-0.38 0.52,0.38 z m 0.73,0 h -0.71 l -0.2,-0.62 0.54,-0.39 h -0.67 l -0.2,-0.63 -0.21,0.63 h -0.66 l 0.54,0.39 -0.21,0.62 H 8 v -9.19 l 0.5,-0.37 0.53,0.39 -0.2,-0.63 0.53,-0.38 H 8.71 l -0.2,-0.63 -0.09,0.28 -0.13,0.35 H 8 v -1 h 5.38 v 11.18 z m -5.37,-6.76 0.53,0.39 -0.2,0.63 0.53,-0.39 0.53,0.39 -0.2,-0.63 0.53,-0.39 H 9.07 l -0.2,-0.62 -0.2,0.62 z m 1.84,3.57 -0.21,0.63 0.53,-0.39 0.54,0.39 -0.21,-0.63 0.51,-0.39 h -0.62 l -0.21,-0.63 -0.2,0.63 H 9.31 l 0.54,0.39 z"
|
||||||
|
class="cls-2"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200;fill-rule:evenodd"
|
||||||
|
id="polygon28"
|
||||||
|
points="9.38,31.25 9.38,34.23 4.01,34.23 4.01,31.25 "
|
||||||
|
class="cls-2" />
|
||||||
|
<polygon
|
||||||
|
transform="translate(4,1.562208)"
|
||||||
|
style="fill:#e57200;fill-rule:evenodd"
|
||||||
|
id="polygon30"
|
||||||
|
points="26.01,31.25 31.31,31.25 31.31,34.23 26.01,34.23 "
|
||||||
|
class="cls-2" />
|
||||||
|
<path
|
||||||
|
style="fill:#e57200;fill-rule:evenodd"
|
||||||
|
id="path32"
|
||||||
|
d="m 22,35.792206 h -0.6 l 0.3,-0.22 z m -4.06,-0.87 -0.21,0.62 0.54,-0.38 0.53,0.38 -0.2,-0.62 0.53,-0.39 h -0.66 l -0.2,-0.63 -0.27,0.66 h -0.66 l 0.54,0.39 z m 3.43,0.41 -0.15,0.46 h -7 v -3 H 15 l -0.15,0.46 h -0.66 l 0.54,0.39 -0.21,0.63 0.54,-0.39 0.53,0.39 -0.2,-0.63 0.53,-0.39 h -0.66 l -0.15,-0.46 h 13.11 l -0.16,0.46 H 27.4 l 0.54,0.39 -0.21,0.63 0.54,-0.39 0.53,0.39 -0.2,-0.63 0.53,-0.39 h -0.66 l -0.15,-0.46 h 0.91 v 3 h -7.07 l -0.16,-0.46 0.54,-0.38 h -0.66 l -0.21,-0.63 -0.2,0.63 h -0.66 l 0.53,0.38 z m 4,-0.41 0.54,-0.39 h -0.66 l -0.25,-0.63 -0.2,0.63 h -0.66 l 0.53,0.39 -0.2,0.62 0.53,-0.38 0.54,0.38 -0.21,-0.62 z"
|
||||||
|
class="cls-2"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#e57200;fill-rule:evenodd"
|
||||||
|
id="path34"
|
||||||
|
d="m 35.31,22.132206 v 0.51 l -0.14,-0.42 z m 0,9.89 H 30 v -11.21 h 5.3 v 1 h -0.26 l -0.21,-0.63 -0.2,0.63 H 34 l 0.53,0.38 -0.2,0.63 0.53,-0.39 0.47,0.34 v 2.49 h -0.62 l -0.21,-0.62 -0.2,0.62 h -0.66 l 0.53,0.39 -0.2,0.63 0.53,-0.39 0.54,0.39 -0.21,-0.63 0.5,-0.36 v 6.73 z m -3.55,0 -0.2,-0.62 0.53,-0.39 h -0.66 l -0.2,-0.63 -0.21,0.63 h -0.66 l 0.54,0.39 -0.2,0.62 0.53,-0.38 z m 1.75,-3.19 0.53,-0.39 h -0.66 l -0.2,-0.63 -0.2,0.63 h -0.66 l 0.53,0.39 -0.2,0.63 0.53,-0.39 0.53,0.39 z"
|
||||||
|
class="cls-2"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "mail_main_template.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
{{ email_body | safe }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block footer %}
|
||||||
|
{{ super() }}
|
||||||
|
<span>Ramp-Up Toolkit Configurator - University of Virginia</span>
|
||||||
|
{% endblock %}}
|
|
@ -0,0 +1,421 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- This is all stolen from https://github.com/leemunroe/responsive-html-email-template -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>CR-Connect Email</title>
|
||||||
|
<style>
|
||||||
|
/* -------------------------------------
|
||||||
|
GLOBAL RESETS
|
||||||
|
------------------------------------- */
|
||||||
|
|
||||||
|
/*All the styling goes here*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
font-family: sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
mso-table-lspace: 0pt;
|
||||||
|
mso-table-rspace: 0pt;
|
||||||
|
width: 100%; }
|
||||||
|
table td {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
BODY & CONTAINER
|
||||||
|
------------------------------------- */
|
||||||
|
|
||||||
|
.body {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
|
||||||
|
.container {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto !important;
|
||||||
|
/* makes it centered */
|
||||||
|
max-width: 580px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 580px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This should also be a block element, so that it will fill 100% of the .container */
|
||||||
|
.content {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 580px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
HEADER, FOOTER, MAIN
|
||||||
|
------------------------------------- */
|
||||||
|
.main {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-block {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer, .header {
|
||||||
|
clear: both;
|
||||||
|
margin-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #232D48;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.footer td,
|
||||||
|
.footer p,
|
||||||
|
.footer span,
|
||||||
|
.footer a {
|
||||||
|
color: #999999;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.header td.content-block {
|
||||||
|
display: inline-table;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.header td.content-block span {
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
TYPOGRAPHY
|
||||||
|
------------------------------------- */
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4 {
|
||||||
|
color: #000000;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 35px;
|
||||||
|
font-weight: 300;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
p li,
|
||||||
|
ul li,
|
||||||
|
ol li {
|
||||||
|
list-style-position: inside;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
BUTTONS
|
||||||
|
------------------------------------- */
|
||||||
|
.btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%; }
|
||||||
|
.btn > tbody > tr > td {
|
||||||
|
padding-bottom: 15px; }
|
||||||
|
.btn table {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.btn table td {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.btn a {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: solid 1px #3498db;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #3498db;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px 25px;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary table td {
|
||||||
|
background-color: #3498db;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary a {
|
||||||
|
background-color: #3498db;
|
||||||
|
border-color: #3498db;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
OTHER STYLES THAT MIGHT BE USEFUL
|
||||||
|
------------------------------------- */
|
||||||
|
.last {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt0 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb0 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preheader {
|
||||||
|
color: transparent;
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
max-height: 0;
|
||||||
|
max-width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
mso-hide: all;
|
||||||
|
visibility: hidden;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.powered-by a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #f6f6f6;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||||
|
------------------------------------- */
|
||||||
|
@media only screen and (max-width: 620px) {
|
||||||
|
table[class=body] h1 {
|
||||||
|
font-size: 28px !important;
|
||||||
|
margin-bottom: 10px !important;
|
||||||
|
}
|
||||||
|
table[class=body] p,
|
||||||
|
table[class=body] ul,
|
||||||
|
table[class=body] ol,
|
||||||
|
table[class=body] td,
|
||||||
|
table[class=body] span,
|
||||||
|
table[class=body] a {
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
table[class=body] .wrapper,
|
||||||
|
table[class=body] .article {
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
table[class=body] .content {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
table[class=body] .container {
|
||||||
|
padding: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
table[class=body] .main {
|
||||||
|
border-left-width: 0 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
border-right-width: 0 !important;
|
||||||
|
}
|
||||||
|
table[class=body] .btn table {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
table[class=body] .btn a {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
table[class=body] .img-responsive {
|
||||||
|
height: auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------
|
||||||
|
PRESERVE THESE STYLES IN THE HEAD
|
||||||
|
------------------------------------- */
|
||||||
|
@media all {
|
||||||
|
.ExternalClass {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ExternalClass,
|
||||||
|
.ExternalClass p,
|
||||||
|
.ExternalClass span,
|
||||||
|
.ExternalClass font,
|
||||||
|
.ExternalClass td,
|
||||||
|
.ExternalClass div {
|
||||||
|
line-height: 100%;
|
||||||
|
}
|
||||||
|
.apple-link a {
|
||||||
|
color: inherit !important;
|
||||||
|
font-family: inherit !important;
|
||||||
|
font-size: inherit !important;
|
||||||
|
font-weight: inherit !important;
|
||||||
|
line-height: inherit !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
#MessageViewBody a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
.btn-primary table td:hover {
|
||||||
|
background-color: #34495e !important;
|
||||||
|
}
|
||||||
|
.btn-primary a:hover {
|
||||||
|
background-color: #34495e !important;
|
||||||
|
border-color: #34495e !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<title>Research Ramp-Up Toolkit</title>
|
||||||
|
</head>
|
||||||
|
<body class="">
|
||||||
|
<span class="preheader"></span>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td class="container">
|
||||||
|
<div class="content">
|
||||||
|
|
||||||
|
<!-- START HEADER -->
|
||||||
|
<div class="header">
|
||||||
|
<table role="presentation">
|
||||||
|
<tr>
|
||||||
|
<td class="container">
|
||||||
|
<div>
|
||||||
|
<table role="presentation">
|
||||||
|
<tr>
|
||||||
|
<th role="presentation"></th>
|
||||||
|
<td>
|
||||||
|
<img class="logo"
|
||||||
|
src="{{ url_for('static', filename='uva_rotunda.svg', _external=True) }}"
|
||||||
|
alt="University of Virginia">
|
||||||
|
</td>
|
||||||
|
<th role="presentation"></th>
|
||||||
|
<td class="content-block">
|
||||||
|
<span>Research Ramp-Up Toolkit Configurator</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- END HEADER -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- START CENTERED WHITE CONTAINER -->
|
||||||
|
<table role="presentation" class="main">
|
||||||
|
|
||||||
|
<!-- START MAIN CONTENT AREA -->
|
||||||
|
<tr>
|
||||||
|
<td class="wrapper">
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<td>{% block content %}{% endblock %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- END MAIN CONTENT AREA -->
|
||||||
|
</table>
|
||||||
|
<!-- END CENTERED WHITE CONTAINER -->
|
||||||
|
|
||||||
|
<!-- START FOOTER -->
|
||||||
|
<div class="footer">
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<td class="content-block">
|
||||||
|
<span class="apple-link">Ramp-Up Toolkit Configurator - University of Virginia</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- END FOOTER -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?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_1xiske1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||||
|
<bpmn:process id="Process_TestBooleanDefault" name="Test Boolean Default" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_1x41riu</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:userTask id="Activity_SelectBoolean" name="Boolean Select" camunda:formKey="PickOne">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:formData>
|
||||||
|
<camunda:formField id="pick_one" label="Pick One" type="boolean">
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property id="value_expression" value="yes_no" />
|
||||||
|
</camunda:properties>
|
||||||
|
</camunda:formField>
|
||||||
|
</camunda:formData>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_0zp5mss</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0m31ypa</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0m31ypa" sourceRef="Activity_SelectBoolean" targetRef="Activity_GoodBye" />
|
||||||
|
<bpmn:manualTask id="Activity_GoodBye" name="Good Bye">
|
||||||
|
<bpmn:documentation><H1>Good Bye</H1>
|
||||||
|
<div><span>Pick One: {% if pick_one %}{{ pick_one}}{% endif %} </span></div>
|
||||||
|
</bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_0m31ypa</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0f3gndz</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
<bpmn:endEvent id="Event_0rgpb6o">
|
||||||
|
<bpmn:incoming>Flow_0f3gndz</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0f3gndz" sourceRef="Activity_GoodBye" targetRef="Event_0rgpb6o" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_1x41riu" sourceRef="StartEvent_1" targetRef="Activity_Hello" />
|
||||||
|
<bpmn:manualTask id="Activity_Hello" name="Hello">
|
||||||
|
<bpmn:documentation><H1>Hello</H1></bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_1x41riu</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_1i32jb7</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_1i32jb7" sourceRef="Activity_Hello" targetRef="Activity_PreData" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_0zp5mss" sourceRef="Activity_PreData" targetRef="Activity_SelectBoolean" />
|
||||||
|
<bpmn:scriptTask id="Activity_PreData" name="Pre Data">
|
||||||
|
<bpmn:incoming>Flow_1i32jb7</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0zp5mss</bpmn:outgoing>
|
||||||
|
<bpmn:script>if not 'yes_no' in globals():
|
||||||
|
yes_no = False</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_TestBooleanDefault">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0f3gndz_di" bpmnElement="Flow_0f3gndz">
|
||||||
|
<di:waypoint x="820" y="117" />
|
||||||
|
<di:waypoint x="882" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0m31ypa_di" bpmnElement="Flow_0m31ypa">
|
||||||
|
<di:waypoint x="662" y="117" />
|
||||||
|
<di:waypoint x="720" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0zp5mss_di" bpmnElement="Flow_0zp5mss">
|
||||||
|
<di:waypoint x="500" y="117" />
|
||||||
|
<di:waypoint x="562" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1i32jb7_di" bpmnElement="Flow_1i32jb7">
|
||||||
|
<di:waypoint x="340" y="117" />
|
||||||
|
<di:waypoint x="400" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1x41riu_di" bpmnElement="Flow_1x41riu">
|
||||||
|
<di:waypoint x="188" y="117" />
|
||||||
|
<di:waypoint x="240" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0vujv1w_di" bpmnElement="Activity_SelectBoolean">
|
||||||
|
<dc:Bounds x="562" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_13n6p58_di" bpmnElement="Activity_GoodBye">
|
||||||
|
<dc:Bounds x="720" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_0rgpb6o_di" bpmnElement="Event_0rgpb6o">
|
||||||
|
<dc:Bounds x="882" y="99" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0vu3ozg_di" bpmnElement="Activity_Hello">
|
||||||
|
<dc:Bounds x="240" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||||
|
<dc:Bounds x="152" y="99" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0ug5gxt_di" bpmnElement="Activity_PreData">
|
||||||
|
<dc:Bounds x="400" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -0,0 +1,148 @@
|
||||||
|
<?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_0a9entn" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||||
|
<bpmn:process id="Process_1dagb7t" name="TestMessage" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1" name="Start">
|
||||||
|
<bpmn:outgoing>Flow_0xym55y</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_16q1uec" name="TestMessageFlow" sourceRef="Event_TokenReset" targetRef="Activity_TestMessage" />
|
||||||
|
<bpmn:scriptTask id="Activity_TestMessage" name="Test Message" camunda:resultVariable="test_message">
|
||||||
|
<bpmn:incoming>Flow_16q1uec</bpmn:incoming>
|
||||||
|
<bpmn:script>update_study("title:'New Title'")
|
||||||
|
print('New Title')</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0xym55y" sourceRef="StartEvent_1" targetRef="Activity_Hello" />
|
||||||
|
<bpmn:userTask id="Activity_HowMany" name="HowMany" camunda:formKey="HowMany">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:formData>
|
||||||
|
<camunda:formField id="how_many" label="How many?" type="long" defaultValue="1" />
|
||||||
|
</camunda:formData>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_1e9j7mj</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_07i0gvv</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_07i0gvv" sourceRef="Activity_HowMany" targetRef="Activity_Modify" />
|
||||||
|
<bpmn:boundaryEvent id="Event_TokenReset" name="TokenReset" attachedToRef="Activity_HowMany">
|
||||||
|
<bpmn:outgoing>Flow_16q1uec</bpmn:outgoing>
|
||||||
|
<bpmn:cancelEventDefinition id="CancelEventDefinition_1d5hszc" />
|
||||||
|
</bpmn:boundaryEvent>
|
||||||
|
<bpmn:manualTask id="Activity_Hello" name="Hello">
|
||||||
|
<bpmn:documentation><H1>Hello</H1></bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_0xym55y</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_1e9j7mj</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_1e9j7mj" sourceRef="Activity_Hello" targetRef="Activity_HowMany" />
|
||||||
|
<bpmn:endEvent id="Event_10cp2vv">
|
||||||
|
<bpmn:incoming>Flow_0rus4fi</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0rus4fi" sourceRef="Activity_GoodBye" targetRef="Event_10cp2vv" />
|
||||||
|
<bpmn:manualTask id="Activity_GoodBye" name="Good Bye">
|
||||||
|
<bpmn:documentation><H1>Good Bye</H1></bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_0f79pbo</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0rus4fi</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
<bpmn:userTask id="Activity_Modify" name="Modify" camunda:formKey="FormModify">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:formData>
|
||||||
|
<camunda:formField id="modify" label="Modify Data?" type="boolean" defaultValue="True" />
|
||||||
|
</camunda:formData>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_07i0gvv</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0f79pbo</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0f79pbo" sourceRef="Activity_Modify" targetRef="Activity_GoodBye" />
|
||||||
|
<bpmn:boundaryEvent id="Event_TokenReset2" name="TokenReset" attachedToRef="Activity_Modify">
|
||||||
|
<bpmn:outgoing>Flow_13xidv2</bpmn:outgoing>
|
||||||
|
<bpmn:cancelEventDefinition id="CancelEventDefinition_1r2giko" />
|
||||||
|
</bpmn:boundaryEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_13xidv2" name="CancelMessageFlow" sourceRef="Event_TokenReset2" targetRef="Activity_CancelMessage" />
|
||||||
|
<bpmn:scriptTask id="Activity_CancelMessage" name="Cancel Message" camunda:resultVariable="cancel_message">
|
||||||
|
<bpmn:documentation><H1>Cancel Message</H1></bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_13xidv2</bpmn:incoming>
|
||||||
|
<bpmn:script>update_study("title:'Second Title'")
|
||||||
|
print('Second Title')</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmn:message id="Message_0iyvlbz" name="token_reset" />
|
||||||
|
<bpmn:message id="Message_1ow6ruy" name="Message_00ldv4i" />
|
||||||
|
<bpmn:signal id="Signal_1fbgshz" name="token_reset" />
|
||||||
|
<bpmn:message id="Message_1czi5ye" name="token_reset" />
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1dagb7t">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1e9j7mj_di" bpmnElement="Flow_1e9j7mj">
|
||||||
|
<di:waypoint x="370" y="118" />
|
||||||
|
<di:waypoint x="441" y="118" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_07i0gvv_di" bpmnElement="Flow_07i0gvv">
|
||||||
|
<di:waypoint x="541" y="118" />
|
||||||
|
<di:waypoint x="627" y="118" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_16q1uec_di" bpmnElement="Flow_16q1uec">
|
||||||
|
<di:waypoint x="491" y="176" />
|
||||||
|
<di:waypoint x="491" y="223" />
|
||||||
|
<di:waypoint x="490" y="223" />
|
||||||
|
<di:waypoint x="490" y="269" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="496" y="196" width="89" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0f79pbo_di" bpmnElement="Flow_0f79pbo">
|
||||||
|
<di:waypoint x="727" y="118" />
|
||||||
|
<di:waypoint x="797" y="118" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0rus4fi_di" bpmnElement="Flow_0rus4fi">
|
||||||
|
<di:waypoint x="897" y="118" />
|
||||||
|
<di:waypoint x="969" y="118" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_13xidv2_di" bpmnElement="Flow_13xidv2">
|
||||||
|
<di:waypoint x="687" y="176" />
|
||||||
|
<di:waypoint x="687" y="269" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="694" y="226" width="86" height="27" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0xym55y_di" bpmnElement="Flow_0xym55y">
|
||||||
|
<di:waypoint x="189" y="118" />
|
||||||
|
<di:waypoint x="270" y="118" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0bieozg_di" bpmnElement="Activity_TestMessage">
|
||||||
|
<dc:Bounds x="440" y="269" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0hkt70o_di" bpmnElement="Activity_HowMany">
|
||||||
|
<dc:Bounds x="441" y="78" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_00p1v49_di" bpmnElement="Activity_Modify">
|
||||||
|
<dc:Bounds x="627" y="78" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0n39q5x_di" bpmnElement="Activity_GoodBye">
|
||||||
|
<dc:Bounds x="797" y="78" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_10cp2vv_di" bpmnElement="Event_10cp2vv">
|
||||||
|
<dc:Bounds x="969" y="100" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0a9mhpp_di" bpmnElement="Activity_CancelMessage">
|
||||||
|
<dc:Bounds x="637" y="269" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1e3uaeb_di" bpmnElement="Activity_Hello">
|
||||||
|
<dc:Bounds x="270" y="78" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||||
|
<dc:Bounds x="153" y="100" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="159" y="143" width="24" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_1yxxtrb_di" bpmnElement="Event_TokenReset">
|
||||||
|
<dc:Bounds x="473" y="140" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="501" y="174" width="59" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_10t25ob_di" bpmnElement="Event_TokenReset2">
|
||||||
|
<dc:Bounds x="669" y="140" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="714" y="167" width="59" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -0,0 +1,107 @@
|
||||||
|
from tests.base_test import BaseTest
|
||||||
|
|
||||||
|
from crc import session
|
||||||
|
from crc.models.study import StudyModel, StudySchema
|
||||||
|
from crc.models.workflow import WorkflowModel, WorkflowSpecModel
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class TestStudyCancellations(BaseTest):
|
||||||
|
|
||||||
|
def update_study_status(self, study, study_schema):
|
||||||
|
put_response = self.app.put('/v1.0/study/%i' % study.id,
|
||||||
|
content_type="application/json",
|
||||||
|
headers=self.logged_in_headers(),
|
||||||
|
data=json.dumps(study_schema))
|
||||||
|
self.assert_success(put_response)
|
||||||
|
|
||||||
|
# The error happened when the dashboard reloaded,
|
||||||
|
# in particular, when we got the studies for the user
|
||||||
|
api_response = self.app.get('/v1.0/study', headers=self.logged_in_headers(), content_type="application/json")
|
||||||
|
self.assert_success(api_response)
|
||||||
|
|
||||||
|
study_result = session.query(StudyModel).filter(StudyModel.id == study.id).first()
|
||||||
|
return study_result
|
||||||
|
|
||||||
|
def put_study_on_hold(self, study_id):
|
||||||
|
study = session.query(StudyModel).filter_by(id=study_id).first()
|
||||||
|
|
||||||
|
study_schema = StudySchema().dump(study)
|
||||||
|
study_schema['status'] = 'hold'
|
||||||
|
study_schema['comment'] = 'This is my hold comment'
|
||||||
|
|
||||||
|
self.update_study_status(study, study_schema)
|
||||||
|
|
||||||
|
study_result = session.query(StudyModel).filter(StudyModel.id == study_id).first()
|
||||||
|
return study_result
|
||||||
|
|
||||||
|
def load_workflow(self):
|
||||||
|
self.load_example_data()
|
||||||
|
workflow = self.create_workflow('study_cancellations')
|
||||||
|
study_id = workflow.study_id
|
||||||
|
return workflow, study_id
|
||||||
|
|
||||||
|
def get_first_task(self, workflow):
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
first_task = workflow_api.next_task
|
||||||
|
self.assertEqual('Activity_Hello', first_task.name)
|
||||||
|
return workflow_api, first_task
|
||||||
|
|
||||||
|
def get_second_task(self, workflow):
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
second_task = workflow_api.next_task
|
||||||
|
self.assertEqual('Activity_HowMany', second_task.name)
|
||||||
|
return workflow_api, second_task
|
||||||
|
|
||||||
|
def get_third_task(self, workflow):
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
third_task = workflow_api.next_task
|
||||||
|
self.assertEqual('Activity_Modify', third_task.name)
|
||||||
|
return workflow_api, third_task
|
||||||
|
|
||||||
|
def test_before_cancel(self):
|
||||||
|
|
||||||
|
workflow, study_id = self.load_workflow()
|
||||||
|
self.get_first_task(workflow)
|
||||||
|
|
||||||
|
study_result = self.put_study_on_hold(study_id)
|
||||||
|
self.assertEqual('Beer consumption in the bipedal software engineer', study_result.title)
|
||||||
|
|
||||||
|
def test_first_cancel(self):
|
||||||
|
workflow, study_id = self.load_workflow()
|
||||||
|
workflow_api, first_task = self.get_first_task(workflow)
|
||||||
|
|
||||||
|
self.complete_form(workflow_api, first_task, {})
|
||||||
|
|
||||||
|
study_result = self.put_study_on_hold(study_id)
|
||||||
|
self.assertEqual('New Title', study_result.title)
|
||||||
|
|
||||||
|
def test_second_cancel(self):
|
||||||
|
|
||||||
|
workflow, study_id = self.load_workflow()
|
||||||
|
workflow_api, first_task = self.get_first_task(workflow)
|
||||||
|
|
||||||
|
self.complete_form(workflow_api, first_task, {})
|
||||||
|
|
||||||
|
workflow_api, next_task = self.get_second_task(workflow)
|
||||||
|
self.complete_form(workflow_api, next_task, {'how_many': 3})
|
||||||
|
|
||||||
|
study_result = self.put_study_on_hold(study_id)
|
||||||
|
self.assertEqual('Second Title', study_result.title)
|
||||||
|
|
||||||
|
def test_after_cancel(self):
|
||||||
|
|
||||||
|
workflow, study_id = self.load_workflow()
|
||||||
|
workflow_api, first_task = self.get_first_task(workflow)
|
||||||
|
|
||||||
|
self.complete_form(workflow_api, first_task, {})
|
||||||
|
|
||||||
|
workflow_api, second_task = self.get_second_task(workflow)
|
||||||
|
self.complete_form(workflow_api, second_task, {'how_many': 3})
|
||||||
|
|
||||||
|
workflow_api, third_task = self.get_third_task(workflow)
|
||||||
|
self.complete_form(workflow_api, third_task, {})
|
||||||
|
|
||||||
|
study_result = self.put_study_on_hold(study_id)
|
||||||
|
self.assertEqual('Beer consumption in the bipedal software engineer', study_result.title)
|
|
@ -54,7 +54,8 @@ class TestLookupService(BaseTest):
|
||||||
|
|
||||||
# restart the workflow, so it can pick up the changes.
|
# restart the workflow, so it can pick up the changes.
|
||||||
|
|
||||||
processor = WorkflowProcessor.reset(workflow)
|
processor = WorkflowProcessor(workflow)
|
||||||
|
processor.reset(workflow)
|
||||||
workflow = processor.workflow_model
|
workflow = processor.workflow_model
|
||||||
|
|
||||||
LookupService.lookup(workflow, "sponsor", "sam", limit=10)
|
LookupService.lookup(workflow, "sponsor", "sam", limit=10)
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
from tests.base_test import BaseTest
|
||||||
|
|
||||||
|
|
||||||
|
class TestBooleanDefault(BaseTest):
|
||||||
|
|
||||||
|
def do_test(self, yes_no):
|
||||||
|
workflow = self.create_workflow('boolean_default_value')
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
first_task = workflow_api.next_task
|
||||||
|
result = self.complete_form(workflow_api, first_task, {'yes_no': yes_no})
|
||||||
|
return result
|
||||||
|
|
||||||
|
def test_boolean_true_string(self):
|
||||||
|
|
||||||
|
yes_no = 'True'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(True, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_true_string_lower(self):
|
||||||
|
|
||||||
|
yes_no = 'true'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(True, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_t_string(self):
|
||||||
|
|
||||||
|
yes_no = 'T'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(True, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_t_string_lower(self):
|
||||||
|
|
||||||
|
yes_no = 't'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(True, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_true(self):
|
||||||
|
|
||||||
|
yes_no = True
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(True, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_false_string(self):
|
||||||
|
|
||||||
|
yes_no = 'False'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(False, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_false_string_lower(self):
|
||||||
|
|
||||||
|
yes_no = 'false'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(False, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_f_string(self):
|
||||||
|
|
||||||
|
yes_no = 'F'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(False, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_f_string_lower(self):
|
||||||
|
|
||||||
|
yes_no = 'f'
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(False, result.next_task.data['pick_one'])
|
||||||
|
|
||||||
|
def test_boolean_false(self):
|
||||||
|
|
||||||
|
yes_no = False
|
||||||
|
result = self.do_test(yes_no)
|
||||||
|
self.assertEqual(False, result.next_task.data['pick_one'])
|
|
@ -279,7 +279,7 @@ class TestWorkflowProcessor(BaseTest):
|
||||||
self.assertFalse(processor2.is_latest_spec) # Still at version 1.
|
self.assertFalse(processor2.is_latest_spec) # Still at version 1.
|
||||||
|
|
||||||
# Do a hard reset, which should bring us back to the beginning, but retain the data.
|
# Do a hard reset, which should bring us back to the beginning, but retain the data.
|
||||||
WorkflowProcessor.reset(processor2.workflow_model)
|
processor2.reset(processor2.workflow_model)
|
||||||
processor3 = WorkflowProcessor(processor.workflow_model)
|
processor3 = WorkflowProcessor(processor.workflow_model)
|
||||||
processor3.do_engine_steps()
|
processor3.do_engine_steps()
|
||||||
self.assertEqual("Step 1", processor3.next_task().task_spec.description)
|
self.assertEqual("Step 1", processor3.next_task().task_spec.description)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from tests.base_test import BaseTest
|
from tests.base_test import BaseTest
|
||||||
|
|
||||||
|
from crc import session
|
||||||
|
from crc.models.study import StudyModel
|
||||||
|
|
||||||
class TestMessageEvent(BaseTest):
|
class TestWorkflowRestart(BaseTest):
|
||||||
|
|
||||||
def test_message_event(self):
|
def test_workflow_restart(self):
|
||||||
|
|
||||||
workflow = self.create_workflow('message_event')
|
workflow = self.create_workflow('message_event')
|
||||||
|
|
||||||
|
@ -32,3 +34,49 @@ class TestMessageEvent(BaseTest):
|
||||||
self.assertNotIn('formdata', workflow_api.next_task.data)
|
self.assertNotIn('formdata', workflow_api.next_task.data)
|
||||||
|
|
||||||
print('Nice Test')
|
print('Nice Test')
|
||||||
|
|
||||||
|
def test_workflow_restart_on_cancel_notify(self):
|
||||||
|
workflow = self.create_workflow('message_event')
|
||||||
|
study_id = workflow.study_id
|
||||||
|
|
||||||
|
# Start the workflow.
|
||||||
|
first_task = self.get_workflow_api(workflow).next_task
|
||||||
|
self.assertEqual('Activity_GetData', first_task.name)
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
self.complete_form(workflow_api, first_task, {'formdata': 'asdf'})
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
self.assertEqual('Activity_HowMany', workflow_api.next_task.name)
|
||||||
|
|
||||||
|
workflow_api = self.restart_workflow_api(workflow)
|
||||||
|
study_result = session.query(StudyModel).filter(StudyModel.id == study_id).first()
|
||||||
|
self.assertEqual('New Title', study_result.title)
|
||||||
|
|
||||||
|
def test_workflow_restart_before_cancel_notify(self):
|
||||||
|
workflow = self.create_workflow('message_event')
|
||||||
|
study_id = workflow.study_id
|
||||||
|
|
||||||
|
first_task = self.get_workflow_api(workflow).next_task
|
||||||
|
self.assertEqual('Activity_GetData', first_task.name)
|
||||||
|
|
||||||
|
study_result = session.query(StudyModel).filter(StudyModel.id == study_id).first()
|
||||||
|
self.assertEqual('Beer consumption in the bipedal software engineer', study_result.title)
|
||||||
|
|
||||||
|
def test_workflow_restart_after_cancel_notify(self):
|
||||||
|
workflow = self.create_workflow('message_event')
|
||||||
|
study_id = workflow.study_id
|
||||||
|
|
||||||
|
# Start the workflow.
|
||||||
|
first_task = self.get_workflow_api(workflow).next_task
|
||||||
|
self.assertEqual('Activity_GetData', first_task.name)
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
self.complete_form(workflow_api, first_task, {'formdata': 'asdf'})
|
||||||
|
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
next_task = workflow_api.next_task
|
||||||
|
self.assertEqual('Activity_HowMany', next_task.name)
|
||||||
|
self.complete_form(workflow_api, next_task, {'how_many': 3})
|
||||||
|
|
||||||
|
workflow_api = self.restart_workflow_api(workflow)
|
||||||
|
study_result = session.query(StudyModel).filter(StudyModel.id == study_id).first()
|
||||||
|
self.assertEqual('Beer consumption in the bipedal software engineer', study_result.title)
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,10 @@ class TestWorkflowSpec(BaseTest):
|
||||||
def test_add_new_workflow_specification(self):
|
def test_add_new_workflow_specification(self):
|
||||||
self.load_example_data()
|
self.load_example_data()
|
||||||
num_before = session.query(WorkflowSpecModel).count()
|
num_before = session.query(WorkflowSpecModel).count()
|
||||||
|
category_id = session.query(WorkflowSpecCategoryModel).first().id
|
||||||
|
category_count = session.query(WorkflowSpecModel).filter_by(category_id=category_id).count()
|
||||||
spec = WorkflowSpecModel(id='make_cookies', name='make_cookies', display_name='Cooooookies',
|
spec = WorkflowSpecModel(id='make_cookies', name='make_cookies', display_name='Cooooookies',
|
||||||
description='Om nom nom delicious cookies')
|
description='Om nom nom delicious cookies', category_id=category_id)
|
||||||
rv = self.app.post('/v1.0/workflow-specification',
|
rv = self.app.post('/v1.0/workflow-specification',
|
||||||
headers=self.logged_in_headers(),
|
headers=self.logged_in_headers(),
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
|
@ -36,6 +38,9 @@ class TestWorkflowSpec(BaseTest):
|
||||||
self.assertEqual(spec.display_name, db_spec.display_name)
|
self.assertEqual(spec.display_name, db_spec.display_name)
|
||||||
num_after = session.query(WorkflowSpecModel).count()
|
num_after = session.query(WorkflowSpecModel).count()
|
||||||
self.assertEqual(num_after, num_before + 1)
|
self.assertEqual(num_after, num_before + 1)
|
||||||
|
self.assertEqual(category_count, db_spec.display_order)
|
||||||
|
category_count_after = session.query(WorkflowSpecModel).filter_by(category_id=category_id).count()
|
||||||
|
self.assertEqual(category_count_after, category_count + 1)
|
||||||
|
|
||||||
def test_get_workflow_specification(self):
|
def test_get_workflow_specification(self):
|
||||||
self.load_example_data()
|
self.load_example_data()
|
||||||
|
|
Loading…
Reference in New Issue