From bc7c5920b2e9133ffc9a62485386611130e78c73 Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 5 Dec 2022 16:06:08 -0500 Subject: [PATCH] cleaned up more api routes for permissions w/ burnettk --- .../src/spiffworkflow_backend/api.yml | 46 +++++------ .../config/permissions/development.yml | 6 +- .../routes/process_api_blueprint.py | 6 +- .../helpers/base_test.py | 2 +- .../integration/test_logging_service.py | 2 +- .../integration/test_process_api.py | 11 +-- .../src/components/ProcessInstanceRun.tsx | 2 +- .../src/components/ProcessModelForm.tsx | 1 - .../src/hooks/UriListForPermissions.tsx | 5 +- .../src/routes/ProcessInstanceLogList.tsx | 8 +- .../src/routes/ProcessInstanceShow.tsx | 81 ++++++++++++------- .../src/routes/TaskShow.tsx | 72 ++++++++++------- 12 files changed, 139 insertions(+), 103 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml index fe783918..a8204d39 100755 --- a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml @@ -646,7 +646,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-models/{modified_process_model_id}/process-instances: + /process-instances/{modified_process_model_id}: parameters: - name: modified_process_model_id in: path @@ -654,7 +654,6 @@ paths: description: The unique id of an existing process model. schema: type: string - # process_instance_create post: operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_create summary: Creates an process instance from a process model and returns the instance @@ -668,28 +667,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}: - parameters: - - name: process_instance_id - in: path - required: true - description: The unique id of an existing process instance. - schema: - type: integer - delete: - operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_delete - summary: Deletes a single process instance - tags: - - Process Instances - responses: - "200": - description: The process instance was deleted. - content: - application/json: - schema: - $ref: "#/components/schemas/OkTrue" - - /process-models/{modified_process_model_identifier}/process-instances/{process_instance_id}: + /process-instances/{modified_process_model_identifier}/{process_instance_id}: parameters: - name: modified_process_model_identifier in: path @@ -715,6 +693,18 @@ paths: application/json: schema: $ref: "#/components/schemas/Workflow" + delete: + operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_delete + summary: Deletes a single process instance + tags: + - Process Instances + responses: + "200": + description: The process instance was deleted. + content: + application/json: + schema: + $ref: "#/components/schemas/OkTrue" /process-instances/{modified_process_model_identifier}/{process_instance_id}/run: parameters: @@ -743,7 +733,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}/terminate: + /process-instances/{modified_process_model_identifier}/{process_instance_id}/terminate: parameters: - name: process_instance_id in: path @@ -764,7 +754,7 @@ paths: schema: $ref: "#/components/schemas/OkTrue" - /process-instances/{process_instance_id}/suspend: + /process-instances/{modified_process_model_identifier}/{process_instance_id}/suspend: parameters: - name: process_instance_id in: path @@ -785,7 +775,7 @@ paths: schema: $ref: "#/components/schemas/OkTrue" - /process-instances/{process_instance_id}/resume: + /process-instances/{modified_process_model_identifier}/{process_instance_id}/resume: parameters: - name: process_instance_id in: path @@ -1326,7 +1316,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}/logs: + /logs/{modified_process_model_identifier}/{process_instance_id}: parameters: - name: process_instance_id in: path diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml index b404aa97..9a2f2284 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml @@ -175,17 +175,17 @@ permissions: uri: /v1.0/process-instances/manage-procurement:vendor-lifecycle-management:* core1-admin-models-instantiate: - groups: ["core-contributor"] + groups: ["core-contributor", "Finance Team"] users: [] allowed_permissions: [create] uri: /v1.0/process-models/misc:category_number_one:process-model-with-form/process-instances core1-admin-instances: - groups: ["core-contributor"] + groups: ["core-contributor", "Finance Team"] users: [] allowed_permissions: [create, read] uri: /v1.0/process-instances/misc:category_number_one:process-model-with-form:* core1-admin-instances-slash: - groups: ["core-contributor"] + groups: ["core-contributor", "Finance Team"] users: [] allowed_permissions: [create, read] uri: /v1.0/process-instances/misc:category_number_one:process-model-with-form/* diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index 6843fb15..77fe594c 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -565,6 +565,7 @@ def process_instance_run( def process_instance_terminate( process_instance_id: int, + modified_process_model_identifier: str, ) -> flask.wrappers.Response: """Process_instance_run.""" process_instance = ProcessInstanceService().get_process_instance( @@ -577,6 +578,7 @@ def process_instance_terminate( def process_instance_suspend( process_instance_id: int, + modified_process_model_identifier: str, ) -> flask.wrappers.Response: """Process_instance_suspend.""" process_instance = ProcessInstanceService().get_process_instance( @@ -589,6 +591,7 @@ def process_instance_suspend( def process_instance_resume( process_instance_id: int, + modified_process_model_identifier: str, ) -> flask.wrappers.Response: """Process_instance_resume.""" process_instance = ProcessInstanceService().get_process_instance( @@ -600,6 +603,7 @@ def process_instance_resume( def process_instance_log_list( + modified_process_model_identifier: str, process_instance_id: int, page: int = 1, per_page: int = 100, @@ -1071,7 +1075,7 @@ def process_instance_show( return make_response(jsonify(process_instance), 200) -def process_instance_delete(process_instance_id: int) -> flask.wrappers.Response: +def process_instance_delete(process_instance_id: int, modified_process_model_identifier: str) -> flask.wrappers.Response: """Create_process_instance.""" process_instance = find_process_instance_by_id_or_raise(process_instance_id) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py b/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py index 8d56853b..48982fc6 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py @@ -265,7 +265,7 @@ class BaseTest: ) modified_process_model_id = test_process_model_id.replace("/", ":") response = client.post( - f"/v1.0/process-models/{modified_process_model_id}/process-instances", + f"/v1.0/process-instances/{modified_process_model_id}", headers=headers, ) assert response.status_code == 201 diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py index 2f56d1d6..f9dd4452 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py @@ -57,7 +57,7 @@ class TestLoggingService(BaseTest): assert response.status_code == 200 log_response = client.get( - f"/v1.0/process-instances/{process_instance_id}/logs", + f"/v1.0/logs/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}", headers=headers, ) assert log_response.status_code == 200 diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py index cd2d37c6..9d719a23 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -912,7 +912,7 @@ class TestProcessApi(BaseTest): modified_process_model_identifier = process_model_identifier.replace("/", ":") response = client.post( - f"/v1.0/process-models/{modified_process_model_identifier}/process-instances", + f"/v1.0/process-instances/{modified_process_model_identifier}", headers=self.logged_in_headers(with_super_admin_user), ) assert response.status_code == 201 @@ -1154,10 +1154,11 @@ class TestProcessApi(BaseTest): headers=self.logged_in_headers(with_super_admin_user), ) show_response = client.get( - f"/v1.0/process-models/{modified_process_model_identifier}/process-instances/{process_instance_id}", + f"/v1.0/process-instances/{modified_process_model_identifier}/{process_instance_id}", headers=self.logged_in_headers(with_super_admin_user), ) assert show_response.json is not None + assert show_response.status_code == 200 file_system_root = FileSystemService.root_path() file_path = ( f"{file_system_root}/{process_model_identifier}/{process_model_id}.bpmn" @@ -1320,7 +1321,7 @@ class TestProcessApi(BaseTest): assert response.json is not None response = client.post( - f"/v1.0/process-instances/{process_instance_id}/terminate", + f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/terminate", headers=self.logged_in_headers(with_super_admin_user), ) assert response.status_code == 200 @@ -1367,7 +1368,7 @@ class TestProcessApi(BaseTest): assert response.json is not None delete_response = client.delete( - f"/v1.0/process-instances/{process_instance_id}", + f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}", headers=self.logged_in_headers(with_super_admin_user), ) assert delete_response.status_code == 200 @@ -2366,7 +2367,7 @@ class TestProcessApi(BaseTest): assert process_instance.status == "user_input_required" client.post( - f"/v1.0/process-instances/{process_instance_id}/suspend", + f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/suspend", headers=self.logged_in_headers(with_super_admin_user), ) process_instance = ProcessInstanceService().get_process_instance( diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx index 87406f80..dafe20d5 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx @@ -83,7 +83,7 @@ export default function ProcessInstanceRun({ processModel.id ); - const processInstanceActionPath = `/v1.0/process-models/${modifiedProcessModelId}/process-instances`; + const processInstanceActionPath = `/v1.0/process-instances/${modifiedProcessModelId}`; let permissionRequestData: PermissionsToCheck = { [processInstanceActionPath]: ['POST'], }; diff --git a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx index 1599aff5..7cfd4d61 100644 --- a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx +++ b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx @@ -194,7 +194,6 @@ export default function ProcessModelForm({ onChange={(event: any) => { onDisplayNameChanged(event.target.value); }} - onBlur={(event: any) => console.log('event', event)} />, ]; diff --git a/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx b/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx index 9496e9e0..67958723 100644 --- a/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx +++ b/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx @@ -9,10 +9,11 @@ export const useUriListForPermissions = () => { messageInstanceListPath: '/v1.0/messages', processGroupListPath: '/v1.0/process-groups', processGroupShowPath: `/v1.0/process-groups/${params.process_group_id}`, - processInstanceActionPath: `/v1.0/process-models/${params.process_model_id}/process-instances`, + processInstanceActionPath: `/v1.0/process-instances/${params.process_model_id}`, processInstanceListPath: '/v1.0/process-instances', - processInstanceTaskListPath: `/v1.0/task-data/${params.process_model_id}/${params.process_instance_id}`, + processInstanceLogListPath: `/v1.0/logs/${params.process_model_id}/${params.process_instance_id}`, processInstanceReportListPath: '/v1.0/process-instances/reports', + processInstanceTaskListPath: `/v1.0/task-data/${params.process_model_id}/${params.process_instance_id}`, processModelCreatePath: `/v1.0/process-models/${params.process_group_id}`, processModelFileCreatePath: `/v1.0/process-models/${params.process_model_id}/files`, processModelFileShowPath: `/v1.0/process-models/${params.process_model_id}/files/${params.file_name}`, diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx index f41caf94..7b09c89f 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx @@ -10,6 +10,7 @@ import { convertSecondsToFormattedDateTime, } from '../helpers'; import HttpService from '../services/HttpService'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; export default function ProcessInstanceLogList() { const params = useParams(); @@ -19,6 +20,7 @@ export default function ProcessInstanceLogList() { const modifiedProcessModelId = modifyProcessIdentifierForPathParam( `${params.process_model_id}` ); + const { targetUris } = useUriListForPermissions(); useEffect(() => { const setProcessInstanceLogListFromResult = (result: any) => { @@ -27,7 +29,7 @@ export default function ProcessInstanceLogList() { }; const { page, perPage } = getPageInfoFromSearchParams(searchParams); HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/logs?per_page=${perPage}&page=${page}`, + path: `${targetUris.processInstanceLogListPath}?per_page=${perPage}&page=${page}`, successCallback: setProcessInstanceLogListFromResult, }); }, [searchParams, params]); @@ -46,7 +48,7 @@ export default function ProcessInstanceLogList() { {convertSecondsToFormattedDateTime(rowToUse.timestamp)} @@ -86,7 +88,7 @@ export default function ProcessInstanceLogList() { }, [ `Process Instance: ${params.process_instance_id}`, - `/admin/process-models/${params.process_model_id}/process-instances/${params.process_instance_id}`, + `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`, ], ['Logs'], ]} diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 0b0aca14..481f8d6f 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -59,6 +59,11 @@ export default function ProcessInstanceShow() { const permissionRequestData: PermissionsToCheck = { [targetUris.messageInstanceListPath]: ['GET'], [targetUris.processInstanceTaskListPath]: ['GET'], + [targetUris.processInstanceActionPath]: ['DELETE'], + [targetUris.processInstanceLogListPath]: ['GET'], + [`${targetUris.processInstanceActionPath}/suspend`]: ['PUT'], + [`${targetUris.processInstanceActionPath}/terminate`]: ['PUT'], + [`${targetUris.processInstanceActionPath}/resume`]: ['PUT'], }; const { ability, permissionsLoaded } = usePermissionFetcher( permissionRequestData @@ -97,7 +102,7 @@ export default function ProcessInstanceShow() { const deleteProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}`, + path: targetUris.processInstanceActionPath, successCallback: navigateToProcessInstances, httpMethod: 'DELETE', }); @@ -110,7 +115,7 @@ export default function ProcessInstanceShow() { const terminateProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/terminate`, + path: `${targetUris.processInstanceActionPath}/terminate`, successCallback: refreshPage, httpMethod: 'POST', }); @@ -118,7 +123,7 @@ export default function ProcessInstanceShow() { const suspendProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/suspend`, + path: `${targetUris.processInstanceActionPath}/suspend`, successCallback: refreshPage, httpMethod: 'POST', }); @@ -126,7 +131,7 @@ export default function ProcessInstanceShow() { const resumeProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/resume`, + path: `${targetUris.processInstanceActionPath}/resume`, successCallback: refreshPage, httpMethod: 'POST', }); @@ -209,7 +214,7 @@ export default function ProcessInstanceShow() { if (currentEndDate) { currentEndDateTag = ( - + Completed:{' '} @@ -235,7 +240,7 @@ export default function ProcessInstanceShow() { return ( <> - + Started:{' '} @@ -246,7 +251,7 @@ export default function ProcessInstanceShow() { {currentEndDateTag} - + Status:{' '} @@ -259,14 +264,20 @@ export default function ProcessInstanceShow() { - + + { const elements = []; - elements.push(terminateButton(processInstanceToUse)); - elements.push(suspendButton(processInstanceToUse)); - elements.push(resumeButton(processInstanceToUse)); - elements.push( - - ); + if ( + ability.can('POST', `${targetUris.processInstanceActionPath}/terminate`) + ) { + elements.push(terminateButton(processInstanceToUse)); + } + if ( + ability.can('POST', `${targetUris.processInstanceActionPath}/suspend`) + ) { + elements.push(suspendButton(processInstanceToUse)); + } + if (ability.can('POST', `${targetUris.processInstanceActionPath}/resume`)) { + elements.push(resumeButton(processInstanceToUse)); + } + if (ability.can('DELETE', targetUris.processInstanceActionPath)) { + elements.push( + + ); + } return elements; }; diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 88e23de7..9e0f65c5 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -26,6 +26,9 @@ import Form from '../themes/carbon'; import HttpService from '../services/HttpService'; import ErrorContext from '../contexts/ErrorContext'; import { modifyProcessIdentifierForPathParam } from '../helpers'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; +import { PermissionsToCheck } from '../interfaces'; +import { usePermissionFetcher } from '../hooks/PermissionService'; export default function TaskShow() { const [task, setTask] = useState(null); @@ -35,24 +38,36 @@ export default function TaskShow() { const setErrorMessage = (useContext as any)(ErrorContext)[1]; - useEffect(() => { - const processResult = (result: any) => { - setTask(result); - HttpService.makeCallToBackend({ - path: `/task-data/${modifyProcessIdentifierForPathParam( - result.process_model_identifier - )}/${params.process_instance_id}`, - successCallback: setUserTasks, - }); - }; + const { targetUris } = useUriListForPermissions(); + const permissionRequestData: PermissionsToCheck = { + [targetUris.processInstanceTaskListPath]: ['GET'], + }; + const { ability, permissionsLoaded } = usePermissionFetcher( + permissionRequestData + ); - HttpService.makeCallToBackend({ - path: `/tasks/${params.process_instance_id}/${params.task_id}`, - successCallback: processResult, - // This causes the page to continuously reload - // failureCallback: setErrorMessage, - }); - }, [params]); + useEffect(() => { + if (permissionsLoaded) { + const processResult = (result: any) => { + setTask(result); + if (ability.can('GET', targetUris.processInstanceTaskListPath)) { + HttpService.makeCallToBackend({ + path: `/task-data/${modifyProcessIdentifierForPathParam( + result.process_model_identifier + )}/${params.process_instance_id}`, + successCallback: setUserTasks, + }); + } + }; + + HttpService.makeCallToBackend({ + path: `/tasks/${params.process_instance_id}/${params.task_id}`, + successCallback: processResult, + // This causes the page to continuously reload + // failureCallback: setErrorMessage, + }); + } + }, [params, permissionsLoaded, ability, targetUris]); const processSubmitResult = (result: any) => { setErrorMessage(null); @@ -116,17 +131,18 @@ export default function TaskShow() { } return null; }); + return ( + + + {userTasksElement} + + + ); } - return ( - - - {userTasksElement} - - - ); + return null; }; const formElement = (taskToUse: any) => { @@ -207,7 +223,7 @@ export default function TaskShow() { ); }; - if (task && userTasks) { + if (task) { const taskToUse = task as any; let statusString = ''; if (taskToUse.state !== 'READY') {