Merge commit '39f9dcba4d497b121ef7f24e58e735b62b0e03d4' into main
This commit is contained in:
commit
d1e612e7d2
|
@ -4,6 +4,7 @@ from dataclasses import field
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
import marshmallow
|
||||||
from marshmallow import INCLUDE
|
from marshmallow import INCLUDE
|
||||||
from marshmallow import Schema
|
from marshmallow import Schema
|
||||||
|
|
||||||
|
@ -61,6 +62,20 @@ CONTENT_TYPES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass()
|
||||||
|
class FileReference:
|
||||||
|
"""File Reference Information.
|
||||||
|
|
||||||
|
Includes items such as the process id and name for a BPMN,
|
||||||
|
or the Decision id and Decision name for a DMN file. There may be more than
|
||||||
|
one reference that points to a particular file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
type: str # can be 'process', 'decision', or just 'file'
|
||||||
|
|
||||||
|
|
||||||
@dataclass(order=True)
|
@dataclass(order=True)
|
||||||
class File:
|
class File:
|
||||||
"""File."""
|
"""File."""
|
||||||
|
@ -70,17 +85,12 @@ class File:
|
||||||
content_type: str
|
content_type: str
|
||||||
name: str
|
name: str
|
||||||
type: str
|
type: str
|
||||||
document: dict
|
|
||||||
last_modified: datetime
|
last_modified: datetime
|
||||||
size: int
|
size: int
|
||||||
process_instance_id: Optional[int] = None
|
references: Optional[list[FileReference]] = None
|
||||||
irb_doc_code: Optional[str] = None
|
|
||||||
data_store: Optional[dict] = field(default_factory=dict)
|
|
||||||
user_uid: Optional[str] = None
|
|
||||||
file_contents: Optional[bytes] = None
|
file_contents: Optional[bytes] = None
|
||||||
process_model_id: Optional[str] = None
|
process_model_id: Optional[str] = None
|
||||||
process_group_id: Optional[str] = None
|
process_group_id: Optional[str] = None
|
||||||
archived: bool = False
|
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
"""__post_init__."""
|
"""__post_init__."""
|
||||||
|
@ -100,7 +110,6 @@ class File:
|
||||||
name=file_name,
|
name=file_name,
|
||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
type=file_type.value,
|
type=file_type.value,
|
||||||
document={},
|
|
||||||
last_modified=last_modified,
|
last_modified=last_modified,
|
||||||
size=file_size,
|
size=file_size,
|
||||||
)
|
)
|
||||||
|
@ -118,32 +127,29 @@ class FileSchema(Schema):
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"content_type",
|
"content_type",
|
||||||
"process_instance_id",
|
|
||||||
"irb_doc_code",
|
|
||||||
"last_modified",
|
"last_modified",
|
||||||
"type",
|
"type",
|
||||||
"archived",
|
|
||||||
"size",
|
"size",
|
||||||
"data_store",
|
"data_store",
|
||||||
"document",
|
|
||||||
"user_uid",
|
"user_uid",
|
||||||
"url",
|
"url",
|
||||||
"file_contents",
|
"file_contents",
|
||||||
"process_model_id",
|
"references",
|
||||||
"process_group_id",
|
"process_group_id",
|
||||||
|
"process_model_id",
|
||||||
]
|
]
|
||||||
unknown = INCLUDE
|
unknown = INCLUDE
|
||||||
|
references = marshmallow.fields.List(
|
||||||
|
marshmallow.fields.Nested("FileReferenceSchema")
|
||||||
|
)
|
||||||
|
|
||||||
# url = Method("get_url")
|
|
||||||
#
|
class FileReferenceSchema(Schema):
|
||||||
# def get_url(self, obj):
|
"""FileSchema."""
|
||||||
# token = 'not_available'
|
|
||||||
# if hasattr(obj, 'id') and obj.id is not None:
|
class Meta:
|
||||||
# file_url = url_for("/v1_0.crc_api_file_get_file_data_link", file_id=obj.id, _external=True)
|
"""Meta."""
|
||||||
# if hasattr(flask.g, 'user'):
|
|
||||||
# token = flask.g.user.encode_auth_token()
|
model = FileReference
|
||||||
# url = file_url + '?auth_token=' + urllib.parse.quote_plus(token)
|
fields = ["id", "name", "type"]
|
||||||
# return url
|
unknown = INCLUDE
|
||||||
# else:
|
|
||||||
# return ""
|
|
||||||
#
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ from spiffworkflow_backend.services.error_handling_service import ErrorHandlingS
|
||||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||||
from spiffworkflow_backend.services.git_service import GitService
|
from spiffworkflow_backend.services.git_service import GitService
|
||||||
from spiffworkflow_backend.services.message_service import MessageService
|
from spiffworkflow_backend.services.message_service import MessageService
|
||||||
|
from spiffworkflow_backend.services.process_instance_processor import MyCustomParser
|
||||||
from spiffworkflow_backend.services.process_instance_processor import (
|
from spiffworkflow_backend.services.process_instance_processor import (
|
||||||
ProcessInstanceProcessor,
|
ProcessInstanceProcessor,
|
||||||
)
|
)
|
||||||
|
@ -263,6 +264,10 @@ def process_model_show(process_group_id: str, process_model_id: str) -> Any:
|
||||||
process_model = get_process_model(process_model_id, process_group_id)
|
process_model = get_process_model(process_model_id, process_group_id)
|
||||||
files = sorted(SpecFileService.get_files(process_model))
|
files = sorted(SpecFileService.get_files(process_model))
|
||||||
process_model.files = files
|
process_model.files = files
|
||||||
|
for file in process_model.files:
|
||||||
|
file.references = SpecFileService.get_references_for_file(
|
||||||
|
file, process_model, MyCustomParser
|
||||||
|
)
|
||||||
process_model_json = ProcessModelInfoSchema().dump(process_model)
|
process_model_json = ProcessModelInfoSchema().dump(process_model)
|
||||||
return process_model_json
|
return process_model_json
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException #
|
||||||
|
|
||||||
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
||||||
from spiffworkflow_backend.models.file import File
|
from spiffworkflow_backend.models.file import File
|
||||||
|
from spiffworkflow_backend.models.file import FileReference
|
||||||
from spiffworkflow_backend.models.file import FileType
|
from spiffworkflow_backend.models.file import FileType
|
||||||
from spiffworkflow_backend.models.message_correlation_property import (
|
from spiffworkflow_backend.models.message_correlation_property import (
|
||||||
MessageCorrelationPropertyModel,
|
MessageCorrelationPropertyModel,
|
||||||
|
@ -54,6 +56,41 @@ class SpecFileService(FileSystemService):
|
||||||
)
|
)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_references_for_file(
|
||||||
|
file: File, process_model_info: ProcessModelInfo, parser_class: Any
|
||||||
|
) -> list[FileReference]:
|
||||||
|
"""Uses spiffworkflow to parse BPMN and DMN files to determine how they can be externally referenced.
|
||||||
|
|
||||||
|
Returns a list of Reference objects that contain the type of reference, the id, the name.
|
||||||
|
Ex.
|
||||||
|
id = {str} 'Level3'
|
||||||
|
name = {str} 'Level 3'
|
||||||
|
type = {str} 'process'
|
||||||
|
"""
|
||||||
|
references: list[FileReference] = []
|
||||||
|
file_path = SpecFileService.file_path(process_model_info, file.name)
|
||||||
|
parser = parser_class()
|
||||||
|
parser_type = None
|
||||||
|
sub_parser = None
|
||||||
|
if file.type == FileType.bpmn.value:
|
||||||
|
parser.add_bpmn_file(file_path)
|
||||||
|
parser_type = "process"
|
||||||
|
sub_parsers = list(parser.process_parsers.values())
|
||||||
|
elif file.type == FileType.dmn.value:
|
||||||
|
parser.add_dmn_file(file_path)
|
||||||
|
sub_parsers = list(parser.dmn_parsers.values())
|
||||||
|
parser_type = "decision"
|
||||||
|
else:
|
||||||
|
return references
|
||||||
|
for sub_parser in sub_parsers:
|
||||||
|
references.append(
|
||||||
|
FileReference(
|
||||||
|
id=sub_parser.get_id(), name=sub_parser.get_name(), type=parser_type
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return references
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_file(
|
def add_file(
|
||||||
process_model_info: ProcessModelInfo, file_name: str, binary_data: bytes
|
process_model_info: ProcessModelInfo, file_name: str, binary_data: bytes
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -21,7 +21,6 @@ def create_test_file(type: str, name: str) -> File:
|
||||||
type=type,
|
type=type,
|
||||||
name=name,
|
name=name,
|
||||||
content_type=type,
|
content_type=type,
|
||||||
document={},
|
|
||||||
last_modified=datetime.now(),
|
last_modified=datetime.now(),
|
||||||
size=1,
|
size=1,
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,10 +5,13 @@ import pytest
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_bpmn.api.api_error import ApiError
|
from flask_bpmn.api.api_error import ApiError
|
||||||
from flask_bpmn.models.db import db
|
from flask_bpmn.models.db import db
|
||||||
|
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore
|
||||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||||
|
|
||||||
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
||||||
|
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||||
|
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||||
|
|
||||||
|
|
||||||
class TestSpecFileService(BaseTest):
|
class TestSpecFileService(BaseTest):
|
||||||
|
@ -95,3 +98,44 @@ class TestSpecFileService(BaseTest):
|
||||||
bpmn_process_id_lookups[0].bpmn_file_relative_path
|
bpmn_process_id_lookups[0].bpmn_file_relative_path
|
||||||
== self.call_activity_nested_relative_file_path
|
== self.call_activity_nested_relative_file_path
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_load_reference_information(
|
||||||
|
self, app: Flask, with_db_and_bpmn_file_cleanup: None
|
||||||
|
) -> None:
|
||||||
|
"""Test_load_reference_information.
|
||||||
|
|
||||||
|
When getting files from the spec_file service, each file includes
|
||||||
|
details about how the file can be referenced -- for instance
|
||||||
|
it is possible to reference a DMN file with a Decision.id or
|
||||||
|
a bpmn file with a process.id. These Decisions and processes
|
||||||
|
can also have human readable display names, which should also be avaiable.
|
||||||
|
Note that a single bpmn file can contain many processes, and
|
||||||
|
a DMN file can (theoretically) contain many decisions. So this
|
||||||
|
is an array.
|
||||||
|
"""
|
||||||
|
load_test_spec(
|
||||||
|
"call_activity_nested",
|
||||||
|
process_model_source_directory="call_activity_nested",
|
||||||
|
)
|
||||||
|
process_model_info = ProcessModelService().get_process_model(
|
||||||
|
"call_activity_nested"
|
||||||
|
)
|
||||||
|
files = SpecFileService.get_files(process_model_info)
|
||||||
|
|
||||||
|
file = next(filter(lambda f: f.name == "call_activity_level_3.bpmn", files))
|
||||||
|
ca_3 = SpecFileService.get_references_for_file(
|
||||||
|
file, process_model_info, BpmnDmnParser
|
||||||
|
)
|
||||||
|
assert len(ca_3) == 1
|
||||||
|
assert ca_3[0].name == "Level 3"
|
||||||
|
assert ca_3[0].id == "Level3"
|
||||||
|
assert ca_3[0].type == "process"
|
||||||
|
|
||||||
|
file = next(filter(lambda f: f.name == "level2c.dmn", files))
|
||||||
|
dmn1 = SpecFileService.get_references_for_file(
|
||||||
|
file, process_model_info, BpmnDmnParser
|
||||||
|
)
|
||||||
|
assert len(dmn1) == 1
|
||||||
|
assert dmn1[0].name == "Decision 1"
|
||||||
|
assert dmn1[0].id == "Decision_0vrtcmk"
|
||||||
|
assert dmn1[0].type == "decision"
|
||||||
|
|
Loading…
Reference in New Issue