From 623144aad28d2d0c7f327db57acd868c7e034944 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 2 Nov 2022 12:42:49 -0400 Subject: [PATCH 1/3] add date ranges for process instances search w/ burnettk --- src/spiffworkflow_backend/api.yml | 4 ++-- .../routes/process_api_blueprint.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/spiffworkflow_backend/api.yml b/src/spiffworkflow_backend/api.yml index 614d4f26..de10f598 100755 --- a/src/spiffworkflow_backend/api.yml +++ b/src/spiffworkflow_backend/api.yml @@ -429,7 +429,7 @@ paths: description: For filtering - beginning of start window - in seconds since epoch schema: type: integer - - name: start_till + - name: start_to in: query required: false description: For filtering - end of start window - in seconds since epoch @@ -441,7 +441,7 @@ paths: description: For filtering - beginning of end window - in seconds since epoch schema: type: integer - - name: end_till + - name: end_to in: query required: false description: For filtering - end of end window - in seconds since epoch diff --git a/src/spiffworkflow_backend/routes/process_api_blueprint.py b/src/spiffworkflow_backend/routes/process_api_blueprint.py index f2ffec20..012cb52f 100644 --- a/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -651,9 +651,9 @@ def process_instance_list( page: int = 1, per_page: int = 100, start_from: Optional[int] = None, - start_till: Optional[int] = None, + start_to: Optional[int] = None, end_from: Optional[int] = None, - end_till: Optional[int] = None, + end_to: Optional[int] = None, process_status: Optional[str] = None, ) -> flask.wrappers.Response: """Process_instance_list.""" @@ -684,17 +684,17 @@ def process_instance_list( process_instance_query = process_instance_query.filter( ProcessInstanceModel.start_in_seconds >= start_from ) - if start_till is not None: + if start_to is not None: process_instance_query = process_instance_query.filter( - ProcessInstanceModel.start_in_seconds <= start_till + ProcessInstanceModel.start_in_seconds <= start_to ) if end_from is not None: process_instance_query = process_instance_query.filter( ProcessInstanceModel.end_in_seconds >= end_from ) - if end_till is not None: + if end_to is not None: process_instance_query = process_instance_query.filter( - ProcessInstanceModel.end_in_seconds <= end_till + ProcessInstanceModel.end_in_seconds <= end_to ) if process_status is not None: process_status_array = process_status.split(",") From bdc812121153c33f31010f0e197cbdad40916deb Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 3 Nov 2022 15:55:50 -0400 Subject: [PATCH 2/3] some more updates for group forms w/ burnettk --- src/spiffworkflow_backend/api.yml | 2 -- .../models/process_group.py | 7 ++++++ .../routes/process_api_blueprint.py | 23 ++++++++----------- .../services/process_model_service.py | 3 ++- .../integration/test_process_api.py | 13 ++++++++--- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/spiffworkflow_backend/api.yml b/src/spiffworkflow_backend/api.yml index de10f598..2ca57999 100755 --- a/src/spiffworkflow_backend/api.yml +++ b/src/spiffworkflow_backend/api.yml @@ -153,7 +153,6 @@ paths: description: The number of groups to show per page. Defaults to page 10. schema: type: integer - # process_groups_list get: operationId: spiffworkflow_backend.routes.process_api_blueprint.process_groups_list summary: get list @@ -168,7 +167,6 @@ paths: type: array items: $ref: "#/components/schemas/ProcessModelCategory" - # process_group_add post: operationId: spiffworkflow_backend.routes.process_api_blueprint.process_group_add summary: Add process group diff --git a/src/spiffworkflow_backend/models/process_group.py b/src/spiffworkflow_backend/models/process_group.py index 0b100ed4..549ab008 100644 --- a/src/spiffworkflow_backend/models/process_group.py +++ b/src/spiffworkflow_backend/models/process_group.py @@ -1,5 +1,6 @@ """Process_group.""" from __future__ import annotations +import dataclasses from dataclasses import dataclass from dataclasses import field @@ -20,6 +21,7 @@ class ProcessGroup: id: str # A unique string name, lower case, under scores (ie, 'my_group') display_name: str + description: str | None = None display_order: int | None = 0 admin: bool | None = False process_models: list[ProcessModelInfo] = field( @@ -38,6 +40,11 @@ class ProcessGroup: return True return False + @property + def serialized(self) -> dict: + original_dict = dataclasses.asdict(self) + return {x: original_dict[x] for x in original_dict if x not in ["sort_index"]} + class ProcessGroupSchema(Schema): """ProcessGroupSchema.""" diff --git a/src/spiffworkflow_backend/routes/process_api_blueprint.py b/src/spiffworkflow_backend/routes/process_api_blueprint.py index fd20341c..63c717d1 100644 --- a/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -43,7 +43,7 @@ from spiffworkflow_backend.models.message_triggerable_process_model import ( MessageTriggerableProcessModel, ) from spiffworkflow_backend.models.principal import PrincipalModel -from spiffworkflow_backend.models.process_group import ProcessGroupSchema +from spiffworkflow_backend.models.process_group import ProcessGroup, ProcessGroupSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema @@ -135,17 +135,13 @@ def permissions_check(body: Dict[str, Dict[str, list[str]]]) -> flask.wrappers.R def process_group_add( - body: Dict[str, Union[str, bool, int]] + body: dict ) -> flask.wrappers.Response: """Add_process_group.""" process_model_service = ProcessModelService() - process_group = ProcessGroupSchema().load(body) + process_group = ProcessGroup(**body) process_model_service.add_process_group(process_group) - return Response( - json.dumps(ProcessGroupSchema().dump(process_group)), - status=201, - mimetype="application/json", - ) + return make_response(jsonify(process_group), 201) def process_group_delete(process_group_id: str) -> flask.wrappers.Response: @@ -155,12 +151,12 @@ def process_group_delete(process_group_id: str) -> flask.wrappers.Response: def process_group_update( - process_group_id: str, body: Dict[str, Union[str, bool, int]] -) -> Dict[str, Union[str, bool, int]]: + process_group_id: str, body: dict +) -> flask.wrappers.Response: """Process Group Update.""" - process_group = ProcessGroupSchema().load(body) + process_group = ProcessGroup(id=process_group_id, **body) ProcessModelService().update_process_group(process_group) - return ProcessGroupSchema().dump(process_group) # type: ignore + return make_response(jsonify(process_group), 200) def process_groups_list(page: int = 1, per_page: int = 100) -> flask.wrappers.Response: @@ -173,6 +169,7 @@ def process_groups_list(page: int = 1, per_page: int = 100) -> flask.wrappers.Re remainder = len(process_groups) % per_page if remainder > 0: pages += 1 + response_json = { "results": ProcessGroupSchema(many=True).dump(batch), "pagination": { @@ -198,7 +195,7 @@ def process_group_show( status_code=400, ) ) from exception - return ProcessGroupSchema().dump(process_group) + return make_response(jsonify(process_group), 200) def process_model_add( diff --git a/src/spiffworkflow_backend/services/process_model_service.py b/src/spiffworkflow_backend/services/process_model_service.py index 57d84229..7789493f 100644 --- a/src/spiffworkflow_backend/services/process_model_service.py +++ b/src/spiffworkflow_backend/services/process_model_service.py @@ -1,4 +1,5 @@ """Process_model_service.""" +import dataclasses import json import os import shutil @@ -170,7 +171,7 @@ class ProcessModelService(FileSystemService): json_path = os.path.join(cat_path, self.CAT_JSON_FILE) with open(json_path, "w") as cat_json: json.dump( - self.GROUP_SCHEMA.dump(process_group), + process_group.serialized, cat_json, indent=4, sort_keys=True, diff --git a/tests/spiffworkflow_backend/integration/test_process_api.py b/tests/spiffworkflow_backend/integration/test_process_api.py index 9a923b97..6fe38f40 100644 --- a/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/tests/spiffworkflow_backend/integration/test_process_api.py @@ -1,4 +1,5 @@ """Test Process Api Blueprint.""" +import dataclasses import io import json import time @@ -8,6 +9,7 @@ import pytest from flask.app import Flask from flask.testing import FlaskClient from flask_bpmn.models.db import db +from spiffworkflow_backend import MyJSONEncoder from tests.spiffworkflow_backend.helpers.base_test import BaseTest from tests.spiffworkflow_backend.helpers.test_data import load_test_spec @@ -17,7 +19,7 @@ from spiffworkflow_backend.exceptions.process_entity_not_found_error import ( from spiffworkflow_backend.models.active_task import ActiveTaskModel from spiffworkflow_backend.models.group import GroupModel 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.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_instance_report import ( @@ -388,25 +390,30 @@ class TestProcessApi(BaseTest): display_name="Another Test Category", display_order=0, admin=False, + description="Test Description" ) response = client.post( "/v1.0/process-groups", headers=self.logged_in_headers(with_super_admin_user), content_type="application/json", - data=json.dumps(ProcessGroupSchema().dump(process_group)), + data=json.dumps(process_group.serialized), + ) assert response.status_code == 201 + assert response.json # Check what is returned - result = ProcessGroupSchema().loads(response.get_data(as_text=True)) + result = ProcessGroup(**response.json) assert result is not None assert result.display_name == "Another Test Category" assert result.id == "test" + assert result.description == "Test Description" # Check what is persisted persisted = ProcessModelService().get_process_group("test") assert persisted.display_name == "Another Test Category" assert persisted.id == "test" + assert persisted.description == "Test Description" def test_process_group_delete( self, From ad13a4112798a1056ab0632a91d1b92c9ff2ae41 Mon Sep 17 00:00:00 2001 From: jasquat Date: Fri, 4 Nov 2022 11:03:40 -0400 Subject: [PATCH 3/3] pyl is passing w/ burnettk --- .../models/process_group.py | 3 ++- .../models/process_model.py | 1 - .../routes/process_api_blueprint.py | 21 +++++++++++-------- .../services/process_model_service.py | 2 -- .../integration/test_process_api.py | 15 ++++++------- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/spiffworkflow_backend/models/process_group.py b/src/spiffworkflow_backend/models/process_group.py index 549ab008..381f8f63 100644 --- a/src/spiffworkflow_backend/models/process_group.py +++ b/src/spiffworkflow_backend/models/process_group.py @@ -1,7 +1,7 @@ """Process_group.""" from __future__ import annotations -import dataclasses +import dataclasses from dataclasses import dataclass from dataclasses import field from typing import Any @@ -42,6 +42,7 @@ class ProcessGroup: @property def serialized(self) -> dict: + """Serialized.""" original_dict = dataclasses.asdict(self) return {x: original_dict[x] for x in original_dict if x not in ["sort_index"]} diff --git a/src/spiffworkflow_backend/models/process_model.py b/src/spiffworkflow_backend/models/process_model.py index 9558a79b..1928f312 100644 --- a/src/spiffworkflow_backend/models/process_model.py +++ b/src/spiffworkflow_backend/models/process_model.py @@ -30,7 +30,6 @@ class ProcessModelInfo: display_name: str description: str process_group_id: str = "" - process_group: Any | None = None primary_file_name: str | None = None primary_process_id: str | None = None display_order: int | None = 0 diff --git a/src/spiffworkflow_backend/routes/process_api_blueprint.py b/src/spiffworkflow_backend/routes/process_api_blueprint.py index 63c717d1..65fc299b 100644 --- a/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -43,7 +43,8 @@ from spiffworkflow_backend.models.message_triggerable_process_model import ( MessageTriggerableProcessModel, ) from spiffworkflow_backend.models.principal import PrincipalModel -from spiffworkflow_backend.models.process_group import ProcessGroup, ProcessGroupSchema +from spiffworkflow_backend.models.process_group import ProcessGroup +from spiffworkflow_backend.models.process_group import ProcessGroupSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema @@ -134,9 +135,7 @@ def permissions_check(body: Dict[str, Dict[str, list[str]]]) -> flask.wrappers.R return make_response(jsonify({"results": response_dict}), 200) -def process_group_add( - body: dict -) -> flask.wrappers.Response: +def process_group_add(body: dict) -> flask.wrappers.Response: """Add_process_group.""" process_model_service = ProcessModelService() process_group = ProcessGroup(**body) @@ -150,11 +149,16 @@ def process_group_delete(process_group_id: str) -> flask.wrappers.Response: return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") -def process_group_update( - process_group_id: str, body: dict -) -> flask.wrappers.Response: +def process_group_update(process_group_id: str, body: dict) -> flask.wrappers.Response: """Process Group Update.""" - process_group = ProcessGroup(id=process_group_id, **body) + body_include_list = ["display_name", "description"] + body_filtered = { + include_item: body[include_item] + for include_item in body_include_list + if include_item in body + } + + process_group = ProcessGroup(id=process_group_id, **body_filtered) ProcessModelService().update_process_group(process_group) return make_response(jsonify(process_group), 200) @@ -221,7 +225,6 @@ def process_model_add( status_code=400, ) - process_model_info.process_group = process_group process_model_service.add_spec(process_model_info) return Response( json.dumps(ProcessModelInfoSchema().dump(process_model_info)), diff --git a/src/spiffworkflow_backend/services/process_model_service.py b/src/spiffworkflow_backend/services/process_model_service.py index 7789493f..e10092d5 100644 --- a/src/spiffworkflow_backend/services/process_model_service.py +++ b/src/spiffworkflow_backend/services/process_model_service.py @@ -1,5 +1,4 @@ """Process_model_service.""" -import dataclasses import json import os import shutil @@ -275,6 +274,5 @@ class ProcessModelService(FileSystemService): with open(spec_path, "w") as wf_json: json.dump(self.WF_SCHEMA.dump(spec), wf_json, indent=4) if process_group: - spec.process_group = process_group spec.process_group_id = process_group.id return spec diff --git a/tests/spiffworkflow_backend/integration/test_process_api.py b/tests/spiffworkflow_backend/integration/test_process_api.py index 6fe38f40..9b8b75da 100644 --- a/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/tests/spiffworkflow_backend/integration/test_process_api.py @@ -1,5 +1,4 @@ """Test Process Api Blueprint.""" -import dataclasses import io import json import time @@ -9,7 +8,6 @@ import pytest from flask.app import Flask from flask.testing import FlaskClient from flask_bpmn.models.db import db -from spiffworkflow_backend import MyJSONEncoder from tests.spiffworkflow_backend.helpers.base_test import BaseTest from tests.spiffworkflow_backend.helpers.test_data import load_test_spec @@ -19,7 +17,6 @@ from spiffworkflow_backend.exceptions.process_entity_not_found_error import ( from spiffworkflow_backend.models.active_task import ActiveTaskModel from spiffworkflow_backend.models.group import GroupModel from spiffworkflow_backend.models.process_group import ProcessGroup -# from spiffworkflow_backend.models.process_group import ProcessGroupSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_instance_report import ( @@ -390,14 +387,13 @@ class TestProcessApi(BaseTest): display_name="Another Test Category", display_order=0, admin=False, - description="Test Description" + description="Test Description", ) response = client.post( "/v1.0/process-groups", headers=self.logged_in_headers(with_super_admin_user), content_type="application/json", data=json.dumps(process_group.serialized), - ) assert response.status_code == 201 assert response.json @@ -468,7 +464,7 @@ class TestProcessApi(BaseTest): f"/v1.0/process-groups/{group_id}", headers=self.logged_in_headers(with_super_admin_user), content_type="application/json", - data=json.dumps(ProcessGroupSchema().dump(process_group)), + data=json.dumps(process_group.serialized), ) assert response.status_code == 200 @@ -795,6 +791,7 @@ class TestProcessApi(BaseTest): f"/v1.0/process-groups/{test_process_group_id}", headers=self.logged_in_headers(with_super_admin_user), ) + assert response.status_code == 200 assert response.json is not None assert response.json["id"] == test_process_group_id @@ -1304,7 +1301,7 @@ class TestProcessApi(BaseTest): # start > 2000, end < 5000 - this should eliminate the first 2 and the last response = client.get( - "/v1.0/process-instances?start_from=2001&end_till=5999", + "/v1.0/process-instances?start_from=2001&end_to=5999", headers=self.logged_in_headers(with_super_admin_user), ) assert response.json is not None @@ -1315,7 +1312,7 @@ class TestProcessApi(BaseTest): # start > 1000, start < 4000 - this should eliminate the first and the last 2 response = client.get( - "/v1.0/process-instances?start_from=1001&start_till=3999", + "/v1.0/process-instances?start_from=1001&start_to=3999", headers=self.logged_in_headers(with_super_admin_user), ) assert response.json is not None @@ -1326,7 +1323,7 @@ class TestProcessApi(BaseTest): # end > 2000, end < 6000 - this should eliminate the first and the last response = client.get( - "/v1.0/process-instances?end_from=2001&end_till=5999", + "/v1.0/process-instances?end_from=2001&end_to=5999", headers=self.logged_in_headers(with_super_admin_user), ) assert response.json is not None