Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
8672a88116
|
@ -2,6 +2,7 @@ import logging
|
|||
import os
|
||||
|
||||
import connexion
|
||||
from flask_cors import CORS
|
||||
from flask_marshmallow import Marshmallow
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
|
@ -26,6 +27,7 @@ ma = Marshmallow(app)
|
|||
from crc import models
|
||||
|
||||
connexion_app.add_api('api.yml')
|
||||
cors = CORS(connexion_app.app)
|
||||
|
||||
@app.cli.command()
|
||||
def load_example_data():
|
||||
|
|
17
crc/api.py
17
crc/api.py
|
@ -3,7 +3,7 @@ from flask_marshmallow import Schema
|
|||
|
||||
from crc import db, ma
|
||||
from crc.models import WorkflowModel, WorkflowSchema, StudySchema, StudyModel, WorkflowSpecSchema, WorkflowSpecModel, \
|
||||
WorkflowStatus
|
||||
WorkflowStatus, Task, TaskSchema
|
||||
from crc.workflow_processor import WorkflowProcessor
|
||||
|
||||
|
||||
|
@ -61,11 +61,24 @@ def add_workflow_to_study(study_id, body):
|
|||
workflow_spec_id=workflow_spec_model.id)
|
||||
db.session.add(workflow)
|
||||
db.session.commit()
|
||||
return get_study_workflows(study_id)
|
||||
|
||||
|
||||
def get_workflow(workflow_id):
|
||||
return db.session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||
schema = WorkflowSchema()
|
||||
workflow = db.session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||
return schema.dump(workflow)
|
||||
|
||||
|
||||
def get_tasks(workflow_id):
|
||||
workflow = db.session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||
processor = WorkflowProcessor(workflow.workflow_spec_id, workflow.bpmn_workflow_json)
|
||||
spiff_tasks = processor.get_ready_user_tasks()
|
||||
tasks = []
|
||||
for st in spiff_tasks:
|
||||
tasks.append(Task.from_spiff(st))
|
||||
return TaskSchema(many=True).dump(tasks)
|
||||
|
||||
def get_task(workflow_id, task_id):
|
||||
workflow = db.session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||
return workflow.bpmn_workflow().get_task(task_id)
|
||||
|
|
57
crc/api.yml
57
crc/api.yml
|
@ -192,7 +192,35 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
/workflow/{workflow_id}/tasks:
|
||||
get:
|
||||
operationId: crc.api.get_tasks
|
||||
summary: Return a list of all tasks for this workflow
|
||||
tags:
|
||||
- Workflows and Tasks
|
||||
parameters:
|
||||
- name: workflow_id
|
||||
in: path
|
||||
required: true
|
||||
description: The id of the workflow
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: Expected response to a valid request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Task"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
# /v1.0/workflow/0/task/0
|
||||
/workflow/{workflow_id}/task/{task_id}:
|
||||
get:
|
||||
|
@ -265,19 +293,10 @@ paths:
|
|||
components:
|
||||
schemas:
|
||||
Study:
|
||||
required:
|
||||
- id
|
||||
- title
|
||||
- last_updated
|
||||
- pb_status
|
||||
- pi
|
||||
- sponsor
|
||||
- ind_number
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: string
|
||||
example: AB1234
|
||||
type: integer
|
||||
example: 1234
|
||||
title:
|
||||
type: string
|
||||
example: The impact of fried pickles on beer consumption in bipedal software developers.
|
||||
|
@ -285,11 +304,11 @@ components:
|
|||
type: string
|
||||
format: date_time
|
||||
example: "2019-12-25T09:12:33.001Z"
|
||||
pb_status:
|
||||
protocol_builder_status:
|
||||
type: string
|
||||
enum: [started, done]
|
||||
enum: [out_of_date, in_process, complete, updating]
|
||||
example: done
|
||||
pi:
|
||||
primary_investigator_id:
|
||||
type: string
|
||||
example: dhf8r
|
||||
sponsor:
|
||||
|
@ -356,16 +375,20 @@ components:
|
|||
type: string
|
||||
type:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
form:
|
||||
$ref: "#/components/schemas/Form"
|
||||
example:
|
||||
{
|
||||
id: study_identification,
|
||||
name: "Study Identification",
|
||||
type: form,
|
||||
state: "ready",
|
||||
type: "form",
|
||||
form: {
|
||||
key: "oncology_form",
|
||||
field: {
|
||||
id: adult_oncology,
|
||||
id: "is_adult_patient",
|
||||
type: enum,
|
||||
label: "Is this study treating adult oncology patients?",
|
||||
options: ["yes", "no"],
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import enum
|
||||
|
||||
from SpiffWorkflow import Task
|
||||
from flask_marshmallow.sqla import ModelSchema
|
||||
from marshmallow import post_load, fields, Schema
|
||||
from marshmallow_enum import EnumField
|
||||
from sqlalchemy import func
|
||||
|
||||
from crc import db
|
||||
from crc import db, ma
|
||||
|
||||
|
||||
class ProtocolBuilderStatus(enum.Enum):
|
||||
|
@ -56,10 +58,58 @@ class WorkflowModel(db.Model):
|
|||
study_id = db.Column(db.Integer, db.ForeignKey('study.id'))
|
||||
workflow_spec_id = db.Column(db.Integer, db.ForeignKey('workflow_spec.id'))
|
||||
|
||||
|
||||
class WorkflowSchema(ModelSchema):
|
||||
class Meta:
|
||||
model = WorkflowModel
|
||||
status = EnumField(WorkflowStatus)
|
||||
|
||||
|
||||
class Task:
|
||||
def __init__(self, id, name, type, state, form):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.state = state
|
||||
self.form = form
|
||||
|
||||
@classmethod
|
||||
def from_spiff(cls, spiff_task):
|
||||
instance = cls(spiff_task.id,
|
||||
spiff_task.task_spec.name,
|
||||
spiff_task.get_state_name(),
|
||||
"task",
|
||||
{})
|
||||
if hasattr(spiff_task.task_spec, "form"):
|
||||
instance.type = "form"
|
||||
instance.form = spiff_task.task_spec.form
|
||||
return instance
|
||||
|
||||
|
||||
class OptionSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "name"]
|
||||
|
||||
|
||||
class FieldSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "type", "label", "defaultValue", "options"]
|
||||
options = fields.List(fields.Nested(OptionSchema))
|
||||
|
||||
|
||||
class FormSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["key", "fields"]
|
||||
fields = fields.List(fields.Nested(FieldSchema))
|
||||
|
||||
|
||||
class TaskSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ["id", "name", "type", "state", "form"]
|
||||
|
||||
form = fields.Nested(FormSchema)
|
||||
@post_load
|
||||
def make_task(self, data, **kwargs):
|
||||
return Task(**data)
|
||||
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class WorkflowProcessor:
|
|||
self.bpmn_workflow.do_engine_steps()
|
||||
|
||||
def serialize(self):
|
||||
return self.bpmn_workflow.serialize(JSONSerializer())
|
||||
return self._serializer.serialize_workflow(self.bpmn_workflow)
|
||||
|
||||
def next_user_tasks(self):
|
||||
return self.bpmn_workflow.get_ready_user_tasks()
|
||||
|
@ -77,3 +77,6 @@ class WorkflowProcessor:
|
|||
|
||||
def get_data(self):
|
||||
return self.bpmn_workflow.data
|
||||
|
||||
def get_ready_user_tasks(self):
|
||||
return self.bpmn_workflow.get_ready_user_tasks()
|
||||
|
|
|
@ -4,7 +4,9 @@ import unittest
|
|||
from sqlalchemy import func
|
||||
|
||||
from crc import db
|
||||
from crc.models import StudyModel, StudySchema, WorkflowSpecModel, WorkflowSpecSchema, WorkflowModel, WorkflowStatus
|
||||
from crc.models import StudyModel, StudySchema, WorkflowSpecModel, WorkflowSpecSchema, WorkflowModel, WorkflowStatus, \
|
||||
WorkflowSchema, TaskSchema
|
||||
from crc.workflow_processor import WorkflowProcessor
|
||||
from tests.base_test import BaseTest
|
||||
|
||||
|
||||
|
@ -62,3 +64,19 @@ class TestStudy(BaseTest, unittest.TestCase):
|
|||
self.assertIsNotNone(workflow.bpmn_workflow_json)
|
||||
self.assertEqual(spec.id, workflow.workflow_spec_id)
|
||||
|
||||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
workflows = WorkflowSchema(many=True).load(json_data, session=db.session)
|
||||
self.assertEqual(workflows[0].id, workflow.id)
|
||||
|
||||
def test_get_current_user_tasks(self):
|
||||
self.load_example_data()
|
||||
study = db.session.query(StudyModel).first()
|
||||
spec = db.session.query(WorkflowSpecModel).filter_by(id='random_fact').first()
|
||||
self.app.post('/v1.0/study/%i/workflows' % study.id, content_type="application/json",
|
||||
data=json.dumps(WorkflowSpecSchema().dump(spec)))
|
||||
rv = self.app.get('/v1.0/workflow/%i/tasks' % study.id, content_type="application/json")
|
||||
self.assert_success(rv)
|
||||
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"]))
|
Loading…
Reference in New Issue