basic support to find a process instance by id w/ burnettk
This commit is contained in:
parent
49a71d8981
commit
158cbb4bfd
|
@ -946,6 +946,27 @@ paths:
|
|||
schema:
|
||||
$ref: "#/components/schemas/Workflow"
|
||||
|
||||
/process-instances/find-by-id/{process_instance_id}:
|
||||
parameters:
|
||||
- name: process_instance_id
|
||||
in: path
|
||||
required: true
|
||||
description: The unique id of an existing process instance.
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_find_by_id
|
||||
summary: Find a process instance based on its id only
|
||||
tags:
|
||||
- Process Instances
|
||||
responses:
|
||||
"200":
|
||||
description: One Process Instance
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Workflow"
|
||||
|
||||
/process-instances/{modified_process_model_identifier}/{process_instance_id}:
|
||||
parameters:
|
||||
- name: modified_process_model_identifier
|
||||
|
|
|
@ -30,6 +30,12 @@ permissions:
|
|||
allowed_permissions: [read]
|
||||
uri: /*
|
||||
|
||||
process-instances-find-by-id:
|
||||
groups: [everybody]
|
||||
users: []
|
||||
allowed_permissions: [read]
|
||||
uri: /process-instances/find-by-id/*
|
||||
|
||||
tasks-crud:
|
||||
groups: [everybody]
|
||||
users: []
|
||||
|
|
|
@ -58,6 +58,14 @@ class ProcessModelInfo:
|
|||
"""Id_for_file_path."""
|
||||
return self.id.replace("/", os.sep)
|
||||
|
||||
@classmethod
|
||||
def modify_process_identifier_for_path_param(cls, identifier: str) -> str:
|
||||
"""Identifier."""
|
||||
if "\\" in identifier:
|
||||
raise Exception(f"Found backslash in identifier: {identifier}")
|
||||
|
||||
return identifier.replace("/", ":")
|
||||
|
||||
|
||||
class ProcessModelInfoSchema(Schema):
|
||||
"""ProcessModelInfoSchema."""
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""APIs for dealing with process groups, process models, and process instances."""
|
||||
import json
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
|
@ -88,9 +90,7 @@ def process_instance_run(
|
|||
do_engine_steps: bool = True,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Process_instance_run."""
|
||||
process_instance = ProcessInstanceService().get_process_instance(
|
||||
process_instance_id
|
||||
)
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
if process_instance.status != "not_started":
|
||||
raise ApiError(
|
||||
error_code="process_instance_not_runnable",
|
||||
|
@ -138,9 +138,7 @@ def process_instance_terminate(
|
|||
modified_process_model_identifier: str,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Process_instance_run."""
|
||||
process_instance = ProcessInstanceService().get_process_instance(
|
||||
process_instance_id
|
||||
)
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.terminate()
|
||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||
|
@ -151,9 +149,7 @@ def process_instance_suspend(
|
|||
modified_process_model_identifier: str,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Process_instance_suspend."""
|
||||
process_instance = ProcessInstanceService().get_process_instance(
|
||||
process_instance_id
|
||||
)
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.suspend()
|
||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||
|
@ -164,9 +160,7 @@ def process_instance_resume(
|
|||
modified_process_model_identifier: str,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Process_instance_resume."""
|
||||
process_instance = ProcessInstanceService().get_process_instance(
|
||||
process_instance_id
|
||||
)
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.resume()
|
||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||
|
@ -575,14 +569,38 @@ def process_instance_reset(
|
|||
spiff_step: int = 0,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Reset a process instance to a particular step."""
|
||||
process_instance = ProcessInstanceService().get_process_instance(
|
||||
process_instance_id
|
||||
)
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.reset_process(spiff_step)
|
||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||
|
||||
|
||||
def process_instance_find_by_id(
|
||||
process_instance_id: int,
|
||||
) -> flask.wrappers.Response:
|
||||
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
modified_process_model_identifier = ProcessModelInfo.modify_process_identifier_for_path_param(process_instance.process_model_identifier)
|
||||
process_instance_uri = f'/process-instances/{modified_process_model_identifier}/{process_instance.id}'
|
||||
has_permission = AuthorizationService.user_has_permission(
|
||||
user=g.user,
|
||||
permission='read',
|
||||
target_uri=process_instance_uri,
|
||||
)
|
||||
|
||||
uri_type = None
|
||||
if not has_permission:
|
||||
process_instance = _find_process_instance_for_me_or_raise(process_instance_id)
|
||||
uri_type = 'for-me'
|
||||
|
||||
response_json = {
|
||||
"process_instance": process_instance,
|
||||
"uri_type": uri_type,
|
||||
|
||||
}
|
||||
return make_response(jsonify(response_json), 200)
|
||||
|
||||
|
||||
def _get_process_instance(
|
||||
modified_process_model_identifier: str,
|
||||
process_instance: ProcessInstanceModel,
|
||||
|
|
|
@ -624,6 +624,83 @@ class AuthorizationService:
|
|||
|
||||
return permissions_to_assign
|
||||
|
||||
@classmethod
|
||||
def set_basic_permissions(cls) -> list[PermissionToAssign]:
|
||||
permissions_to_assign: list[PermissionToAssign] = []
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission="read", target_uri="/process-instances/for-me"
|
||||
)
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission="read", target_uri="/processes")
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission="read", target_uri="/service-tasks")
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission="read", target_uri="/user-groups/for-current-user"
|
||||
)
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission="read", target_uri="/process-instances/find-by-id/*"
|
||||
)
|
||||
)
|
||||
|
||||
for permission in ["create", "read", "update", "delete"]:
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission=permission, target_uri="/process-instances/reports/*"
|
||||
)
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission=permission, target_uri="/tasks/*")
|
||||
)
|
||||
return permissions_to_assign
|
||||
|
||||
@classmethod
|
||||
def set_process_group_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]:
|
||||
permissions_to_assign: list[PermissionToAssign] = []
|
||||
process_group_identifier = (
|
||||
target.removeprefix("PG:").replace("/", ":").removeprefix(":")
|
||||
)
|
||||
process_related_path_segment = f"{process_group_identifier}:*"
|
||||
if process_group_identifier == "ALL":
|
||||
process_related_path_segment = "*"
|
||||
target_uris = [
|
||||
f"/process-groups/{process_related_path_segment}",
|
||||
f"/process-models/{process_related_path_segment}",
|
||||
]
|
||||
permissions_to_assign = (
|
||||
permissions_to_assign
|
||||
+ cls.get_permissions_to_assign(
|
||||
permission_set, process_related_path_segment, target_uris
|
||||
)
|
||||
)
|
||||
return permissions_to_assign
|
||||
|
||||
@classmethod
|
||||
def set_process_model_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]:
|
||||
permissions_to_assign: list[PermissionToAssign] = []
|
||||
process_model_identifier = (
|
||||
target.removeprefix("PM:").replace("/", ":").removeprefix(":")
|
||||
)
|
||||
process_related_path_segment = f"{process_model_identifier}/*"
|
||||
|
||||
if process_model_identifier == "ALL":
|
||||
process_related_path_segment = "*"
|
||||
|
||||
target_uris = [f"/process-models/{process_related_path_segment}"]
|
||||
permissions_to_assign = (
|
||||
permissions_to_assign
|
||||
+ cls.get_permissions_to_assign(
|
||||
permission_set, process_related_path_segment, target_uris
|
||||
)
|
||||
)
|
||||
return permissions_to_assign
|
||||
|
||||
@classmethod
|
||||
def explode_permissions(
|
||||
cls, permission_set: str, target: str
|
||||
|
@ -654,72 +731,16 @@ class AuthorizationService:
|
|||
permissions = ["create", "read", "update", "delete"]
|
||||
|
||||
if target.startswith("PG:"):
|
||||
process_group_identifier = (
|
||||
target.removeprefix("PG:").replace("/", ":").removeprefix(":")
|
||||
)
|
||||
process_related_path_segment = f"{process_group_identifier}:*"
|
||||
if process_group_identifier == "ALL":
|
||||
process_related_path_segment = "*"
|
||||
target_uris = [
|
||||
f"/process-groups/{process_related_path_segment}",
|
||||
f"/process-models/{process_related_path_segment}",
|
||||
]
|
||||
permissions_to_assign = (
|
||||
permissions_to_assign
|
||||
+ cls.get_permissions_to_assign(
|
||||
permission_set, process_related_path_segment, target_uris
|
||||
)
|
||||
)
|
||||
|
||||
permissions_to_assign += cls.set_process_group_permissions(target, permission_set)
|
||||
elif target.startswith("PM:"):
|
||||
process_model_identifier = (
|
||||
target.removeprefix("PM:").replace("/", ":").removeprefix(":")
|
||||
)
|
||||
process_related_path_segment = f"{process_model_identifier}/*"
|
||||
|
||||
if process_model_identifier == "ALL":
|
||||
process_related_path_segment = "*"
|
||||
|
||||
target_uris = [f"/process-models/{process_related_path_segment}"]
|
||||
permissions_to_assign = (
|
||||
permissions_to_assign
|
||||
+ cls.get_permissions_to_assign(
|
||||
permission_set, process_related_path_segment, target_uris
|
||||
)
|
||||
)
|
||||
|
||||
permissions_to_assign += cls.set_process_model_permissions(target, permission_set)
|
||||
elif permission_set == "start":
|
||||
raise InvalidPermissionError(
|
||||
"Permission 'start' is only available for macros PM and PG."
|
||||
)
|
||||
|
||||
elif target.startswith("BASIC"):
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission="read", target_uri="/process-instances/for-me"
|
||||
)
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission="read", target_uri="/processes")
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission="read", target_uri="/service-tasks")
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission="read", target_uri="/user-groups/for-current-user"
|
||||
)
|
||||
)
|
||||
|
||||
for permission in ["create", "read", "update", "delete"]:
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(
|
||||
permission=permission, target_uri="/process-instances/reports/*"
|
||||
)
|
||||
)
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission=permission, target_uri="/tasks/*")
|
||||
)
|
||||
permissions_to_assign += cls.set_basic_permissions()
|
||||
elif target == "ALL":
|
||||
for permission in permissions:
|
||||
permissions_to_assign.append(
|
||||
|
|
|
@ -354,11 +354,7 @@ class BaseTest:
|
|||
assert has_permission is expected_result
|
||||
|
||||
def modify_process_identifier_for_path_param(self, identifier: str) -> str:
|
||||
"""Identifier."""
|
||||
if "\\" in identifier:
|
||||
raise Exception(f"Found backslash in identifier: {identifier}")
|
||||
|
||||
return identifier.replace("/", ":")
|
||||
return ProcessModelInfo.modify_process_identifier_for_path_param(identifier)
|
||||
|
||||
def un_modify_modified_process_identifier_for_path_param(
|
||||
self, modified_identifier: str
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
"""Test_users_controller."""
|
||||
from flask.app import Flask
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
from flask.testing import FlaskClient
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
|
||||
|
||||
class TestProcessInstancesController(BaseTest):
|
||||
def test_find_by_id(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_user_search_returns_a_user."""
|
||||
user_one = self.create_user_with_permission(username="user_one", target_uri="/process-instances/find-by-id/*")
|
||||
user_two = self.create_user_with_permission(username="user_two", target_uri="/process-instances/find-by-id/*")
|
||||
|
||||
process_model = load_test_spec(
|
||||
process_model_id="group/sample",
|
||||
bpmn_file_name="sample.bpmn",
|
||||
process_model_source_directory="sample",
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(
|
||||
process_model=process_model, user=user_one
|
||||
)
|
||||
|
||||
response = client.get(
|
||||
f"/v1.0/process-instances/find-by-id/{process_instance.id}",
|
||||
headers=self.logged_in_headers(user_one),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json
|
||||
assert response.json['id'] == process_instance.id
|
||||
|
||||
response = client.get(
|
||||
f"/v1.0/process-instances/find-by-id/{process_instance.id}",
|
||||
headers=self.logged_in_headers(user_two),
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
response = client.get(
|
||||
f"/v1.0/process-instances/find-by-id/{process_instance.id}",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json
|
||||
assert response.json['id'] == process_instance.id
|
|
@ -277,6 +277,7 @@ class TestAuthorizationService(BaseTest):
|
|||
) -> None:
|
||||
"""Test_explode_permissions_basic."""
|
||||
expected_permissions = [
|
||||
("/process-instances/find-by-id/*", "read"),
|
||||
("/process-instances/for-me", "read"),
|
||||
("/process-instances/reports/*", "create"),
|
||||
("/process-instances/reports/*", "delete"),
|
||||
|
|
Loading…
Reference in New Issue