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 typing import Optional
|
||||
|
||||
import marshmallow
|
||||
from marshmallow import INCLUDE
|
||||
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)
|
||||
class File:
|
||||
"""File."""
|
||||
|
@ -70,17 +85,12 @@ class File:
|
|||
content_type: str
|
||||
name: str
|
||||
type: str
|
||||
document: dict
|
||||
last_modified: datetime
|
||||
size: int
|
||||
process_instance_id: Optional[int] = None
|
||||
irb_doc_code: Optional[str] = None
|
||||
data_store: Optional[dict] = field(default_factory=dict)
|
||||
user_uid: Optional[str] = None
|
||||
references: Optional[list[FileReference]] = None
|
||||
file_contents: Optional[bytes] = None
|
||||
process_model_id: Optional[str] = None
|
||||
process_group_id: Optional[str] = None
|
||||
archived: bool = False
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""__post_init__."""
|
||||
|
@ -100,7 +110,6 @@ class File:
|
|||
name=file_name,
|
||||
content_type=content_type,
|
||||
type=file_type.value,
|
||||
document={},
|
||||
last_modified=last_modified,
|
||||
size=file_size,
|
||||
)
|
||||
|
@ -118,32 +127,29 @@ class FileSchema(Schema):
|
|||
"id",
|
||||
"name",
|
||||
"content_type",
|
||||
"process_instance_id",
|
||||
"irb_doc_code",
|
||||
"last_modified",
|
||||
"type",
|
||||
"archived",
|
||||
"size",
|
||||
"data_store",
|
||||
"document",
|
||||
"user_uid",
|
||||
"url",
|
||||
"file_contents",
|
||||
"process_model_id",
|
||||
"references",
|
||||
"process_group_id",
|
||||
"process_model_id",
|
||||
]
|
||||
unknown = INCLUDE
|
||||
references = marshmallow.fields.List(
|
||||
marshmallow.fields.Nested("FileReferenceSchema")
|
||||
)
|
||||
|
||||
# url = Method("get_url")
|
||||
#
|
||||
# def get_url(self, obj):
|
||||
# token = 'not_available'
|
||||
# if hasattr(obj, 'id') and obj.id is not None:
|
||||
# file_url = url_for("/v1_0.crc_api_file_get_file_data_link", file_id=obj.id, _external=True)
|
||||
# if hasattr(flask.g, 'user'):
|
||||
# token = flask.g.user.encode_auth_token()
|
||||
# url = file_url + '?auth_token=' + urllib.parse.quote_plus(token)
|
||||
# return url
|
||||
# else:
|
||||
# return ""
|
||||
#
|
||||
|
||||
class FileReferenceSchema(Schema):
|
||||
"""FileSchema."""
|
||||
|
||||
class Meta:
|
||||
"""Meta."""
|
||||
|
||||
model = FileReference
|
||||
fields = ["id", "name", "type"]
|
||||
unknown = INCLUDE
|
||||
|
|
|
@ -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.git_service import GitService
|
||||
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 (
|
||||
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)
|
||||
files = sorted(SpecFileService.get_files(process_model))
|
||||
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)
|
||||
return process_model_json
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from typing import List
|
||||
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.file import File
|
||||
from spiffworkflow_backend.models.file import FileReference
|
||||
from spiffworkflow_backend.models.file import FileType
|
||||
from spiffworkflow_backend.models.message_correlation_property import (
|
||||
MessageCorrelationPropertyModel,
|
||||
|
@ -54,6 +56,41 @@ class SpecFileService(FileSystemService):
|
|||
)
|
||||
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
|
||||
def add_file(
|
||||
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,
|
||||
name=name,
|
||||
content_type=type,
|
||||
document={},
|
||||
last_modified=datetime.now(),
|
||||
size=1,
|
||||
)
|
||||
|
|
|
@ -5,10 +5,13 @@ import pytest
|
|||
from flask import Flask
|
||||
from flask_bpmn.api.api_error import ApiError
|
||||
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.test_data import load_test_spec
|
||||
|
||||
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):
|
||||
|
@ -95,3 +98,44 @@ class TestSpecFileService(BaseTest):
|
|||
bpmn_process_id_lookups[0].bpmn_file_relative_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