Clean up process references when deleting models and groups (#1561)

This commit is contained in:
jbirddog 2024-05-16 14:52:55 -04:00 committed by GitHub
parent afd598bb8f
commit 10e9511cfc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 169 additions and 0 deletions

View File

@ -12,6 +12,7 @@ from flask.wrappers import Response
from spiffworkflow_backend.exceptions.api_error import ApiError from spiffworkflow_backend.exceptions.api_error import ApiError
from spiffworkflow_backend.exceptions.error import NotAuthorizedError from spiffworkflow_backend.exceptions.error import NotAuthorizedError
from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError
from spiffworkflow_backend.models.db import db
from spiffworkflow_backend.models.process_group import ProcessGroup from spiffworkflow_backend.models.process_group import ProcessGroup
from spiffworkflow_backend.models.process_group import ProcessGroupSchema from spiffworkflow_backend.models.process_group import ProcessGroupSchema
from spiffworkflow_backend.routes.process_api_blueprint import _commit_and_push_to_git from spiffworkflow_backend.routes.process_api_blueprint import _commit_and_push_to_git
@ -19,6 +20,7 @@ from spiffworkflow_backend.routes.process_api_blueprint import _un_modify_modifi
from spiffworkflow_backend.services.authorization_service import AuthorizationService from spiffworkflow_backend.services.authorization_service import AuthorizationService
from spiffworkflow_backend.services.process_model_service import ProcessModelService from spiffworkflow_backend.services.process_model_service import ProcessModelService
from spiffworkflow_backend.services.process_model_service import ProcessModelWithInstancesNotDeletableError from spiffworkflow_backend.services.process_model_service import ProcessModelWithInstancesNotDeletableError
from spiffworkflow_backend.services.spec_file_service import SpecFileService
from spiffworkflow_backend.services.user_service import UserService from spiffworkflow_backend.services.user_service import UserService
@ -49,6 +51,11 @@ def process_group_delete(modified_process_group_id: str) -> flask.wrappers.Respo
try: try:
ProcessModelService.process_group_delete(process_group_id) ProcessModelService.process_group_delete(process_group_id)
# can't do this in the ProcessModelService due to circular imports
SpecFileService.clear_caches_for_process_group(process_group_id)
db.session.commit()
except ProcessModelWithInstancesNotDeletableError as exception: except ProcessModelWithInstancesNotDeletableError as exception:
raise ApiError( raise ApiError(
error_code="existing_instances", error_code="existing_instances",

View File

@ -112,7 +112,12 @@ def process_model_delete(
) -> flask.wrappers.Response: ) -> flask.wrappers.Response:
process_model_identifier = modified_process_model_identifier.replace(":", "/") process_model_identifier = modified_process_model_identifier.replace(":", "/")
try: try:
process_model = _get_process_model(process_model_identifier)
ProcessModelService.process_model_delete(process_model_identifier) ProcessModelService.process_model_delete(process_model_identifier)
# can't do this in the ProcessModelService due to circular imports
SpecFileService.clear_caches_for_process_model(process_model)
db.session.commit()
except ProcessModelWithInstancesNotDeletableError as exception: except ProcessModelWithInstancesNotDeletableError as exception:
raise ApiError( raise ApiError(
error_code="existing_instances", error_code="existing_instances",

View File

@ -275,6 +275,36 @@ class SpecFileService(FileSystemService):
ProcessCallerService.clear_cache_for_process_ids(reference_cache_ids) ProcessCallerService.clear_cache_for_process_ids(reference_cache_ids)
@staticmethod
def clear_caches_for_process_group(process_group_id: str) -> None:
records = (
db.session.query(ReferenceCacheModel)
.filter(ReferenceCacheModel.relative_location.like(f"{process_group_id}/%")) # type: ignore
.all()
)
reference_cache_ids = []
for record in records:
reference_cache_ids.append(record.id)
db.session.delete(record)
ProcessCallerService.clear_cache_for_process_ids(reference_cache_ids)
@staticmethod
def clear_caches_for_process_model(process_model_info: ProcessModelInfo) -> None:
records = (
db.session.query(ReferenceCacheModel).filter(ReferenceCacheModel.relative_location == process_model_info.id).all()
)
reference_cache_ids = []
for record in records:
reference_cache_ids.append(record.id)
db.session.delete(record)
ProcessCallerService.clear_cache_for_process_ids(reference_cache_ids)
@staticmethod @staticmethod
def update_process_cache(ref: Reference) -> None: def update_process_cache(ref: Reference) -> None:
process_id_lookup = ( process_id_lookup = (

View File

@ -0,0 +1,127 @@
from flask.app import Flask
from flask.testing import FlaskClient
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
from spiffworkflow_backend.models.user import UserModel
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
class TestProcessCallers(BaseTest):
def test_references_after_process_model_create(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
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",
)
response = client.get(
"/v1.0/processes",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert isinstance(response.json, list)
assert len(response.json) == 4
response = client.get(
"/v1.0/processes/callers/Level2",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert isinstance(response.json, list)
assert len(response.json) == 1
def test_references_after_process_model_delete(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
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",
)
response = client.delete(
"/v1.0/process-models/test_group_two:call_activity_nested",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
response = client.get(
"/v1.0/processes",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert isinstance(response.json, list)
assert len(response.json) == 0
response = client.get(
"/v1.0/processes/callers/Level2",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert isinstance(response.json, list)
assert len(response.json) == 0
def test_references_after_process_group_delete(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
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",
)
response = client.delete(
"/v1.0/process-groups/test_group_two",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
response = client.get(
"/v1.0/processes",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert isinstance(response.json, list)
assert len(response.json) == 0
response = client.get(
"/v1.0/processes/callers/Level2",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
assert isinstance(response.json, list)
assert len(response.json) == 0