unique bpmn process ids (#927)

* remove SpecReferenceCache

* make sure strings are sometimes unique

* lint

* more random

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: burnettk <burnettk@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Kevin Burnett 2024-01-30 12:48:44 -08:00 committed by GitHub
parent 4cb1f33ac9
commit 711da2b048
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 17 additions and 92 deletions

View File

@ -23,9 +23,6 @@ from spiffworkflow_backend.models.principal import PrincipalModel # noqa: F401
from spiffworkflow_backend.models.human_task import HumanTaskModel # noqa: F401
from spiffworkflow_backend.models.spec_reference import (
SpecReferenceCache,
) # noqa: F401
from spiffworkflow_backend.models.cache_generation import (
CacheGenerationModel,
) # noqa: F401

View File

@ -59,7 +59,6 @@ class Reference:
return os.path.join(self.relative_location, self.file_name).replace("/", os.sep)
# SpecReferenceCache
class ReferenceCacheModel(SpiffworkflowBaseDBModel):
"""A cache of information about all the Processes and Decisions defined in all files."""

View File

@ -1,85 +0,0 @@
from dataclasses import dataclass
from flask_marshmallow import Schema # type: ignore
from marshmallow import INCLUDE
from sqlalchemy import UniqueConstraint
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
from spiffworkflow_backend.models.db import db
class SpecReferenceNotFoundError(Exception):
pass
@dataclass()
class SpecReference:
"""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 - if for instance, there are
three executable processes in a collaboration within a BPMN Diagram.
"""
identifier: str # The id of the process or decision. "Process_1234"
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.
called_element_ids: list # The element ids of any called elements
class SpecReferenceCache(SpiffworkflowBaseDBModel):
"""A cache of information about all the Processes and Decisions defined in all files."""
__tablename__ = "spec_reference_cache"
__table_args__ = (UniqueConstraint("identifier", "type", name="_identifier_type_unique"),)
id = db.Column(db.Integer, primary_key=True)
identifier = db.Column(db.String(255), index=True)
display_name = db.Column(db.String(255), index=True)
process_model_id = db.Column(db.String(255), index=True)
type = db.Column(db.String(255), index=True) # either 'process' or 'decision'
file_name = db.Column(db.String(255))
relative_path = db.Column(db.String(255))
has_lanes = db.Column(db.Boolean())
is_executable = db.Column(db.Boolean())
is_primary = db.Column(db.Boolean())
@classmethod
def from_spec_reference(cls, ref: SpecReference) -> "SpecReferenceCache":
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,
)
class SpecReferenceSchema(Schema): # type: ignore
class Meta:
model = SpecReference
fields = [
"identifier",
"display_name",
"process_group_id",
"process_model_id",
"type",
"file_name",
"has_lanes",
"is_executable",
"is_primary",
]
unknown = INCLUDE

View File

@ -1,7 +1,9 @@
"""APIs for dealing with process groups, process models, and process instances."""
import json
import os
import random
import re
import string
from hashlib import sha256
from typing import Any
@ -83,6 +85,15 @@ def process_model_create(
with open(template_file) as f:
contents = f.read()
process_model_id_for_bpmn_file = process_model_info.id.split("/")[-1]
# convert dashes to underscores for process id
underscored_process_id = process_model_id_for_bpmn_file.replace("-", "_")
# make process id unique by adding random string to add
fuzz = "".join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(7))
process_id_with_fuzz = f"Process_{underscored_process_id}_{fuzz}"
contents = contents.replace("Process_replace_me_just_for_template", process_id_with_fuzz)
SpecFileService.update_file(process_model_info, f"{process_model_id_for_bpmn_file}.bpmn", contents.encode())
_commit_and_push_to_git(f"User: {g.user.username} created process model {process_model_info.id}")

View File

@ -1,6 +1,6 @@
<?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:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Process_ynixgwm" isExecutable="true">
<bpmn:process id="Process_replace_me_just_for_template" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_17db3yp</bpmn:outgoing>
</bpmn:startEvent>
@ -27,7 +27,7 @@ You can also change the text you are reading here by updating the *Instructions*
</bpmn:manualTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_ynixgwm">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_replace_me_just_for_template">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>

View File

@ -166,7 +166,7 @@ class TestNestedGroups(BaseTest):
data=json.dumps(ProcessGroupSchema().dump(process_group_c)),
)
def test_process_model_create(
def test_process_model_create_nested(
self,
app: Flask,
client: FlaskClient,

View File

@ -173,6 +173,9 @@ class TestProcessApi(BaseTest):
assert model_display_name == process_model.display_name
assert 0 == process_model.display_order
assert 1 == len(ProcessModelService.get_process_groups())
assert process_model.primary_file_name == f"{process_model_id}.bpmn"
assert process_model.primary_process_id
assert process_model.primary_process_id.startswith(f"Process_{process_model_id}")
# add bpmn file to the model
bpmn_file_name = "sample.bpmn"