From 610fd2e777367feba6fd3be84e7ceab7f71e98c8 Mon Sep 17 00:00:00 2001 From: burnettk Date: Sat, 25 Feb 2023 23:31:23 -0500 Subject: [PATCH 1/5] wip for get_last_user_completing_task script task --- .../migrations/versions/b91143f4e414_.py | 28 +++++++++++ .../models/human_task.py | 1 + .../scripts/get_last_user_completing_task.py | 46 ++++++++++++++++++ .../services/process_instance_processor.py | 3 ++ .../tests/data/model_with_lanes/lanes.bpmn | 18 +++---- .../unit/test_process_instance_processor.py | 48 +++++++++++++++++++ 6 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 spiffworkflow-backend/migrations/versions/b91143f4e414_.py create mode 100644 spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py diff --git a/spiffworkflow-backend/migrations/versions/b91143f4e414_.py b/spiffworkflow-backend/migrations/versions/b91143f4e414_.py new file mode 100644 index 00000000..041359dc --- /dev/null +++ b/spiffworkflow-backend/migrations/versions/b91143f4e414_.py @@ -0,0 +1,28 @@ +"""empty message + +Revision ID: b91143f4e414 +Revises: 63fc8d693b9f +Create Date: 2023-02-25 22:46:03.533624 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b91143f4e414' +down_revision = '63fc8d693b9f' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('human_task', sa.Column('process_model_identifier', sa.String(length=255), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('human_task', 'process_model_identifier') + # ### end Alembic commands ### diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py index 3317f773..e27b4cc1 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py @@ -49,6 +49,7 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): task_type: str = db.Column(db.String(50)) task_status: str = db.Column(db.String(50)) process_model_display_name: str = db.Column(db.String(255)) + process_model_identifier: str = db.Column(db.String(255)) completed: bool = db.Column(db.Boolean, default=False, nullable=False, index=True) human_task_users = relationship("HumanTaskUserModel", cascade="delete") diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py new file mode 100644 index 00000000..905e1298 --- /dev/null +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py @@ -0,0 +1,46 @@ +"""Get current user.""" +from typing import Any +from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.models.human_task import HumanTaskModel + +from flask import current_app +from flask import g + +from spiffworkflow_backend.models.script_attributes_context import ( + ScriptAttributesContext, +) +from spiffworkflow_backend.scripts.script import Script + + +class GetLastUserCompletingTask(Script): + @staticmethod + def requires_privileged_permissions() -> bool: + """We have deemed this function safe to run without elevated permissions.""" + return False + + def get_description(self) -> str: + return """Return the last user who completed the given task.""" + + def run( + self, + script_attributes_context: ScriptAttributesContext, + *_args: Any, + **kwargs: Any + ) -> Any: + """Run.""" + # dump the user using our json encoder and then load it back up as a dict + # to remove unwanted field types + if len(_args) == 2: + process_model_identifier = _args[0] + task_bpmn_identifier = _args[1] + else: + process_model_identifier = kwargs["process_model_identifier"] + task_bpmn_identifier = kwargs["task_bpmn_identifier"] + process_model_identifier = _args[0] or kwargs["process_model_identifier"] + print(f"process_model_identifier: {process_model_identifier}") + import pdb; pdb.set_trace() + # human_task = HumanTaskModel.query.filter_by(process_model_identifier=process_model_identifier).order_by(HumanTaskModel.id.desc()).first() + human_task = HumanTaskModel.query.filter_by(process_model_identifier=process_model_identifier).order_by(HumanTaskModel.id.desc()).join(UserModel, UserModel.id == HumanTaskModel.completed_by_user_id).first() + return human_task.completed_by_user + # user_as_json_string = current_app.json.dumps(g.user) + # return current_app.json.loads(user_as_json_string) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 19b6f4da..b3aa7000 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -875,11 +875,13 @@ class ProcessInstanceProcessor: ).all() ready_or_waiting_tasks = self.get_all_ready_or_waiting_tasks() process_model_display_name = "" + process_model_identifier = "" process_model_info = self.process_model_service.get_process_model( self.process_instance_model.process_model_identifier ) if process_model_info is not None: process_model_display_name = process_model_info.display_name + process_model_identifier = process_model_info.id self.extract_metadata(process_model_info) @@ -911,6 +913,7 @@ class ProcessInstanceProcessor: human_task = HumanTaskModel( process_instance_id=self.process_instance_model.id, process_model_display_name=process_model_display_name, + process_model_identifier=process_model_identifier, form_file_name=form_file_name, ui_form_file_name=ui_form_file_name, task_id=str(ready_or_waiting_task.id), diff --git a/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn b/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn index 3ee43501..99c9c63c 100644 --- a/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn +++ b/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn @@ -7,7 +7,7 @@ StartEvent_1 - initator_one + initiator_one Event_06f4e68 initiator_two @@ -18,18 +18,19 @@ Flow_1tbyols - - - + + + - This is initiator user? + This is for the initiator user + user_completing_task = get_last_user_completing_task("misc/category_number_one/lanes", "initiator_one") Flow_1tbyols Flow_16ppta1 - This is finance user? + This is for a Finance Team user Flow_16ppta1 Flow_1cfcauf @@ -41,7 +42,8 @@ - This is initiator again? + This is initiator again + Flow_1cfcauf Flow_0x92f7d @@ -63,7 +65,7 @@ - + diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py index b46ba1e1..ea6e08cf 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py @@ -65,6 +65,54 @@ class TestProcessInstanceProcessor(BaseTest): app.config["THREAD_LOCAL_DATA"].process_model_identifier = None app.config["THREAD_LOCAL_DATA"].process_instance_id = None + def test_get_last_user_completing_task_script_works( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + """Test_sets_permission_correctly_on_human_task.""" + self.create_process_group( + client, with_super_admin_user, "test_group", "test_group" + ) + initiator_user = self.find_or_create_user("initiator_user") + finance_user = self.find_or_create_user("testuser2") + assert initiator_user.principal is not None + assert finance_user.principal is not None + AuthorizationService.import_permissions_from_yaml_file() + + finance_group = GroupModel.query.filter_by(identifier="Finance Team").first() + assert finance_group is not None + + process_model = load_test_spec( + process_model_id="misc/category_number_one/lanes", + bpmn_file_name="lanes.bpmn", + process_model_source_directory="model_with_lanes", + ) + process_instance = self.create_process_instance_from_process_model( + process_model=process_model, user=initiator_user + ) + processor = ProcessInstanceProcessor(process_instance) + processor.do_engine_steps(save=True) + + assert len(process_instance.active_human_tasks) == 1 + human_task = process_instance.active_human_tasks[0] + assert human_task.lane_assignment_id is None + assert len(human_task.potential_owners) == 1 + assert human_task.potential_owners[0] == initiator_user + + spiff_task = processor.__class__.get_task_by_bpmn_identifier( + human_task.task_name, processor.bpmn_process_instance + ) + ProcessInstanceService.complete_form_task( + processor, spiff_task, {}, initiator_user, human_task + ) + print(f"initiator_user.username: {initiator_user.username}") + print(f"data: {processor.get_data()}") + print(f"task_data: {spiff_task.data}") + assert initiator_user.username == spiff_task.get_data("user_completing_task")["username"] + def test_sets_permission_correctly_on_human_task( self, app: Flask, From 9ce870274cdf7adaece9397754b1d5f350e830a3 Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 27 Feb 2023 12:08:07 -0500 Subject: [PATCH 2/5] script to get last user completing a task is working w/ burnettk --- .../{b91143f4e414_.py => d6e5b3af0908_.py} | 10 +- .../models/human_task.py | 8 +- .../src/spiffworkflow_backend/models/task.py | 3 + .../scripts/get_last_user_completing_task.py | 37 +- .../services/process_instance_processor.py | 10 +- spiffworkflow-backend/t2.json | 353 ++++++++++++++++++ spiffworkflow-backend/test.json | 1 + .../tests/data/model_with_lanes/lanes.bpmn | 1 - .../tests/data/simple_form/simple_form.bpmn | 5 +- .../test_get_last_user_completing_task.py | 71 ++++ .../unit/test_process_instance_processor.py | 48 --- 11 files changed, 468 insertions(+), 79 deletions(-) rename spiffworkflow-backend/migrations/versions/{b91143f4e414_.py => d6e5b3af0908_.py} (62%) create mode 100644 spiffworkflow-backend/t2.json create mode 100644 spiffworkflow-backend/test.json create mode 100644 spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py diff --git a/spiffworkflow-backend/migrations/versions/b91143f4e414_.py b/spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py similarity index 62% rename from spiffworkflow-backend/migrations/versions/b91143f4e414_.py rename to spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py index 041359dc..89561ca3 100644 --- a/spiffworkflow-backend/migrations/versions/b91143f4e414_.py +++ b/spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: b91143f4e414 +Revision ID: d6e5b3af0908 Revises: 63fc8d693b9f -Create Date: 2023-02-25 22:46:03.533624 +Create Date: 2023-02-27 11:10:28.058014 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'b91143f4e414' +revision = 'd6e5b3af0908' down_revision = '63fc8d693b9f' branch_labels = None depends_on = None @@ -18,11 +18,11 @@ depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('human_task', sa.Column('process_model_identifier', sa.String(length=255), nullable=True)) + op.add_column('human_task', sa.Column('bpmn_process_identifier', sa.String(length=255), nullable=True)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('human_task', 'process_model_identifier') + op.drop_column('human_task', 'bpmn_process_identifier') # ### end Alembic commands ### diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py index e27b4cc1..43415352 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py @@ -34,6 +34,8 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): lane_assignment_id: int | None = db.Column(ForeignKey(GroupModel.id)) completed_by_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) # type: ignore + completed_by_user = relationship("UserModel", foreign_keys=[completed_by_user_id]) + actual_owner_id: int = db.Column(ForeignKey(UserModel.id)) # type: ignore # actual_owner: RelationshipProperty[UserModel] = relationship(UserModel) @@ -49,7 +51,7 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): task_type: str = db.Column(db.String(50)) task_status: str = db.Column(db.String(50)) process_model_display_name: str = db.Column(db.String(255)) - process_model_identifier: str = db.Column(db.String(255)) + bpmn_process_identifier: str = db.Column(db.String(255)) completed: bool = db.Column(db.Boolean, default=False, nullable=False, index=True) human_task_users = relationship("HumanTaskUserModel", cascade="delete") @@ -75,8 +77,8 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): new_task.process_model_display_name = task.process_model_display_name if hasattr(task, "process_group_identifier"): new_task.process_group_identifier = task.process_group_identifier - if hasattr(task, "process_model_identifier"): - new_task.process_model_identifier = task.process_model_identifier + if hasattr(task, "bpmn_process_identifier"): + new_task.bpmn_process_identifier = task.bpmn_process_identifier # human tasks only have status when getting the list on the home page # and it comes from the process_instance. it should not be confused with task_status. diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py index 4012b077..148df231 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py @@ -45,6 +45,7 @@ class Task: process_model_display_name: Union[str, None] = None, process_group_identifier: Union[str, None] = None, process_model_identifier: Union[str, None] = None, + bpmn_process_identifier: Union[str, None] = None, form_schema: Union[dict, None] = None, form_ui_schema: Union[dict, None] = None, parent: Optional[str] = None, @@ -76,6 +77,7 @@ class Task: self.process_instance_status = process_instance_status self.process_group_identifier = process_group_identifier self.process_model_identifier = process_model_identifier + self.bpmn_process_identifier = bpmn_process_identifier self.process_model_display_name = process_model_display_name self.form_schema = form_schema self.form_ui_schema = form_ui_schema @@ -122,6 +124,7 @@ class Task: "process_model_display_name": self.process_model_display_name, "process_group_identifier": self.process_group_identifier, "process_model_identifier": self.process_model_identifier, + "bpmn_process_identifier": self.bpmn_process_identifier, "form_schema": self.form_schema, "form_ui_schema": self.form_ui_schema, "parent": self.parent, diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py index 905e1298..eea757d6 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py @@ -1,14 +1,13 @@ """Get current user.""" from typing import Any -from spiffworkflow_backend.models.user import UserModel -from spiffworkflow_backend.models.human_task import HumanTaskModel from flask import current_app -from flask import g +from spiffworkflow_backend.models.human_task import HumanTaskModel from spiffworkflow_backend.models.script_attributes_context import ( ScriptAttributesContext, ) +from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.scripts.script import Script @@ -25,22 +24,28 @@ class GetLastUserCompletingTask(Script): self, script_attributes_context: ScriptAttributesContext, *_args: Any, - **kwargs: Any + **kwargs: Any, ) -> Any: """Run.""" # dump the user using our json encoder and then load it back up as a dict # to remove unwanted field types if len(_args) == 2: - process_model_identifier = _args[0] - task_bpmn_identifier = _args[1] + bpmn_process_identifier = _args[0] + task_name = _args[1] else: - process_model_identifier = kwargs["process_model_identifier"] - task_bpmn_identifier = kwargs["task_bpmn_identifier"] - process_model_identifier = _args[0] or kwargs["process_model_identifier"] - print(f"process_model_identifier: {process_model_identifier}") - import pdb; pdb.set_trace() - # human_task = HumanTaskModel.query.filter_by(process_model_identifier=process_model_identifier).order_by(HumanTaskModel.id.desc()).first() - human_task = HumanTaskModel.query.filter_by(process_model_identifier=process_model_identifier).order_by(HumanTaskModel.id.desc()).join(UserModel, UserModel.id == HumanTaskModel.completed_by_user_id).first() - return human_task.completed_by_user - # user_as_json_string = current_app.json.dumps(g.user) - # return current_app.json.loads(user_as_json_string) + bpmn_process_identifier = kwargs["bpmn_process_identifier"] + task_name = kwargs["task_bpmn_identifier"] + + human_task = ( + HumanTaskModel.query.filter_by( + bpmn_process_identifier=bpmn_process_identifier, task_name=task_name + ) + .order_by(HumanTaskModel.id.desc()) # type: ignore + .join(UserModel, UserModel.id == HumanTaskModel.completed_by_user_id) + .first() + ) + + # dump the user using our json encoder and then load it back up as a dict + # to remove unwanted field types + user_as_json_string = current_app.json.dumps(human_task.completed_by_user) + return current_app.json.loads(user_as_json_string) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index b3aa7000..21eafd97 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -874,14 +874,13 @@ class ProcessInstanceProcessor: process_instance_id=self.process_instance_model.id, completed=False ).all() ready_or_waiting_tasks = self.get_all_ready_or_waiting_tasks() + process_model_display_name = "" - process_model_identifier = "" process_model_info = self.process_model_service.get_process_model( self.process_instance_model.process_model_identifier ) if process_model_info is not None: process_model_display_name = process_model_info.display_name - process_model_identifier = process_model_info.id self.extract_metadata(process_model_info) @@ -894,6 +893,10 @@ class ProcessInstanceProcessor: ) extensions = task_spec.extensions + # in the xml, it's the id attribute. this identifies the process where the activity lives. + # if it's in a subprocess, it's the inner process. + bpmn_process_identifier = ready_or_waiting_task.workflow.name + form_file_name = None ui_form_file_name = None if "properties" in extensions: @@ -913,7 +916,7 @@ class ProcessInstanceProcessor: human_task = HumanTaskModel( process_instance_id=self.process_instance_model.id, process_model_display_name=process_model_display_name, - process_model_identifier=process_model_identifier, + bpmn_process_identifier=bpmn_process_identifier, form_file_name=form_file_name, ui_form_file_name=ui_form_file_name, task_id=str(ready_or_waiting_task.id), @@ -1744,7 +1747,6 @@ class ProcessInstanceProcessor: details_model.end_in_seconds = time.time() details_model.task_json = self.get_task_json_from_spiff_task(task) db.session.add(details_model) - # this is the thing that actually commits the db transaction (on behalf of the other updates above as well) self.save() diff --git a/spiffworkflow-backend/t2.json b/spiffworkflow-backend/t2.json new file mode 100644 index 00000000..8ea7dec9 --- /dev/null +++ b/spiffworkflow-backend/t2.json @@ -0,0 +1,353 @@ +{ + "data": { + "validate_only": false, + "spiff__python_env_state": {} + }, + "last_task": "d139f273-e735-4c8c-8183-66cb946eb8a6", + "success": true, + "tasks": { + "d278c748-e3b1-4eeb-a64e-e927e61a80ed": { + "id": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", + "parent": null, + "children": [ + "42edeac7-afb6-41d9-b02c-53f6889b530b" + ], + "last_state_change": 1677513437.654198, + "state": 32, + "task_spec": "Root", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "42edeac7-afb6-41d9-b02c-53f6889b530b": { + "id": "42edeac7-afb6-41d9-b02c-53f6889b530b", + "parent": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", + "children": [ + "d139f273-e735-4c8c-8183-66cb946eb8a6" + ], + "last_state_change": 1677513437.6548965, + "state": 32, + "task_spec": "Start", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "d139f273-e735-4c8c-8183-66cb946eb8a6": { + "id": "d139f273-e735-4c8c-8183-66cb946eb8a6", + "parent": "42edeac7-afb6-41d9-b02c-53f6889b530b", + "children": [ + "83f7924b-01a0-43f7-9a50-f9dca568f0d8" + ], + "last_state_change": 1677513437.655577, + "state": 32, + "task_spec": "StartEvent_1", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": { + "event_fired": true + }, + "data": {} + }, + "83f7924b-01a0-43f7-9a50-f9dca568f0d8": { + "id": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", + "parent": "d139f273-e735-4c8c-8183-66cb946eb8a6", + "children": [ + "55c92211-cf14-43f8-8f25-950c0691fb30" + ], + "last_state_change": 1677513437.6557715, + "state": 16, + "task_spec": "initiator_one", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "55c92211-cf14-43f8-8f25-950c0691fb30": { + "id": "55c92211-cf14-43f8-8f25-950c0691fb30", + "parent": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", + "children": [ + "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69" + ], + "last_state_change": 1677513437.6543038, + "state": 4, + "task_spec": "finance_approval", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69": { + "id": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", + "parent": "55c92211-cf14-43f8-8f25-950c0691fb30", + "children": [ + "0795b348-5eef-4b67-8cfa-6444d1fb1a49" + ], + "last_state_change": 1677513437.6543193, + "state": 4, + "task_spec": "initiator_two", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "0795b348-5eef-4b67-8cfa-6444d1fb1a49": { + "id": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", + "parent": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", + "children": [ + "35d0aecc-23d6-4d42-a593-571b8de0cbcf" + ], + "last_state_change": 1677513437.6543357, + "state": 4, + "task_spec": "Event_06f4e68", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "35d0aecc-23d6-4d42-a593-571b8de0cbcf": { + "id": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", + "parent": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", + "children": [ + "7a7af0ac-2f31-4025-b739-27822470f3ec" + ], + "last_state_change": 1677513437.654353, + "state": 4, + "task_spec": "Proccess_yhito9d.EndJoin", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + }, + "7a7af0ac-2f31-4025-b739-27822470f3ec": { + "id": "7a7af0ac-2f31-4025-b739-27822470f3ec", + "parent": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", + "children": [], + "last_state_change": 1677513437.654371, + "state": 4, + "task_spec": "End", + "triggered": false, + "workflow_name": "Proccess_yhito9d", + "internal_data": {}, + "data": {} + } + }, + "root": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", + "spec": { + "name": "Proccess_yhito9d", + "description": "Proccess_yhito9d", + "file": "lanes.bpmn", + "task_specs": { + "Start": { + "id": "Proccess_yhito9d_1", + "name": "Start", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [ + "StartEvent_1" + ], + "typename": "StartTask" + }, + "Proccess_yhito9d.EndJoin": { + "id": "Proccess_yhito9d_2", + "name": "Proccess_yhito9d.EndJoin", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Event_06f4e68" + ], + "outputs": [ + "End" + ], + "typename": "_EndJoin" + }, + "End": { + "id": "Proccess_yhito9d_3", + "name": "End", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Proccess_yhito9d.EndJoin" + ], + "outputs": [], + "typename": "Simple" + }, + "StartEvent_1": { + "id": "Proccess_yhito9d_4", + "name": "StartEvent_1", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "Start" + ], + "outputs": [ + "initiator_one" + ], + "lane": "Process Initiator", + "documentation": null, + "position": { + "x": 179, + "y": 159 + }, + "data_input_associations": [], + "data_output_associations": [], + "io_specification": null, + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "StartEvent", + "extensions": {} + }, + "initiator_one": { + "id": "Proccess_yhito9d_5", + "name": "initiator_one", + "description": "Initiator One", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "StartEvent_1" + ], + "outputs": [ + "finance_approval" + ], + "lane": "Process Initiator", + "documentation": null, + "position": { + "x": 270, + "y": 137 + }, + "data_input_associations": [], + "data_output_associations": [], + "io_specification": null, + "prescript": null, + "postscript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")", + "typename": "ManualTask", + "extensions": { + "instructionsForEndUser": "This is for the initiator user", + "postScript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")" + } + }, + "finance_approval": { + "id": "Proccess_yhito9d_6", + "name": "finance_approval", + "description": "Finance Approval", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "initiator_one" + ], + "outputs": [ + "initiator_two" + ], + "lane": "Finance Team", + "documentation": null, + "position": { + "x": 310, + "y": 320 + }, + "data_input_associations": [], + "data_output_associations": [], + "io_specification": null, + "prescript": null, + "postscript": null, + "typename": "ManualTask", + "extensions": { + "instructionsForEndUser": "This is for a Finance Team user" + } + }, + "initiator_two": { + "id": "Proccess_yhito9d_7", + "name": "initiator_two", + "description": "Initiator Two", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "finance_approval" + ], + "outputs": [ + "Event_06f4e68" + ], + "lane": "Process Initiator", + "documentation": null, + "position": { + "x": 440, + "y": 137 + }, + "data_input_associations": [], + "data_output_associations": [], + "io_specification": null, + "prescript": null, + "postscript": null, + "typename": "ManualTask", + "extensions": { + "instructionsForEndUser": "This is initiator again", + "postScript": null + } + }, + "Event_06f4e68": { + "id": "Proccess_yhito9d_8", + "name": "Event_06f4e68", + "description": null, + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [ + "initiator_two" + ], + "outputs": [ + "Proccess_yhito9d.EndJoin" + ], + "lane": "Process Initiator", + "documentation": null, + "position": { + "x": 572, + "y": 159 + }, + "data_input_associations": [], + "data_output_associations": [], + "io_specification": null, + "event_definition": { + "internal": false, + "external": false, + "typename": "NoneEventDefinition" + }, + "typename": "EndEvent", + "extensions": {} + }, + "Root": { + "id": "Proccess_yhito9d_9", + "name": "Root", + "description": "", + "manual": false, + "internal": false, + "lookahead": 2, + "inputs": [], + "outputs": [], + "typename": "Simple" + } + }, + "io_specification": null, + "data_objects": {}, + "correlation_keys": {}, + "typename": "BpmnProcessSpec" + }, + "subprocess_specs": {}, + "subprocesses": {}, + "bpmn_messages": [], + "serializer_version": "1.0-spiffworkflow-backend" +} diff --git a/spiffworkflow-backend/test.json b/spiffworkflow-backend/test.json new file mode 100644 index 00000000..cf7dc282 --- /dev/null +++ b/spiffworkflow-backend/test.json @@ -0,0 +1 @@ +{"data": {"validate_only": false, "spiff__python_env_state": {}}, "last_task": "d139f273-e735-4c8c-8183-66cb946eb8a6", "success": true, "tasks": {"d278c748-e3b1-4eeb-a64e-e927e61a80ed": {"id": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", "parent": null, "children": ["42edeac7-afb6-41d9-b02c-53f6889b530b"], "last_state_change": 1677513437.654198, "state": 32, "task_spec": "Root", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "42edeac7-afb6-41d9-b02c-53f6889b530b": {"id": "42edeac7-afb6-41d9-b02c-53f6889b530b", "parent": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", "children": ["d139f273-e735-4c8c-8183-66cb946eb8a6"], "last_state_change": 1677513437.6548965, "state": 32, "task_spec": "Start", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "d139f273-e735-4c8c-8183-66cb946eb8a6": {"id": "d139f273-e735-4c8c-8183-66cb946eb8a6", "parent": "42edeac7-afb6-41d9-b02c-53f6889b530b", "children": ["83f7924b-01a0-43f7-9a50-f9dca568f0d8"], "last_state_change": 1677513437.655577, "state": 32, "task_spec": "StartEvent_1", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {"event_fired": true}, "data": {}}, "83f7924b-01a0-43f7-9a50-f9dca568f0d8": {"id": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", "parent": "d139f273-e735-4c8c-8183-66cb946eb8a6", "children": ["55c92211-cf14-43f8-8f25-950c0691fb30"], "last_state_change": 1677513437.6557715, "state": 16, "task_spec": "initiator_one", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "55c92211-cf14-43f8-8f25-950c0691fb30": {"id": "55c92211-cf14-43f8-8f25-950c0691fb30", "parent": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", "children": ["022792f0-6a6c-4bcb-8b7a-67c59a2c8c69"], "last_state_change": 1677513437.6543038, "state": 4, "task_spec": "finance_approval", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69": {"id": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", "parent": "55c92211-cf14-43f8-8f25-950c0691fb30", "children": ["0795b348-5eef-4b67-8cfa-6444d1fb1a49"], "last_state_change": 1677513437.6543193, "state": 4, "task_spec": "initiator_two", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "0795b348-5eef-4b67-8cfa-6444d1fb1a49": {"id": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", "parent": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", "children": ["35d0aecc-23d6-4d42-a593-571b8de0cbcf"], "last_state_change": 1677513437.6543357, "state": 4, "task_spec": "Event_06f4e68", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "35d0aecc-23d6-4d42-a593-571b8de0cbcf": {"id": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", "parent": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", "children": ["7a7af0ac-2f31-4025-b739-27822470f3ec"], "last_state_change": 1677513437.654353, "state": 4, "task_spec": "Proccess_yhito9d.EndJoin", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "7a7af0ac-2f31-4025-b739-27822470f3ec": {"id": "7a7af0ac-2f31-4025-b739-27822470f3ec", "parent": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", "children": [], "last_state_change": 1677513437.654371, "state": 4, "task_spec": "End", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}}, "root": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", "spec": {"name": "Proccess_yhito9d", "description": "Proccess_yhito9d", "file": "lanes.bpmn", "task_specs": {"Start": {"id": "Proccess_yhito9d_1", "name": "Start", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": [], "outputs": ["StartEvent_1"], "typename": "StartTask"}, "Proccess_yhito9d.EndJoin": {"id": "Proccess_yhito9d_2", "name": "Proccess_yhito9d.EndJoin", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": ["Event_06f4e68"], "outputs": ["End"], "typename": "_EndJoin"}, "End": {"id": "Proccess_yhito9d_3", "name": "End", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": ["Proccess_yhito9d.EndJoin"], "outputs": [], "typename": "Simple"}, "StartEvent_1": {"id": "Proccess_yhito9d_4", "name": "StartEvent_1", "description": null, "manual": false, "internal": false, "lookahead": 2, "inputs": ["Start"], "outputs": ["initiator_one"], "lane": "Process Initiator", "documentation": null, "position": {"x": 179.0, "y": 159.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "event_definition": {"internal": false, "external": false, "typename": "NoneEventDefinition"}, "typename": "StartEvent", "extensions": {}}, "initiator_one": {"id": "Proccess_yhito9d_5", "name": "initiator_one", "description": "Initiator One", "manual": false, "internal": false, "lookahead": 2, "inputs": ["StartEvent_1"], "outputs": ["finance_approval"], "lane": "Process Initiator", "documentation": null, "position": {"x": 270.0, "y": 137.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "prescript": null, "postscript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")", "typename": "ManualTask", "extensions": {"instructionsForEndUser": "This is for the initiator user", "postScript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")"}}, "finance_approval": {"id": "Proccess_yhito9d_6", "name": "finance_approval", "description": "Finance Approval", "manual": false, "internal": false, "lookahead": 2, "inputs": ["initiator_one"], "outputs": ["initiator_two"], "lane": "Finance Team", "documentation": null, "position": {"x": 310.0, "y": 320.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "prescript": null, "postscript": null, "typename": "ManualTask", "extensions": {"instructionsForEndUser": "This is for a Finance Team user"}}, "initiator_two": {"id": "Proccess_yhito9d_7", "name": "initiator_two", "description": "Initiator Two", "manual": false, "internal": false, "lookahead": 2, "inputs": ["finance_approval"], "outputs": ["Event_06f4e68"], "lane": "Process Initiator", "documentation": null, "position": {"x": 440.0, "y": 137.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "prescript": null, "postscript": null, "typename": "ManualTask", "extensions": {"instructionsForEndUser": "This is initiator again", "postScript": null}}, "Event_06f4e68": {"id": "Proccess_yhito9d_8", "name": "Event_06f4e68", "description": null, "manual": false, "internal": false, "lookahead": 2, "inputs": ["initiator_two"], "outputs": ["Proccess_yhito9d.EndJoin"], "lane": "Process Initiator", "documentation": null, "position": {"x": 572.0, "y": 159.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "event_definition": {"internal": false, "external": false, "typename": "NoneEventDefinition"}, "typename": "EndEvent", "extensions": {}}, "Root": {"id": "Proccess_yhito9d_9", "name": "Root", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": [], "outputs": [], "typename": "Simple"}}, "io_specification": null, "data_objects": {}, "correlation_keys": {}, "typename": "BpmnProcessSpec"}, "subprocess_specs": {}, "subprocesses": {}, "bpmn_messages": [], "serializer_version": "1.0-spiffworkflow-backend"} \ No newline at end of file diff --git a/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn b/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn index 99c9c63c..ed6195ac 100644 --- a/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn +++ b/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn @@ -23,7 +23,6 @@ This is for the initiator user - user_completing_task = get_last_user_completing_task("misc/category_number_one/lanes", "initiator_one") Flow_1tbyols Flow_16ppta1 diff --git a/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn b/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn index 41056173..9c302418 100644 --- a/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn +++ b/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn @@ -1,6 +1,6 @@ - + Flow_0smvjir @@ -14,6 +14,7 @@ Hello {{ name }} Department: {{ department }} + user_completing_task = get_last_user_completing_task("Process_WithForm", "Activity_SimpleForm") Flow_1ly1khd Flow_1boyhcj @@ -31,7 +32,7 @@ Department: {{ department }} - + diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py new file mode 100644 index 00000000..661428d6 --- /dev/null +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py @@ -0,0 +1,71 @@ +"""Test_get_localtime.""" +from spiffworkflow_backend.services.authorization_service import AuthorizationService +from tests.spiffworkflow_backend.helpers.test_data import load_test_spec + +from flask.app import Flask +from flask.testing import FlaskClient +from tests.spiffworkflow_backend.helpers.base_test import BaseTest + +from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.services.process_instance_processor import ( + ProcessInstanceProcessor, +) +from spiffworkflow_backend.services.process_instance_service import ( + ProcessInstanceService, +) + + +class TestGetLastUserCompletingTask(BaseTest): + + def test_get_last_user_completing_task_script_works( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + """Test_sets_permission_correctly_on_human_task.""" + self.create_process_group( + client, with_super_admin_user, "test_group", "test_group" + ) + initiator_user = self.find_or_create_user("initiator_user") + assert initiator_user.principal is not None + AuthorizationService.import_permissions_from_yaml_file() + + process_model = load_test_spec( + process_model_id="misc/category_number_one/simple_form", + # bpmn_file_name="simp.bpmn", + process_model_source_directory="simple_form", + ) + process_instance = self.create_process_instance_from_process_model( + process_model=process_model, user=initiator_user + ) + processor = ProcessInstanceProcessor(process_instance) + processor.do_engine_steps(save=True) + + assert len(process_instance.active_human_tasks) == 1 + human_task = process_instance.active_human_tasks[0] + assert len(human_task.potential_owners) == 1 + assert human_task.potential_owners[0] == initiator_user + + spiff_task = processor.__class__.get_task_by_bpmn_identifier( + human_task.task_name, processor.bpmn_process_instance + ) + ProcessInstanceService.complete_form_task( + processor, spiff_task, {"name": "HEY"}, initiator_user, human_task + ) + + assert len(process_instance.active_human_tasks) == 1 + human_task = process_instance.active_human_tasks[0] + spiff_task = processor.__class__.get_task_by_bpmn_identifier( + human_task.task_name, processor.bpmn_process_instance + ) + ProcessInstanceService.complete_form_task( + processor, spiff_task, {}, initiator_user, human_task + ) + + assert spiff_task is not None + assert ( + initiator_user.username + == spiff_task.get_data("user_completing_task")["username"] + ) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py index ea6e08cf..b46ba1e1 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py @@ -65,54 +65,6 @@ class TestProcessInstanceProcessor(BaseTest): app.config["THREAD_LOCAL_DATA"].process_model_identifier = None app.config["THREAD_LOCAL_DATA"].process_instance_id = None - def test_get_last_user_completing_task_script_works( - self, - app: Flask, - client: FlaskClient, - with_db_and_bpmn_file_cleanup: None, - with_super_admin_user: UserModel, - ) -> None: - """Test_sets_permission_correctly_on_human_task.""" - self.create_process_group( - client, with_super_admin_user, "test_group", "test_group" - ) - initiator_user = self.find_or_create_user("initiator_user") - finance_user = self.find_or_create_user("testuser2") - assert initiator_user.principal is not None - assert finance_user.principal is not None - AuthorizationService.import_permissions_from_yaml_file() - - finance_group = GroupModel.query.filter_by(identifier="Finance Team").first() - assert finance_group is not None - - process_model = load_test_spec( - process_model_id="misc/category_number_one/lanes", - bpmn_file_name="lanes.bpmn", - process_model_source_directory="model_with_lanes", - ) - process_instance = self.create_process_instance_from_process_model( - process_model=process_model, user=initiator_user - ) - processor = ProcessInstanceProcessor(process_instance) - processor.do_engine_steps(save=True) - - assert len(process_instance.active_human_tasks) == 1 - human_task = process_instance.active_human_tasks[0] - assert human_task.lane_assignment_id is None - assert len(human_task.potential_owners) == 1 - assert human_task.potential_owners[0] == initiator_user - - spiff_task = processor.__class__.get_task_by_bpmn_identifier( - human_task.task_name, processor.bpmn_process_instance - ) - ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user, human_task - ) - print(f"initiator_user.username: {initiator_user.username}") - print(f"data: {processor.get_data()}") - print(f"task_data: {spiff_task.data}") - assert initiator_user.username == spiff_task.get_data("user_completing_task")["username"] - def test_sets_permission_correctly_on_human_task( self, app: Flask, From e3ae71777fb91df0cf450df0f68fc80281a8ae9e Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 27 Feb 2023 12:08:40 -0500 Subject: [PATCH 3/5] remove unwanted test files w/ burnettk --- spiffworkflow-backend/t2.json | 353 -------------------------------- spiffworkflow-backend/test.json | 1 - 2 files changed, 354 deletions(-) delete mode 100644 spiffworkflow-backend/t2.json delete mode 100644 spiffworkflow-backend/test.json diff --git a/spiffworkflow-backend/t2.json b/spiffworkflow-backend/t2.json deleted file mode 100644 index 8ea7dec9..00000000 --- a/spiffworkflow-backend/t2.json +++ /dev/null @@ -1,353 +0,0 @@ -{ - "data": { - "validate_only": false, - "spiff__python_env_state": {} - }, - "last_task": "d139f273-e735-4c8c-8183-66cb946eb8a6", - "success": true, - "tasks": { - "d278c748-e3b1-4eeb-a64e-e927e61a80ed": { - "id": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", - "parent": null, - "children": [ - "42edeac7-afb6-41d9-b02c-53f6889b530b" - ], - "last_state_change": 1677513437.654198, - "state": 32, - "task_spec": "Root", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "42edeac7-afb6-41d9-b02c-53f6889b530b": { - "id": "42edeac7-afb6-41d9-b02c-53f6889b530b", - "parent": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", - "children": [ - "d139f273-e735-4c8c-8183-66cb946eb8a6" - ], - "last_state_change": 1677513437.6548965, - "state": 32, - "task_spec": "Start", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "d139f273-e735-4c8c-8183-66cb946eb8a6": { - "id": "d139f273-e735-4c8c-8183-66cb946eb8a6", - "parent": "42edeac7-afb6-41d9-b02c-53f6889b530b", - "children": [ - "83f7924b-01a0-43f7-9a50-f9dca568f0d8" - ], - "last_state_change": 1677513437.655577, - "state": 32, - "task_spec": "StartEvent_1", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": { - "event_fired": true - }, - "data": {} - }, - "83f7924b-01a0-43f7-9a50-f9dca568f0d8": { - "id": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", - "parent": "d139f273-e735-4c8c-8183-66cb946eb8a6", - "children": [ - "55c92211-cf14-43f8-8f25-950c0691fb30" - ], - "last_state_change": 1677513437.6557715, - "state": 16, - "task_spec": "initiator_one", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "55c92211-cf14-43f8-8f25-950c0691fb30": { - "id": "55c92211-cf14-43f8-8f25-950c0691fb30", - "parent": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", - "children": [ - "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69" - ], - "last_state_change": 1677513437.6543038, - "state": 4, - "task_spec": "finance_approval", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69": { - "id": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", - "parent": "55c92211-cf14-43f8-8f25-950c0691fb30", - "children": [ - "0795b348-5eef-4b67-8cfa-6444d1fb1a49" - ], - "last_state_change": 1677513437.6543193, - "state": 4, - "task_spec": "initiator_two", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "0795b348-5eef-4b67-8cfa-6444d1fb1a49": { - "id": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", - "parent": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", - "children": [ - "35d0aecc-23d6-4d42-a593-571b8de0cbcf" - ], - "last_state_change": 1677513437.6543357, - "state": 4, - "task_spec": "Event_06f4e68", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "35d0aecc-23d6-4d42-a593-571b8de0cbcf": { - "id": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", - "parent": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", - "children": [ - "7a7af0ac-2f31-4025-b739-27822470f3ec" - ], - "last_state_change": 1677513437.654353, - "state": 4, - "task_spec": "Proccess_yhito9d.EndJoin", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - }, - "7a7af0ac-2f31-4025-b739-27822470f3ec": { - "id": "7a7af0ac-2f31-4025-b739-27822470f3ec", - "parent": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", - "children": [], - "last_state_change": 1677513437.654371, - "state": 4, - "task_spec": "End", - "triggered": false, - "workflow_name": "Proccess_yhito9d", - "internal_data": {}, - "data": {} - } - }, - "root": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", - "spec": { - "name": "Proccess_yhito9d", - "description": "Proccess_yhito9d", - "file": "lanes.bpmn", - "task_specs": { - "Start": { - "id": "Proccess_yhito9d_1", - "name": "Start", - "description": "", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [], - "outputs": [ - "StartEvent_1" - ], - "typename": "StartTask" - }, - "Proccess_yhito9d.EndJoin": { - "id": "Proccess_yhito9d_2", - "name": "Proccess_yhito9d.EndJoin", - "description": "", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "Event_06f4e68" - ], - "outputs": [ - "End" - ], - "typename": "_EndJoin" - }, - "End": { - "id": "Proccess_yhito9d_3", - "name": "End", - "description": "", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "Proccess_yhito9d.EndJoin" - ], - "outputs": [], - "typename": "Simple" - }, - "StartEvent_1": { - "id": "Proccess_yhito9d_4", - "name": "StartEvent_1", - "description": null, - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "Start" - ], - "outputs": [ - "initiator_one" - ], - "lane": "Process Initiator", - "documentation": null, - "position": { - "x": 179, - "y": 159 - }, - "data_input_associations": [], - "data_output_associations": [], - "io_specification": null, - "event_definition": { - "internal": false, - "external": false, - "typename": "NoneEventDefinition" - }, - "typename": "StartEvent", - "extensions": {} - }, - "initiator_one": { - "id": "Proccess_yhito9d_5", - "name": "initiator_one", - "description": "Initiator One", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "StartEvent_1" - ], - "outputs": [ - "finance_approval" - ], - "lane": "Process Initiator", - "documentation": null, - "position": { - "x": 270, - "y": 137 - }, - "data_input_associations": [], - "data_output_associations": [], - "io_specification": null, - "prescript": null, - "postscript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")", - "typename": "ManualTask", - "extensions": { - "instructionsForEndUser": "This is for the initiator user", - "postScript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")" - } - }, - "finance_approval": { - "id": "Proccess_yhito9d_6", - "name": "finance_approval", - "description": "Finance Approval", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "initiator_one" - ], - "outputs": [ - "initiator_two" - ], - "lane": "Finance Team", - "documentation": null, - "position": { - "x": 310, - "y": 320 - }, - "data_input_associations": [], - "data_output_associations": [], - "io_specification": null, - "prescript": null, - "postscript": null, - "typename": "ManualTask", - "extensions": { - "instructionsForEndUser": "This is for a Finance Team user" - } - }, - "initiator_two": { - "id": "Proccess_yhito9d_7", - "name": "initiator_two", - "description": "Initiator Two", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "finance_approval" - ], - "outputs": [ - "Event_06f4e68" - ], - "lane": "Process Initiator", - "documentation": null, - "position": { - "x": 440, - "y": 137 - }, - "data_input_associations": [], - "data_output_associations": [], - "io_specification": null, - "prescript": null, - "postscript": null, - "typename": "ManualTask", - "extensions": { - "instructionsForEndUser": "This is initiator again", - "postScript": null - } - }, - "Event_06f4e68": { - "id": "Proccess_yhito9d_8", - "name": "Event_06f4e68", - "description": null, - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [ - "initiator_two" - ], - "outputs": [ - "Proccess_yhito9d.EndJoin" - ], - "lane": "Process Initiator", - "documentation": null, - "position": { - "x": 572, - "y": 159 - }, - "data_input_associations": [], - "data_output_associations": [], - "io_specification": null, - "event_definition": { - "internal": false, - "external": false, - "typename": "NoneEventDefinition" - }, - "typename": "EndEvent", - "extensions": {} - }, - "Root": { - "id": "Proccess_yhito9d_9", - "name": "Root", - "description": "", - "manual": false, - "internal": false, - "lookahead": 2, - "inputs": [], - "outputs": [], - "typename": "Simple" - } - }, - "io_specification": null, - "data_objects": {}, - "correlation_keys": {}, - "typename": "BpmnProcessSpec" - }, - "subprocess_specs": {}, - "subprocesses": {}, - "bpmn_messages": [], - "serializer_version": "1.0-spiffworkflow-backend" -} diff --git a/spiffworkflow-backend/test.json b/spiffworkflow-backend/test.json deleted file mode 100644 index cf7dc282..00000000 --- a/spiffworkflow-backend/test.json +++ /dev/null @@ -1 +0,0 @@ -{"data": {"validate_only": false, "spiff__python_env_state": {}}, "last_task": "d139f273-e735-4c8c-8183-66cb946eb8a6", "success": true, "tasks": {"d278c748-e3b1-4eeb-a64e-e927e61a80ed": {"id": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", "parent": null, "children": ["42edeac7-afb6-41d9-b02c-53f6889b530b"], "last_state_change": 1677513437.654198, "state": 32, "task_spec": "Root", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "42edeac7-afb6-41d9-b02c-53f6889b530b": {"id": "42edeac7-afb6-41d9-b02c-53f6889b530b", "parent": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", "children": ["d139f273-e735-4c8c-8183-66cb946eb8a6"], "last_state_change": 1677513437.6548965, "state": 32, "task_spec": "Start", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "d139f273-e735-4c8c-8183-66cb946eb8a6": {"id": "d139f273-e735-4c8c-8183-66cb946eb8a6", "parent": "42edeac7-afb6-41d9-b02c-53f6889b530b", "children": ["83f7924b-01a0-43f7-9a50-f9dca568f0d8"], "last_state_change": 1677513437.655577, "state": 32, "task_spec": "StartEvent_1", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {"event_fired": true}, "data": {}}, "83f7924b-01a0-43f7-9a50-f9dca568f0d8": {"id": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", "parent": "d139f273-e735-4c8c-8183-66cb946eb8a6", "children": ["55c92211-cf14-43f8-8f25-950c0691fb30"], "last_state_change": 1677513437.6557715, "state": 16, "task_spec": "initiator_one", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "55c92211-cf14-43f8-8f25-950c0691fb30": {"id": "55c92211-cf14-43f8-8f25-950c0691fb30", "parent": "83f7924b-01a0-43f7-9a50-f9dca568f0d8", "children": ["022792f0-6a6c-4bcb-8b7a-67c59a2c8c69"], "last_state_change": 1677513437.6543038, "state": 4, "task_spec": "finance_approval", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69": {"id": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", "parent": "55c92211-cf14-43f8-8f25-950c0691fb30", "children": ["0795b348-5eef-4b67-8cfa-6444d1fb1a49"], "last_state_change": 1677513437.6543193, "state": 4, "task_spec": "initiator_two", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "0795b348-5eef-4b67-8cfa-6444d1fb1a49": {"id": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", "parent": "022792f0-6a6c-4bcb-8b7a-67c59a2c8c69", "children": ["35d0aecc-23d6-4d42-a593-571b8de0cbcf"], "last_state_change": 1677513437.6543357, "state": 4, "task_spec": "Event_06f4e68", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "35d0aecc-23d6-4d42-a593-571b8de0cbcf": {"id": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", "parent": "0795b348-5eef-4b67-8cfa-6444d1fb1a49", "children": ["7a7af0ac-2f31-4025-b739-27822470f3ec"], "last_state_change": 1677513437.654353, "state": 4, "task_spec": "Proccess_yhito9d.EndJoin", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}, "7a7af0ac-2f31-4025-b739-27822470f3ec": {"id": "7a7af0ac-2f31-4025-b739-27822470f3ec", "parent": "35d0aecc-23d6-4d42-a593-571b8de0cbcf", "children": [], "last_state_change": 1677513437.654371, "state": 4, "task_spec": "End", "triggered": false, "workflow_name": "Proccess_yhito9d", "internal_data": {}, "data": {}}}, "root": "d278c748-e3b1-4eeb-a64e-e927e61a80ed", "spec": {"name": "Proccess_yhito9d", "description": "Proccess_yhito9d", "file": "lanes.bpmn", "task_specs": {"Start": {"id": "Proccess_yhito9d_1", "name": "Start", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": [], "outputs": ["StartEvent_1"], "typename": "StartTask"}, "Proccess_yhito9d.EndJoin": {"id": "Proccess_yhito9d_2", "name": "Proccess_yhito9d.EndJoin", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": ["Event_06f4e68"], "outputs": ["End"], "typename": "_EndJoin"}, "End": {"id": "Proccess_yhito9d_3", "name": "End", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": ["Proccess_yhito9d.EndJoin"], "outputs": [], "typename": "Simple"}, "StartEvent_1": {"id": "Proccess_yhito9d_4", "name": "StartEvent_1", "description": null, "manual": false, "internal": false, "lookahead": 2, "inputs": ["Start"], "outputs": ["initiator_one"], "lane": "Process Initiator", "documentation": null, "position": {"x": 179.0, "y": 159.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "event_definition": {"internal": false, "external": false, "typename": "NoneEventDefinition"}, "typename": "StartEvent", "extensions": {}}, "initiator_one": {"id": "Proccess_yhito9d_5", "name": "initiator_one", "description": "Initiator One", "manual": false, "internal": false, "lookahead": 2, "inputs": ["StartEvent_1"], "outputs": ["finance_approval"], "lane": "Process Initiator", "documentation": null, "position": {"x": 270.0, "y": 137.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "prescript": null, "postscript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")", "typename": "ManualTask", "extensions": {"instructionsForEndUser": "This is for the initiator user", "postScript": "user_completing_task = get_last_user_completing_task(\"misc/category_number_one/lanes\", \"initiator_one\")"}}, "finance_approval": {"id": "Proccess_yhito9d_6", "name": "finance_approval", "description": "Finance Approval", "manual": false, "internal": false, "lookahead": 2, "inputs": ["initiator_one"], "outputs": ["initiator_two"], "lane": "Finance Team", "documentation": null, "position": {"x": 310.0, "y": 320.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "prescript": null, "postscript": null, "typename": "ManualTask", "extensions": {"instructionsForEndUser": "This is for a Finance Team user"}}, "initiator_two": {"id": "Proccess_yhito9d_7", "name": "initiator_two", "description": "Initiator Two", "manual": false, "internal": false, "lookahead": 2, "inputs": ["finance_approval"], "outputs": ["Event_06f4e68"], "lane": "Process Initiator", "documentation": null, "position": {"x": 440.0, "y": 137.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "prescript": null, "postscript": null, "typename": "ManualTask", "extensions": {"instructionsForEndUser": "This is initiator again", "postScript": null}}, "Event_06f4e68": {"id": "Proccess_yhito9d_8", "name": "Event_06f4e68", "description": null, "manual": false, "internal": false, "lookahead": 2, "inputs": ["initiator_two"], "outputs": ["Proccess_yhito9d.EndJoin"], "lane": "Process Initiator", "documentation": null, "position": {"x": 572.0, "y": 159.0}, "data_input_associations": [], "data_output_associations": [], "io_specification": null, "event_definition": {"internal": false, "external": false, "typename": "NoneEventDefinition"}, "typename": "EndEvent", "extensions": {}}, "Root": {"id": "Proccess_yhito9d_9", "name": "Root", "description": "", "manual": false, "internal": false, "lookahead": 2, "inputs": [], "outputs": [], "typename": "Simple"}}, "io_specification": null, "data_objects": {}, "correlation_keys": {}, "typename": "BpmnProcessSpec"}, "subprocess_specs": {}, "subprocesses": {}, "bpmn_messages": [], "serializer_version": "1.0-spiffworkflow-backend"} \ No newline at end of file From df17c5145303ad27b660a082987b549425756677 Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 27 Feb 2023 14:28:19 -0500 Subject: [PATCH 4/5] added script to get process initiator w/ burnettk --- .../models/human_task.py | 4 +- .../src/spiffworkflow_backend/models/user.py | 8 +++ .../scripts/get_last_user_completing_task.py | 11 ++-- .../scripts/get_process_initiator_user.py | 36 +++++++++++ .../dynamic_enums_ask_for_color.bpmn | 4 +- .../tests/data/error/instructions_error.bpmn | 4 +- .../data/get_localtime/get_localtime.bpmn | 4 +- .../tests/data/manual_task/manual_task.bpmn | 4 +- .../tests/data/model_with_lanes/lanes.bpmn | 4 +- .../lanes_with_owner_dict.bpmn | 4 +- .../tests/data/simple_form/simple_form.bpmn | 1 + .../simple_form_with_error.bpmn | 4 +- .../data/simple_script/simple_script.bpmn | 4 +- .../integration/test_process_api.py | 2 +- .../test_get_last_user_completing_task.py | 6 +- .../test_get_process_initiator_user.py | 62 +++++++++++++++++++ 16 files changed, 133 insertions(+), 29 deletions(-) create mode 100644 spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_initiator_user.py create mode 100644 spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_process_initiator_user.py diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py index 43415352..5cc208b1 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py @@ -34,7 +34,9 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): lane_assignment_id: int | None = db.Column(ForeignKey(GroupModel.id)) completed_by_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) # type: ignore - completed_by_user = relationship("UserModel", foreign_keys=[completed_by_user_id]) + completed_by_user = relationship( + "UserModel", foreign_keys=[completed_by_user_id], viewonly=True + ) actual_owner_id: int = db.Column(ForeignKey(UserModel.id)) # type: ignore # actual_owner: RelationshipProperty[UserModel] = relationship(UserModel) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/user.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/user.py index 464bdc8b..f32a35d7 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/user.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/user.py @@ -2,6 +2,7 @@ from __future__ import annotations from dataclasses import dataclass +from typing import Any import jwt import marshmallow @@ -82,6 +83,13 @@ class UserModel(SpiffworkflowBaseDBModel): # # return instance + def as_dict(self) -> dict[str, Any]: + # dump the user using our json encoder and then load it back up as a dict + # to remove unwanted field types + user_as_json_string = current_app.json.dumps(self) + user_dict: dict[str, Any] = current_app.json.loads(user_as_json_string) + return user_dict + class UserModelSchema(Schema): """UserModelSchema.""" diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py index eea757d6..8d63610b 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_last_user_completing_task.py @@ -1,8 +1,6 @@ """Get current user.""" from typing import Any -from flask import current_app - from spiffworkflow_backend.models.human_task import HumanTaskModel from spiffworkflow_backend.models.script_attributes_context import ( ScriptAttributesContext, @@ -38,14 +36,13 @@ class GetLastUserCompletingTask(Script): human_task = ( HumanTaskModel.query.filter_by( - bpmn_process_identifier=bpmn_process_identifier, task_name=task_name + process_instance_id=script_attributes_context.process_instance_id, + bpmn_process_identifier=bpmn_process_identifier, + task_name=task_name, ) .order_by(HumanTaskModel.id.desc()) # type: ignore .join(UserModel, UserModel.id == HumanTaskModel.completed_by_user_id) .first() ) - # dump the user using our json encoder and then load it back up as a dict - # to remove unwanted field types - user_as_json_string = current_app.json.dumps(human_task.completed_by_user) - return current_app.json.loads(user_as_json_string) + return human_task.completed_by_user.as_dict() diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_initiator_user.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_initiator_user.py new file mode 100644 index 00000000..266fa57b --- /dev/null +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_initiator_user.py @@ -0,0 +1,36 @@ +"""Get current user.""" +from typing import Any + +from spiffworkflow_backend.models.process_instance import ProcessInstanceModel +from spiffworkflow_backend.models.script_attributes_context import ( + ScriptAttributesContext, +) +from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.scripts.script import Script + + +class GetProcessInitiatorUser(Script): + @staticmethod + def requires_privileged_permissions() -> bool: + """We have deemed this function safe to run without elevated permissions.""" + return False + + def get_description(self) -> str: + return """Return the user that initiated the process instance.""" + + def run( + self, + script_attributes_context: ScriptAttributesContext, + *_args: Any, + **kwargs: Any, + ) -> Any: + """Run.""" + process_instance = ( + ProcessInstanceModel.query.filter_by( + id=script_attributes_context.process_instance_id + ) + .join(UserModel, UserModel.id == ProcessInstanceModel.process_initiator_id) + .first() + ) + + return process_instance.process_initiator.as_dict() diff --git a/spiffworkflow-backend/tests/data/dynamic_enum_select_fields/dynamic_enums_ask_for_color.bpmn b/spiffworkflow-backend/tests/data/dynamic_enum_select_fields/dynamic_enums_ask_for_color.bpmn index d4f1aa5d..9b15cb09 100644 --- a/spiffworkflow-backend/tests/data/dynamic_enum_select_fields/dynamic_enums_ask_for_color.bpmn +++ b/spiffworkflow-backend/tests/data/dynamic_enum_select_fields/dynamic_enums_ask_for_color.bpmn @@ -1,6 +1,6 @@ - + Flow_1my9ag5 @@ -28,7 +28,7 @@ form_ui_hidden_fields = ["veryImportantFieldButOnlySometimes", "building.floor"] - + diff --git a/spiffworkflow-backend/tests/data/error/instructions_error.bpmn b/spiffworkflow-backend/tests/data/error/instructions_error.bpmn index 24039bbb..1db55f39 100644 --- a/spiffworkflow-backend/tests/data/error/instructions_error.bpmn +++ b/spiffworkflow-backend/tests/data/error/instructions_error.bpmn @@ -1,6 +1,6 @@ - + Flow_0smvjir @@ -21,7 +21,7 @@ Department: {{ department }} - + diff --git a/spiffworkflow-backend/tests/data/get_localtime/get_localtime.bpmn b/spiffworkflow-backend/tests/data/get_localtime/get_localtime.bpmn index 5660ba0b..2efa2fa6 100644 --- a/spiffworkflow-backend/tests/data/get_localtime/get_localtime.bpmn +++ b/spiffworkflow-backend/tests/data/get_localtime/get_localtime.bpmn @@ -1,6 +1,6 @@ - + Flow_0ijucqh @@ -40,7 +40,7 @@ localtime = get_localtime(some_time, timezone) - + diff --git a/spiffworkflow-backend/tests/data/manual_task/manual_task.bpmn b/spiffworkflow-backend/tests/data/manual_task/manual_task.bpmn index aefbb376..4f0fba72 100644 --- a/spiffworkflow-backend/tests/data/manual_task/manual_task.bpmn +++ b/spiffworkflow-backend/tests/data/manual_task/manual_task.bpmn @@ -1,6 +1,6 @@ - + Flow_1xlck7g @@ -18,7 +18,7 @@ - + diff --git a/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn b/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn index ed6195ac..b396bf71 100644 --- a/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn +++ b/spiffworkflow-backend/tests/data/model_with_lanes/lanes.bpmn @@ -1,9 +1,9 @@ - + - + StartEvent_1 diff --git a/spiffworkflow-backend/tests/data/model_with_lanes/lanes_with_owner_dict.bpmn b/spiffworkflow-backend/tests/data/model_with_lanes/lanes_with_owner_dict.bpmn index 0c2af8d4..9d0f2a30 100644 --- a/spiffworkflow-backend/tests/data/model_with_lanes/lanes_with_owner_dict.bpmn +++ b/spiffworkflow-backend/tests/data/model_with_lanes/lanes_with_owner_dict.bpmn @@ -1,9 +1,9 @@ - + - + StartEvent_1 diff --git a/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn b/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn index 9c302418..a2f29fd3 100644 --- a/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn +++ b/spiffworkflow-backend/tests/data/simple_form/simple_form.bpmn @@ -26,6 +26,7 @@ Department: {{ department }} + process_initiator_user = get_process_initiator_user() Flow_0smvjir Flow_1ly1khd diff --git a/spiffworkflow-backend/tests/data/simple_form_with_error/simple_form_with_error.bpmn b/spiffworkflow-backend/tests/data/simple_form_with_error/simple_form_with_error.bpmn index 351d53a6..43d3d116 100644 --- a/spiffworkflow-backend/tests/data/simple_form_with_error/simple_form_with_error.bpmn +++ b/spiffworkflow-backend/tests/data/simple_form_with_error/simple_form_with_error.bpmn @@ -1,6 +1,6 @@ - + Flow_0smvjir @@ -31,7 +31,7 @@ Department: {{ department }} - + diff --git a/spiffworkflow-backend/tests/data/simple_script/simple_script.bpmn b/spiffworkflow-backend/tests/data/simple_script/simple_script.bpmn index 6e14807f..f5efba61 100644 --- a/spiffworkflow-backend/tests/data/simple_script/simple_script.bpmn +++ b/spiffworkflow-backend/tests/data/simple_script/simple_script.bpmn @@ -1,6 +1,6 @@ - + Flow_0r3ua0i @@ -48,7 +48,7 @@ b = 2 - + 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 29d1d33f..cce940be 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -583,7 +583,7 @@ class TestProcessApi(BaseTest): # We should get 5 back, as one of the items in the cache is a decision. assert len(response.json) == 5 simple_form = next( - p for p in response.json if p["identifier"] == "Proccess_WithForm" + p for p in response.json if p["identifier"] == "Process_WithForm" ) assert simple_form["display_name"] == "Process With Form" assert simple_form["process_model_id"] == "test_group_one/simple_form" diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py index 661428d6..d6533eae 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_last_user_completing_task.py @@ -1,12 +1,11 @@ """Test_get_localtime.""" -from spiffworkflow_backend.services.authorization_service import AuthorizationService -from tests.spiffworkflow_backend.helpers.test_data import load_test_spec - from flask.app import Flask from flask.testing import FlaskClient from tests.spiffworkflow_backend.helpers.base_test import BaseTest +from tests.spiffworkflow_backend.helpers.test_data import load_test_spec from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.services.authorization_service import AuthorizationService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, ) @@ -16,7 +15,6 @@ from spiffworkflow_backend.services.process_instance_service import ( class TestGetLastUserCompletingTask(BaseTest): - def test_get_last_user_completing_task_script_works( self, app: Flask, diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_process_initiator_user.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_process_initiator_user.py new file mode 100644 index 00000000..5e734227 --- /dev/null +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_process_initiator_user.py @@ -0,0 +1,62 @@ +"""Test_get_localtime.""" +from spiffworkflow_backend.services.authorization_service import AuthorizationService +from tests.spiffworkflow_backend.helpers.test_data import load_test_spec + +from flask.app import Flask +from flask.testing import FlaskClient +from tests.spiffworkflow_backend.helpers.base_test import BaseTest + +from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.services.process_instance_processor import ( + ProcessInstanceProcessor, +) +from spiffworkflow_backend.services.process_instance_service import ( + ProcessInstanceService, +) + + +class TestGetProcessInitiatorUser(BaseTest): + + def test_get_process_initiator_user( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + """Test_sets_permission_correctly_on_human_task.""" + self.create_process_group( + client, with_super_admin_user, "test_group", "test_group" + ) + initiator_user = self.find_or_create_user("initiator_user") + assert initiator_user.principal is not None + AuthorizationService.import_permissions_from_yaml_file() + + process_model = load_test_spec( + process_model_id="misc/category_number_one/simple_form", + # bpmn_file_name="simp.bpmn", + process_model_source_directory="simple_form", + ) + process_instance = self.create_process_instance_from_process_model( + process_model=process_model, user=initiator_user + ) + processor = ProcessInstanceProcessor(process_instance) + processor.do_engine_steps(save=True) + + assert len(process_instance.active_human_tasks) == 1 + human_task = process_instance.active_human_tasks[0] + assert len(human_task.potential_owners) == 1 + assert human_task.potential_owners[0] == initiator_user + + spiff_task = processor.__class__.get_task_by_bpmn_identifier( + human_task.task_name, processor.bpmn_process_instance + ) + ProcessInstanceService.complete_form_task( + processor, spiff_task, {"name": "HEY"}, initiator_user, human_task + ) + + assert spiff_task is not None + assert ( + initiator_user.username + == spiff_task.get_data("process_initiator_user")["username"] + ) From 24ee23f28c3e298d0ce0517c1f2e9bab2445bf0c Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 27 Feb 2023 14:33:55 -0500 Subject: [PATCH 5/5] fixed conflict with db migrations w/ burnettk --- spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py b/spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py index 89561ca3..f47b4b57 100644 --- a/spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py +++ b/spiffworkflow-backend/migrations/versions/d6e5b3af0908_.py @@ -1,7 +1,7 @@ """empty message Revision ID: d6e5b3af0908 -Revises: 63fc8d693b9f +Revises: 9f0b1662a8af Create Date: 2023-02-27 11:10:28.058014 """ @@ -11,7 +11,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'd6e5b3af0908' -down_revision = '63fc8d693b9f' +down_revision = '9f0b1662a8af' branch_labels = None depends_on = None