This commit is contained in:
burnettk 2022-11-15 10:11:26 -05:00
parent a3dcae016f
commit 5008626b19
10 changed files with 102 additions and 89 deletions

View File

@ -1,5 +1,3 @@
from __future__ import with_statement
import logging
from logging.config import fileConfig

View File

@ -375,7 +375,7 @@ paths:
/processes:
get:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_list
summary: Return a list of all processes (not just primary process of a process model)
summary: Return a list of all processes (not just primary process of a process model)
useful for finding processes for call activites.
tags:
- Process Models

View File

@ -63,8 +63,6 @@ CONTENT_TYPES = {
}
@dataclass(order=True)
class File:
"""File."""
@ -131,6 +129,3 @@ class FileSchema(Schema):
references = marshmallow.fields.List(
marshmallow.fields.Nested("SpecReferenceSchema")
)

View File

@ -18,21 +18,21 @@ class SpecReference:
"""
identifier: str # The id of the process or decision. "Process_1234"
display_name: str # The name of the process or decision. "Invoice Submission"
display_name: str # The name of the process or decision. "Invoice Submission"
process_model_id: str
type: str # can be 'process' or 'decision'
file_name: str # The name of the file where this process or decision is defined.
relative_path: str # The path to the file.
has_lanes: bool # If this is a process, whether it has lanes or not.
is_executable: bool # Whether this process or decision is designated as executable.
is_primary: bool # Whether this is the primary process of a process model
messages: dict # Any messages defined in the same file where this process is defined.
correlations: dict # Any correlations defined in the same file with this process.
start_messages: list # The names of any messages that would start this process.
file_name: str # The name of the file where this process or decision is defined.
relative_path: str # The path to the file.
has_lanes: bool # If this is a process, whether it has lanes or not.
is_executable: bool # Whether this process or decision is designated as executable.
is_primary: bool # Whether this is the primary process of a process model
messages: dict # Any messages defined in the same file where this process is defined.
correlations: dict # Any correlations defined in the same file with this process.
start_messages: list # The names of any messages that would start this process.
class SpecReferenceCache(SpiffworkflowBaseDBModel):
"""A cache of information about all the Processes and Decisions defined in all files. """
"""A cache of information about all the Processes and Decisions defined in all files."""
__tablename__ = "spec_reference_cache"
@ -49,16 +49,18 @@ class SpecReferenceCache(SpiffworkflowBaseDBModel):
@classmethod
def from_spec_reference(cls, ref):
"""From_spec_reference."""
return cls(
identifier=ref.identifier,
display_name=ref.display_name,
process_model_id=ref.process_model_id,
type=ref.type,
file_name=ref.file_name,
has_lanes=ref.has_lanes,
is_executable=ref.is_executable,
is_primary=ref.is_primary,
relative_path=ref.relative_path,)
identifier=ref.identifier,
display_name=ref.display_name,
process_model_id=ref.process_model_id,
type=ref.type,
file_name=ref.file_name,
has_lanes=ref.has_lanes,
is_executable=ref.is_executable,
is_primary=ref.is_primary,
relative_path=ref.relative_path,
)
class SpecReferenceSchema(Schema):
@ -68,8 +70,15 @@ class SpecReferenceSchema(Schema):
"""Meta."""
model = SpecReference
fields = ["identifier", "display_name",
"process_group_id", "process_model_id",
"type", "file_name", "has_lanes",
"is_executable", "is_primary"]
unknown = INCLUDE
fields = [
"identifier",
"display_name",
"process_group_id",
"process_model_id",
"type",
"file_name",
"has_lanes",
"is_executable",
"is_primary",
]
unknown = INCLUDE

View File

@ -59,7 +59,8 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
from spiffworkflow_backend.models.secret_model import SecretModel
from spiffworkflow_backend.models.secret_model import SecretModelSchema
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache, SpecReferenceSchema
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.spec_reference import SpecReferenceSchema
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
from spiffworkflow_backend.models.user import UserModel
@ -340,8 +341,8 @@ def process_model_list(
def process_list() -> any:
"""Returns a list of all known processes - this includes processes that are not the
primary process - helpful for finding possible call activities. """
references = SpecReferenceCache.query.filter_by(type = "process")
primary process - helpful for finding possible call activities."""
references = SpecReferenceCache.query.filter_by(type="process")
return SpecReferenceSchema(many=True).dump(references)

View File

