Squashed 'spiffworkflow-backend/' changes from 4f71a03e3..1b7c530a9

1b7c530a9 added some debug code for Processor failed to obtain task error w/ burnettk
cf5bbf0e7 Merge commit 'ec431349e8b5cc2e8aa1ee1799bcb768fd3116c3'
dfaa699f9 Merge pull request #7 from sartography/feature/get-local-time
3e1d6773e mypy
3471ab792 Added `get_localtime` script Added test for new script, with test process

git-subtree-dir: spiffworkflow-backend
git-subtree-split: 1b7c530a9ab2335a4a7b7efd1026464b333311aa
This commit is contained in:
burnettk 2022-10-26 13:42:08 -04:00
parent ec431349e8
commit 00dc4e149d
8 changed files with 243 additions and 17 deletions

View File

@ -20,7 +20,7 @@ groups:
natalia, natalia,
] ]
finance: Finance Team:
users: [finance_user1] users: [finance_user1]
permissions: permissions:
@ -30,11 +30,24 @@ permissions:
allowed_permissions: [create, read, update, delete, list, instantiate] allowed_permissions: [create, read, update, delete, list, instantiate]
uri: /* uri: /*
finance-admin: tasks-crud:
groups: [finance] groups: [everybody]
users: [] users: []
allowed_permissions: [create, read, update, delete] allowed_permissions: [create, read, update, delete]
uri: /v1.0/process-groups/execute-procure-to-pay/* uri: /v1.0/tasks/*
# TODO: all uris should really have the same structure
finance-admin-group:
groups: ["Finance Team"]
users: []
allowed_permissions: [create, read, update, delete]
uri: /v1.0/process-groups/finance/*
finance-admin-model:
groups: ["Finance Team"]
users: []
allowed_permissions: [create, read, update, delete]
uri: /v1.0/process-models/finance/*
read-all: read-all:
groups: [finance, admin] groups: [finance, admin]

View File

@ -46,12 +46,12 @@ class ActiveTaskModel(SpiffworkflowBaseDBModel):
updated_at_in_seconds: int = db.Column(db.Integer) updated_at_in_seconds: int = db.Column(db.Integer)
created_at_in_seconds: int = db.Column(db.Integer) created_at_in_seconds: int = db.Column(db.Integer)
task_id = db.Column(db.String(50)) task_id: str = db.Column(db.String(50))
task_name = db.Column(db.String(50)) task_name: str = db.Column(db.String(50))
task_title = db.Column(db.String(50)) task_title: str = db.Column(db.String(50))
task_type = db.Column(db.String(50)) task_type: str = db.Column(db.String(50))
task_status = db.Column(db.String(50)) task_status: str = db.Column(db.String(50))
process_model_display_name = db.Column(db.String(255)) process_model_display_name: str = db.Column(db.String(255))
active_task_users = relationship("ActiveTaskUserModel", cascade="delete") active_task_users = relationship("ActiveTaskUserModel", cascade="delete")
potential_owners = relationship( # type: ignore potential_owners = relationship( # type: ignore

View File

@ -1,4 +1,5 @@
"""APIs for dealing with process groups, process models, and process instances.""" """APIs for dealing with process groups, process models, and process instances."""
import dataclasses
import json import json
import os import os
import random import random
@ -1352,6 +1353,13 @@ def get_spiff_task_from_process_instance(
task_uuid = uuid.UUID(task_id) task_uuid = uuid.UUID(task_id)
spiff_task = processor.bpmn_process_instance.get_task(task_uuid) spiff_task = processor.bpmn_process_instance.get_task(task_uuid)
# FOR DEBUGGING: save this variable so we get it in sentry when something fails
active_task = ActiveTaskModel.query.filter_by(task_id=task_id).first()
if active_task:
task_json = dataclasses.asdict(active_task)
print(f"task_json: {task_json}")
########
if spiff_task is None: if spiff_task is None:
raise ( raise (
ApiError( ApiError(

View File

@ -0,0 +1,43 @@
from flask_bpmn.api.api_error import ApiError
from spiffworkflow_backend.scripts.script import Script
from datetime import datetime
import pytz
from typing import Any
from typing import Optional
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
class GetLocaltime(Script):
def get_description(self) -> str:
return """Converts a Datetime object into a Datetime object for a specific timezone.
Defaults to US/Eastern"""
def run(
self,
task: Optional[SpiffTask],
environment_identifier: str,
*args: Any,
**kwargs: Any
) -> datetime:
if len(args) > 0 or 'datetime' in kwargs:
if 'datetime' in kwargs:
date_time = kwargs['datetime']
else:
date_time = args[0]
if 'timezone' in kwargs:
timezone = kwargs['timezone']
elif len(args) > 1:
timezone = args[1]
else:
timezone = 'US/Eastern'
localtime: datetime = date_time.astimezone(pytz.timezone(timezone))
return localtime
else:
raise ApiError(error_code='missing_datetime',
message='You must include a datetime to convert.')

View File

@ -20,10 +20,12 @@ class DataSetupService:
failing_process_models = [] failing_process_models = []
process_models = ProcessModelService().get_process_models() process_models = ProcessModelService().get_process_models()
for process_model in process_models: for process_model in process_models:
if process_model.primary_file_name: process_model_files = SpecFileService.get_files(
process_model, extension_filter=".bpmn"
)
for process_model_file in process_model_files:
bpmn_xml_file_contents = SpecFileService.get_data( bpmn_xml_file_contents = SpecFileService.get_data(
process_model, process_model.primary_file_name process_model, process_model_file.name
) )
bad_files = [ bad_files = [
"B.1.0.bpmn", "B.1.0.bpmn",
@ -32,21 +34,21 @@ class DataSetupService:
"C.6.0.bpmn", "C.6.0.bpmn",
"TC-5.1.bpmn", "TC-5.1.bpmn",
] ]
if process_model.primary_file_name in bad_files: if process_model_file.name in bad_files:
continue continue
current_app.logger.debug( current_app.logger.debug(
f"primary_file_name: {process_model.primary_file_name}" f"primary_file_name: {process_model_file.name}"
) )
try: try:
SpecFileService.update_file( SpecFileService.update_file(
process_model, process_model,
process_model.primary_file_name, process_model_file.name,
bpmn_xml_file_contents, bpmn_xml_file_contents,
) )
except Exception as ex: except Exception as ex:
failing_process_models.append( failing_process_models.append(
( (
f"{process_model.process_group_id}/{process_model.id}/{process_model.primary_file_name}", f"{process_model.process_group_id}/{process_model.id}/{process_model_file.name}",
str(ex), str(ex),
) )
) )

View File

@ -0,0 +1,79 @@
<?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:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_LocalTime" name="Get LocalTime" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0ijucqh</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0ijucqh" sourceRef="StartEvent_1" targetRef="Activity_GetTimezone" />
<bpmn:scriptTask id="Activity_GetTime" name="Get Time">
<bpmn:documentation>Get Time</bpmn:documentation>
<bpmn:incoming>Flow_10y2eax</bpmn:incoming>
<bpmn:outgoing>Flow_1gcfk27</bpmn:outgoing>
<bpmn:script>some_time = datetime.now()
localtime = get_localtime(some_time, timezone)</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_1gcfk27" sourceRef="Activity_GetTime" targetRef="Activity_DisplayTime" />
<bpmn:endEvent id="Event_1c50ix7">
<bpmn:incoming>Flow_0dcc306</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0dcc306" sourceRef="Activity_DisplayTime" targetRef="Event_1c50ix7" />
<bpmn:manualTask id="Activity_DisplayTime" name="Display Time">
<bpmn:documentation>Display the time</bpmn:documentation>
<bpmn:extensionElements>
<spiffworkflow:instructionsForEndUser>## Time
### Some Time: {{ some_time }}
### Timezone: {{ timezone }}
### Localtime: {{ localtime }}</spiffworkflow:instructionsForEndUser>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1gcfk27</bpmn:incoming>
<bpmn:outgoing>Flow_0dcc306</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:sequenceFlow id="Flow_10y2eax" sourceRef="Activity_GetTimezone" targetRef="Activity_GetTime" />
<bpmn:userTask id="Activity_GetTimezone" name="Get Timezone">
<bpmn:extensionElements>
<spiffworkflow:properties>
<spiffworkflow:property name="formJsonSchemaFilename" value="get_localtime.json" />
</spiffworkflow:properties>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0ijucqh</bpmn:incoming>
<bpmn:outgoing>Flow_10y2eax</bpmn:outgoing>
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_LocalTime">
<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_1ahvmya_di" bpmnElement="Activity_GetTime">
<dc:Bounds x="430" y="137" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1c50ix7_di" bpmnElement="Event_1c50ix7">
<dc:Bounds x="752" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1gfsyxd_di" bpmnElement="Activity_DisplayTime">
<dc:Bounds x="590" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1x3u69s_di" bpmnElement="Activity_GetTimezone">
<dc:Bounds x="270" y="137" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0ijucqh_di" bpmnElement="Flow_0ijucqh">
<di:waypoint x="215" y="177" />
<di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1gcfk27_di" bpmnElement="Flow_1gcfk27">
<di:waypoint x="530" y="177" />
<di:waypoint x="590" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0dcc306_di" bpmnElement="Flow_0dcc306">
<di:waypoint x="690" y="177" />
<di:waypoint x="752" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_10y2eax_di" bpmnElement="Flow_10y2eax">
<di:waypoint x="370" y="177" />
<di:waypoint x="430" y="177" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,20 @@
{
"title": "Get Timezone",
"description": "Form to select a timezone.",
"type": "object",
"required": [
"timezone"
],
"properties": {
"timezone": {
"type": "string",
"title": "Timezone",
"enum": [
"US/Eastern",
"US/Pacific",
"Europe/Berlin",
"Australia/ACT"
]
}
}
}

View File

@ -0,0 +1,61 @@
import datetime
import pytz
from flask.app import Flask
from flask.testing import FlaskClient
from spiffworkflow_backend.scripts.get_localtime import GetLocaltime
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
from spiffworkflow_backend.services.process_instance_service import ProcessInstanceService
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
class TestGetLocaltime(BaseTest):
"""TestProcessAPi."""
def test_get_localtime_script_directly(self) -> None:
current_time = datetime.datetime.now()
timezone = "US/Pacific"
result = GetLocaltime().run(task=None, environment_identifier='testing', datetime=current_time, timezone=timezone)
assert result == current_time.astimezone(pytz.timezone(timezone))
def test_get_localtime_script_through_bpmn(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
) -> None:
"""Test_process_instance_run."""
initiator_user = self.find_or_create_user("initiator_user")
process_model = load_test_spec(
process_model_id="get_localtime", bpmn_file_name="get_localtime.bpmn"
)
process_instance = self.create_process_instance_from_process_model(
process_model=process_model, user=initiator_user
)
processor = ProcessInstanceProcessor(process_instance)
processor.do_engine_steps(save=True)
active_task = process_instance.active_tasks[0]
spiff_task = processor.__class__.get_task_by_bpmn_identifier(
active_task.task_name, processor.bpmn_process_instance
)
ProcessInstanceService.complete_form_task(
processor, spiff_task, {"timezone": "US/Pacific"}, initiator_user
)
active_task = process_instance.active_tasks[0]
spiff_task = processor.__class__.get_task_by_bpmn_identifier(
active_task.task_name, processor.bpmn_process_instance
)
assert spiff_task
data = spiff_task.data
some_time = data['some_time']
localtime = data['localtime']
timezone = data['timezone']
assert localtime == some_time.astimezone(pytz.timezone(timezone))