Refactor models into seperate directories
This commit is contained in:
parent
cc33f686e5
commit
c4cbaeb64e
|
@ -147,7 +147,7 @@ paths:
|
|||
operationId: crc.api.workflow.all_specifications
|
||||
summary: Provides a list of workflows specifications that can be added to a study manually. Please note that Protocol Builder will handle this most of the time.
|
||||
tags:
|
||||
- Workflow
|
||||
- Workflows and Tasks
|
||||
responses:
|
||||
'200':
|
||||
description: An array of workflow specifications
|
||||
|
@ -424,6 +424,11 @@ paths:
|
|||
|
||||
components:
|
||||
schemas:
|
||||
DataModel:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
|
||||
Study:
|
||||
properties:
|
||||
id:
|
||||
|
|
|
@ -7,7 +7,7 @@ from flask import send_file
|
|||
|
||||
from crc import db
|
||||
from crc.api.common import ApiErrorSchema, ApiError
|
||||
from crc.models import FileSchema, FileModel, FileDataModel, FileType
|
||||
from crc.models.file import FileSchema, FileModel, FileDataModel, FileType
|
||||
|
||||
|
||||
def update_file_from_request(file_model):
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
import os
|
||||
from datetime import datetime
|
||||
|
||||
import connexion
|
||||
from connexion import NoContent
|
||||
from flask_marshmallow import Schema
|
||||
|
||||
from crc import db, ma, connexion_app
|
||||
from crc import db
|
||||
from crc.api.common import ApiError, ApiErrorSchema
|
||||
from crc.models import WorkflowModel, WorkflowSchema, StudySchema, StudyModel, WorkflowSpecSchema, WorkflowSpecModel, \
|
||||
WorkflowStatus, Task, TaskSchema, FileSchema, FileModel, FileDataModel, FileType
|
||||
from crc.models.study import StudySchema, StudyModel
|
||||
from crc.models.workflow import WorkflowModel, WorkflowSchema, WorkflowSpecModel
|
||||
from crc.workflow_processor import WorkflowProcessor
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from crc import db
|
||||
from crc.models import WorkflowModel, WorkflowSchema, WorkflowSpecSchema, WorkflowSpecModel, \
|
||||
from crc.models.workflow import WorkflowModel, WorkflowSchema, WorkflowSpecSchema, WorkflowSpecModel, \
|
||||
Task, TaskSchema
|
||||
from crc.workflow_processor import WorkflowProcessor
|
||||
|
||||
|
@ -36,7 +36,9 @@ def get_task(workflow_id, task_id):
|
|||
|
||||
|
||||
def update_task(workflow_id, task_id, body):
|
||||
global bpmn_workflow
|
||||
for field in body["task"]["form"]:
|
||||
print("Setting " + field["id"] + " to " + field["value"])
|
||||
workflow_spec_model = db.session.query(WorkflowSpecModel).filter_by(id=body["id"]).first()
|
||||
task = TaskSchema().load(body)
|
||||
if task.form:
|
||||
for field in task.form["fields"]:
|
||||
print("Setting " + field["id"] + " to " + field["value"])
|
||||
return body
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import enum
|
||||
|
||||
from flask_marshmallow.sqla import ModelSchema
|
||||
from marshmallow_enum import EnumField
|
||||
from sqlalchemy import func
|
||||
|
||||
from crc import db
|
||||
|
||||
|
||||
class FileType(enum.Enum):
|
||||
bpmn = "bpmm"
|
||||
svg = "svg"
|
||||
dmn = "dmn"
|
||||
|
||||
|
||||
class FileDataModel(db.Model):
|
||||
__tablename__ = 'file_data'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
data = db.Column(db.LargeBinary)
|
||||
file_model_id = db.Column(db.Integer, db.ForeignKey('file.id'))
|
||||
file_model = db.relationship("FileModel")
|
||||
|
||||
class FileModel(db.Model):
|
||||
__tablename__ = 'file'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String)
|
||||
version = db.Column(db.Integer, default=0)
|
||||
last_updated = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||
type = db.Column(db.Enum(FileType))
|
||||
primary = db.Column(db.Boolean)
|
||||
content_type = db.Column(db.String)
|
||||
workflow_spec_id = db.Column(db.Integer, db.ForeignKey('workflow_spec.id'))
|
||||
|
||||
|
||||
class FileSchema(ModelSchema):
|
||||
class Meta:
|
||||
model = FileModel
|
||||
type = EnumField(FileType)
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import enum
|
||||
|
||||
from marshmallow_enum import EnumField
|
||||
from marshmallow_sqlalchemy import ModelSchema
|
||||
from sqlalchemy import func
|
||||
|
||||
from crc import db
|
||||
|
||||
|
||||
class ProtocolBuilderStatus(enum.Enum):
|
||||
out_of_date = "out_of_date"
|
||||
in_process = "in_process"
|
||||
complete = "complete"
|
||||
updating = "updating"
|
||||
|
||||
|
||||
class StudyModel(db.Model):
|
||||
__tablename__ = 'study'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
title = db.Column(db.String)
|
||||
last_updated = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||
protocol_builder_status = db.Column(db.Enum(ProtocolBuilderStatus))
|
||||
primary_investigator_id = db.Column(db.String)
|
||||
sponsor = db.Column(db.String)
|
||||
ind_number = db.Column(db.String)
|
||||
|
||||
|
||||
class StudySchema(ModelSchema):
|
||||
class Meta:
|
||||
model = StudyModel
|
||||
|
||||
protocol_builder_status = EnumField(ProtocolBuilderStatus)
|
|
@ -1,39 +1,12 @@
|
|||
import enum
|
||||
|
||||
from SpiffWorkflow import Task
|
||||
from flask_marshmallow.sqla import ModelSchema
|
||||
from marshmallow import post_load, fields
|
||||
import marshmallow
|
||||
from marshmallow_enum import EnumField
|
||||
from sqlalchemy import func
|
||||
from marshmallow_sqlalchemy import ModelSchema
|
||||
|
||||
from crc import db, ma
|
||||
|
||||
|
||||
class ProtocolBuilderStatus(enum.Enum):
|
||||
out_of_date = "out_of_date"
|
||||
in_process = "in_process"
|
||||
complete = "complete"
|
||||
updating = "updating"
|
||||
|
||||
|
||||
class StudyModel(db.Model):
|
||||
__tablename__ = 'study'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
title = db.Column(db.String)
|
||||
last_updated = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||
protocol_builder_status = db.Column(db.Enum(ProtocolBuilderStatus))
|
||||
primary_investigator_id = db.Column(db.String)
|
||||
sponsor = db.Column(db.String)
|
||||
ind_number = db.Column(db.String)
|
||||
|
||||
|
||||
class StudySchema(ModelSchema):
|
||||
class Meta:
|
||||
model = StudyModel
|
||||
|
||||
protocol_builder_status = EnumField(ProtocolBuilderStatus)
|
||||
|
||||
|
||||
class WorkflowSpecModel(db.Model):
|
||||
__tablename__ = 'workflow_spec'
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
|
@ -45,38 +18,6 @@ class WorkflowSpecSchema(ModelSchema):
|
|||
class Meta:
|
||||
model = WorkflowSpecModel
|
||||
|
||||
|
||||
class FileType(enum.Enum):
|
||||
bpmn = "bpmm"
|
||||
svg = "svg"
|
||||
dmn = "dmn"
|
||||
|
||||
|
||||
class FileDataModel(db.Model):
|
||||
__tablename__ = 'file_data'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
data = db.Column(db.LargeBinary)
|
||||
file_model_id = db.Column(db.Integer, db.ForeignKey('file.id'))
|
||||
file_model = db.relationship("FileModel")
|
||||
|
||||
class FileModel(db.Model):
|
||||
__tablename__ = 'file'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String)
|
||||
version = db.Column(db.Integer, default=0)
|
||||
last_updated = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||
type = db.Column(db.Enum(FileType))
|
||||
primary = db.Column(db.Boolean)
|
||||
content_type = db.Column(db.String)
|
||||
workflow_spec_id = db.Column(db.Integer, db.ForeignKey('workflow_spec.id'))
|
||||
|
||||
|
||||
class FileSchema(ModelSchema):
|
||||
class Meta:
|
||||
model = FileModel
|
||||
type = EnumField(FileType)
|
||||
|
||||
|
||||
class WorkflowStatus(enum.Enum):
|
||||
new = "new"
|
||||
user_input_required = "user_input_required"
|
||||
|
@ -140,30 +81,28 @@ class PropertiesSchema(ma.Schema):
|
|||
fields = ["id", "value"]
|
||||
|
||||
|
||||
class FieldSchema(ma.Schema):
|
||||
class FormFieldSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = [
|
||||
"id", "type", "label", "defaultValue", "options", "validation", "properties"
|
||||
"id", "type", "label", "defaultValue", "options", "validation", "properties", "value"
|
||||
]
|
||||
|
||||
options = fields.List(fields.Nested(OptionSchema))
|
||||
validation = fields.List(fields.Nested(ValidationSchema))
|
||||
properties = fields.List(fields.Nested(PropertiesSchema))
|
||||
options = marshmallow.fields.List(marshmallow.fields.Nested(OptionSchema))
|
||||
validation = marshmallow.fields.List(marshmallow.fields.Nested(ValidationSchema))
|
||||
properties = marshmallow.fields.List(marshmallow.fields.Nested(PropertiesSchema))
|
||||
|
||||
|
||||
class FormSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["key", "fields"]
|
||||
|
||||
fields = fields.List(fields.Nested(FieldSchema))
|
||||
key = marshmallow.fields.String(required=True, allow_none=False)
|
||||
fields = marshmallow.fields.List(marshmallow.fields.Nested(FormFieldSchema))
|
||||
|
||||
|
||||
class TaskSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "name", "title", "type", "state", "form", "documentation"]
|
||||
documentation = marshmallow.fields.String(required=False, allow_none=True)
|
||||
form = marshmallow.fields.Nested(FormSchema)
|
||||
|
||||
form = fields.Nested(FormSchema)
|
||||
|
||||
@post_load
|
||||
@marshmallow.post_load
|
||||
def make_task(self, data, **kwargs):
|
||||
return Task(**data)
|
|
@ -95,7 +95,7 @@
|
|||
<dc:Bounds x="270" y="210" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="ScriptTask_10keafb_di" bpmnElement="Task_Get_Fact_From_API">
|
||||
<dc:Bounds x="480" y="210" width="100" height="80" />
|
||||
<dc:Bounds x="470" y="210" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="TextAnnotation_09fq7kh_di" bpmnElement="TextAnnotation_09fq7kh">
|
||||
<dc:Bounds x="330" y="116" width="99.99202297383536" height="68.28334396936822" />
|
||||
|
@ -108,19 +108,19 @@
|
|||
<dc:Bounds x="570" y="120" width="100" height="68" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Association_1qirnyy_di" bpmnElement="Association_1qirnyy">
|
||||
<di:waypoint x="567" y="210" />
|
||||
<di:waypoint x="588" y="188" />
|
||||
<di:waypoint x="561" y="210" />
|
||||
<di:waypoint x="584" y="188" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="EndEvent_0u1cgrf_di" bpmnElement="EndEvent_0u1cgrf">
|
||||
<dc:Bounds x="692" y="232" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0am07in_di" bpmnElement="SequenceFlow_0am07in">
|
||||
<di:waypoint x="580" y="250" />
|
||||
<di:waypoint x="570" y="250" />
|
||||
<di:waypoint x="692" y="250" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1291h6i_di" bpmnElement="SequenceFlow_1291h6i">
|
||||
<di:waypoint x="370" y="250" />
|
||||
<di:waypoint x="480" y="250" />
|
||||
<di:waypoint x="470" y="250" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
|
@ -1,14 +1,14 @@
|
|||
import os
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
|
||||
from SpiffWorkflow.bpmn.BpmnScriptEngine import BpmnScriptEngine
|
||||
from SpiffWorkflow.bpmn.serializer.CompactWorkflowSerializer import CompactWorkflowSerializer
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
|
||||
from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser
|
||||
from SpiffWorkflow.camunda.serializer.CamundaSerializer import CamundaSerializer
|
||||
|
||||
from crc import app, db
|
||||
from crc.models import WorkflowStatus, WorkflowSpecModel, FileDataModel, FileModel
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
from crc import db
|
||||
from crc.models.file import FileDataModel, FileModel
|
||||
from crc.models.workflow import WorkflowStatus
|
||||
|
||||
|
||||
class CustomBpmnScriptEngine(BpmnScriptEngine):
|
||||
"""This is a custom script processor that can be easily injected into Spiff Workflow.
|
||||
|
|
|
@ -2,7 +2,9 @@ import datetime
|
|||
import os
|
||||
|
||||
from crc import db, app
|
||||
from crc.models import StudyModel, WorkflowSpecModel, FileType, FileModel, FileDataModel
|
||||
from crc.models.study import StudyModel
|
||||
from crc.models.workflow import WorkflowSpecModel
|
||||
from crc.models.file import FileType, FileModel, FileDataModel
|
||||
|
||||
|
||||
class ExampleDataLoader:
|
||||
|
@ -28,31 +30,33 @@ class ExampleDataLoader:
|
|||
),
|
||||
]
|
||||
|
||||
workflow_specs = [WorkflowSpecModel(
|
||||
id="random_fact",
|
||||
display_name="Random Fact Generator",
|
||||
description='Displays a random fact about a topic of your choosing.',
|
||||
)]
|
||||
workflow_specifications = \
|
||||
self.create_spec(id="random_fact",
|
||||
display_name="Random Fact Generator",
|
||||
description='Displays a random fact about a topic of your choosing.')
|
||||
workflow_specifications += \
|
||||
self.create_spec(id="two_forms",
|
||||
display_name="Two dump questions on two seperate tasks",
|
||||
description='Displays a random fact about a topic of your choosing.')
|
||||
|
||||
workflow_spec_files = [WorkflowSpecModel(
|
||||
id="random_fact",
|
||||
display_name="Random Fact Generator",
|
||||
description='Displays a random fact about a topic of your choosing.',
|
||||
)]
|
||||
|
||||
workflow_spec_files = [FileModel(name="random_fact.bpmn",
|
||||
type=FileType.bpmn,
|
||||
version="1",
|
||||
last_updated=datetime.datetime.now(),
|
||||
primary=True,
|
||||
workflow_spec_id=workflow_specs[0].id)]
|
||||
|
||||
filename = os.path.join(app.root_path, 'static', 'bpmn', 'random_fact', 'random_fact.bpmn')
|
||||
file = open(filename, "rb")
|
||||
workflow_data = [FileDataModel(data=file.read(), file_model=workflow_spec_files[0])]
|
||||
all_data = studies+workflow_specs+workflow_spec_files+workflow_data
|
||||
all_data = studies + workflow_specifications
|
||||
return all_data
|
||||
|
||||
def create_spec(self, id, display_name, description):
|
||||
"""Assumes that a file exists in static/bpmn with the same name as the given id.
|
||||
returns an array of data models to be added to the database."""
|
||||
spec = WorkflowSpecModel(id=id,
|
||||
display_name=display_name,
|
||||
description=description)
|
||||
file_model = FileModel(name=id + ".bpmn", type=FileType.bpmn, version="1",
|
||||
last_updated=datetime.datetime.now(), primary=True,
|
||||
workflow_spec_id=id)
|
||||
filename = os.path.join(app.root_path, 'static', 'bpmn', id + ".bpmn")
|
||||
file = open(filename, "rb")
|
||||
workflow_data = FileDataModel(data=file.read(), file_model=file_model)
|
||||
file.close()
|
||||
return [spec, file_model, workflow_data]
|
||||
|
||||
@staticmethod
|
||||
def clean_db():
|
||||
db.session.flush() # Clear out any transactions before deleting it all to avoid spurious errors.
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import json
|
||||
import unittest
|
||||
|
||||
from sqlalchemy import func
|
||||
|
||||
from crc import db
|
||||
from crc.models import StudyModel, StudySchema, WorkflowSpecModel, WorkflowSpecSchema, WorkflowModel, WorkflowStatus, \
|
||||
from crc.models.study import StudyModel, StudySchema
|
||||
from crc.models.workflow import WorkflowSpecModel, WorkflowSpecSchema, WorkflowModel, WorkflowStatus, \
|
||||
WorkflowSchema, TaskSchema
|
||||
from crc.workflow_processor import WorkflowProcessor
|
||||
from tests.base_test import BaseTest
|
||||
|
||||
|
||||
|
@ -81,7 +79,6 @@ class TestStudy(BaseTest, unittest.TestCase):
|
|||
self.assert_success(rv)
|
||||
self.assertEqual(0, db.session.query(WorkflowModel).count())
|
||||
|
||||
|
||||
def test_get_current_user_tasks(self):
|
||||
self.load_example_data()
|
||||
study = db.session.query(StudyModel).first()
|
||||
|
@ -93,4 +90,24 @@ class TestStudy(BaseTest, unittest.TestCase):
|
|||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
tasks = TaskSchema(many=True).load(json_data)
|
||||
self.assertEqual("Task_User_Select_Type", tasks[0].name)
|
||||
self.assertEqual(3, len(tasks[0].form["fields"][0]["options"]))
|
||||
self.assertEqual(3, len(tasks[0].form["fields"][0]["options"]))
|
||||
|
||||
def test_two_forms_task(self):
|
||||
self.load_example_data()
|
||||
study = db.session.query(StudyModel).first()
|
||||
spec = db.session.query(WorkflowSpecModel).filter_by(id='two_forms').first()
|
||||
rv = self.app.post('/v1.0/study/%i/workflows' % study.id, content_type="application/json",
|
||||
data=json.dumps(WorkflowSpecSchema().dump(spec)))
|
||||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
workflow = WorkflowSchema().load(json_data, session=db.session)
|
||||
|
||||
rv = self.app.get('/v1.0/workflow/%i/tasks' % workflow.id, content_type="application/json")
|
||||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
tasks = TaskSchema(many=True).load(json_data)
|
||||
self.assertEqual(1, len(tasks))
|
||||
self.assertIsNotNone(tasks[0].form)
|
||||
self.assertEqual(1, len(tasks[0].form['fields']))
|
||||
tasks[0].form['fields'][0]['value']="Blue"
|
||||
rv = self.app.put('/v1.0/workflow/%i/task/%s' % (workflow.id, tasks[0].id), content_type="application/json",
|
||||
data=json.dumps(TaskSchema().dump(tasks[0])))
|
||||
self.assert_success(rv)
|
||||
|
|
|
@ -4,7 +4,8 @@ import unittest
|
|||
from datetime import datetime
|
||||
|
||||
from crc import db
|
||||
from crc.models import WorkflowSpecModel, FileModel, FileType, FileSchema, FileDataModel
|
||||
from crc.models.workflow import WorkflowSpecModel
|
||||
from crc.models.file import FileModel, FileType, FileSchema, FileDataModel
|
||||
from tests.base_test import BaseTest
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import unittest
|
||||
|
||||
from crc import db
|
||||
from crc.models import WorkflowSpecModel, WorkflowStatus
|
||||
from crc.models.workflow import WorkflowSpecModel, WorkflowStatus
|
||||
from crc.workflow_processor import WorkflowProcessor
|
||||
from tests.base_test import BaseTest
|
||||
|
||||
|
@ -31,3 +31,13 @@ class TestWorkflowProcessor(BaseTest, unittest.TestCase):
|
|||
data = processor.get_data()
|
||||
self.assertIsNotNone(data)
|
||||
self.assertIn("details", data)
|
||||
|
||||
def test_two_forms(self):
|
||||
self.load_example_data()
|
||||
workflow_spec_model = db.session.query(WorkflowSpecModel).filter_by(id="two_forms").first()
|
||||
processor = WorkflowProcessor.create(workflow_spec_model.id)
|
||||
self.assertEqual(WorkflowStatus.user_input_required, processor.get_status())
|
||||
next_user_tasks = processor.next_user_tasks()
|
||||
task = next_user_tasks[0]
|
||||
data = processor.get_data()
|
||||
|
||||
|
|
Loading…
Reference in New Issue