@ -67,7 +67,6 @@ from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
from spiffworkflow_backend.models.active_task import ActiveTaskModel
from spiffworkflow_backend.models.active_task_user import ActiveTaskUserModel
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.file import File
from spiffworkflow_backend.models.file import FileType
from spiffworkflow_backend.models.group import GroupModel
@ -86,6 +85,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.models.user import UserModelSchema
@ -671,8 +671,9 @@ class ProcessInstanceProcessor:
return parser
@staticmethod
def backfill_missing_spec_reference_records(bpmn_process_identifier: str) -> Optional[str]:
def backfill_missing_spec_reference_records(
bpmn_process_identifier: str,
) -> Optional[str]:
"""Backfill_missing_spec_reference_records."""
process_models = ProcessModelService().get_process_models()
for process_model in process_models:
@ -695,11 +696,15 @@ class ProcessInstanceProcessor:
"bpmn_file_full_path_from_bpmn_process_identifier: bpmn_process_identifier is unexpectedly None"
)
spec_reference = SpecReferenceCache.query.filter_by(identifier=bpmn_process_identifier).first()
spec_reference = SpecReferenceCache.query.filter_by(
identifier=bpmn_process_identifier
).first()
bpmn_file_full_path = None
if spec_reference is None:
bpmn_file_full_path = ProcessInstanceProcessor.backfill_missing_spec_reference_records(
bpmn_process_identifier
bpmn_file_full_path = (
ProcessInstanceProcessor.backfill_missing_spec_reference_records(
bpmn_process_identifier
)
)
else:
bpmn_file_full_path = os.path.join(

View File

@ -8,10 +8,9 @@ from typing import Optional
from flask_bpmn.models.db import db
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.file import File
from spiffworkflow_backend.models.file import SpecReference
from spiffworkflow_backend.models.file import FileType
from spiffworkflow_backend.models.file import SpecReference
from spiffworkflow_backend.models.message_correlation_property import (
MessageCorrelationPropertyModel,
)
@ -20,6 +19,7 @@ from spiffworkflow_backend.models.message_triggerable_process_model import (
MessageTriggerableProcessModel,
)
from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.services.custom_parser import MyCustomParser
from spiffworkflow_backend.services.file_system_service import FileSystemService
from spiffworkflow_backend.services.process_model_service import ProcessModelService
@ -55,7 +55,7 @@ class SpecFileService(FileSystemService):
@staticmethod
def reference_map(references: list[SpecReference]) -> dict[str, SpecReference]:
""" Creates a dict with provided references organized by id. """
"""Creates a dict with provided references organized by id."""
ref_map = {}
for ref in references:
ref_map[ref.identifier] = ref
@ -63,13 +63,15 @@ class SpecFileService(FileSystemService):
@staticmethod
def get_references(process_models: List[ProcessModelInfo]) -> list[SpecReference]:
"""Returns all references -- process_ids, and decision ids, across all process models provided"""
"""Returns all references -- process_ids, and decision ids, across all process models provided."""
references = []
for process_model in process_models:
references.extend(SpecFileService.get_references_for_process(process_model))
@staticmethod
def get_references_for_process(process_model_info: ProcessModelInfo) -> list[SpecReference]:
def get_references_for_process(
process_model_info: ProcessModelInfo,
) -> list[SpecReference]:
"""Get_references_for_process."""
files = SpecFileService.get_files(process_model_info)
references = []
@ -80,7 +82,9 @@ class SpecFileService(FileSystemService):
return references
@staticmethod
def get_references_for_file(file: File, process_model_info: ProcessModelInfo) -> list[SpecReference]:
def get_references_for_file(
file: File, process_model_info: ProcessModelInfo
) -> list[SpecReference]:
"""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.
@ -116,9 +120,11 @@ class SpecFileService(FileSystemService):
for sub_parser in sub_parsers:
if parser_type == "process":
has_lanes = sub_parser.has_lanes()
executable = sub_parser.process_executable
sub_parser.process_executable
start_messages = sub_parser.start_messages()
is_primary = sub_parser.get_id() == process_model_info.primary_process_id
is_primary = (
sub_parser.get_id() == process_model_info.primary_process_id
)
references.append(
SpecReference(
@ -133,7 +139,7 @@ class SpecFileService(FileSystemService):
messages=messages,
is_primary=is_primary,
correlations=correlations,
start_messages=start_messages
start_messages=start_messages,
)
)
return references
@ -166,11 +172,12 @@ class SpecFileService(FileSystemService):
if ref.is_primary:
ProcessModelService().update_spec(
process_model_info, {
process_model_info,
{
"primary_process_id": ref.identifier,
"primary_file_name": file_name,
"is_review": ref.has_lanes,
}
},
)
SpecFileService.update_process_cache(ref)
SpecFileService.update_message_cache(ref)
@ -229,7 +236,10 @@ class SpecFileService(FileSystemService):
@staticmethod
def update_process_cache(ref: SpecReference) -> None:
process_id_lookup = SpecReferenceCache.query.filter_by(identifier=ref.identifier).first()
"""Update_process_cache."""
process_id_lookup = SpecReferenceCache.query.filter_by(
identifier=ref.identifier
).first()
if process_id_lookup is None:
process_id_lookup = SpecReferenceCache.from_spec_reference(ref)
db.session.add(process_id_lookup)
@ -246,9 +256,7 @@ class SpecFileService(FileSystemService):
f"{process_id_lookup.relative_path}. It cannot be reused."
)
else:
process_id_lookup.relative_path = (
ref.relative_path
)
process_id_lookup.relative_path = ref.relative_path
db.session.add(process_id_lookup)
db.session.commit()
@ -269,7 +277,7 @@ class SpecFileService(FileSystemService):
@staticmethod
def update_message_trigger_cache(
ref: SpecReference, process_model_info: ProcessModelInfo
ref: SpecReference, process_model_info: ProcessModelInfo
) -> None:
"""Assure we know which messages can trigger the start of a process."""
for message_model_identifier in ref.start_messages:

View File

@ -9,8 +9,6 @@ import pytest
from flask.app import Flask
from flask.testing import FlaskClient
from flask_bpmn.models.db import db
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
@ -27,6 +25,7 @@ from spiffworkflow_backend.models.process_instance_report import (
)
from spiffworkflow_backend.models.process_model import NotificationType
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.services.authorization_service import AuthorizationService
from spiffworkflow_backend.services.file_system_service import FileSystemService
@ -441,45 +440,49 @@ class TestProcessApi(BaseTest):
assert response.json["pagination"]["total"] == 5
assert response.json["pagination"]["pages"] == 2
def test_process_list(self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
):
def test_process_list(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
):
"""It should be possible to get a list of all processes known to the system."""
load_test_spec(
"test_group_one/simple_form",
process_model_source_directory='simple_form',
bpmn_file_name='simple_form'
process_model_source_directory="simple_form",
bpmn_file_name="simple_form",
)
# When adding a process model with one Process, no decisions, and some json files, only one process is recorded.
assert(len(SpecReferenceCache.query.all()) == 1)
assert len(SpecReferenceCache.query.all()) == 1
self.create_group_and_model_with_bpmn(
client=client,
user=with_super_admin_user,
process_group_id='test_group_two',
process_model_id='call_activity_nested',
bpmn_file_location='call_activity_nested'
process_group_id="test_group_two",
process_model_id="call_activity_nested",
bpmn_file_location="call_activity_nested",
)
# When adding a process model with 4 processes and a decision, 5 new records will be in the Cache
assert(len(SpecReferenceCache.query.all()) == 6)
assert len(SpecReferenceCache.query.all()) == 6
# get the results
response = client.get("/v1.0/processes", headers=self.logged_in_headers(with_super_admin_user),
response = client.get(
"/v1.0/processes",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.json is not None
# We should get 5 back, as one of the items in the cache is a decision.
assert len(response.json) == 5
simple_form = next(p for p in response.json if p['identifier'] == 'Proccess_WithForm')
assert(simple_form['display_name'] == 'Process With Form')
assert(simple_form['process_model_id'] == 'test_group_one/simple_form')
assert(simple_form['has_lanes'] == False)
assert(simple_form['is_executable'] == True)
assert(simple_form['is_primary'] == True)
simple_form = next(
p for p in response.json if p["identifier"] == "Proccess_WithForm"
)
assert simple_form["display_name"] == "Process With Form"
assert simple_form["process_model_id"] == "test_group_one/simple_form"
assert simple_form["has_lanes"] == False
assert simple_form["is_executable"] == True
assert simple_form["is_primary"] == True
def test_process_group_add(
self,

View File

@ -5,8 +5,8 @@ from flask_bpmn.models.db import db
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.services.process_instance_processor import (
ProcessInstanceProcessor,

View File

@ -69,10 +69,7 @@ class TestSpecFileService(BaseTest):
)
bpmn_process_id_lookups = SpecReferenceCache.query.all()
assert len(bpmn_process_id_lookups) == 1
assert (
bpmn_process_id_lookups[0].identifier
== bpmn_process_identifier
)
assert bpmn_process_id_lookups[0].identifier == bpmn_process_identifier
assert (
bpmn_process_id_lookups[0].relative_path
== self.call_activity_nested_relative_file_path
@ -115,10 +112,7 @@ class TestSpecFileService(BaseTest):
bpmn_process_id_lookups = SpecReferenceCache.query.all()
assert len(bpmn_process_id_lookups) == 1
assert (
bpmn_process_id_lookups[0].identifier
== bpmn_process_identifier
)
assert bpmn_process_id_lookups[0].identifier == bpmn_process_identifier
assert (
bpmn_process_id_lookups[0].relative_path
== self.call_activity_nested_relative_file_path