mirror of
https://github.com/sartography/spiff-arena.git
synced 2025-02-26 16:10:44 +00:00
added method to create process models based on english string w/ burnettk
This commit is contained in:
parent
09e012674a
commit
df462e0dd0
@ -396,7 +396,6 @@ def process_instance_report_update(
|
|||||||
report_id: int,
|
report_id: int,
|
||||||
body: Dict[str, Any],
|
body: Dict[str, Any],
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_report_create."""
|
|
||||||
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
||||||
id=report_id,
|
id=report_id,
|
||||||
created_by_id=g.user.id,
|
created_by_id=g.user.id,
|
||||||
@ -417,7 +416,6 @@ def process_instance_report_update(
|
|||||||
def process_instance_report_delete(
|
def process_instance_report_delete(
|
||||||
report_id: int,
|
report_id: int,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_report_create."""
|
|
||||||
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
||||||
id=report_id,
|
id=report_id,
|
||||||
created_by_id=g.user.id,
|
created_by_id=g.user.id,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
"""APIs for dealing with process groups, process models, and process instances."""
|
"""APIs for dealing with process groups, process models, and process instances."""
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
from spiffworkflow_backend.models.process_instance_report import ProcessInstanceReportModel
|
||||||
|
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
@ -26,6 +29,7 @@ from spiffworkflow_backend.routes.process_api_blueprint import (
|
|||||||
)
|
)
|
||||||
from spiffworkflow_backend.services.git_service import GitService
|
from spiffworkflow_backend.services.git_service import GitService
|
||||||
from spiffworkflow_backend.services.git_service import MissingGitConfigsError
|
from spiffworkflow_backend.services.git_service import MissingGitConfigsError
|
||||||
|
from spiffworkflow_backend.services.process_instance_report_service import ProcessInstanceReportService
|
||||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||||
|
|
||||||
@ -302,20 +306,6 @@ def process_model_create_with_natural_language(
|
|||||||
modified_process_group_id: str, body: Dict[str, str]
|
modified_process_group_id: str, body: Dict[str, str]
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_model_create_with_natural_language."""
|
"""Process_model_create_with_natural_language."""
|
||||||
# body_include_list = [
|
|
||||||
# "id",
|
|
||||||
# "display_name",
|
|
||||||
# "primary_file_name",
|
|
||||||
# "primary_process_id",
|
|
||||||
# "description",
|
|
||||||
# "metadata_extraction_paths",
|
|
||||||
# ]
|
|
||||||
# body_filtered = {
|
|
||||||
# include_item: body[include_item]
|
|
||||||
# for include_item in body_include_list
|
|
||||||
# if include_item in body
|
|
||||||
# }
|
|
||||||
|
|
||||||
pattern = re.compile(
|
pattern = re.compile(
|
||||||
r"Create a (?P<pm_name>.*?) process model with a (?P<form_name>.*?) form that"
|
r"Create a (?P<pm_name>.*?) process model with a (?P<form_name>.*?) form that"
|
||||||
r" collects (?P<columns>.*)"
|
r" collects (?P<columns>.*)"
|
||||||
@ -333,17 +323,13 @@ def process_model_create_with_natural_language(
|
|||||||
process_model_display_name = match.group("pm_name")
|
process_model_display_name = match.group("pm_name")
|
||||||
process_model_identifier = re.sub(r"[ _]", "-", process_model_display_name)
|
process_model_identifier = re.sub(r"[ _]", "-", process_model_display_name)
|
||||||
process_model_identifier = re.sub(r"-{2,}", "-", process_model_identifier).lower()
|
process_model_identifier = re.sub(r"-{2,}", "-", process_model_identifier).lower()
|
||||||
print(f"process_model_identifier: {process_model_identifier}")
|
|
||||||
|
|
||||||
form_name = match.group("form_name")
|
form_name = match.group("form_name")
|
||||||
form_identifier = re.sub(r"[ _]", "-", form_name)
|
form_identifier = re.sub(r"[ _]", "-", form_name)
|
||||||
form_identifier = re.sub(r"-{2,}", "-", form_identifier).lower()
|
form_identifier = re.sub(r"-{2,}", "-", form_identifier).lower()
|
||||||
print(f"form_identifier: {form_identifier}")
|
|
||||||
|
|
||||||
column_names = match.group("columns")
|
column_names = match.group("columns")
|
||||||
print(f"column_names: {column_names}")
|
|
||||||
columns = re.sub(r"(, (and )?)", ",", column_names).split(",")
|
columns = re.sub(r"(, (and )?)", ",", column_names).split(",")
|
||||||
print(f"columns: {columns}")
|
|
||||||
|
|
||||||
process_group = _get_process_group_from_modified_identifier(
|
process_group = _get_process_group_from_modified_identifier(
|
||||||
modified_process_group_id
|
modified_process_group_id
|
||||||
@ -371,14 +357,59 @@ def process_model_create_with_natural_language(
|
|||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
bpmn_template_file = os.path.join(current_app.root_path, 'templates', 'basic_with_user_task_template.bpmn')
|
||||||
|
if not os.path.exists(bpmn_template_file):
|
||||||
|
raise ApiError(
|
||||||
|
error_code="bpmn_template_file_does_not_exist",
|
||||||
|
message=f"Could not find the bpmn template file to create process model.",
|
||||||
|
status_code=500,
|
||||||
|
)
|
||||||
|
|
||||||
ProcessModelService.add_process_model(process_model_info)
|
ProcessModelService.add_process_model(process_model_info)
|
||||||
|
bpmn_process_identifier = f"{process_model_info.id}_process"
|
||||||
|
bpmn_template_contents = ''
|
||||||
|
with open(bpmn_template_file, encoding="utf-8") as f:
|
||||||
|
bpmn_template_contents = f.read()
|
||||||
|
|
||||||
|
bpmn_template_contents = bpmn_template_contents.replace('natural_language_process_id_template', bpmn_process_identifier)
|
||||||
|
bpmn_template_contents = bpmn_template_contents.replace('form-identifier-id-template-', form_identifier)
|
||||||
|
|
||||||
|
form_uischema_json: dict = {
|
||||||
|
"ui:order": []
|
||||||
|
}
|
||||||
|
|
||||||
|
form_properties: dict = {}
|
||||||
|
for column in columns:
|
||||||
|
form_properties[column] = {
|
||||||
|
"type": "string",
|
||||||
|
"title": column,
|
||||||
|
}
|
||||||
|
form_schema_json = {
|
||||||
|
"title": form_identifier,
|
||||||
|
"description": "",
|
||||||
|
"properties": form_properties,
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecFileService.add_file(process_model_info, f"{process_model_identifier}.bpmn", str.encode(bpmn_template_contents))
|
||||||
|
SpecFileService.add_file(process_model_info, f"{form_identifier}-schema.json", str.encode(json.dumps(form_schema_json)))
|
||||||
|
SpecFileService.add_file(process_model_info, f"{form_identifier}-uischema.json", str.encode(json.dumps(form_uischema_json)))
|
||||||
|
|
||||||
_commit_and_push_to_git(
|
_commit_and_push_to_git(
|
||||||
f"User: {g.user.username} created process model via natural language:"
|
f"User: {g.user.username} created process model via natural language:"
|
||||||
f" {process_model_info.id}"
|
f" {process_model_info.id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Create a form json schema and UI schema
|
default_report_metadata = ProcessInstanceReportService.system_metadata_map('default')
|
||||||
# TODO: Add report
|
for column in columns:
|
||||||
|
default_report_metadata['columns'].append({
|
||||||
|
"Header": column, "accessor": column
|
||||||
|
})
|
||||||
|
ProcessInstanceReportModel.create_report(
|
||||||
|
identifier=process_model_identifier,
|
||||||
|
user=g.user,
|
||||||
|
report_metadata=default_report_metadata,
|
||||||
|
)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
json.dumps(ProcessModelInfoSchema().dump(process_model_info)),
|
json.dumps(ProcessModelInfoSchema().dump(process_model_info)),
|
||||||
|
@ -40,10 +40,9 @@ class FileSystemService:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def root_path() -> str:
|
def root_path() -> str:
|
||||||
"""Root_path."""
|
"""Root_path."""
|
||||||
# fixme: allow absolute files
|
|
||||||
dir_name = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"]
|
dir_name = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"]
|
||||||
app_root = current_app.root_path
|
# ensure this is a string - thanks mypy...
|
||||||
return os.path.abspath(os.path.join(app_root, "..", dir_name))
|
return os.path.abspath(os.path.join(dir_name, ''))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def id_string_to_relative_path(id_string: str) -> str:
|
def id_string_to_relative_path(id_string: str) -> str:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""Process_instance_report_service."""
|
"""Process_instance_report_service."""
|
||||||
import re
|
import re
|
||||||
|
from typing import Any
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -84,29 +85,7 @@ class ProcessInstanceReportService:
|
|||||||
"""ProcessInstanceReportService."""
|
"""ProcessInstanceReportService."""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def report_with_identifier(
|
def system_metadata_map(cls, metadata_key: str) -> dict[str, Any]:
|
||||||
cls,
|
|
||||||
user: UserModel,
|
|
||||||
report_id: Optional[int] = None,
|
|
||||||
report_identifier: Optional[str] = None,
|
|
||||||
) -> ProcessInstanceReportModel:
|
|
||||||
"""Report_with_filter."""
|
|
||||||
if report_id is not None:
|
|
||||||
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
|
||||||
id=report_id, created_by_id=user.id
|
|
||||||
).first()
|
|
||||||
if process_instance_report is not None:
|
|
||||||
return process_instance_report # type: ignore
|
|
||||||
|
|
||||||
if report_identifier is None:
|
|
||||||
report_identifier = "default"
|
|
||||||
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
|
||||||
identifier=report_identifier, created_by_id=user.id
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if process_instance_report is not None:
|
|
||||||
return process_instance_report # type: ignore
|
|
||||||
|
|
||||||
# TODO replace with system reports that are loaded on launch (or similar)
|
# TODO replace with system reports that are loaded on launch (or similar)
|
||||||
temp_system_metadata_map = {
|
temp_system_metadata_map = {
|
||||||
"default": {
|
"default": {
|
||||||
@ -151,10 +130,36 @@ class ProcessInstanceReportService:
|
|||||||
"order_by": ["-start_in_seconds", "-id"],
|
"order_by": ["-start_in_seconds", "-id"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
return temp_system_metadata_map[metadata_key]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def report_with_identifier(
|
||||||
|
cls,
|
||||||
|
user: UserModel,
|
||||||
|
report_id: Optional[int] = None,
|
||||||
|
report_identifier: Optional[str] = None,
|
||||||
|
) -> ProcessInstanceReportModel:
|
||||||
|
"""Report_with_filter."""
|
||||||
|
if report_id is not None:
|
||||||
|
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
||||||
|
id=report_id, created_by_id=user.id
|
||||||
|
).first()
|
||||||
|
if process_instance_report is not None:
|
||||||
|
return process_instance_report # type: ignore
|
||||||
|
|
||||||
|
if report_identifier is None:
|
||||||
|
report_identifier = "default"
|
||||||
|
process_instance_report = ProcessInstanceReportModel.query.filter_by(
|
||||||
|
identifier=report_identifier, created_by_id=user.id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if process_instance_report is not None:
|
||||||
|
return process_instance_report # type: ignore
|
||||||
|
|
||||||
process_instance_report = ProcessInstanceReportModel(
|
process_instance_report = ProcessInstanceReportModel(
|
||||||
identifier=report_identifier,
|
identifier=report_identifier,
|
||||||
created_by_id=user.id,
|
created_by_id=user.id,
|
||||||
report_metadata=temp_system_metadata_map[report_identifier],
|
report_metadata=cls.system_metadata_map(report_identifier),
|
||||||
)
|
)
|
||||||
|
|
||||||
return process_instance_report # type: ignore
|
return process_instance_report # type: ignore
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
<?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" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||||
|
<bpmn:process id="natural_language_process_id_template" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_0gixxkm</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0gixxkm" sourceRef="StartEvent_1" targetRef="present_form" />
|
||||||
|
<bpmn:userTask id="present_form" name="Present Form">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<spiffworkflow:properties>
|
||||||
|
<spiffworkflow:property name="formJsonSchemaFilename" value="form-identifier-id-template-schema.json" />
|
||||||
|
<spiffworkflow:property name="formUiSchemaFilename" value="form-identifier-id-template-uischema.json" />
|
||||||
|
</spiffworkflow:properties>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_0gixxkm</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_1oi9nsn</bpmn:outgoing>
|
||||||
|
</bpmn:userTask>
|
||||||
|
<bpmn:endEvent id="Event_003bxs1">
|
||||||
|
<bpmn:incoming>Flow_1oi9nsn</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_1oi9nsn" sourceRef="present_form" targetRef="Event_003bxs1" />
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="natural_language_process_id_template">
|
||||||
|
<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_0ajk9gf_di" bpmnElement="present_form">
|
||||||
|
<dc:Bounds x="270" y="137" width="100" height="80" />
|
||||||
|
<bpmndi:BPMNLabel />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_003bxs1_di" bpmnElement="Event_003bxs1">
|
||||||
|
<dc:Bounds x="432" y="159" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0gixxkm_di" bpmnElement="Flow_0gixxkm">
|
||||||
|
<di:waypoint x="215" y="177" />
|
||||||
|
<di:waypoint x="270" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1oi9nsn_di" bpmnElement="Flow_1oi9nsn">
|
||||||
|
<di:waypoint x="370" y="177" />
|
||||||
|
<di:waypoint x="432" y="177" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"title": "{FORM_IDENTIFIER}",
|
||||||
|
"description": "",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"ui:order": []
|
||||||
|
}
|
@ -205,6 +205,25 @@ class TestProcessApi(BaseTest):
|
|||||||
{"key": "priority", "path": "priority"},
|
{"key": "priority", "path": "priority"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
process_model = ProcessModelService.get_process_model(response.json['id'])
|
||||||
|
process_model_path = os.path.join(
|
||||||
|
FileSystemService.root_path(),
|
||||||
|
FileSystemService.id_string_to_relative_path(process_model.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
process_model_diagram = os.path.join(process_model_path, "bug-tracker.bpmn")
|
||||||
|
assert os.path.exists(process_model_diagram)
|
||||||
|
form_schema_json = os.path.join(process_model_path, "bug-details-schema.json")
|
||||||
|
assert os.path.exists(form_schema_json)
|
||||||
|
form_uischema_json = os.path.join(process_model_path, "bug-details-uischema.json")
|
||||||
|
assert os.path.exists(form_uischema_json)
|
||||||
|
|
||||||
|
process_instance_report = ProcessInstanceReportModel.query.filter_by(identifier='bug-tracker').first()
|
||||||
|
assert process_instance_report is not None
|
||||||
|
report_column_accessors = [i['accessor'] for i in process_instance_report.report_metadata['columns']]
|
||||||
|
expected_column_accessors = ['id', 'process_model_display_name', 'start_in_seconds', 'end_in_seconds', 'username', 'status', 'summary', 'description', 'priority']
|
||||||
|
assert report_column_accessors == expected_column_accessors
|
||||||
|
|
||||||
def test_primary_process_id_updates_via_xml(
|
def test_primary_process_id_updates_via_xml(
|
||||||
self,
|
self,
|
||||||
app: Flask,
|
app: Flask,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user