Merge branch 'dev' into chore/view-as-382
This commit is contained in:
commit
84f364ce37
|
@ -102,7 +102,7 @@ def user_studies():
|
|||
if len(studies) == 0:
|
||||
studies = StudyService().get_studies_for_user(user, include_invalid=True)
|
||||
if len(studies) > 0:
|
||||
message = f"All studies associated with User: {user.display_name} failed study validation"
|
||||
message = f"All studies associated with User: {user.uid} failed study validation"
|
||||
raise ApiError(code="study_integrity_error", message=message)
|
||||
|
||||
results = StudySchema(many=True).dump(studies)
|
||||
|
|
|
@ -26,5 +26,5 @@ class EmailModelSchema(ma.Schema):
|
|||
|
||||
class Meta:
|
||||
model = EmailModel
|
||||
fields = ["id", "subject", "sender", "recipients", "cc", "bcc", "content", "content_html",
|
||||
fields = ["id", "subject", "sender", "recipients", "cc", "bcc", "content",
|
||||
"study_id", "timestamp", "workflow_spec_id"]
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
from crc import db, ma
|
||||
from crc.models.study import StudyModel
|
||||
from crc.models.workflow import WorkflowModel
|
||||
from sqlalchemy import func
|
||||
|
||||
|
||||
class TaskLogModel(db.Model):
|
||||
__tablename__ = 'task_log'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
level = db.Column(db.String)
|
||||
code = db.Column(db.String)
|
||||
message = db.Column(db.String)
|
||||
study_id = db.Column(db.Integer, db.ForeignKey(StudyModel.id), nullable=False)
|
||||
workflow_id = db.Column(db.Integer, db.ForeignKey(WorkflowModel.id), nullable=False)
|
||||
task = db.Column(db.String)
|
||||
timestamp = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||
|
||||
|
||||
class TaskLogModelSchema(ma.Schema):
|
||||
|
||||
class Meta:
|
||||
model = TaskLogModel
|
||||
fields = ["id", "level", "code", "message", "study_id", "workflow_id", "timestamp"]
|
|
@ -1,5 +1,6 @@
|
|||
import sys
|
||||
import traceback
|
||||
import datetime
|
||||
|
||||
from crc import app, session
|
||||
from crc.api.common import ApiError
|
||||
|
@ -45,7 +46,8 @@ email(subject="My Subject", recipients="user@example.com", attachments=['Study_A
|
|||
subject = self.get_subject(kwargs['subject'])
|
||||
recipients = self.get_email_addresses(kwargs['recipients'], study_id)
|
||||
content, content_html = EmailService().get_rendered_content(task.task_spec.documentation, task.data)
|
||||
email_model = EmailModel(subject=subject,
|
||||
email_model = EmailModel(id=1,
|
||||
subject=subject,
|
||||
recipients=recipients,
|
||||
content=content,
|
||||
content_html=content_html,
|
||||
|
|
|
@ -2,7 +2,9 @@ from crc.scripts.script import Script
|
|||
from crc.api.common import ApiError
|
||||
from crc import session
|
||||
from crc.models.email import EmailModel, EmailModelSchema
|
||||
import json
|
||||
from crc.services.email_service import EmailService
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
class EmailData(Script):
|
||||
|
@ -12,11 +14,23 @@ class EmailData(Script):
|
|||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if 'email_id' in kwargs or 'workflow_spec_id' in kwargs:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
subject = 'My Test Email'
|
||||
recipients = 'user@example.com'
|
||||
content = "Hello"
|
||||
content_html = "<!DOCTYPE html><html><head></head><body><div><h2>Hello</h2></div></body></html>"
|
||||
email_model = EmailModel(subject=subject,
|
||||
recipients=recipients,
|
||||
content=content,
|
||||
content_html=content_html,
|
||||
timestamp=datetime.datetime.utcnow())
|
||||
return EmailModelSchema(many=True).dump([email_model])
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, **kwargs):
|
||||
else:
|
||||
raise ApiError.from_task(code='missing_email_id',
|
||||
message='You must include an email_id or workflow_spec_id with the get_email_data script.',
|
||||
task=task)
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
email_models = None
|
||||
email_data = None
|
||||
if 'email_id' in kwargs:
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import datetime
|
||||
|
||||
from crc.api.common import ApiError
|
||||
from crc.scripts.script import Script
|
||||
|
||||
|
@ -14,16 +12,21 @@ class GetLocaltime(Script):
|
|||
Defaults to US/Eastern"""
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if 'timestamp' in kwargs:
|
||||
return datetime.datetime.now()
|
||||
if len(args) > 0 or 'timestamp' in kwargs:
|
||||
return self.do_task(task, study_id, workflow_id, *args, **kwargs)
|
||||
raise ApiError(code='missing_timestamp',
|
||||
message='You must include a timestamp to convert.')
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if 'timestamp' in kwargs:
|
||||
timestamp = kwargs['timestamp']
|
||||
if len(args) > 0 or 'timestamp' in kwargs:
|
||||
if 'timestamp' in kwargs:
|
||||
timestamp = kwargs['timestamp']
|
||||
else:
|
||||
timestamp = args[0]
|
||||
if 'timezone' in kwargs:
|
||||
timezone = kwargs['timezone']
|
||||
elif len(args) > 1:
|
||||
timezone = args[1]
|
||||
else:
|
||||
timezone = 'US/Eastern'
|
||||
parsed_timestamp = dateparser.parse(timestamp)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
from crc import session
|
||||
from crc.models.task_log import TaskLogModel, TaskLogModelSchema
|
||||
from crc.scripts.script import Script
|
||||
|
||||
|
||||
class GetLogsByWorkflow(Script):
|
||||
|
||||
def get_description(self):
|
||||
return """Script to retrieve logs for the current workflow.
|
||||
Accepts an optional `code` argument that is used to filter the DB query.
|
||||
"""
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
log_model = TaskLogModel(level='info',
|
||||
code='mocked_code',
|
||||
message='This is my logging message',
|
||||
study_id=study_id,
|
||||
workflow_id=workflow_id,
|
||||
task=task.get_name())
|
||||
TaskLogModelSchema(many=True).dump([log_model])
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
code = None
|
||||
if 'code' in kwargs:
|
||||
code = kwargs['code']
|
||||
elif len(args) > 0:
|
||||
code = args[0]
|
||||
if code is not None:
|
||||
log_models = session.query(TaskLogModel).\
|
||||
filter(TaskLogModel.code == code).\
|
||||
filter(TaskLogModel.workflow_id == workflow_id).\
|
||||
all()
|
||||
else:
|
||||
log_models = session.query(TaskLogModel). \
|
||||
filter(TaskLogModel.workflow_id == workflow_id). \
|
||||
all()
|
||||
|
||||
return TaskLogModelSchema(many=True).dump(log_models)
|
|
@ -0,0 +1,38 @@
|
|||
from crc import session
|
||||
from crc.models.task_log import TaskLogModel, TaskLogModelSchema
|
||||
from crc.scripts.script import Script
|
||||
|
||||
|
||||
class GetLogsByWorkflow(Script):
|
||||
|
||||
def get_description(self):
|
||||
return """Script to retrieve logs for the current study.
|
||||
Accepts an optional `code` argument that is used to filter the DB query.
|
||||
"""
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
log_model = TaskLogModel(level='info',
|
||||
code='mocked_code',
|
||||
message='This is my logging message',
|
||||
study_id=study_id,
|
||||
workflow_id=workflow_id,
|
||||
task=task.get_name())
|
||||
return TaskLogModelSchema(many=True).dump([log_model])
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
code = None
|
||||
if 'code' in kwargs:
|
||||
code = kwargs['code']
|
||||
elif len(args) > 0:
|
||||
code = args[0]
|
||||
if code is not None:
|
||||
log_models = session.query(TaskLogModel).\
|
||||
filter(TaskLogModel.code == code).\
|
||||
filter(TaskLogModel.study_id == study_id).\
|
||||
all()
|
||||
else:
|
||||
log_models = session.query(TaskLogModel). \
|
||||
filter(TaskLogModel.study_id == study_id). \
|
||||
all()
|
||||
|
||||
return TaskLogModelSchema(many=True).dump(log_models)
|
|
@ -0,0 +1,64 @@
|
|||
from crc import session
|
||||
from crc.api.common import ApiError
|
||||
from crc.models.task_log import TaskLogModel, TaskLogModelSchema
|
||||
from crc.scripts.script import Script
|
||||
|
||||
|
||||
class TaskLog(Script):
|
||||
|
||||
def get_description(self):
|
||||
return """Script to log events in a Script Task.
|
||||
Takes `level`, `code`, and `message` arguments.
|
||||
Example:
|
||||
log(level='info', code='missing_info', message='You must include the correct info!')
|
||||
|
||||
Level must be `debug`, `info`, `warning`, `error` or `critical`.
|
||||
Code is a short string meant for searching the logs. By convention, it is lower case with underscores.
|
||||
Message is a more descriptive string, including any info you want to log.
|
||||
"""
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if len(args) == 3 or ('level' in kwargs and 'code' in kwargs and 'message' in kwargs):
|
||||
log_model = TaskLogModel(level='info',
|
||||
code='mocked_code',
|
||||
message='This is my logging message',
|
||||
study_id=study_id,
|
||||
workflow_id=workflow_id,
|
||||
task=task.get_name())
|
||||
return TaskLogModelSchema().dump(log_model)
|
||||
else:
|
||||
raise ApiError.from_task(code='missing_arguments',
|
||||
message='You must include a level, code, and message to log.',
|
||||
task=task)
|
||||
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if len(args) == 3 or ('level' in kwargs and 'code' in kwargs and 'message' in kwargs):
|
||||
if 'level' in kwargs:
|
||||
level = kwargs['level']
|
||||
else:
|
||||
level = args[0]
|
||||
if 'code' in kwargs:
|
||||
code = kwargs['code']
|
||||
else:
|
||||
code = args[1]
|
||||
if 'message' in kwargs:
|
||||
message = kwargs['message']
|
||||
else:
|
||||
message = args[2]
|
||||
task_name = task.get_name()
|
||||
log_model = TaskLogModel(level=level,
|
||||
code=code,
|
||||
message=message,
|
||||
study_id=study_id,
|
||||
workflow_id=workflow_id,
|
||||
task=task_name)
|
||||
session.add(log_model)
|
||||
session.commit()
|
||||
|
||||
return TaskLogModelSchema().dump(log_model)
|
||||
|
||||
else:
|
||||
raise ApiError.from_task(code='missing_arguments',
|
||||
message='You must include a level, code, and message to log.',
|
||||
task=task)
|
|
@ -13,12 +13,12 @@ class Script(object):
|
|||
raise ApiError("invalid_script",
|
||||
"This script does not supply a description.")
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, **kwargs):
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
raise ApiError("invalid_script",
|
||||
"This is an internal error. The script you are trying to execute '%s' " % self.__class__.__name__ +
|
||||
"does not properly implement the do_task function.")
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, **kwargs):
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
raise ApiError("invalid_script",
|
||||
"This is an internal error. The script you are trying to execute '%s' " % self.__class__.__name__ +
|
||||
"does must provide a validate_only option that mimics the do_task, " +
|
||||
|
|
|
@ -45,13 +45,15 @@ class FileService(object):
|
|||
def add_workflow_spec_file(workflow_spec: WorkflowSpecModel,
|
||||
name, content_type, binary_data, primary=False, is_status=False):
|
||||
"""Create a new file and associate it with a workflow spec."""
|
||||
# Raise ApiError if the file already exists
|
||||
if session.query(FileModel)\
|
||||
file_model = session.query(FileModel)\
|
||||
.filter(FileModel.workflow_spec_id == workflow_spec.id)\
|
||||
.filter(FileModel.name == name).first():
|
||||
.filter(FileModel.name == name).first()
|
||||
|
||||
raise ApiError(code="Duplicate File",
|
||||
message='If you want to replace the file, use the update mechanism.')
|
||||
if file_model:
|
||||
if not file_model.archived:
|
||||
# Raise ApiError if the file already exists and is not archived
|
||||
raise ApiError(code="duplicate_file",
|
||||
message='If you want to replace the file, use the update mechanism.')
|
||||
else:
|
||||
file_model = FileModel(
|
||||
workflow_spec_id=workflow_spec.id,
|
||||
|
@ -60,7 +62,7 @@ class FileService(object):
|
|||
is_status=is_status,
|
||||
)
|
||||
|
||||
return FileService.update_file(file_model, binary_data, content_type)
|
||||
return FileService.update_file(file_model, binary_data, content_type)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -363,6 +363,10 @@ class WorkflowService(object):
|
|||
def evaluate_property(property_name, field, task):
|
||||
expression = field.get_property(property_name)
|
||||
data = task.data
|
||||
# If there's a field key with no initial value, give it one (None)
|
||||
for field in task.task_spec.form.fields:
|
||||
if field.id not in data:
|
||||
data[field.id] = None
|
||||
if field.has_property(Task.FIELD_PROP_REPEAT):
|
||||
# Then you must evaluate the expression based on the data within the group, if that data exists.
|
||||
# There may not be data available in the group, if no groups where added
|
||||
|
|
|
@ -2,7 +2,7 @@ alabaster==0.7.12
|
|||
alembic==1.4.3
|
||||
aniso8601==8.0.0
|
||||
attrs==20.3.0
|
||||
babel==2.9.0
|
||||
babel==2.9.1
|
||||
bcrypt==3.2.0
|
||||
beautifulsoup4==4.9.3
|
||||
blinker==1.4
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
"""add log table
|
||||
|
||||
Revision ID: a4f87f90cc64
|
||||
Revises: ba6df7e560a1
|
||||
Create Date: 2021-10-27 10:54:40.233325
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a4f87f90cc64'
|
||||
down_revision = 'ba6df7e560a1'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table('task_log',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('level', sa.String(), nullable=True),
|
||||
sa.Column('code', sa.String(), nullable=True),
|
||||
sa.Column('message', sa.String(), nullable=True),
|
||||
sa.Column('study_id', sa.Integer(), nullable=False),
|
||||
sa.Column('workflow_id', sa.Integer(), nullable=False),
|
||||
sa.Column('task', sa.String(), nullable=True),
|
||||
sa.Column('timestamp', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['study_id'], ['study.id'], ),
|
||||
sa.ForeignKeyConstraint(['workflow_id'], ['workflow.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('task_log')
|
|
@ -1,58 +1,85 @@
|
|||
<?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_0szq8v9" 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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_0szq8v9" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||
<bpmn:process id="Process_1dxw783" name="Get Localtime" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0lnc9x0</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0lnc9x0" sourceRef="StartEvent_1" targetRef="Activity_0aq21yg" />
|
||||
<bpmn:sequenceFlow id="Flow_0gtgzcf" sourceRef="Activity_0aq21yg" targetRef="Activity_1by2ose" />
|
||||
<bpmn:sequenceFlow id="Flow_0k1hbif" sourceRef="Activity_1by2ose" targetRef="Activity_0d5fjpa" />
|
||||
<bpmn:sequenceFlow id="Flow_0lnc9x0" sourceRef="StartEvent_1" targetRef="Activity_GetData" />
|
||||
<bpmn:sequenceFlow id="Flow_0gtgzcf" sourceRef="Activity_GetData" targetRef="Activity_GetLocaltime" />
|
||||
<bpmn:sequenceFlow id="Flow_0k1hbif" sourceRef="Activity_GetLocaltime" targetRef="Activity_0d5fjpa" />
|
||||
<bpmn:endEvent id="Event_1vxo45i">
|
||||
<bpmn:incoming>Flow_0kgtoh1</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0kgtoh1" sourceRef="Activity_0d5fjpa" targetRef="Event_1vxo45i" />
|
||||
<bpmn:scriptTask id="Activity_0aq21yg" name="Send Email">
|
||||
<bpmn:documentation>This is my email</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0lnc9x0</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0gtgzcf</bpmn:outgoing>
|
||||
<bpmn:script>email_model = email(subject='My Email Subject', recipients='user@example.com')</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:scriptTask id="Activity_1by2ose" name="Get Localtime">
|
||||
<bpmn:scriptTask id="Activity_GetLocaltime" name="Get Localtime">
|
||||
<bpmn:documentation>timestamp = email_model.timestamp
|
||||
localtime = get_localtime(str(timestamp))</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0gtgzcf</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0k1hbif</bpmn:outgoing>
|
||||
<bpmn:script>timestamp=email_model.timestamp
|
||||
localtime = get_localtime(timestamp=timestamp)</bpmn:script>
|
||||
<bpmn:script>if with_timestamp:
|
||||
if with_timezone:
|
||||
localtime_with = get_localtime(timestamp=timestamp, timezone=timezone)
|
||||
localtime_without = get_localtime(timestamp, timezone)
|
||||
else:
|
||||
localtime_with = get_localtime(timestamp=timestamp)
|
||||
localtime_without = get_localtime(timestamp)
|
||||
else:
|
||||
localtime = get_localtime()</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:manualTask id="Activity_0d5fjpa" name="Display Times">
|
||||
<bpmn:documentation># Timestamp
|
||||
{{ timestamp }}
|
||||
|
||||
# Timezone
|
||||
{{ timezone }}
|
||||
|
||||
# Localtime
|
||||
{{ localtime }}</bpmn:documentation>
|
||||
# Localtime With
|
||||
{{ localtime_with }}
|
||||
|
||||
# Localtime Without
|
||||
{{ localtime_without }}</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0k1hbif</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0kgtoh1</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:userTask id="Activity_GetData" name="Get Data" camunda:formKey="DataForm">
|
||||
<bpmn:documentation>This is my email</bpmn:documentation>
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="with_timestamp" label="With Timestamp" type="boolean" defaultValue="False">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
</camunda:formField>
|
||||
<camunda:formField id="with_timezone" label="With Timezone" type="boolean" defaultValue="False">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
</camunda:formField>
|
||||
<camunda:formField id="timestamp" label="Timestamp" type="string" />
|
||||
<camunda:formField id="timezone" label="Timezone" type="string" />
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0lnc9x0</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0gtgzcf</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1dxw783">
|
||||
<bpmndi:BPMNEdge id="Flow_0lnc9x0_di" bpmnElement="Flow_0lnc9x0">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0gtgzcf_di" bpmnElement="Flow_0gtgzcf">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
<bpmndi:BPMNEdge id="Flow_0kgtoh1_di" bpmnElement="Flow_0kgtoh1">
|
||||
<di:waypoint x="690" y="117" />
|
||||
<di:waypoint x="752" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0k1hbif_di" bpmnElement="Flow_0k1hbif">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="590" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0kgtoh1_di" bpmnElement="Flow_0kgtoh1">
|
||||
<di:waypoint x="690" y="117" />
|
||||
<di:waypoint x="752" y="117" />
|
||||
<bpmndi:BPMNEdge id="Flow_0gtgzcf_di" bpmnElement="Flow_0gtgzcf">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0lnc9x0_di" bpmnElement="Flow_0lnc9x0">
|
||||
<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" />
|
||||
|
@ -60,15 +87,15 @@ localtime = get_localtime(timestamp=timestamp)</bpmn:script>
|
|||
<bpmndi:BPMNShape id="Event_1vxo45i_di" bpmnElement="Event_1vxo45i">
|
||||
<dc:Bounds x="752" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_01qg6wo_di" bpmnElement="Activity_0aq21yg">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0q4ycxr_di" bpmnElement="Activity_1by2ose">
|
||||
<bpmndi:BPMNShape id="Activity_0q4ycxr_di" bpmnElement="Activity_GetLocaltime">
|
||||
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_178gn50_di" bpmnElement="Activity_0d5fjpa">
|
||||
<dc:Bounds x="590" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0jhiwc1_di" bpmnElement="Activity_GetData">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
<?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_e3059e6" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||
<bpmn:process id="Process_LoggingTask" name="Logging Task" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0d5wpav</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:scriptTask id="Activity_LogEvent" name="Log Event">
|
||||
<bpmn:incoming>Flow_0pc42yp</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0n34cdi</bpmn:outgoing>
|
||||
<bpmn:script>log_model_info = log(level='info', code='test_code', message='You forgot to include the correct data.')
|
||||
log_model_debug = log(level='degug', code='debug_test_code', message='This is my debugging message')</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:manualTask id="Activity_DisplayLog" name="DisplayLog">
|
||||
<bpmn:documentation># Logging Models Pre
|
||||
{{ logging_models_pre }}
|
||||
|
||||
# Log Model
|
||||
{{ log_model }}
|
||||
|
||||
# Logging Models All Post
|
||||
{{ logging_models_all_post }}
|
||||
|
||||
|
||||
# Logging Models Info Post
|
||||
{{ logging_models_info_post }}
|
||||
|
||||
|
||||
# Logging Models Debug Post
|
||||
{{ logging_models_debug_post }}</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_07j4f0v</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_016ui0e</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:endEvent id="Event_06g3ojm">
|
||||
<bpmn:incoming>Flow_016ui0e</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_016ui0e" sourceRef="Activity_DisplayLog" targetRef="Event_06g3ojm" />
|
||||
<bpmn:scriptTask id="Activity_GetLoggingPre" name="Get Logging Pre">
|
||||
<bpmn:incoming>Flow_0d5wpav</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0pc42yp</bpmn:outgoing>
|
||||
<bpmn:script>logging_models_pre = get_logs()</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:scriptTask id="Activity_GetLoggingPost" name="Get Logging Post">
|
||||
<bpmn:incoming>Flow_0n34cdi</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_07j4f0v</bpmn:outgoing>
|
||||
<bpmn:script>logging_models_all_post = get_logs()
|
||||
logging_models_info_post = get_logs('test_code')
|
||||
logging_models_debug_post = get_logs('debug_test_code')</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_0d5wpav" sourceRef="StartEvent_1" targetRef="Activity_GetLoggingPre" />
|
||||
<bpmn:sequenceFlow id="Flow_0pc42yp" sourceRef="Activity_GetLoggingPre" targetRef="Activity_LogEvent" />
|
||||
<bpmn:sequenceFlow id="Flow_0n34cdi" sourceRef="Activity_LogEvent" targetRef="Activity_GetLoggingPost" />
|
||||
<bpmn:sequenceFlow id="Flow_07j4f0v" sourceRef="Activity_GetLoggingPost" targetRef="Activity_DisplayLog" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_LoggingTask">
|
||||
<bpmndi:BPMNEdge id="Flow_07j4f0v_di" bpmnElement="Flow_07j4f0v">
|
||||
<di:waypoint x="650" y="117" />
|
||||
<di:waypoint x="710" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0n34cdi_di" bpmnElement="Flow_0n34cdi">
|
||||
<di:waypoint x="490" y="117" />
|
||||
<di:waypoint x="550" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0pc42yp_di" bpmnElement="Flow_0pc42yp">
|
||||
<di:waypoint x="330" y="117" />
|
||||
<di:waypoint x="390" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0d5wpav_di" bpmnElement="Flow_0d5wpav">
|
||||
<di:waypoint x="188" y="117" />
|
||||
<di:waypoint x="230" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_016ui0e_di" bpmnElement="Flow_016ui0e">
|
||||
<di:waypoint x="810" y="117" />
|
||||
<di:waypoint x="872" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="152" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_08z1eq4_di" bpmnElement="Activity_LogEvent">
|
||||
<dc:Bounds x="390" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0amiq7i_di" bpmnElement="Activity_DisplayLog">
|
||||
<dc:Bounds x="710" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_06g3ojm_di" bpmnElement="Event_06g3ojm">
|
||||
<dc:Bounds x="872" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_07mg1d2_di" bpmnElement="Activity_GetLoggingPre">
|
||||
<dc:Bounds x="230" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_167quv8_di" bpmnElement="Activity_GetLoggingPost">
|
||||
<dc:Bounds x="550" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,90 @@
|
|||
<?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_0tt6u6r" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||
<bpmn:process id="Process_0jo811u" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0bbqksl</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0bbqksl" sourceRef="StartEvent_1" targetRef="Activity_ManualTask" />
|
||||
<bpmn:manualTask id="Activity_ManualTask" name="Manual Task">
|
||||
<bpmn:documentation># Hello
|
||||
You may manipulate this in a test, as you see fit</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0bbqksl</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0lh4lq8</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:sequenceFlow id="Flow_0lh4lq8" sourceRef="Activity_ManualTask" targetRef="Activity_AddLogs" />
|
||||
<bpmn:scriptTask id="Activity_AddLogs" name="Add Logs">
|
||||
<bpmn:incoming>Flow_0lh4lq8</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_10fc3fk</bpmn:outgoing>
|
||||
<bpmn:script>some_text = 'variable'
|
||||
log('info', 'some_code', 'Some longer message')
|
||||
log('info', 'some_other_code', 'Another really long message')
|
||||
log('debug', 'debug_code', f'This message has a { some_text }!')</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_10fc3fk" sourceRef="Activity_AddLogs" targetRef="Activity_GetLogs" />
|
||||
<bpmn:scriptTask id="Activity_GetLogs" name="Get Logs">
|
||||
<bpmn:incoming>Flow_10fc3fk</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1dfqchi</bpmn:outgoing>
|
||||
<bpmn:script>workflow_logs = get_logs()
|
||||
study_logs = get_logs_for_study()</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_1dfqchi" sourceRef="Activity_GetLogs" targetRef="Activity_DisplayInfo" />
|
||||
<bpmn:manualTask id="Activity_DisplayInfo" name="Display Info">
|
||||
<bpmn:documentation># Display Info
|
||||
|
||||
## Workflow Logs
|
||||
{{ workflow_logs }}
|
||||
|
||||
|
||||
## Study Logs
|
||||
{{ study_logs }}</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_1dfqchi</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0yxmlin</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:endEvent id="Event_1dg0buo">
|
||||
<bpmn:incoming>Flow_0yxmlin</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0yxmlin" sourceRef="Activity_DisplayInfo" targetRef="Event_1dg0buo" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0jo811u">
|
||||
<bpmndi:BPMNEdge id="Flow_0bbqksl_di" bpmnElement="Flow_0bbqksl">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0lh4lq8_di" bpmnElement="Flow_0lh4lq8">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_10fc3fk_di" bpmnElement="Flow_10fc3fk">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="590" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1dfqchi_di" bpmnElement="Flow_1dfqchi">
|
||||
<di:waypoint x="690" y="117" />
|
||||
<di:waypoint x="750" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0yxmlin_di" bpmnElement="Flow_0yxmlin">
|
||||
<di:waypoint x="850" y="117" />
|
||||
<di:waypoint x="912" 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="Activity_0gphpwt_di" bpmnElement="Activity_ManualTask">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0yb5wv4_di" bpmnElement="Activity_AddLogs">
|
||||
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1d90rzn_di" bpmnElement="Activity_GetLogs">
|
||||
<dc:Bounds x="590" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_016wmmv_di" bpmnElement="Activity_DisplayInfo">
|
||||
<dc:Bounds x="750" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1dg0buo_di" bpmnElement="Event_1dg0buo">
|
||||
<dc:Bounds x="912" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,54 @@
|
|||
<?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_e3059e6" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="Process_LoggingTask" name="Logging Task" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_1vjxvjd</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1vjxvjd" sourceRef="StartEvent_1" targetRef="Activity_LogEvent" />
|
||||
<bpmn:scriptTask id="Activity_LogEvent" name="Log Event">
|
||||
<bpmn:incoming>Flow_1vjxvjd</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1mw0dlv</bpmn:outgoing>
|
||||
<bpmn:script>log_model = log(level='info', code='test_code', message='You forgot to include the correct data.')</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_1mw0dlv" sourceRef="Activity_LogEvent" targetRef="Activity_DisplayLog" />
|
||||
<bpmn:manualTask id="Activity_DisplayLog" name="DisplayLog">
|
||||
<bpmn:documentation># Log Model
|
||||
{{ log_model }}
|
||||
</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_1mw0dlv</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_016ui0e</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:endEvent id="Event_06g3ojm">
|
||||
<bpmn:incoming>Flow_016ui0e</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_016ui0e" sourceRef="Activity_DisplayLog" targetRef="Event_06g3ojm" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_LoggingTask">
|
||||
<bpmndi:BPMNEdge id="Flow_016ui0e_di" bpmnElement="Flow_016ui0e">
|
||||
<di:waypoint x="530" y="177" />
|
||||
<di:waypoint x="592" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1mw0dlv_di" bpmnElement="Flow_1mw0dlv">
|
||||
<di:waypoint x="370" y="177" />
|
||||
<di:waypoint x="430" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1vjxvjd_di" bpmnElement="Flow_1vjxvjd">
|
||||
<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_08z1eq4_di" bpmnElement="Activity_LogEvent">
|
||||
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0amiq7i_di" bpmnElement="Activity_DisplayLog">
|
||||
<dc:Bounds x="430" y="137" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_06g3ojm_di" bpmnElement="Event_06g3ojm">
|
||||
<dc:Bounds x="592" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -5,7 +5,7 @@ import os
|
|||
from tests.base_test import BaseTest
|
||||
|
||||
from crc import session, db, app
|
||||
from crc.models.file import FileModel, FileType, FileSchema, FileModelSchema
|
||||
from crc.models.file import FileModel, FileType, FileModelSchema, FileDataModel
|
||||
from crc.models.workflow import WorkflowSpecModel
|
||||
from crc.services.file_service import FileService
|
||||
from crc.services.workflow_processor import WorkflowProcessor
|
||||
|
@ -13,6 +13,8 @@ from crc.models.data_store import DataStoreModel
|
|||
from crc.services.document_service import DocumentService
|
||||
from example_data import ExampleDataLoader
|
||||
|
||||
from sqlalchemy import desc
|
||||
|
||||
|
||||
class TestFilesApi(BaseTest):
|
||||
|
||||
|
@ -376,3 +378,48 @@ class TestFilesApi(BaseTest):
|
|||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
self.assertTrue(json_data['primary'])
|
||||
self.assertIsNotNone(json_data['primary_process_id'])
|
||||
|
||||
def test_file_upload_with_previous_name(self):
|
||||
self.load_example_data()
|
||||
workflow_spec_model = session.query(WorkflowSpecModel).first()
|
||||
|
||||
# Add file
|
||||
data = {'file': (io.BytesIO(b'asdf'), 'test_file.xlsx')}
|
||||
rv = self.app.post('/v1.0/file?workflow_spec_id=%s' % workflow_spec_model.id,
|
||||
data=data,
|
||||
follow_redirects=True,
|
||||
content_type='multipart/form-data',
|
||||
headers=self.logged_in_headers())
|
||||
|
||||
self.assert_success(rv)
|
||||
file_json = json.loads(rv.get_data(as_text=True))
|
||||
file_id = file_json['id']
|
||||
|
||||
# Set file to archived
|
||||
file_model = session.query(FileModel).filter_by(id=file_id).first()
|
||||
file_model.archived = True
|
||||
session.commit()
|
||||
|
||||
# Assert we have the correct file data and the file is archived
|
||||
file_data_model = session.query(FileDataModel).filter(FileDataModel.file_model_id == file_model.id).first()
|
||||
self.assertEqual(b'asdf', file_data_model.data)
|
||||
file_model = session.query(FileModel).filter_by(id=file_model.id).first()
|
||||
self.assertEqual(True, file_model.archived)
|
||||
|
||||
# Upload file with same name
|
||||
data = {'file': (io.BytesIO(b'xyzpdq'), 'test_file.xlsx')}
|
||||
rv = self.app.post('/v1.0/file?workflow_spec_id=%s' % workflow_spec_model.id,
|
||||
data=data,
|
||||
follow_redirects=True,
|
||||
content_type='multipart/form-data',
|
||||
headers=self.logged_in_headers())
|
||||
|
||||
self.assert_success(rv)
|
||||
file_json = json.loads(rv.get_data(as_text=True))
|
||||
file_id = file_json['id']
|
||||
|
||||
# Assert we have the correct file data and the file is *not* archived
|
||||
file_data_model = session.query(FileDataModel).filter(FileDataModel.file_model_id == file_id).order_by(desc(FileDataModel.version)).first()
|
||||
self.assertEqual(b'xyzpdq', file_data_model.data)
|
||||
file_model = session.query(FileModel).filter_by(id=file_id).first()
|
||||
self.assertEqual(False, file_model.archived)
|
||||
|
|
|
@ -6,6 +6,12 @@ from crc.services.email_service import EmailService
|
|||
|
||||
class TestGetEmailData(BaseTest):
|
||||
|
||||
def test_email_data_validation(self):
|
||||
self.load_example_data()
|
||||
spec_model = self.load_test_spec('get_email_data')
|
||||
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
|
||||
self.assertEqual([], rv.json)
|
||||
|
||||
def test_get_email_data_by_email_id(self):
|
||||
self.load_example_data()
|
||||
workflow = self.create_workflow('get_email_data')
|
||||
|
@ -32,6 +38,8 @@ class TestGetEmailData(BaseTest):
|
|||
self.assertEqual('My Email Subject', email_data[0]['subject'])
|
||||
self.assertEqual('sender@example.com', email_data[0]['sender'])
|
||||
self.assertEqual('[\'joe@example.com\']', email_data[0]['recipients'])
|
||||
# Make sure we remove content_html from email_data
|
||||
self.assertNotIn('content_html', email_data[0])
|
||||
|
||||
def test_get_email_data_by_workflow_spec_id(self):
|
||||
self.load_example_data()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from tests.base_test import BaseTest
|
||||
from crc.scripts.get_localtime import GetLocaltime
|
||||
import dateparser
|
||||
import datetime
|
||||
|
||||
|
||||
class TestGetLocaltime(BaseTest):
|
||||
|
@ -8,11 +9,51 @@ class TestGetLocaltime(BaseTest):
|
|||
def test_get_localtime(self):
|
||||
self.load_example_data()
|
||||
|
||||
timestamp = datetime.datetime.utcnow()
|
||||
workflow = self.create_workflow('get_localtime')
|
||||
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
timestamp = task.data['timestamp']
|
||||
localtime = task.data['localtime']
|
||||
workflow_api = self.complete_form(workflow, task, {'with_timestamp': True,
|
||||
'with_timezone': False,
|
||||
'timestamp': str(timestamp)})
|
||||
task = workflow_api.next_task
|
||||
|
||||
self.assertEqual(dateparser.parse(localtime), GetLocaltime().do_task(None, None, None, timestamp=timestamp))
|
||||
# The workflow calls get_localtime twice, once with named arguments and once without
|
||||
localtime_with = task.data['localtime_with']
|
||||
localtime_without = task.data['localtime_without']
|
||||
|
||||
self.assertEqual(dateparser.parse(localtime_with), GetLocaltime().do_task(None, None, None, timestamp=str(timestamp)))
|
||||
self.assertEqual(dateparser.parse(localtime_without), GetLocaltime().do_task(None, None, None, str(timestamp)))
|
||||
|
||||
def test_get_localtime_with_timezone(self):
|
||||
self.load_example_data()
|
||||
|
||||
timestamp = datetime.datetime.utcnow()
|
||||
workflow = self.create_workflow('get_localtime')
|
||||
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
workflow_api = self.complete_form(workflow, task, {'with_timestamp': True,
|
||||
'with_timezone': True,
|
||||
'timestamp': str(timestamp),
|
||||
'timezone': 'US/Eastern'})
|
||||
task = workflow_api.next_task
|
||||
|
||||
# The workflow calls get_localtime twice, once with named arguments and once without
|
||||
localtime_with = task.data['localtime_with']
|
||||
localtime_without = task.data['localtime_without']
|
||||
|
||||
self.assertEqual(dateparser.parse(localtime_with), GetLocaltime().do_task(None, None, None, timestamp=str(timestamp), timezone='US/Eastern'))
|
||||
self.assertEqual(dateparser.parse(localtime_without), GetLocaltime().do_task(None, None, None, str(timestamp), 'US/Eastern'))
|
||||
|
||||
def test_get_localtime_no_timestamp(self):
|
||||
workflow = self.create_workflow('get_localtime')
|
||||
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
self.complete_form(workflow, task, {'with_timestamp': False, 'with_timezone': False})
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
from tests.base_test import BaseTest
|
||||
|
||||
from crc import session
|
||||
from crc.models.api_models import Task
|
||||
from crc.models.task_log import TaskLogModel
|
||||
from crc.models.study import StudyModel
|
||||
from crc.scripts.log import TaskLog
|
||||
|
||||
import types
|
||||
|
||||
|
||||
class TestTaskLogging(BaseTest):
|
||||
|
||||
def test_logging_validation(self):
|
||||
self.load_example_data()
|
||||
spec_model = self.load_test_spec('logging_task')
|
||||
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
|
||||
self.assertEqual([], rv.json)
|
||||
|
||||
def test_add_log(self):
|
||||
workflow = self.create_workflow('logging_task')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
log_id = task.data['log_model']['id']
|
||||
log_model = session.query(TaskLogModel).filter(TaskLogModel.id == log_id).first()
|
||||
|
||||
self.assertEqual('test_code', log_model.code)
|
||||
self.assertEqual('info', log_model.level)
|
||||
self.assertEqual('Activity_LogEvent', log_model.task)
|
||||
|
||||
def test_get_logging_validation(self):
|
||||
self.load_example_data()
|
||||
spec_model = self.load_test_spec('get_logging')
|
||||
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
|
||||
self.assertEqual([], rv.json)
|
||||
|
||||
def test_get_logs(self):
|
||||
workflow = self.create_workflow('get_logging')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
self.assertEqual(2, len(task.data['logging_models_all_post']))
|
||||
self.assertEqual(1, len(task.data['logging_models_info_post']))
|
||||
self.assertEqual(1, len(task.data['logging_models_debug_post']))
|
||||
self.assertIn(task.data['logging_models_info_post'][0], task.data['logging_models_all_post'])
|
||||
self.assertIn(task.data['logging_models_debug_post'][0], task.data['logging_models_all_post'])
|
||||
self.assertEqual('test_code', task.data['logging_models_info_post'][0]['code'])
|
||||
self.assertEqual('debug_test_code', task.data['logging_models_debug_post'][0]['code'])
|
||||
|
||||
def test_get_logs_for_study(self):
|
||||
self.load_example_data()
|
||||
study = session.query(StudyModel).first()
|
||||
|
||||
workflow = self.create_workflow('hello_world', study=study)
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
task_model = Task(id=task.id,
|
||||
name=task.name,
|
||||
title=task.title,
|
||||
type=task.type,
|
||||
state=task.state,
|
||||
lane=task.lane,
|
||||
form=task.form,
|
||||
documentation=task.documentation,
|
||||
data=task.data,
|
||||
multi_instance_type=task.multi_instance_type,
|
||||
multi_instance_count=task.multi_instance_count,
|
||||
multi_instance_index=task.multi_instance_index,
|
||||
process_name=task.process_name,
|
||||
properties=task.properties)
|
||||
|
||||
task_model.get_name = types.MethodType(lambda x: x.name, task_model)
|
||||
|
||||
TaskLog().do_task(task_model, study.id, workflow.id,
|
||||
level='critical',
|
||||
code='critical_code',
|
||||
message='This is my critical message.')
|
||||
|
||||
TaskLog().do_task(task_model, study.id, workflow.id,
|
||||
level='debug',
|
||||
code='debug_code',
|
||||
message='This is my debug message.')
|
||||
|
||||
# This workflow adds 3 logs
|
||||
# some_text = 'variable'
|
||||
# log('info', 'some_code', 'Some longer message')
|
||||
# log('info', 'some_other_code', 'Another really long message')
|
||||
# log('debug', 'debug_code', f'This message has a { some_text }!')
|
||||
workflow = self.create_workflow('get_logging_for_study', study=study)
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
workflow_api = self.complete_form(workflow, task, {})
|
||||
task = workflow_api.next_task
|
||||
workflow_logs = task.data['workflow_logs']
|
||||
study_logs = task.data['study_logs']
|
||||
self.assertEqual(3, len(workflow_logs))
|
||||
self.assertEqual(5, len(study_logs))
|
|
@ -3,6 +3,7 @@ from tests.base_test import BaseTest
|
|||
|
||||
class TestValueExpression(BaseTest):
|
||||
|
||||
# If there is no default value, a value of 'None' should be given.
|
||||
def test_value_expression_no_default(self):
|
||||
|
||||
workflow = self.create_workflow('test_value_expression')
|
||||
|
@ -14,7 +15,7 @@ class TestValueExpression(BaseTest):
|
|||
workflow_api = self.get_workflow_api(workflow)
|
||||
second_task = workflow_api.next_task
|
||||
self.assertEqual('', second_task.data['value_expression_value'])
|
||||
self.assertNotIn('color', second_task.data)
|
||||
self.assertIn('color', second_task.data)
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue