Merge branch 'dev' of https://github.com/sartography/cr-connect-workflow into dev
This commit is contained in:
commit
05ba28b67b
|
@ -979,7 +979,7 @@
|
||||||
},
|
},
|
||||||
"spiffworkflow": {
|
"spiffworkflow": {
|
||||||
"git": "https://github.com/sartography/SpiffWorkflow.git",
|
"git": "https://github.com/sartography/SpiffWorkflow.git",
|
||||||
"ref": "66555b92ef1d8d9ce117b6f2ccf6aa248df9835f"
|
"ref": "59d12e25e5313977b83e7d65b6deb65572dee71c"
|
||||||
},
|
},
|
||||||
"sqlalchemy": {
|
"sqlalchemy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|
|
@ -63,6 +63,7 @@ PB_REQUIRED_DOCS_URL = environ.get('PB_REQUIRED_DOCS_URL', default=PB_BASE_URL +
|
||||||
PB_STUDY_DETAILS_URL = environ.get('PB_STUDY_DETAILS_URL', default=PB_BASE_URL + "study?studyid=%i")
|
PB_STUDY_DETAILS_URL = environ.get('PB_STUDY_DETAILS_URL', default=PB_BASE_URL + "study?studyid=%i")
|
||||||
PB_SPONSORS_URL = environ.get('PB_SPONSORS_URL', default=PB_BASE_URL + "sponsors?studyid=%i")
|
PB_SPONSORS_URL = environ.get('PB_SPONSORS_URL', default=PB_BASE_URL + "sponsors?studyid=%i")
|
||||||
PB_IRB_INFO_URL = environ.get('PB_IRB_INFO_URL', default=PB_BASE_URL + "current_irb_info/%i")
|
PB_IRB_INFO_URL = environ.get('PB_IRB_INFO_URL', default=PB_BASE_URL + "current_irb_info/%i")
|
||||||
|
PB_CHECK_STUDY_URL = environ.get('PB_CHECK_STUDY_URL', default=PB_BASE_URL + "check_study/%i")
|
||||||
|
|
||||||
# Ldap Configuration
|
# Ldap Configuration
|
||||||
LDAP_URL = environ.get('LDAP_URL', default="ldap.virginia.edu").strip('/') # No trailing slash or http://
|
LDAP_URL = environ.get('LDAP_URL', default="ldap.virginia.edu").strip('/') # No trailing slash or http://
|
||||||
|
|
|
@ -68,6 +68,7 @@ class FileDataModel(db.Model):
|
||||||
date_created = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
date_created = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||||
file_model_id = db.Column(db.Integer, db.ForeignKey('file.id'))
|
file_model_id = db.Column(db.Integer, db.ForeignKey('file.id'))
|
||||||
file_model = db.relationship("FileModel", foreign_keys=[file_model_id])
|
file_model = db.relationship("FileModel", foreign_keys=[file_model_id])
|
||||||
|
user_uid = db.Column(db.String, db.ForeignKey('user.uid'), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class FileModel(db.Model):
|
class FileModel(db.Model):
|
||||||
|
@ -114,6 +115,7 @@ class File(object):
|
||||||
instance.last_modified = data_model.date_created
|
instance.last_modified = data_model.date_created
|
||||||
instance.latest_version = data_model.version
|
instance.latest_version = data_model.version
|
||||||
instance.size = data_model.size
|
instance.size = data_model.size
|
||||||
|
instance.user_uid = data_model.user_uid
|
||||||
else:
|
else:
|
||||||
instance.last_modified = None
|
instance.last_modified = None
|
||||||
instance.latest_version = None
|
instance.latest_version = None
|
||||||
|
@ -141,7 +143,7 @@ class FileSchema(Schema):
|
||||||
fields = ["id", "name", "is_status", "is_reference", "content_type",
|
fields = ["id", "name", "is_status", "is_reference", "content_type",
|
||||||
"primary", "primary_process_id", "workflow_spec_id", "workflow_id",
|
"primary", "primary_process_id", "workflow_spec_id", "workflow_id",
|
||||||
"irb_doc_code", "last_modified", "latest_version", "type", "size", "data_store",
|
"irb_doc_code", "last_modified", "latest_version", "type", "size", "data_store",
|
||||||
"document"]
|
"document", "user_uid"]
|
||||||
unknown = INCLUDE
|
unknown = INCLUDE
|
||||||
type = EnumField(FileType)
|
type = EnumField(FileType)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
from crc.scripts.script import Script
|
||||||
|
from crc.api.common import ApiError
|
||||||
|
from crc.services.protocol_builder import ProtocolBuilderService
|
||||||
|
from crc.services.study_service import StudyService
|
||||||
|
|
||||||
|
|
||||||
|
class CheckStudy(Script):
|
||||||
|
|
||||||
|
pb = ProtocolBuilderService()
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
return """Returns the Check Study data for a Study"""
|
||||||
|
|
||||||
|
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
|
study = StudyService.get_study(study_id)
|
||||||
|
if study:
|
||||||
|
return {"DETAIL": "Passed validation.", "STATUS": "No Error"}
|
||||||
|
else:
|
||||||
|
raise ApiError.from_task(code='bad_study',
|
||||||
|
message=f'No study for study_id {study_id}',
|
||||||
|
task=task)
|
||||||
|
|
||||||
|
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
|
check_study = self.pb.check_study(study_id)
|
||||||
|
if check_study:
|
||||||
|
return check_study
|
||||||
|
else:
|
||||||
|
raise ApiError.from_task(code='missing_check_study',
|
||||||
|
message='There was a problem checking information for this study.',
|
||||||
|
task=task)
|
|
@ -19,6 +19,7 @@ from crc.models.data_store import DataStoreModel
|
||||||
from crc.models.file import FileType, FileDataModel, FileModel, LookupFileModel, LookupDataModel
|
from crc.models.file import FileType, FileDataModel, FileModel, LookupFileModel, LookupDataModel
|
||||||
from crc.models.workflow import WorkflowSpecModel, WorkflowModel, WorkflowSpecDependencyFile
|
from crc.models.workflow import WorkflowSpecModel, WorkflowModel, WorkflowSpecDependencyFile
|
||||||
from crc.services.cache_service import cache
|
from crc.services.cache_service import cache
|
||||||
|
from crc.services.user_service import UserService
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,10 +169,14 @@ class FileService(object):
|
||||||
except XMLSyntaxError as xse:
|
except XMLSyntaxError as xse:
|
||||||
raise ApiError("invalid_xml", "Failed to parse xml: " + str(xse), file_name=file_model.name)
|
raise ApiError("invalid_xml", "Failed to parse xml: " + str(xse), file_name=file_model.name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_uid = UserService.current_user().uid
|
||||||
|
except ApiError as ae:
|
||||||
|
user_uid = None
|
||||||
new_file_data_model = FileDataModel(
|
new_file_data_model = FileDataModel(
|
||||||
data=binary_data, file_model_id=file_model.id, file_model=file_model,
|
data=binary_data, file_model_id=file_model.id, file_model=file_model,
|
||||||
version=version, md5_hash=md5_checksum, date_created=datetime.utcnow(),
|
version=version, md5_hash=md5_checksum, date_created=datetime.utcnow(),
|
||||||
size=size
|
size=size, user_uid=user_uid
|
||||||
)
|
)
|
||||||
session.add_all([file_model, new_file_data_model])
|
session.add_all([file_model, new_file_data_model])
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
|
@ -15,6 +15,7 @@ class ProtocolBuilderService(object):
|
||||||
STUDY_DETAILS_URL = app.config['PB_STUDY_DETAILS_URL']
|
STUDY_DETAILS_URL = app.config['PB_STUDY_DETAILS_URL']
|
||||||
SPONSORS_URL = app.config['PB_SPONSORS_URL']
|
SPONSORS_URL = app.config['PB_SPONSORS_URL']
|
||||||
IRB_INFO_URL = app.config['PB_IRB_INFO_URL']
|
IRB_INFO_URL = app.config['PB_IRB_INFO_URL']
|
||||||
|
CHECK_STUDY_URL = app.config['PB_CHECK_STUDY_URL']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_enabled():
|
def is_enabled():
|
||||||
|
@ -64,6 +65,10 @@ class ProtocolBuilderService(object):
|
||||||
def get_sponsors(study_id) -> {}:
|
def get_sponsors(study_id) -> {}:
|
||||||
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.SPONSORS_URL)
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.SPONSORS_URL)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_study(study_id) -> {}:
|
||||||
|
return ProtocolBuilderService.__make_request(study_id, ProtocolBuilderService.CHECK_STUDY_URL)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __enabled_or_raise():
|
def __enabled_or_raise():
|
||||||
if not ProtocolBuilderService.is_enabled():
|
if not ProtocolBuilderService.is_enabled():
|
||||||
|
|
|
@ -7,7 +7,7 @@ import shlex
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from SpiffWorkflow import Task as SpiffTask, WorkflowException
|
from SpiffWorkflow import Task as SpiffTask, WorkflowException, Task
|
||||||
from SpiffWorkflow.bpmn.BpmnScriptEngine import BpmnScriptEngine
|
from SpiffWorkflow.bpmn.BpmnScriptEngine import BpmnScriptEngine
|
||||||
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException
|
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException
|
||||||
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
|
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
|
||||||
|
@ -30,6 +30,8 @@ from crc.services.file_service import FileService
|
||||||
from crc import app
|
from crc import app
|
||||||
from crc.services.user_service import UserService
|
from crc.services.user_service import UserService
|
||||||
|
|
||||||
|
from difflib import SequenceMatcher
|
||||||
|
|
||||||
class CustomBpmnScriptEngine(BpmnScriptEngine):
|
class CustomBpmnScriptEngine(BpmnScriptEngine):
|
||||||
"""This is a custom script processor that can be easily injected into Spiff Workflow.
|
"""This is a custom script processor that can be easily injected into Spiff Workflow.
|
||||||
It will execute python code read in from the bpmn. It will also make any scripts in the
|
It will execute python code read in from the bpmn. It will also make any scripts in the
|
||||||
|
@ -50,13 +52,11 @@ class CustomBpmnScriptEngine(BpmnScriptEngine):
|
||||||
workflow_id = task.workflow.data[WorkflowProcessor.WORKFLOW_ID_KEY]
|
workflow_id = task.workflow.data[WorkflowProcessor.WORKFLOW_ID_KEY]
|
||||||
else:
|
else:
|
||||||
workflow_id = None
|
workflow_id = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if task.workflow.data[WorkflowProcessor.VALIDATION_PROCESS_KEY]:
|
if task.workflow.data[WorkflowProcessor.VALIDATION_PROCESS_KEY]:
|
||||||
augment_methods = Script.generate_augmented_validate_list(task, study_id, workflow_id)
|
augment_methods = Script.generate_augmented_validate_list(task, study_id, workflow_id)
|
||||||
else:
|
else:
|
||||||
augment_methods = Script.generate_augmented_list(task, study_id, workflow_id)
|
augment_methods = Script.generate_augmented_list(task, study_id, workflow_id)
|
||||||
|
|
||||||
super().execute(task, script, data, external_methods=augment_methods)
|
super().execute(task, script, data, external_methods=augment_methods)
|
||||||
except WorkflowException as e:
|
except WorkflowException as e:
|
||||||
raise e
|
raise e
|
||||||
|
@ -337,6 +337,9 @@ class WorkflowProcessor(object):
|
||||||
if bpmn_workflow.is_completed():
|
if bpmn_workflow.is_completed():
|
||||||
return WorkflowStatus.complete
|
return WorkflowStatus.complete
|
||||||
user_tasks = bpmn_workflow.get_ready_user_tasks()
|
user_tasks = bpmn_workflow.get_ready_user_tasks()
|
||||||
|
waiting_tasks = bpmn_workflow.get_tasks(Task.WAITING)
|
||||||
|
if len(waiting_tasks) > 0:
|
||||||
|
return WorkflowStatus.waiting
|
||||||
if len(user_tasks) > 0:
|
if len(user_tasks) > 0:
|
||||||
return WorkflowStatus.user_input_required
|
return WorkflowStatus.user_input_required
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
"""add user_uid column to file_data table
|
||||||
|
|
||||||
|
Revision ID: 30e017a03948
|
||||||
|
Revises: bbf064082623
|
||||||
|
Create Date: 2021-07-06 10:39:04.661704
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '30e017a03948'
|
||||||
|
down_revision = 'bbf064082623'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('file_data', sa.Column('user_uid', sa.String(), nullable=True))
|
||||||
|
op.create_foreign_key(None, 'file_data', 'user', ['user_uid'], ['uid'])
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# op.drop_constraint('file_data_user_uid_fkey', 'file_data', type_='foreignkey')
|
||||||
|
# op.execute("update file_data set user_uid = NULL WHERE user_uid IS NOT NULL")
|
||||||
|
op.drop_column('file_data', 'user_uid')
|
|
@ -148,13 +148,6 @@ class BaseTest(unittest.TestCase):
|
||||||
otherwise it depends on a small setup for running tests."""
|
otherwise it depends on a small setup for running tests."""
|
||||||
from example_data import ExampleDataLoader
|
from example_data import ExampleDataLoader
|
||||||
ExampleDataLoader.clean_db()
|
ExampleDataLoader.clean_db()
|
||||||
if use_crc_data:
|
|
||||||
ExampleDataLoader().load_all()
|
|
||||||
elif use_rrt_data:
|
|
||||||
ExampleDataLoader().load_rrt()
|
|
||||||
else:
|
|
||||||
ExampleDataLoader().load_test_data()
|
|
||||||
|
|
||||||
# If in production mode, only add the first user.
|
# If in production mode, only add the first user.
|
||||||
if app.config['PRODUCTION']:
|
if app.config['PRODUCTION']:
|
||||||
session.add(UserModel(**self.users[0]))
|
session.add(UserModel(**self.users[0]))
|
||||||
|
@ -162,6 +155,13 @@ class BaseTest(unittest.TestCase):
|
||||||
for user_json in self.users:
|
for user_json in self.users:
|
||||||
session.add(UserModel(**user_json))
|
session.add(UserModel(**user_json))
|
||||||
|
|
||||||
|
if use_crc_data:
|
||||||
|
ExampleDataLoader().load_all()
|
||||||
|
elif use_rrt_data:
|
||||||
|
ExampleDataLoader().load_rrt()
|
||||||
|
else:
|
||||||
|
ExampleDataLoader().load_test_data()
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
for study_json in self.studies:
|
for study_json in self.studies:
|
||||||
study_model = StudyModel(**study_json)
|
study_model = StudyModel(**study_json)
|
||||||
|
|
|
@ -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_3fd9241" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||||
|
<bpmn:process id="Process_9d7b2c2" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_17nzcku</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_17nzcku" sourceRef="StartEvent_1" targetRef="Activity_GetCheckStudy" />
|
||||||
|
<bpmn:scriptTask id="Activity_GetCheckStudy" name="Get Check Study">
|
||||||
|
<bpmn:incoming>Flow_17nzcku</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0oozrfg</bpmn:outgoing>
|
||||||
|
<bpmn:script>check_study = check_study()</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0oozrfg" sourceRef="Activity_GetCheckStudy" targetRef="Activity_DisplayCheckStudy" />
|
||||||
|
<bpmn:manualTask id="Activity_DisplayCheckStudy" name="Display Check Study">
|
||||||
|
<bpmn:documentation># Check Study
|
||||||
|
<div><span>{{check_study}}</span></div></bpmn:documentation>
|
||||||
|
<bpmn:incoming>Flow_0oozrfg</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_10sc31i</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
<bpmn:endEvent id="Event_0embsc7">
|
||||||
|
<bpmn:incoming>Flow_10sc31i</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_10sc31i" sourceRef="Activity_DisplayCheckStudy" targetRef="Event_0embsc7" />
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_9d7b2c2">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_10sc31i_di" bpmnElement="Flow_10sc31i">
|
||||||
|
<di:waypoint x="530" y="177" />
|
||||||
|
<di:waypoint x="592" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0oozrfg_di" bpmnElement="Flow_0oozrfg">
|
||||||
|
<di:waypoint x="370" y="177" />
|
||||||
|
<di:waypoint x="430" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_17nzcku_di" bpmnElement="Flow_17nzcku">
|
||||||
|
<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="Activity_1f9d5ew_di" bpmnElement="Activity_GetCheckStudy">
|
||||||
|
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_01vscea_di" bpmnElement="Activity_DisplayCheckStudy">
|
||||||
|
<dc:Bounds x="430" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_0embsc7_di" bpmnElement="Event_0embsc7">
|
||||||
|
<dc:Bounds x="592" y="159" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -0,0 +1,3 @@
|
||||||
|
[
|
||||||
|
{"DETAIL": "Passed validation.", "STATUS": "No Error"}
|
||||||
|
]
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?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" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_8983dae" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||||
|
<bpmn:process id="Process_2a4c7a5" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_13jyds8</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_13jyds8" sourceRef="StartEvent_1" targetRef="Activity_GetData" />
|
||||||
|
<bpmn:endEvent id="Event_03x966p">
|
||||||
|
<bpmn:incoming>Flow_18kybym</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_18kybym" sourceRef="Activity_RunScript" targetRef="Event_03x966p" />
|
||||||
|
<bpmn:scriptTask id="Activity_RunScript" name="Run Script">
|
||||||
|
<bpmn:incoming>Flow_1jqzan6</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_18kybym</bpmn:outgoing>
|
||||||
|
<bpmn:script>print(ham)</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_1jqzan6" sourceRef="Activity_GetData" targetRef="Activity_RunScript" />
|
||||||
|
<bpmn:userTask id="Activity_GetData" name="Get Data" camunda:formKey="DataForm">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:formData>
|
||||||
|
<camunda:formField id="user" label="User" type="string" defaultValue="World" />
|
||||||
|
<camunda:formField id="spam" label="Spam" type="boolean" defaultValue="False" />
|
||||||
|
</camunda:formData>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_13jyds8</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_1jqzan6</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_2a4c7a5">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_18kybym_di" bpmnElement="Flow_18kybym">
|
||||||
|
<di:waypoint x="370" y="177" />
|
||||||
|
<di:waypoint x="432" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_13jyds8_di" bpmnElement="Flow_13jyds8">
|
||||||
|
<di:waypoint x="48" y="177" />
|
||||||
|
<di:waypoint x="90" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1jqzan6_di" bpmnElement="Flow_1jqzan6">
|
||||||
|
<di:waypoint x="190" y="177" />
|
||||||
|
<di:waypoint x="270" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNShape id="Event_03x966p_di" bpmnElement="Event_03x966p">
|
||||||
|
<dc:Bounds x="432" y="159" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1d9d2u8_di" bpmnElement="Activity_RunScript">
|
||||||
|
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||||
|
<dc:Bounds x="12" y="159" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_10ypwag_di" bpmnElement="Activity_GetData">
|
||||||
|
<dc:Bounds x="90" y="137" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -126,6 +126,7 @@ class TestFilesApi(BaseTest):
|
||||||
self.assertEqual(FileType.xlsx, file.type)
|
self.assertEqual(FileType.xlsx, file.type)
|
||||||
self.assertTrue(file.is_reference)
|
self.assertTrue(file.is_reference)
|
||||||
self.assertEqual("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.content_type)
|
self.assertEqual("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", file.content_type)
|
||||||
|
self.assertEqual('dhf8r', json_data['user_uid'])
|
||||||
|
|
||||||
def test_set_reference_file_bad_extension(self):
|
def test_set_reference_file_bad_extension(self):
|
||||||
file_name = DocumentService.DOCUMENT_LIST
|
file_name = DocumentService.DOCUMENT_LIST
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
from tests.base_test import BaseTest
|
||||||
|
from crc import app
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
class TestCheckStudy(BaseTest):
|
||||||
|
|
||||||
|
def test_check_study_script_validation(self):
|
||||||
|
self.load_example_data()
|
||||||
|
spec_model = self.load_test_spec('check_study_script')
|
||||||
|
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
|
||||||
|
self.assertEqual([], rv.json)
|
||||||
|
|
||||||
|
@patch('crc.services.protocol_builder.requests.get')
|
||||||
|
def test_check_study(self, mock_get):
|
||||||
|
app.config['PB_ENABLED'] = True
|
||||||
|
app.config['PB_ENABLED'] = True
|
||||||
|
mock_get.return_value.ok = True
|
||||||
|
mock_get.return_value.text = self.protocol_builder_response('check_study.json')
|
||||||
|
workflow = self.create_workflow('check_study_script')
|
||||||
|
workflow_api = self.get_workflow_api(workflow)
|
||||||
|
task = workflow_api.next_task
|
||||||
|
|
||||||
|
self.assertIn('DETAIL', task.documentation)
|
||||||
|
self.assertIn('STATUS', task.documentation)
|
|
@ -72,3 +72,13 @@ class TestProtocolBuilder(BaseTest):
|
||||||
self.assertEqual('IRB Event 1', response[0]["IRBEVENT"])
|
self.assertEqual('IRB Event 1', response[0]["IRBEVENT"])
|
||||||
self.assertEqual('IRB Event 2', response[1]["IRBEVENT"])
|
self.assertEqual('IRB Event 2', response[1]["IRBEVENT"])
|
||||||
self.assertEqual('IRB Event 3', response[2]["IRBEVENT"])
|
self.assertEqual('IRB Event 3', response[2]["IRBEVENT"])
|
||||||
|
|
||||||
|
@patch('crc.services.protocol_builder.requests.get')
|
||||||
|
def test_check_study(self, mock_get):
|
||||||
|
app.config['PB_ENABLED'] = True
|
||||||
|
mock_get.return_value.ok = True
|
||||||
|
mock_get.return_value.text = self.protocol_builder_response('check_study.json')
|
||||||
|
response = ProtocolBuilderService.check_study(self.test_study_id)
|
||||||
|
self.assertIsNotNone(response)
|
||||||
|
self.assertIn('DETAIL', response[0].keys())
|
||||||
|
self.assertIn('STATUS', response[0].keys())
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from tests.base_test import BaseTest
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class TestNameErrorHint(BaseTest):
|
||||||
|
|
||||||
|
def test_name_error_hint(self):
|
||||||
|
self.load_example_data()
|
||||||
|
spec_model = self.load_test_spec('script_with_name_error')
|
||||||
|
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
|
||||||
|
json_data = json.loads(rv.get_data(as_text=True))
|
||||||
|
self.assertIn('Did you mean \'[\'spam\'', json_data[0]['message'])
|
Loading…
Reference in New Issue