Merge pull request #253 from sartography/220-short-study-name
Add short_title to study, change update_study task to use kw argument…
This commit is contained in:
commit
9c31d69c12
|
@ -40,6 +40,7 @@ class StudyModel(db.Model):
|
||||||
__tablename__ = 'study'
|
__tablename__ = 'study'
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
title = db.Column(db.String)
|
title = db.Column(db.String)
|
||||||
|
short_title = db.Column(db.String, nullable=True)
|
||||||
last_updated = db.Column(db.DateTime(timezone=True), default=func.now())
|
last_updated = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||||
status = db.Column(db.Enum(StudyStatus))
|
status = db.Column(db.Enum(StudyStatus))
|
||||||
irb_status = db.Column(db.Enum(IrbStatus))
|
irb_status = db.Column(db.Enum(IrbStatus))
|
||||||
|
@ -161,7 +162,7 @@ class CategorySchema(ma.Schema):
|
||||||
|
|
||||||
class Study(object):
|
class Study(object):
|
||||||
|
|
||||||
def __init__(self, title, last_updated, primary_investigator_id, user_uid,
|
def __init__(self, title, short_title, last_updated, primary_investigator_id, user_uid,
|
||||||
id=None, status=None, irb_status=None, comment="",
|
id=None, status=None, irb_status=None, comment="",
|
||||||
sponsor="", hsr_number="", ind_number="", categories=[],
|
sponsor="", hsr_number="", ind_number="", categories=[],
|
||||||
files=[], approvals=[], enrollment_date=None, events_history=[],
|
files=[], approvals=[], enrollment_date=None, events_history=[],
|
||||||
|
@ -172,6 +173,7 @@ class Study(object):
|
||||||
self.last_activity_date = last_activity_date
|
self.last_activity_date = last_activity_date
|
||||||
self.last_activity_user = last_activity_user
|
self.last_activity_user = last_activity_user
|
||||||
self.title = title
|
self.title = title
|
||||||
|
self.short_title = short_title
|
||||||
self.last_updated = last_updated
|
self.last_updated = last_updated
|
||||||
self.status = status
|
self.status = status
|
||||||
self.irb_status = irb_status
|
self.irb_status = irb_status
|
||||||
|
@ -243,6 +245,7 @@ class StudySchema(ma.Schema):
|
||||||
protocol_builder_status = EnumField(StudyStatus, by_value=True)
|
protocol_builder_status = EnumField(StudyStatus, by_value=True)
|
||||||
status = EnumField(StudyStatus, by_value=True)
|
status = EnumField(StudyStatus, by_value=True)
|
||||||
hsr_number = fields.String(allow_none=True)
|
hsr_number = fields.String(allow_none=True)
|
||||||
|
short_title = fields.String(allow_none=True)
|
||||||
sponsor = fields.String(allow_none=True)
|
sponsor = fields.String(allow_none=True)
|
||||||
ind_number = fields.String(allow_none=True)
|
ind_number = fields.String(allow_none=True)
|
||||||
files = fields.List(fields.Nested(FileSchema), dump_only=True)
|
files = fields.List(fields.Nested(FileSchema), dump_only=True)
|
||||||
|
@ -251,7 +254,7 @@ class StudySchema(ma.Schema):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Study
|
model = Study
|
||||||
additional = ["id", "title", "last_updated", "primary_investigator_id", "user_uid",
|
additional = ["id", "title", "short_title", "last_updated", "primary_investigator_id", "user_uid",
|
||||||
"sponsor", "ind_number", "files", "enrollment_date",
|
"sponsor", "ind_number", "files", "enrollment_date",
|
||||||
"create_user_display", "last_activity_date","last_activity_user",
|
"create_user_display", "last_activity_date","last_activity_user",
|
||||||
"events_history"]
|
"events_history"]
|
||||||
|
|
|
@ -186,6 +186,7 @@ Returns information specific to the protocol.
|
||||||
"info": {
|
"info": {
|
||||||
"id": 12,
|
"id": 12,
|
||||||
"title": "test",
|
"title": "test",
|
||||||
|
"short_title": "tst",
|
||||||
"primary_investigator_id":21,
|
"primary_investigator_id":21,
|
||||||
"user_uid": "dif84",
|
"user_uid": "dif84",
|
||||||
"sponsor": "sponsor",
|
"sponsor": "sponsor",
|
||||||
|
|
|
@ -15,44 +15,37 @@ class mock_study:
|
||||||
class UpdateStudy(Script):
|
class UpdateStudy(Script):
|
||||||
|
|
||||||
argument_error_message = "You must supply at least one argument to the " \
|
argument_error_message = "You must supply at least one argument to the " \
|
||||||
"update_study task, in the form [study_field]:[value]",
|
"update_study task, in the form [study_field]=[value]",
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return """
|
return """
|
||||||
Allows you to set specific attributes on the Study model by mapping them to
|
Allows you to set specific attributes on the Study model by mapping them to
|
||||||
values in the task data. Should be called with the value to set (either title, or pi)
|
values in the task data. Should be called with the value to set (either title, short_title, or pi)
|
||||||
followed by a ":" and then the value to use in dot notation.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
UpdateStudy title:PIComputingID.label pi:PIComputingID.value
|
update_study(title=PIComputingID.label, short_title="Really Short Name")
|
||||||
"""
|
"""
|
||||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
study = mock_study
|
study = mock_study
|
||||||
self.__update_study(task, study, *args)
|
self.__update_study(task, study, *args, **kwargs)
|
||||||
|
|
||||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||||
study = db.session.query(StudyModel).filter(StudyModel.id == study_id).first()
|
study = db.session.query(StudyModel).filter(StudyModel.id == study_id).first()
|
||||||
self.__update_study(task, study, *args)
|
self.__update_study(task, study, *args, **kwargs)
|
||||||
db.session.add(study)
|
db.session.add(study)
|
||||||
|
|
||||||
def __update_study(self, task, study, *args):
|
def __update_study(self, task, study, *args, **kwargs):
|
||||||
if len(args) < 1:
|
if len(kwargs.keys()) < 1:
|
||||||
raise ApiError.from_task("missing_argument", self.argument_error_message,
|
raise ApiError.from_task("missing_argument", self.argument_error_message,
|
||||||
task=task)
|
task=task)
|
||||||
|
|
||||||
for arg in args:
|
for arg in kwargs.keys():
|
||||||
try:
|
if arg.lower() == "title":
|
||||||
field, value_lookup = arg.split(':')
|
study.title = kwargs[arg]
|
||||||
except:
|
elif arg.lower() == "short_title":
|
||||||
raise ApiError.from_task("invalid_argument", self.argument_error_message,
|
study.short_title = kwargs[arg]
|
||||||
task=task)
|
elif arg.lower() == "pi":
|
||||||
|
study.primary_investigator_id = kwargs[arg]
|
||||||
value = task.workflow.script_engine.evaluate_expression(task, value_lookup)
|
|
||||||
|
|
||||||
if field.lower() == "title":
|
|
||||||
study.title = value
|
|
||||||
elif field.lower() == "pi":
|
|
||||||
study.primary_investigator_id = value
|
|
||||||
else:
|
else:
|
||||||
raise ApiError.from_task("invalid_argument", self.argument_error_message,
|
raise ApiError.from_task("invalid_argument", self.argument_error_message,
|
||||||
task=task)
|
task=task)
|
||||||
|
|
|
@ -36,7 +36,7 @@ class StudyService(object):
|
||||||
|
|
||||||
studies = []
|
studies = []
|
||||||
for study_model in db_studies:
|
for study_model in db_studies:
|
||||||
studies.append(StudyService.get_study(study_model.id, study_model))
|
studies.append(StudyService.get_study(study_model.id, study_model,do_status=False))
|
||||||
return studies
|
return studies
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -51,7 +51,7 @@ class StudyService(object):
|
||||||
return studies
|
return studies
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_study(study_id, study_model: StudyModel = None):
|
def get_study(study_id, study_model: StudyModel = None, do_status=True):
|
||||||
"""Returns a study model that contains all the workflows organized by category.
|
"""Returns a study model that contains all the workflows organized by category.
|
||||||
IMPORTANT: This is intended to be a lightweight call, it should never involve
|
IMPORTANT: This is intended to be a lightweight call, it should never involve
|
||||||
loading up and executing all the workflows in a study to calculate information."""
|
loading up and executing all the workflows in a study to calculate information."""
|
||||||
|
@ -81,8 +81,9 @@ class StudyService(object):
|
||||||
if study.status != StudyStatus.abandoned:
|
if study.status != StudyStatus.abandoned:
|
||||||
# this line is taking 99% of the time that is used in get_study.
|
# this line is taking 99% of the time that is used in get_study.
|
||||||
# see ticket #196
|
# see ticket #196
|
||||||
status = StudyService.__get_study_status(study_model)
|
if do_status:
|
||||||
study.warnings = StudyService.__update_status_of_workflow_meta(workflow_metas, status)
|
status = StudyService.__get_study_status(study_model)
|
||||||
|
study.warnings = StudyService.__update_status_of_workflow_meta(workflow_metas, status)
|
||||||
|
|
||||||
# Group the workflows into their categories.
|
# Group the workflows into their categories.
|
||||||
for category in study.categories:
|
for category in study.categories:
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: f28ee3722c49
|
||||||
|
Revises: cb892916166a
|
||||||
|
Create Date: 2021-03-02 08:30:22.879266
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f28ee3722c49'
|
||||||
|
down_revision = 'cb892916166a'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('study', sa.Column('short_title', sa.String(), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('study', 'short_title')
|
||||||
|
# ### end Alembic commands ###
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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="3.7.3">
|
<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="3.7.0">
|
||||||
<bpmn:process id="Process_1dagb7t" name="TestMessage" isExecutable="true">
|
<bpmn:process id="Process_1dagb7t" name="TestMessage" isExecutable="true">
|
||||||
<bpmn:startEvent id="StartEvent_1" name="Start">
|
<bpmn:startEvent id="StartEvent_1" name="Start">
|
||||||
<bpmn:outgoing>Flow_0xym55y</bpmn:outgoing>
|
<bpmn:outgoing>Flow_0xym55y</bpmn:outgoing>
|
||||||
|
@ -7,7 +7,7 @@
|
||||||
<bpmn:sequenceFlow id="Flow_16q1uec" name="TestMessageFlow" sourceRef="Event_TokenReset" targetRef="Activity_TestMessage" />
|
<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:scriptTask id="Activity_TestMessage" name="Test Message" camunda:resultVariable="test_message">
|
||||||
<bpmn:incoming>Flow_16q1uec</bpmn:incoming>
|
<bpmn:incoming>Flow_16q1uec</bpmn:incoming>
|
||||||
<bpmn:script>update_study("title:'New Title'")
|
<bpmn:script>update_study(title='New Title')
|
||||||
print('New Title')</bpmn:script>
|
print('New Title')</bpmn:script>
|
||||||
</bpmn:scriptTask>
|
</bpmn:scriptTask>
|
||||||
<bpmn:userTask id="Activity_GetData" name="GetData" camunda:formKey="FirstTaskForm">
|
<bpmn:userTask id="Activity_GetData" name="GetData" camunda:formKey="FirstTaskForm">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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: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="3.7.0">
|
||||||
<bpmn:process id="Process_1dagb7t" name="TestMessage" isExecutable="true">
|
<bpmn:process id="Process_1dagb7t" name="TestMessage" isExecutable="true">
|
||||||
<bpmn:startEvent id="StartEvent_1" name="Start">
|
<bpmn:startEvent id="StartEvent_1" name="Start">
|
||||||
<bpmn:outgoing>Flow_0xym55y</bpmn:outgoing>
|
<bpmn:outgoing>Flow_0xym55y</bpmn:outgoing>
|
||||||
|
@ -7,7 +7,7 @@
|
||||||
<bpmn:sequenceFlow id="Flow_16q1uec" name="TestMessageFlow" sourceRef="Event_TokenReset" targetRef="Activity_TestMessage" />
|
<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:scriptTask id="Activity_TestMessage" name="Test Message" camunda:resultVariable="test_message">
|
||||||
<bpmn:incoming>Flow_16q1uec</bpmn:incoming>
|
<bpmn:incoming>Flow_16q1uec</bpmn:incoming>
|
||||||
<bpmn:script>update_study("title:'New Title'")
|
<bpmn:script>update_study(title='New Title')
|
||||||
print('New Title')</bpmn:script>
|
print('New Title')</bpmn:script>
|
||||||
</bpmn:scriptTask>
|
</bpmn:scriptTask>
|
||||||
<bpmn:sequenceFlow id="Flow_0xym55y" sourceRef="StartEvent_1" targetRef="Activity_Hello" />
|
<bpmn:sequenceFlow id="Flow_0xym55y" sourceRef="StartEvent_1" targetRef="Activity_Hello" />
|
||||||
|
@ -58,7 +58,7 @@ print('New Title')</bpmn:script>
|
||||||
<bpmn:scriptTask id="Activity_CancelMessage" name="Cancel Message" camunda:resultVariable="cancel_message">
|
<bpmn:scriptTask id="Activity_CancelMessage" name="Cancel Message" camunda:resultVariable="cancel_message">
|
||||||
<bpmn:documentation><H1>Cancel Message</H1></bpmn:documentation>
|
<bpmn:documentation><H1>Cancel Message</H1></bpmn:documentation>
|
||||||
<bpmn:incoming>Flow_13xidv2</bpmn:incoming>
|
<bpmn:incoming>Flow_13xidv2</bpmn:incoming>
|
||||||
<bpmn:script>update_study("title:'Second Title'")
|
<bpmn:script>update_study(title='Second Title')
|
||||||
print('Second Title')</bpmn:script>
|
print('Second Title')</bpmn:script>
|
||||||
</bpmn:scriptTask>
|
</bpmn:scriptTask>
|
||||||
</bpmn:process>
|
</bpmn:process>
|
||||||
|
|
|
@ -2,7 +2,7 @@ from tests.base_test import BaseTest
|
||||||
|
|
||||||
from crc.scripts.update_study import UpdateStudy
|
from crc.scripts.update_study import UpdateStudy
|
||||||
from crc.services.workflow_processor import WorkflowProcessor
|
from crc.services.workflow_processor import WorkflowProcessor
|
||||||
|
from box import Box
|
||||||
|
|
||||||
class TestUpdateStudyScript(BaseTest):
|
class TestUpdateStudyScript(BaseTest):
|
||||||
|
|
||||||
|
@ -12,12 +12,22 @@ class TestUpdateStudyScript(BaseTest):
|
||||||
workflow = self.create_workflow('empty_workflow')
|
workflow = self.create_workflow('empty_workflow')
|
||||||
processor = WorkflowProcessor(workflow)
|
processor = WorkflowProcessor(workflow)
|
||||||
task = processor.next_task()
|
task = processor.next_task()
|
||||||
task.data = {"details": {
|
details = Box({
|
||||||
"label": "My New Title",
|
"label": "My New Title",
|
||||||
"value": "dhf8r"}
|
"short": "My New Short Title",
|
||||||
}
|
"value": "dhf8r"})
|
||||||
|
|
||||||
|
|
||||||
script = UpdateStudy()
|
script = UpdateStudy()
|
||||||
script.do_task(task, workflow.study_id, workflow.id, "title:details.label", "pi:details.value")
|
# note that we changed where the argument gets evaluated
|
||||||
|
# previsously, it took the arguments and then evaluated them within the script
|
||||||
|
# now, it evaluates the arugments in the context of the main script so they get
|
||||||
|
# evaluated before they are passed to the script -
|
||||||
|
# this allows us to do a lot more things like strings, functions, etc.
|
||||||
|
# and it makes the arguments less confusing to use.
|
||||||
|
script.do_task(task, workflow.study_id, workflow.id, title = details.label,
|
||||||
|
short_title = details.short,
|
||||||
|
pi = details.value)
|
||||||
self.assertEqual("My New Title", workflow.study.title)
|
self.assertEqual("My New Title", workflow.study.title)
|
||||||
|
self.assertEqual("My New Short Title", workflow.study.short_title)
|
||||||
self.assertEqual("dhf8r", workflow.study.primary_investigator_id)
|
self.assertEqual("dhf8r", workflow.study.primary_investigator_id)
|
||||||
|
|
|
@ -26,7 +26,7 @@ class TestMessageEvent(BaseTest):
|
||||||
headers=self.logged_in_headers(),
|
headers=self.logged_in_headers(),
|
||||||
content_type="application/json")
|
content_type="application/json")
|
||||||
|
|
||||||
# set_current_task should call the interupt (signal) task
|
# set_current_task should call the interrupt (signal) task
|
||||||
# which should run the script in our task
|
# which should run the script in our task
|
||||||
#
|
#
|
||||||
# test to see if our changes made it to the DB
|
# test to see if our changes made it to the DB
|
||||||
|
|
Loading…
Reference in New Issue