Merge branch 'dev' of github.com:sartography/cr-connect-workflow into dev
This commit is contained in:
commit
7e6645db89
|
@ -17,7 +17,10 @@ API_TOKEN = environ.get('API_TOKEN', default = 'af95596f327c9ecc007b60414fc84b61
|
||||||
NAME = "CR Connect Workflow"
|
NAME = "CR Connect Workflow"
|
||||||
DEFAULT_PORT = "5000"
|
DEFAULT_PORT = "5000"
|
||||||
FLASK_PORT = environ.get('PORT0') or environ.get('FLASK_PORT', default=DEFAULT_PORT)
|
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"))
|
FRONTEND = "localhost:4200"
|
||||||
|
BPMN = "localhost:5002"
|
||||||
|
CORS_DEFAULT = f'{FRONTEND}, {BPMN}'
|
||||||
|
CORS_ALLOW_ORIGINS = re.split(r',\s*', environ.get('CORS_ALLOW_ORIGINS', default=CORS_DEFAULT))
|
||||||
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")
|
||||||
TEST_UID = environ.get('TEST_UID', default="dhf8r")
|
TEST_UID = environ.get('TEST_UID', default="dhf8r")
|
||||||
|
@ -50,7 +53,6 @@ SQLALCHEMY_DATABASE_URI = environ.get(
|
||||||
|
|
||||||
TOKEN_AUTH_TTL_HOURS = float(environ.get('TOKEN_AUTH_TTL_HOURS', default=24))
|
TOKEN_AUTH_TTL_HOURS = float(environ.get('TOKEN_AUTH_TTL_HOURS', default=24))
|
||||||
SECRET_KEY = environ.get('SECRET_KEY', default="Shhhh!!! This is secret! And better darn well not show up in prod.")
|
SECRET_KEY = environ.get('SECRET_KEY', default="Shhhh!!! This is secret! And better darn well not show up in prod.")
|
||||||
FRONTEND_AUTH_CALLBACK = environ.get('FRONTEND_AUTH_CALLBACK', default="http://localhost:4200/session")
|
|
||||||
SWAGGER_AUTH_KEY = environ.get('SWAGGER_AUTH_KEY', default="SWAGGER")
|
SWAGGER_AUTH_KEY = environ.get('SWAGGER_AUTH_KEY', default="SWAGGER")
|
||||||
# %s/%i placeholders expected for uva_id and study_id in various calls.
|
# %s/%i placeholders expected for uva_id and study_id in various calls.
|
||||||
PB_ENABLED = environ.get('PB_ENABLED', default="false") == "true"
|
PB_ENABLED = environ.get('PB_ENABLED', default="false") == "true"
|
||||||
|
|
36
crc/api.yml
36
crc/api.yml
|
@ -740,6 +740,41 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
format: binary
|
format: binary
|
||||||
example: '<?xml version="1.0" encoding="UTF-8"?><bpmn:definitions></bpmn:definitions>'
|
example: '<?xml version="1.0" encoding="UTF-8"?><bpmn:definitions></bpmn:definitions>'
|
||||||
|
/file/{file_id}/download :
|
||||||
|
parameters :
|
||||||
|
- name : file_id
|
||||||
|
in : path
|
||||||
|
required : true
|
||||||
|
description : The id of the File requested
|
||||||
|
schema :
|
||||||
|
type : integer
|
||||||
|
- name : auth_token
|
||||||
|
in : query
|
||||||
|
required : true
|
||||||
|
description : User Auth Toeken
|
||||||
|
schema :
|
||||||
|
type : string
|
||||||
|
- name : version
|
||||||
|
in : query
|
||||||
|
required : false
|
||||||
|
description : The version of the file, or none for latest version
|
||||||
|
schema :
|
||||||
|
type : integer
|
||||||
|
get :
|
||||||
|
operationId : crc.api.file.get_file_data_link
|
||||||
|
summary : Returns only the file contents
|
||||||
|
security: []
|
||||||
|
tags :
|
||||||
|
- Files
|
||||||
|
responses :
|
||||||
|
'200' :
|
||||||
|
description : Returns the actual file
|
||||||
|
content :
|
||||||
|
application/octet-stream :
|
||||||
|
schema :
|
||||||
|
type : string
|
||||||
|
format : binary
|
||||||
|
example : '<?xml version="1.0" encoding="UTF-8"?><bpmn:definitions></bpmn:definitions>'
|
||||||
/file/{file_id}/data:
|
/file/{file_id}/data:
|
||||||
parameters:
|
parameters:
|
||||||
- name: file_id
|
- name: file_id
|
||||||
|
@ -1574,6 +1609,7 @@ components:
|
||||||
standalone:
|
standalone:
|
||||||
type: boolean
|
type: boolean
|
||||||
example: false
|
example: false
|
||||||
|
default: false
|
||||||
workflow_spec_category:
|
workflow_spec_category:
|
||||||
$ref: "#/components/schemas/WorkflowSpecCategory"
|
$ref: "#/components/schemas/WorkflowSpecCategory"
|
||||||
is_status:
|
is_status:
|
||||||
|
|
|
@ -6,6 +6,7 @@ from flask import send_file
|
||||||
|
|
||||||
from crc import session
|
from crc import session
|
||||||
from crc.api.common import ApiError
|
from crc.api.common import ApiError
|
||||||
|
from crc.api.user import verify_token
|
||||||
from crc.models.api_models import DocumentDirectory, DocumentDirectorySchema
|
from crc.models.api_models import DocumentDirectory, DocumentDirectorySchema
|
||||||
from crc.models.file import FileSchema, FileModel, File, FileModelSchema, FileDataModel, FileType
|
from crc.models.file import FileSchema, FileModel, File, FileModelSchema, FileDataModel, FileType
|
||||||
from crc.models.workflow import WorkflowSpecModel
|
from crc.models.workflow import WorkflowSpecModel
|
||||||
|
@ -182,6 +183,22 @@ def get_file_data(file_id, version=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_file_data_link(file_id, auth_token, version=None):
|
||||||
|
if not verify_token(auth_token):
|
||||||
|
raise ApiError('not_authenticated', 'You need to include an authorization token in the URL with this')
|
||||||
|
file_data = FileService.get_file_data(file_id, version)
|
||||||
|
if file_data is None:
|
||||||
|
raise ApiError('no_such_file', 'The file id you provided does not exist')
|
||||||
|
return send_file(
|
||||||
|
io.BytesIO(file_data.data),
|
||||||
|
attachment_filename=file_data.file_model.name,
|
||||||
|
mimetype=file_data.file_model.content_type,
|
||||||
|
cache_timeout=-1, # Don't cache these files on the browser.
|
||||||
|
last_modified=file_data.date_created,
|
||||||
|
as_attachment = True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_file_info(file_id):
|
def get_file_info(file_id):
|
||||||
file_model = session.query(FileModel).filter_by(id=file_id).with_for_update().first()
|
file_model = session.query(FileModel).filter_by(id=file_id).with_for_update().first()
|
||||||
if file_model is None:
|
if file_model is None:
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
from crc.scripts.script import Script
|
||||||
|
from crc import app
|
||||||
|
|
||||||
|
|
||||||
|
class GetDashboardURL(Script):
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
"""Get the URL for the main dashboard. This should be system instance aware.
|
||||||
|
I.e., dev, testing, production, etc."""
|
||||||
|
|
||||||
|
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
|
self.do_task(task, study_id, workflow_id, *args, **kwargs)
|
||||||
|
|
||||||
|
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
|
frontend = app.config['FRONTEND']
|
||||||
|
return f'https://{frontend}'
|
|
@ -1,7 +1,9 @@
|
||||||
|
import urllib
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
import flask
|
||||||
import requests
|
import requests
|
||||||
from SpiffWorkflow import WorkflowException
|
from SpiffWorkflow import WorkflowException
|
||||||
from SpiffWorkflow.exceptions import WorkflowTaskExecException
|
from SpiffWorkflow.exceptions import WorkflowTaskExecException
|
||||||
|
@ -288,9 +290,19 @@ class StudyService(object):
|
||||||
doc_files = FileService.get_files_for_study(study_id=study_id, irb_doc_code=code)
|
doc_files = FileService.get_files_for_study(study_id=study_id, irb_doc_code=code)
|
||||||
doc['count'] = len(doc_files)
|
doc['count'] = len(doc_files)
|
||||||
doc['files'] = []
|
doc['files'] = []
|
||||||
|
|
||||||
|
# when we run tests - it doesn't look like the user is available
|
||||||
|
# so we return a bogus token
|
||||||
|
token = 'not_available'
|
||||||
|
if hasattr(flask.g,'user'):
|
||||||
|
token = flask.g.user.encode_auth_token()
|
||||||
for file in doc_files:
|
for file in doc_files:
|
||||||
doc['files'].append({'file_id': file.id,
|
doc['files'].append({'file_id': file.id,
|
||||||
'name': file.name,
|
'name': file.name,
|
||||||
|
'url': app.config['APPLICATION_ROOT']+
|
||||||
|
'file/' + str(file.id) +
|
||||||
|
'/download?auth_token='+
|
||||||
|
urllib.parse.quote_plus(token),
|
||||||
'workflow_id': file.workflow_id})
|
'workflow_id': file.workflow_id})
|
||||||
|
|
||||||
# update the document status to match the status of the workflow it is in.
|
# update the document status to match the status of the workflow it is in.
|
||||||
|
|
|
@ -22,7 +22,7 @@ from jinja2 import Template
|
||||||
from crc import db, app
|
from crc import db, app
|
||||||
from crc.api.common import ApiError
|
from crc.api.common import ApiError
|
||||||
from crc.models.api_models import Task, MultiInstanceType, WorkflowApi
|
from crc.models.api_models import Task, MultiInstanceType, WorkflowApi
|
||||||
from crc.models.file import LookupDataModel
|
from crc.models.file import LookupDataModel, FileModel
|
||||||
from crc.models.study import StudyModel
|
from crc.models.study import StudyModel
|
||||||
from crc.models.task_event import TaskEventModel
|
from crc.models.task_event import TaskEventModel
|
||||||
from crc.models.user import UserModel, UserModelSchema
|
from crc.models.user import UserModel, UserModelSchema
|
||||||
|
@ -739,10 +739,7 @@ class WorkflowService(object):
|
||||||
|
|
||||||
if hasattr(task.task_spec, 'form'):
|
if hasattr(task.task_spec, 'form'):
|
||||||
for field in task.task_spec.form.fields:
|
for field in task.task_spec.form.fields:
|
||||||
if field.has_property(Task.FIELD_PROP_READ_ONLY) and \
|
if field.has_property(Task.FIELD_PROP_REPEAT):
|
||||||
field.get_property(Task.FIELD_PROP_READ_ONLY).lower().strip() == "true":
|
|
||||||
continue # Don't add read-only data
|
|
||||||
elif field.has_property(Task.FIELD_PROP_REPEAT):
|
|
||||||
group = field.get_property(Task.FIELD_PROP_REPEAT)
|
group = field.get_property(Task.FIELD_PROP_REPEAT)
|
||||||
if group in latest_data:
|
if group in latest_data:
|
||||||
data[group] = latest_data[group]
|
data[group] = latest_data[group]
|
||||||
|
@ -811,3 +808,12 @@ class WorkflowService(object):
|
||||||
def get_standalone_workflow_specs():
|
def get_standalone_workflow_specs():
|
||||||
specs = db.session.query(WorkflowSpecModel).filter_by(standalone=True).all()
|
specs = db.session.query(WorkflowSpecModel).filter_by(standalone=True).all()
|
||||||
return specs
|
return specs
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_primary_workflow(workflow_spec_id):
|
||||||
|
# Returns the FileModel of the primary workflow for a workflow_spec
|
||||||
|
primary = None
|
||||||
|
file = db.session.query(FileModel).filter(FileModel.workflow_spec_id==workflow_spec_id, FileModel.primary==True).first()
|
||||||
|
if file:
|
||||||
|
primary = file
|
||||||
|
return primary
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
from crc.api.file import get_document_directory
|
||||||
|
|
||||||
|
|
||||||
|
def render_files(study_id,irb_codes):
|
||||||
|
files = get_document_directory(study_id)
|
||||||
|
print(files)
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?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:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_024561a" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.5.0">
|
||||||
|
<bpmn:process id="Process_1796d29" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_0c51a4b</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0c51a4b" sourceRef="StartEvent_1" targetRef="Activity_GetURL" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_1ker6ik" sourceRef="Activity_GetURL" targetRef="Activity_EmailURL" />
|
||||||
|
<bpmn:endEvent id="Event_17hmyob">
|
||||||
|
<bpmn:incoming>Flow_1rfvzi5</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_1rfvzi5" sourceRef="Activity_EmailURL" targetRef="Event_17hmyob" />
|
||||||
|
<bpmn:scriptTask id="Activity_GetURL" name="Get Dashboard URL ">
|
||||||
|
<bpmn:incoming>Flow_0c51a4b</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_1ker6ik</bpmn:outgoing>
|
||||||
|
<bpmn:script>dashboard_url = get_dashboard_url()</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:scriptTask id="Activity_EmailURL" name="Email Dashboard URL">
|
||||||
|
<bpmn:documentation><a href="{{dashboard_url}}">{{dashboard_url}}</a></bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_1ker6ik</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_1rfvzi5</bpmn:outgoing>
|
||||||
|
<bpmn:script>email(subject='My Email Subject', recipients="test@example.com")</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1796d29">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1rfvzi5_di" bpmnElement="Flow_1rfvzi5">
|
||||||
|
<di:waypoint x="530" y="117" />
|
||||||
|
<di:waypoint x="592" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1ker6ik_di" bpmnElement="Flow_1ker6ik">
|
||||||
|
<di:waypoint x="370" y="117" />
|
||||||
|
<di:waypoint x="430" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0c51a4b_di" bpmnElement="Flow_0c51a4b">
|
||||||
|
<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="Event_17hmyob_di" bpmnElement="Event_17hmyob">
|
||||||
|
<dc:Bounds x="592" y="99" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1n7b49v_di" bpmnElement="Activity_GetURL">
|
||||||
|
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1dn6kw2_di" bpmnElement="Activity_EmailURL">
|
||||||
|
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
fileid = documents['UVACompl_PRCAppr'].files[0]['file_id']
|
fileid = documents['UVACompl_PRCAppr'].files[0]['file_id']
|
||||||
|
|
||||||
|
fileurl = documents['UVACompl_PRCAppr'].files[0]['url']
|
||||||
|
|
||||||
|
filename = documents['UVACompl_PRCAppr'].files[0]['name']
|
||||||
|
|
||||||
file_data_set(file_id=fileid,key='test',value='me')</bpmn:script>
|
file_data_set(file_id=fileid,key='test',value='me')</bpmn:script>
|
||||||
</bpmn:scriptTask>
|
</bpmn:scriptTask>
|
||||||
<bpmn:endEvent id="Event_1pdyoyv">
|
<bpmn:endEvent id="Event_1pdyoyv">
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?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_5e40639" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||||
|
<bpmn:process id="Process_ReadOnlyField" name="Test Read Only Field" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_0to8etb</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0to8etb" sourceRef="StartEvent_1" targetRef="Activity_SetData" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_04r75ca" sourceRef="Activity_SetData" targetRef="Activity_DisplayOnlyField" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_0g25v76" sourceRef="Activity_DisplayOnlyField" targetRef="Activity_CheckData" />
|
||||||
|
<bpmn:endEvent id="Event_0cfckhy">
|
||||||
|
<bpmn:incoming>Flow_0a95kns</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0a95kns" sourceRef="Activity_CheckData" targetRef="Event_0cfckhy" />
|
||||||
|
<bpmn:scriptTask id="Activity_SetData" name="Set Data">
|
||||||
|
<bpmn:incoming>Flow_0to8etb</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_04r75ca</bpmn:outgoing>
|
||||||
|
<bpmn:script>string_value = 'asdf'</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:userTask id="Activity_DisplayOnlyField" name="Display Only Field " camunda:formKey="ReadOnlyFormField">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:formData>
|
||||||
|
<camunda:formField id="read_only_field" label="Read Only" type="string">
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property id="read_only" value="True" />
|
||||||
|
<camunda:property id="value_expression" value="string_value" />
|
||||||
|
</camunda:properties>
|
||||||
|
</camunda:formField>
|
||||||
|
</camunda:formData>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_04r75ca</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0g25v76</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
<bpmn:manualTask id="Activity_CheckData" name="Check Data Persistence">
|
||||||
|
<bpmn:documentation>Read only is {{ read_only_field }}</bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_0g25v76</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0a95kns</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_ReadOnlyField">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0a95kns_di" bpmnElement="Flow_0a95kns">
|
||||||
|
<di:waypoint x="690" y="177" />
|
||||||
|
<di:waypoint x="752" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0g25v76_di" bpmnElement="Flow_0g25v76">
|
||||||
|
<di:waypoint x="530" y="177" />
|
||||||
|
<di:waypoint x="590" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_04r75ca_di" bpmnElement="Flow_04r75ca">
|
||||||
|
<di:waypoint x="370" y="177" />
|
||||||
|
<di:waypoint x="430" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0to8etb_di" bpmnElement="Flow_0to8etb">
|
||||||
|
<di:waypoint x="215" y="177" />
|
||||||
|
<di:waypoint x="270" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||||
|
<dc:Bounds x="179" y="159" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_0cfckhy_di" bpmnElement="Event_0cfckhy">
|
||||||
|
<dc:Bounds x="752" y="159" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="733" y="202" width="76" height="27" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_10544ek_di" bpmnElement="Activity_SetData">
|
||||||
|
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0ho1wsm_di" bpmnElement="Activity_DisplayOnlyField">
|
||||||
|
<dc:Bounds x="430" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_10ds6m4_di" bpmnElement="Activity_CheckData">
|
||||||
|
<dc:Bounds x="590" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -27,6 +27,8 @@ class TestFileDatastore(BaseTest):
|
||||||
processor = WorkflowProcessor(workflow)
|
processor = WorkflowProcessor(workflow)
|
||||||
processor.do_engine_steps()
|
processor.do_engine_steps()
|
||||||
task_data = processor.bpmn_workflow.last_task.data
|
task_data = processor.bpmn_workflow.last_task.data
|
||||||
|
self.assertTrue(str(task_data['fileid']) in task_data['fileurl'])
|
||||||
|
self.assertEqual(task_data['filename'],'anything.png')
|
||||||
self.assertEqual(task_data['output'], 'me')
|
self.assertEqual(task_data['output'], 'me')
|
||||||
self.assertEqual(task_data['output2'], 'nope')
|
self.assertEqual(task_data['output2'], 'nope')
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
from tests.base_test import BaseTest
|
||||||
|
from crc import app, mail
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetDashboardURL(BaseTest):
|
||||||
|
|
||||||
|
def test_get_dashboard_url(self):
|
||||||
|
with mail.record_messages() as outbox:
|
||||||
|
|
||||||
|
dashboard_url = f'https://{app.config["FRONTEND"]}'
|
||||||
|
workflow = self.create_workflow('email_dashboard_url')
|
||||||
|
self.get_workflow_api(workflow)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(outbox))
|
||||||
|
self.assertEqual('My Email Subject', outbox[0].subject)
|
||||||
|
self.assertEqual(['test@example.com'], outbox[0].recipients)
|
||||||
|
self.assertIn(dashboard_url, outbox[0].body)
|
|
@ -0,0 +1,16 @@
|
||||||
|
from tests.base_test import BaseTest
|
||||||
|
|
||||||
|
|
||||||
|
class TestReadOnlyField(BaseTest):
|
||||||
|
|
||||||
|
def test_read_only(self):
|
||||||
|
|
||||||
|
workflow = self.create_workflow('read_only_field')
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
first_task = workflow_api.next_task
|
||||||
|
read_only_field = first_task.data['read_only_field']
|
||||||
|
self.complete_form(workflow, first_task, {'read_only_field': read_only_field})
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
task = workflow_api.next_task
|
||||||
|
|
||||||
|
self.assertEqual('Read only is asdf', task.documentation)
|
|
@ -10,6 +10,7 @@ from example_data import ExampleDataLoader
|
||||||
from crc import db
|
from crc import db
|
||||||
from crc.models.task_event import TaskEventModel
|
from crc.models.task_event import TaskEventModel
|
||||||
from crc.models.api_models import Task
|
from crc.models.api_models import Task
|
||||||
|
from crc.models.file import FileModel
|
||||||
from crc.api.common import ApiError
|
from crc.api.common import ApiError
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,3 +115,12 @@ class TestWorkflowService(BaseTest):
|
||||||
|
|
||||||
result2 = WorkflowService.get_dot_value(path, {"a.b.c":"garbage"})
|
result2 = WorkflowService.get_dot_value(path, {"a.b.c":"garbage"})
|
||||||
self.assertEqual("garbage", result2)
|
self.assertEqual("garbage", result2)
|
||||||
|
|
||||||
|
def test_get_primary_workflow(self):
|
||||||
|
|
||||||
|
workflow = self.create_workflow('hello_world')
|
||||||
|
workflow_spec_id = workflow.workflow_spec.id
|
||||||
|
primary_workflow = WorkflowService.get_primary_workflow(workflow_spec_id)
|
||||||
|
self.assertIsInstance(primary_workflow, FileModel)
|
||||||
|
self.assertEqual(workflow_spec_id, primary_workflow.workflow_spec_id)
|
||||||
|
self.assertEqual('hello_world.bpmn', primary_workflow.name)
|
||||||
|
|
Loading…
Reference in New Issue