switch to spiff_properties branch of spiff, remove api blueprint, camunda to spiff parser/serializer
This commit is contained in:
parent
3d19d7c51b
commit
100f6454f8
|
@ -618,23 +618,18 @@ develop = false
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
click = "^8.0.1"
|
click = "^8.0.1"
|
||||||
flask = "*"
|
flask = "*"
|
||||||
flask-admin = "*"
|
|
||||||
flask-bcrypt = "*"
|
|
||||||
flask-cors = "*"
|
|
||||||
flask-mail = "*"
|
|
||||||
flask-marshmallow = "*"
|
flask-marshmallow = "*"
|
||||||
flask-migrate = "*"
|
flask-migrate = "*"
|
||||||
flask-restful = "*"
|
sentry-sdk = "1.7.1"
|
||||||
sentry-sdk = "1.7.0"
|
|
||||||
sphinx-autoapi = "^1.8.4"
|
sphinx-autoapi = "^1.8.4"
|
||||||
spiffworkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "feature/parse_spiffworkflow_extensions"}
|
spiffworkflow = "*"
|
||||||
werkzeug = "*"
|
werkzeug = "*"
|
||||||
|
|
||||||
[package.source]
|
[package.source]
|
||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/sartography/flask-bpmn"
|
url = "https://github.com/sartography/flask-bpmn"
|
||||||
reference = "main"
|
reference = "feature/with-spiff-properties"
|
||||||
resolved_reference = "c454e729c634c7c86ff30cf4d388480647d18d7b"
|
resolved_reference = "c7497aabb039420d9e7c68a50d7a4b3e74100e81"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flask-cors"
|
name = "flask-cors"
|
||||||
|
@ -1561,7 +1556,7 @@ requests = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sentry-sdk"
|
name = "sentry-sdk"
|
||||||
version = "1.7.0"
|
version = "1.7.1"
|
||||||
description = "Python client for Sentry (https://sentry.io)"
|
description = "Python client for Sentry (https://sentry.io)"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
|
@ -1806,8 +1801,8 @@ pytz = "*"
|
||||||
[package.source]
|
[package.source]
|
||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/sartography/SpiffWorkflow"
|
url = "https://github.com/sartography/SpiffWorkflow"
|
||||||
reference = "feature/parse_spiffworkflow_extensions"
|
reference = "feature/spiff_properties"
|
||||||
resolved_reference = "67054883d4040d6755bf0555f072ff85aa42093c"
|
resolved_reference = "e108aa12da008bdd8d0319e182d28fbd3afb4c67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlalchemy"
|
name = "sqlalchemy"
|
||||||
|
@ -2098,7 +2093,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "c20a647c5a3e12bb5e1e9280316566acaa548e6722b7e4e13b610f25877bd4d0"
|
content-hash = "83f09337ac9218c85a6095a8dcf82eff5153dda76453f77ca97dadfb9ed58b8a"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
alabaster = [
|
alabaster = [
|
||||||
|
|
|
@ -27,13 +27,13 @@ flask-marshmallow = "*"
|
||||||
flask-migrate = "*"
|
flask-migrate = "*"
|
||||||
flask-restful = "*"
|
flask-restful = "*"
|
||||||
werkzeug = "*"
|
werkzeug = "*"
|
||||||
spiffworkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "feature/parse_spiffworkflow_extensions"}
|
spiffworkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "feature/spiff_properties"}
|
||||||
# spiffworkflow = {develop = true, path = "/home/jason/projects/github/sartography/SpiffWorkflow"}
|
# spiffworkflow = {develop = true, path = "/Users/kevin/projects/github/sartography/SpiffWorkflow"}
|
||||||
sentry-sdk = "1.7.0"
|
sentry-sdk = "1.7.1"
|
||||||
sphinx-autoapi = "^1.8.4"
|
sphinx-autoapi = "^1.8.4"
|
||||||
# flask-bpmn = {develop = true, path = "/home/jason/projects/github/sartography/flask-bpmn"}
|
# flask-bpmn = {develop = true, path = "/home/jason/projects/github/sartography/flask-bpmn"}
|
||||||
# flask-bpmn = {develop = true, path = "/Users/kevin/projects/github/sartography/flask-bpmn"}
|
# flask-bpmn = {develop = true, path = "/Users/kevin/projects/github/sartography/flask-bpmn"}
|
||||||
flask-bpmn = {git = "https://github.com/sartography/flask-bpmn", rev = "main"}
|
flask-bpmn = {git = "https://github.com/sartography/flask-bpmn", rev = "feature/with-spiff-properties"}
|
||||||
mysql-connector-python = "^8.0.29"
|
mysql-connector-python = "^8.0.29"
|
||||||
pytest-flask = "^1.2.0"
|
pytest-flask = "^1.2.0"
|
||||||
pytest-flask-sqlalchemy = "^1.1.0"
|
pytest-flask-sqlalchemy = "^1.1.0"
|
||||||
|
|
|
@ -14,7 +14,6 @@ from flask_mail import Mail # type: ignore
|
||||||
import spiffworkflow_backend.load_database_models # noqa: F401
|
import spiffworkflow_backend.load_database_models # noqa: F401
|
||||||
from spiffworkflow_backend.config import setup_config
|
from spiffworkflow_backend.config import setup_config
|
||||||
from spiffworkflow_backend.routes.admin_blueprint.admin_blueprint import admin_blueprint
|
from spiffworkflow_backend.routes.admin_blueprint.admin_blueprint import admin_blueprint
|
||||||
from spiffworkflow_backend.routes.api_blueprint import api_blueprint
|
|
||||||
from spiffworkflow_backend.routes.process_api_blueprint import process_api_blueprint
|
from spiffworkflow_backend.routes.process_api_blueprint import process_api_blueprint
|
||||||
from spiffworkflow_backend.routes.user_blueprint import user_blueprint
|
from spiffworkflow_backend.routes.user_blueprint import user_blueprint
|
||||||
|
|
||||||
|
@ -55,7 +54,6 @@ def create_app() -> flask.app.Flask:
|
||||||
migrate.init_app(app, db)
|
migrate.init_app(app, db)
|
||||||
|
|
||||||
app.register_blueprint(user_blueprint)
|
app.register_blueprint(user_blueprint)
|
||||||
app.register_blueprint(api_blueprint)
|
|
||||||
app.register_blueprint(process_api_blueprint)
|
app.register_blueprint(process_api_blueprint)
|
||||||
app.register_blueprint(api_error_blueprint)
|
app.register_blueprint(api_error_blueprint)
|
||||||
app.register_blueprint(admin_blueprint, url_prefix="/admin")
|
app.register_blueprint(admin_blueprint, url_prefix="/admin")
|
||||||
|
|
|
@ -165,7 +165,6 @@ class ProcessInstanceApi:
|
||||||
next_task: Task | None,
|
next_task: Task | None,
|
||||||
process_model_identifier: str,
|
process_model_identifier: str,
|
||||||
process_group_identifier: str,
|
process_group_identifier: str,
|
||||||
total_tasks: int,
|
|
||||||
completed_tasks: int,
|
completed_tasks: int,
|
||||||
updated_at_in_seconds: int,
|
updated_at_in_seconds: int,
|
||||||
is_review: bool,
|
is_review: bool,
|
||||||
|
@ -178,7 +177,6 @@ class ProcessInstanceApi:
|
||||||
# self.navigation = navigation fixme: would be a hotness.
|
# self.navigation = navigation fixme: would be a hotness.
|
||||||
self.process_model_identifier = process_model_identifier
|
self.process_model_identifier = process_model_identifier
|
||||||
self.process_group_identifier = process_group_identifier
|
self.process_group_identifier = process_group_identifier
|
||||||
self.total_tasks = total_tasks
|
|
||||||
self.completed_tasks = completed_tasks
|
self.completed_tasks = completed_tasks
|
||||||
self.updated_at_in_seconds = updated_at_in_seconds
|
self.updated_at_in_seconds = updated_at_in_seconds
|
||||||
self.title = title
|
self.title = title
|
||||||
|
@ -199,7 +197,6 @@ class ProcessInstanceApiSchema(Schema):
|
||||||
"navigation",
|
"navigation",
|
||||||
"process_model_identifier",
|
"process_model_identifier",
|
||||||
"process_group_identifier",
|
"process_group_identifier",
|
||||||
"total_tasks",
|
|
||||||
"completed_tasks",
|
"completed_tasks",
|
||||||
"updated_at_in_seconds",
|
"updated_at_in_seconds",
|
||||||
"is_review",
|
"is_review",
|
||||||
|
@ -228,7 +225,6 @@ class ProcessInstanceApiSchema(Schema):
|
||||||
"navigation",
|
"navigation",
|
||||||
"process_model_identifier",
|
"process_model_identifier",
|
||||||
"process_group_identifier",
|
"process_group_identifier",
|
||||||
"total_tasks",
|
|
||||||
"completed_tasks",
|
"completed_tasks",
|
||||||
"updated_at_in_seconds",
|
"updated_at_in_seconds",
|
||||||
"is_review",
|
"is_review",
|
||||||
|
@ -251,7 +247,6 @@ class ProcessInstanceMetadata:
|
||||||
spec_version: str | None = None
|
spec_version: str | None = None
|
||||||
state: str | None = None
|
state: str | None = None
|
||||||
status: str | None = None
|
status: str | None = None
|
||||||
total_tasks: int | None = None
|
|
||||||
completed_tasks: int | None = None
|
completed_tasks: int | None = None
|
||||||
is_review: bool | None = None
|
is_review: bool | None = None
|
||||||
state_message: str | None = None
|
state_message: str | None = None
|
||||||
|
@ -270,7 +265,6 @@ class ProcessInstanceMetadata:
|
||||||
process_group_id=process_model.process_group_id,
|
process_group_id=process_model.process_group_id,
|
||||||
state_message=process_instance.state_message,
|
state_message=process_instance.state_message,
|
||||||
status=process_instance.status,
|
status=process_instance.status,
|
||||||
total_tasks=process_instance.total_tasks,
|
|
||||||
completed_tasks=process_instance.completed_tasks,
|
completed_tasks=process_instance.completed_tasks,
|
||||||
is_review=process_model.is_review,
|
is_review=process_model.is_review,
|
||||||
process_model_identifier=process_instance.process_model_identifier,
|
process_model_identifier=process_instance.process_model_identifier,
|
||||||
|
@ -292,7 +286,6 @@ class ProcessInstanceMetadataSchema(Schema):
|
||||||
"display_name",
|
"display_name",
|
||||||
"description",
|
"description",
|
||||||
"state",
|
"state",
|
||||||
"total_tasks",
|
|
||||||
"completed_tasks",
|
"completed_tasks",
|
||||||
"process_group_id",
|
"process_group_id",
|
||||||
"is_review",
|
"is_review",
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
"""Api."""
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
from flask import Blueprint
|
|
||||||
from flask import current_app
|
|
||||||
from flask import request
|
|
||||||
from flask import Response
|
|
||||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # type: ignore
|
|
||||||
from SpiffWorkflow.camunda.serializer.task_spec_converters import UserTaskConverter # type: ignore
|
|
||||||
from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter # type: ignore
|
|
||||||
|
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
|
||||||
from spiffworkflow_backend.spiff_workflow_connector import parse
|
|
||||||
from spiffworkflow_backend.spiff_workflow_connector import run
|
|
||||||
|
|
||||||
|
|
||||||
wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter(
|
|
||||||
[UserTaskConverter, BusinessRuleTaskConverter]
|
|
||||||
)
|
|
||||||
serializer = BpmnWorkflowSerializer(wf_spec_converter)
|
|
||||||
|
|
||||||
api_blueprint = Blueprint("api", __name__)
|
|
||||||
|
|
||||||
|
|
||||||
@api_blueprint.route("/run_process", methods=["POST"])
|
|
||||||
def run_process() -> Response:
|
|
||||||
"""Run_process."""
|
|
||||||
content = request.json
|
|
||||||
if content is None:
|
|
||||||
return Response(
|
|
||||||
json.dumps({"error": "Could not find json request"}),
|
|
||||||
status=400,
|
|
||||||
mimetype="application/json",
|
|
||||||
)
|
|
||||||
|
|
||||||
bpmn_spec_dir = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"]
|
|
||||||
process = "order_product"
|
|
||||||
dmn = [
|
|
||||||
os.path.join(bpmn_spec_dir, "product_prices.dmn"),
|
|
||||||
os.path.join(bpmn_spec_dir, "shipping_costs.dmn"),
|
|
||||||
]
|
|
||||||
bpmn = [
|
|
||||||
os.path.join(bpmn_spec_dir, "multiinstance.bpmn"),
|
|
||||||
os.path.join(bpmn_spec_dir, "call_activity_multi.bpmn"),
|
|
||||||
]
|
|
||||||
|
|
||||||
workflow = None
|
|
||||||
process_instance = ProcessInstanceModel.query.filter().first()
|
|
||||||
if process_instance is None:
|
|
||||||
workflow = parse(process, bpmn, dmn)
|
|
||||||
else:
|
|
||||||
workflow = serializer.deserialize_json(process_instance.bpmn_json)
|
|
||||||
|
|
||||||
response = run(workflow, content.get("task_identifier"), content.get("answer"))
|
|
||||||
|
|
||||||
return Response(
|
|
||||||
json.dumps({"response": response}), status=200, mimetype="application/json"
|
|
||||||
)
|
|
|
@ -14,6 +14,7 @@ from lxml import etree # type: ignore
|
||||||
from SpiffWorkflow import Task as SpiffTask # type: ignore
|
from SpiffWorkflow import Task as SpiffTask # type: ignore
|
||||||
from SpiffWorkflow import TaskState
|
from SpiffWorkflow import TaskState
|
||||||
from SpiffWorkflow import WorkflowException
|
from SpiffWorkflow import WorkflowException
|
||||||
|
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException # type: ignore
|
||||||
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore
|
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore
|
||||||
from SpiffWorkflow.bpmn.PythonScriptEngine import Box # type: ignore
|
from SpiffWorkflow.bpmn.PythonScriptEngine import Box # type: ignore
|
||||||
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
||||||
|
@ -23,13 +24,12 @@ from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnProcessSpec # type: ig
|
||||||
from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition # type: ignore
|
from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition # type: ignore
|
||||||
from SpiffWorkflow.bpmn.specs.events import EndEvent
|
from SpiffWorkflow.bpmn.specs.events import EndEvent
|
||||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||||
from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser # type: ignore
|
|
||||||
from SpiffWorkflow.camunda.serializer import UserTaskConverter # type: ignore
|
|
||||||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore
|
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore
|
||||||
from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter # type: ignore
|
from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter # type: ignore
|
||||||
from SpiffWorkflow.exceptions import WorkflowTaskExecException # type: ignore
|
|
||||||
from SpiffWorkflow.serializer.exceptions import MissingSpecError # type: ignore
|
from SpiffWorkflow.serializer.exceptions import MissingSpecError # type: ignore
|
||||||
from SpiffWorkflow.specs import WorkflowSpec # type: ignore
|
from SpiffWorkflow.specs import WorkflowSpec # type: ignore
|
||||||
|
from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser # type: ignore
|
||||||
|
from SpiffWorkflow.spiff.serializer import UserTaskConverter # type: ignore
|
||||||
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
|
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
|
||||||
|
|
||||||
from spiffworkflow_backend.models.active_task import ActiveTaskModel
|
from spiffworkflow_backend.models.active_task import ActiveTaskModel
|
||||||
|
@ -90,10 +90,10 @@ class CustomBpmnScriptEngine(PythonScriptEngine): # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class MyCustomParser(BpmnDmnParser): # type: ignore
|
class MyCustomParser(BpmnDmnParser): # type: ignore
|
||||||
"""A BPMN and DMN parser that can also parse Camunda forms."""
|
"""A BPMN and DMN parser that can also parse spiffworkflow-specific extensions."""
|
||||||
|
|
||||||
OVERRIDE_PARSER_CLASSES = BpmnDmnParser.OVERRIDE_PARSER_CLASSES
|
OVERRIDE_PARSER_CLASSES = BpmnDmnParser.OVERRIDE_PARSER_CLASSES
|
||||||
OVERRIDE_PARSER_CLASSES.update(CamundaParser.OVERRIDE_PARSER_CLASSES)
|
OVERRIDE_PARSER_CLASSES.update(SpiffBpmnParser.OVERRIDE_PARSER_CLASSES)
|
||||||
|
|
||||||
|
|
||||||
class ProcessInstanceProcessor:
|
class ProcessInstanceProcessor:
|
||||||
|
@ -355,8 +355,13 @@ class ProcessInstanceProcessor:
|
||||||
extensions = ready_or_waiting_task.task_spec.extensions
|
extensions = ready_or_waiting_task.task_spec.extensions
|
||||||
|
|
||||||
form_file_name = None
|
form_file_name = None
|
||||||
if "formKey" in extensions:
|
if "properties" in extensions:
|
||||||
form_file_name = extensions["formKey"]
|
properties = extensions["properties"]
|
||||||
|
if "formJsonSchemaFilename" in properties:
|
||||||
|
form_file_name = properties["formJsonSchemaFilename"]
|
||||||
|
# FIXME:
|
||||||
|
# if "formUiSchemaFilename" in properties:
|
||||||
|
# form_file_name = properties["formUiSchemaFilename"]
|
||||||
|
|
||||||
active_task = ActiveTaskModel(
|
active_task = ActiveTaskModel(
|
||||||
spiffworkflow_task_id=str(ready_or_waiting_task.id),
|
spiffworkflow_task_id=str(ready_or_waiting_task.id),
|
||||||
|
|
|
@ -67,7 +67,7 @@ class ProcessInstanceService:
|
||||||
|
|
||||||
If requested, and possible, next_task is set to the current_task.
|
If requested, and possible, next_task is set to the current_task.
|
||||||
"""
|
"""
|
||||||
navigation = processor.bpmn_process_instance.get_deep_nav_list()
|
# navigation = processor.bpmn_process_instance.get_deep_nav_list()
|
||||||
# ProcessInstanceService.update_navigation(navigation, processor)
|
# ProcessInstanceService.update_navigation(navigation, processor)
|
||||||
process_model_service = ProcessModelService()
|
process_model_service = ProcessModelService()
|
||||||
process_model = process_model_service.get_process_model(
|
process_model = process_model_service.get_process_model(
|
||||||
|
@ -82,7 +82,7 @@ class ProcessInstanceService:
|
||||||
# navigation=navigation,
|
# navigation=navigation,
|
||||||
process_model_identifier=processor.process_model_identifier,
|
process_model_identifier=processor.process_model_identifier,
|
||||||
process_group_identifier=processor.process_group_identifier,
|
process_group_identifier=processor.process_group_identifier,
|
||||||
total_tasks=len(navigation),
|
# total_tasks=len(navigation),
|
||||||
completed_tasks=processor.process_instance_model.completed_tasks,
|
completed_tasks=processor.process_instance_model.completed_tasks,
|
||||||
updated_at_in_seconds=processor.process_instance_model.updated_at_in_seconds,
|
updated_at_in_seconds=processor.process_instance_model.updated_at_in_seconds,
|
||||||
is_review=is_review_value,
|
is_review=is_review_value,
|
||||||
|
|
|
@ -1,214 +0,0 @@
|
||||||
"""Spiff Workflow Connector."""
|
|
||||||
from typing import Any
|
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from flask_bpmn.models.db import db
|
|
||||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # type: ignore
|
|
||||||
from SpiffWorkflow.bpmn.specs.events.event_types import CatchingEvent # type: ignore
|
|
||||||
from SpiffWorkflow.bpmn.specs.events.event_types import ThrowingEvent
|
|
||||||
from SpiffWorkflow.bpmn.specs.ManualTask import ManualTask # type: ignore
|
|
||||||
from SpiffWorkflow.bpmn.specs.ScriptTask import ScriptTask # type: ignore
|
|
||||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
|
||||||
from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser # type: ignore
|
|
||||||
from SpiffWorkflow.camunda.serializer.task_spec_converters import UserTaskConverter # type: ignore
|
|
||||||
from SpiffWorkflow.camunda.specs.UserTask import EnumFormField # type: ignore
|
|
||||||
from SpiffWorkflow.camunda.specs.UserTask import UserTask
|
|
||||||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore
|
|
||||||
from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter # type: ignore
|
|
||||||
from SpiffWorkflow.task import Task # type: ignore
|
|
||||||
from SpiffWorkflow.task import TaskState
|
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
|
||||||
from spiffworkflow_backend.models.user import UserModel
|
|
||||||
|
|
||||||
|
|
||||||
wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter(
|
|
||||||
[UserTaskConverter, BusinessRuleTaskConverter]
|
|
||||||
)
|
|
||||||
serializer = BpmnWorkflowSerializer(wf_spec_converter)
|
|
||||||
|
|
||||||
|
|
||||||
class Parser(BpmnDmnParser): # type: ignore
|
|
||||||
"""Parser."""
|
|
||||||
|
|
||||||
OVERRIDE_PARSER_CLASSES = BpmnDmnParser.OVERRIDE_PARSER_CLASSES
|
|
||||||
OVERRIDE_PARSER_CLASSES.update(CamundaParser.OVERRIDE_PARSER_CLASSES)
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessStatus(TypedDict, total=False):
|
|
||||||
"""ProcessStatus."""
|
|
||||||
|
|
||||||
last_task: str
|
|
||||||
upcoming_tasks: List[str]
|
|
||||||
next_activity: Dict[str, str]
|
|
||||||
|
|
||||||
|
|
||||||
def parse(process: str, bpmn_files: List[str], dmn_files: List[str]) -> BpmnWorkflow:
|
|
||||||
"""Parse."""
|
|
||||||
parser = Parser()
|
|
||||||
parser.add_bpmn_files(bpmn_files)
|
|
||||||
if dmn_files:
|
|
||||||
parser.add_dmn_files(dmn_files)
|
|
||||||
return BpmnWorkflow(parser.get_spec(process))
|
|
||||||
|
|
||||||
|
|
||||||
def format_task(task: Task, include_state: bool = True) -> str:
|
|
||||||
"""Format_task."""
|
|
||||||
if hasattr(task.task_spec, "lane") and task.task_spec.lane is not None:
|
|
||||||
lane = f"[{task.task_spec.lane}]"
|
|
||||||
else:
|
|
||||||
lane = ""
|
|
||||||
state = f"[{task.get_state_name()}]" if include_state else ""
|
|
||||||
return f"{lane} {task.task_spec.description} ({task.task_spec.name}) {state}"
|
|
||||||
|
|
||||||
|
|
||||||
def process_field(
|
|
||||||
field: Any, answer: Union[dict, None], required_user_input_fields: Dict[str, str]
|
|
||||||
) -> Union[str, int, None]:
|
|
||||||
"""Handles the complexities of figuring out what to do about each necessary user field."""
|
|
||||||
response = None
|
|
||||||
if isinstance(field, EnumFormField):
|
|
||||||
option_map = {opt.name: opt.id for opt in field.options}
|
|
||||||
options = "(" + ", ".join(option_map) + ")"
|
|
||||||
if answer is None:
|
|
||||||
required_user_input_fields[field.label] = options
|
|
||||||
else:
|
|
||||||
response = option_map[answer[field.label]]
|
|
||||||
elif field.type == "string":
|
|
||||||
if answer is None:
|
|
||||||
required_user_input_fields[field.label] = "STRING"
|
|
||||||
else:
|
|
||||||
response = answer[field.label]
|
|
||||||
else:
|
|
||||||
if answer is None:
|
|
||||||
required_user_input_fields[field.label] = "(1..)"
|
|
||||||
else:
|
|
||||||
if field.type == "long":
|
|
||||||
response = int(answer[field.label])
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def complete_user_task(
|
|
||||||
task: Task, answer: Optional[Dict[str, str]] = None
|
|
||||||
) -> Dict[Any, Any]:
|
|
||||||
"""Complete_user_task."""
|
|
||||||
if task.data is None:
|
|
||||||
task.data = {}
|
|
||||||
|
|
||||||
required_user_input_fields: Dict[str, str] = {}
|
|
||||||
for field in task.task_spec.form.fields:
|
|
||||||
response = process_field(field, answer, required_user_input_fields)
|
|
||||||
if answer:
|
|
||||||
task.update_data_var(field.id, response)
|
|
||||||
return required_user_input_fields
|
|
||||||
|
|
||||||
|
|
||||||
def get_state(workflow: BpmnWorkflow) -> ProcessStatus:
|
|
||||||
"""Print_state."""
|
|
||||||
task = workflow.last_task
|
|
||||||
|
|
||||||
return_json: ProcessStatus = {"last_task": format_task(task), "upcoming_tasks": []}
|
|
||||||
|
|
||||||
display_types = (UserTask, ManualTask, ScriptTask, ThrowingEvent, CatchingEvent)
|
|
||||||
all_tasks = [
|
|
||||||
task
|
|
||||||
for task in workflow.get_tasks()
|
|
||||||
if isinstance(task.task_spec, display_types)
|
|
||||||
]
|
|
||||||
upcoming_tasks = [
|
|
||||||
task for task in all_tasks if task.state in [TaskState.READY, TaskState.WAITING]
|
|
||||||
]
|
|
||||||
|
|
||||||
for _idx, task in enumerate(upcoming_tasks):
|
|
||||||
return_json["upcoming_tasks"].append(format_task(task))
|
|
||||||
|
|
||||||
return return_json
|
|
||||||
|
|
||||||
|
|
||||||
def create_user() -> UserModel:
|
|
||||||
"""Create_user."""
|
|
||||||
user = UserModel(username="user1")
|
|
||||||
db.session.add(user)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return user
|
|
||||||
|
|
||||||
|
|
||||||
def create_process_instance() -> ProcessInstanceModel:
|
|
||||||
"""Create_process_instance."""
|
|
||||||
user = UserModel.query.filter().first()
|
|
||||||
if user is None:
|
|
||||||
user = create_user()
|
|
||||||
|
|
||||||
process_instance = ProcessInstanceModel(
|
|
||||||
process_model_identifier="process_model1", process_initiator_id=user.id
|
|
||||||
)
|
|
||||||
db.session.add(process_instance)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return process_instance
|
|
||||||
|
|
||||||
|
|
||||||
def run(
|
|
||||||
workflow: BpmnWorkflow,
|
|
||||||
task_identifier: Optional[str] = None,
|
|
||||||
answer: Optional[Dict[str, str]] = None,
|
|
||||||
) -> Union[ProcessStatus, Dict[str, str]]:
|
|
||||||
"""Run."""
|
|
||||||
workflow.do_engine_steps()
|
|
||||||
tasks_status = ProcessStatus()
|
|
||||||
|
|
||||||
if workflow.is_completed():
|
|
||||||
return tasks_status
|
|
||||||
|
|
||||||
ready_tasks = workflow.get_ready_user_tasks()
|
|
||||||
options = {}
|
|
||||||
formatted_options = {}
|
|
||||||
|
|
||||||
for idx, task in enumerate(ready_tasks):
|
|
||||||
option = format_task(task, False)
|
|
||||||
options[str(idx + 1)] = task
|
|
||||||
formatted_options[str(idx + 1)] = option
|
|
||||||
|
|
||||||
if task_identifier is None:
|
|
||||||
return formatted_options
|
|
||||||
|
|
||||||
next_task = options[task_identifier]
|
|
||||||
if isinstance(next_task.task_spec, UserTask):
|
|
||||||
if answer is None:
|
|
||||||
return complete_user_task(next_task)
|
|
||||||
else:
|
|
||||||
complete_user_task(next_task, answer)
|
|
||||||
next_task.complete()
|
|
||||||
elif isinstance(next_task.task_spec, ManualTask):
|
|
||||||
next_task.complete()
|
|
||||||
else:
|
|
||||||
next_task.complete()
|
|
||||||
|
|
||||||
workflow.refresh_waiting_tasks()
|
|
||||||
workflow.do_engine_steps()
|
|
||||||
tasks_status = get_state(workflow)
|
|
||||||
|
|
||||||
ready_tasks = workflow.get_ready_user_tasks()
|
|
||||||
formatted_options = {}
|
|
||||||
for idx, task in enumerate(ready_tasks):
|
|
||||||
option = format_task(task, False)
|
|
||||||
formatted_options[str(idx + 1)] = option
|
|
||||||
|
|
||||||
state = serializer.serialize_json(workflow)
|
|
||||||
process_instance = ProcessInstanceModel.query.filter().first()
|
|
||||||
|
|
||||||
if process_instance is None:
|
|
||||||
process_instance = create_process_instance()
|
|
||||||
process_instance.bpmn_json = state
|
|
||||||
db.session.add(process_instance)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
tasks_status["next_activity"] = formatted_options
|
|
||||||
|
|
||||||
return tasks_status
|
|
Loading…
Reference in New Issue