mirror of
https://github.com/sartography/spiffworkflow-backend.git
synced 2025-02-23 12:58:13 +00:00
When returning the list of files in a ProcessModel, include all the ways they can be referenced,
for instance, json files, can be referened by file name, bpmn files can be referened by one more process ids, and DMN's files can be referenced by one or more decision ids. This information is now included in the reference. Also cleaned up a number of things in the File Object that were always null / are cary overs from CR-Connect that are not in use, and unlikely to ever be used in this way.
This commit is contained in:
parent
5c6601237e
commit
98e1776edf
@ -4,12 +4,14 @@ from dataclasses import field
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import marshmallow
|
||||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.db import SpiffworkflowBaseDBModel
|
||||
from marshmallow import INCLUDE
|
||||
from marshmallow import Schema
|
||||
|
||||
from spiffworkflow_backend.helpers.spiff_enum import SpiffEnum
|
||||
|
||||
|
||||
class FileType(SpiffEnum):
|
||||
"""FileType."""
|
||||
|
||||
@ -60,6 +62,14 @@ CONTENT_TYPES = {
|
||||
"zip": "application/zip",
|
||||
}
|
||||
|
||||
@dataclass()
|
||||
class FileReference:
|
||||
"""File Reference Information -- 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:
|
||||
@ -70,17 +80,13 @@ 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: 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 +106,6 @@ class File:
|
||||
name=file_name,
|
||||
content_type=content_type,
|
||||
type=file_type.value,
|
||||
document={},
|
||||
last_modified=last_modified,
|
||||
size=file_size,
|
||||
)
|
||||
@ -118,32 +123,36 @@ 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"))
|
||||
|
||||
|
||||
class FileReferenceSchema(Schema):
|
||||
"""FileSchema."""
|
||||
|
||||
class Meta:
|
||||
"""Meta."""
|
||||
|
||||
model = FileReference
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"type"
|
||||
]
|
||||
unknown = INCLUDE
|
||||
|
||||
# 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 ""
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -65,7 +65,7 @@ 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 (
|
||||
ProcessInstanceProcessor,
|
||||
ProcessInstanceProcessor, MyCustomParser,
|
||||
)
|
||||
from spiffworkflow_backend.services.process_instance_service import (
|
||||
ProcessInstanceService,
|
||||
@ -263,6 +263,8 @@ 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
|
||||
|
||||
|
@ -5,6 +5,8 @@ from datetime import datetime
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser
|
||||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser
|
||||
from flask_bpmn.api.api_error import ApiError
|
||||
from flask_bpmn.models.db import db
|
||||
from lxml import etree # type: ignore
|
||||
@ -13,7 +15,7 @@ from lxml.etree import Element as EtreeElement
|
||||
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore
|
||||
|
||||
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
||||
from spiffworkflow_backend.models.file import File
|
||||
from spiffworkflow_backend.models.file import File, FileReference
|
||||
from spiffworkflow_backend.models.file import FileType
|
||||
from spiffworkflow_backend.models.message_correlation_property import (
|
||||
MessageCorrelationPropertyModel,
|
||||
@ -54,6 +56,37 @@ 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 = []
|
||||
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
|
||||
|
1
tests/data/call_activity_nested/schema.json
Normal file
1
tests/data/call_activity_nested/schema.json
Normal file
@ -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,
|
||||
)
|
||||
|
@ -2,9 +2,13 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser
|
||||
from flask import Flask
|
||||
from flask_bpmn.api.api_error import ApiError
|
||||
from flask_bpmn.models.db import db
|
||||
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
@ -95,3 +99,37 @@ 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:
|
||||
"""
|
||||
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…
x
Reference in New Issue
Block a user