Merge branch 'main' of github.com:sartography/spiff-arena into main

This commit is contained in:
Dan 2023-02-27 14:40:52 -05:00
commit 24839a34dd
19 changed files with 297 additions and 30 deletions

View File

@ -0,0 +1,28 @@
"""empty message
Revision ID: d6e5b3af0908
Revises: 9f0b1662a8af
Create Date: 2023-02-27 11:10:28.058014
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'd6e5b3af0908'
down_revision = '9f0b1662a8af'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
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', 'bpmn_process_identifier')
# ### end Alembic commands ###

View File

@ -34,6 +34,10 @@ class HumanTaskModel(SpiffworkflowBaseDBModel):
lane_assignment_id: int | None = db.Column(ForeignKey(GroupModel.id)) 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_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) # type: ignore
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_id: int = db.Column(ForeignKey(UserModel.id)) # type: ignore
# actual_owner: RelationshipProperty[UserModel] = relationship(UserModel) # actual_owner: RelationshipProperty[UserModel] = relationship(UserModel)
@ -49,6 +53,7 @@ class HumanTaskModel(SpiffworkflowBaseDBModel):
task_type: str = db.Column(db.String(50)) task_type: str = db.Column(db.String(50))
task_status: 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_display_name: 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) completed: bool = db.Column(db.Boolean, default=False, nullable=False, index=True)
human_task_users = relationship("HumanTaskUserModel", cascade="delete") human_task_users = relationship("HumanTaskUserModel", cascade="delete")
@ -74,8 +79,8 @@ class HumanTaskModel(SpiffworkflowBaseDBModel):
new_task.process_model_display_name = task.process_model_display_name new_task.process_model_display_name = task.process_model_display_name
if hasattr(task, "process_group_identifier"): if hasattr(task, "process_group_identifier"):
new_task.process_group_identifier = task.process_group_identifier new_task.process_group_identifier = task.process_group_identifier
if hasattr(task, "process_model_identifier"): if hasattr(task, "bpmn_process_identifier"):
new_task.process_model_identifier = task.process_model_identifier new_task.bpmn_process_identifier = task.bpmn_process_identifier
# human tasks only have status when getting the list on the home page # 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. # and it comes from the process_instance. it should not be confused with task_status.

View File

@ -45,6 +45,7 @@ class Task:
process_model_display_name: Union[str, None] = None, process_model_display_name: Union[str, None] = None,
process_group_identifier: Union[str, None] = None, process_group_identifier: Union[str, None] = None,
process_model_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_schema: Union[dict, None] = None,
form_ui_schema: Union[dict, None] = None, form_ui_schema: Union[dict, None] = None,
parent: Optional[str] = None, parent: Optional[str] = None,
@ -76,6 +77,7 @@ class Task:
self.process_instance_status = process_instance_status self.process_instance_status = process_instance_status
self.process_group_identifier = process_group_identifier self.process_group_identifier = process_group_identifier
self.process_model_identifier = process_model_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.process_model_display_name = process_model_display_name
self.form_schema = form_schema self.form_schema = form_schema
self.form_ui_schema = form_ui_schema self.form_ui_schema = form_ui_schema
@ -122,6 +124,7 @@ class Task:
"process_model_display_name": self.process_model_display_name, "process_model_display_name": self.process_model_display_name,
"process_group_identifier": self.process_group_identifier, "process_group_identifier": self.process_group_identifier,
"process_model_identifier": self.process_model_identifier, "process_model_identifier": self.process_model_identifier,
"bpmn_process_identifier": self.bpmn_process_identifier,
"form_schema": self.form_schema, "form_schema": self.form_schema,
"form_ui_schema": self.form_ui_schema, "form_ui_schema": self.form_ui_schema,
"parent": self.parent, "parent": self.parent,

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
import jwt import jwt
import marshmallow import marshmallow
@ -82,6 +83,13 @@ class UserModel(SpiffworkflowBaseDBModel):
# #
# return instance # 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): class UserModelSchema(Schema):
"""UserModelSchema.""" """UserModelSchema."""

View File

@ -0,0 +1,48 @@
"""Get current user."""
from typing import Any
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
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:
bpmn_process_identifier = _args[0]
task_name = _args[1]
else:
bpmn_process_identifier = kwargs["bpmn_process_identifier"]
task_name = kwargs["task_bpmn_identifier"]
human_task = (
HumanTaskModel.query.filter_by(
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()
)
return human_task.completed_by_user.as_dict()

View File

@ -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()

View File

@ -869,6 +869,7 @@ class ProcessInstanceProcessor:
process_instance_id=self.process_instance_model.id, completed=False process_instance_id=self.process_instance_model.id, completed=False
).all() ).all()
ready_or_waiting_tasks = self.get_all_ready_or_waiting_tasks() ready_or_waiting_tasks = self.get_all_ready_or_waiting_tasks()
process_model_display_name = "" process_model_display_name = ""
process_model_info = self.process_model_service.get_process_model( process_model_info = self.process_model_service.get_process_model(
self.process_instance_model.process_model_identifier self.process_instance_model.process_model_identifier
@ -887,6 +888,10 @@ class ProcessInstanceProcessor:
) )
extensions = task_spec.extensions 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 form_file_name = None
ui_form_file_name = None ui_form_file_name = None
if "properties" in extensions: if "properties" in extensions:
@ -906,6 +911,7 @@ class ProcessInstanceProcessor:
human_task = HumanTaskModel( human_task = HumanTaskModel(
process_instance_id=self.process_instance_model.id, process_instance_id=self.process_instance_model.id,
process_model_display_name=process_model_display_name, process_model_display_name=process_model_display_name,
bpmn_process_identifier=bpmn_process_identifier,
form_file_name=form_file_name, form_file_name=form_file_name,
ui_form_file_name=ui_form_file_name, ui_form_file_name=ui_form_file_name,
task_id=str(ready_or_waiting_task.id), task_id=str(ready_or_waiting_task.id),
@ -1635,7 +1641,6 @@ class ProcessInstanceProcessor:
details_model.end_in_seconds = time.time() details_model.end_in_seconds = time.time()
details_model.task_json = self.get_task_json_from_spiff_task(task) details_model.task_json = self.get_task_json_from_spiff_task(task)
db.session.add(details_model) db.session.add(details_model)
# this is the thing that actually commits the db transaction (on behalf of the other updates above as well) # this is the thing that actually commits the db transaction (on behalf of the other updates above as well)
self.save() self.save()

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_0e253c6" isExecutable="true"> <bpmn:process id="Process_0e253c6" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1my9ag5</bpmn:outgoing> <bpmn:outgoing>Flow_1my9ag5</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -28,7 +28,7 @@ form_ui_hidden_fields = ["veryImportantFieldButOnlySometimes", "building.floor"]
</bpmn:userTask> </bpmn:userTask>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_0e253c6"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0e253c6">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0">
<bpmn:process id="Proccess_With_Bad_Form" name="Process With Form" isExecutable="true"> <bpmn:process id="Process_With_Bad_Form" name="Process With Form" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0smvjir</bpmn:outgoing> <bpmn:outgoing>Flow_0smvjir</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -21,7 +21,7 @@ Department: {{ department }}
</bpmn:manualTask> </bpmn:manualTask>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_With_Bad_Form"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_With_Bad_Form">
<bpmndi:BPMNEdge id="Flow_1boyhcj_di" bpmnElement="Flow_1boyhcj"> <bpmndi:BPMNEdge id="Flow_1boyhcj_di" bpmnElement="Flow_1boyhcj">
<di:waypoint x="340" y="117" /> <di:waypoint x="340" y="117" />
<di:waypoint x="382" y="117" /> <di:waypoint x="382" y="117" />

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_LocalTime" name="Get LocalTime" isExecutable="true"> <bpmn:process id="Process_LocalTime" name="Get LocalTime" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0ijucqh</bpmn:outgoing> <bpmn:outgoing>Flow_0ijucqh</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -40,7 +40,7 @@ localtime = get_localtime(some_time, timezone)</bpmn:script>
</bpmn:userTask> </bpmn:userTask>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_LocalTime"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_LocalTime">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_ManualTask" name="Manual Task" isExecutable="true"> <bpmn:process id="Process_ManualTask" name="Manual Task" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1xlck7g</bpmn:outgoing> <bpmn:outgoing>Flow_1xlck7g</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -18,7 +18,7 @@
</bpmn:manualTask> </bpmn:manualTask>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_ManualTask"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_ManualTask">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:collaboration id="Collaboration_0iyw0q7"> <bpmn:collaboration id="Collaboration_0iyw0q7">
<bpmn:participant id="Participant_17eqap4" processRef="Proccess_yhito9d" /> <bpmn:participant id="Participant_17eqap4" processRef="Process_yhito9d" />
</bpmn:collaboration> </bpmn:collaboration>
<bpmn:process id="Proccess_yhito9d" isExecutable="true"> <bpmn:process id="Process_yhito9d" isExecutable="true">
<bpmn:laneSet id="LaneSet_17rankp"> <bpmn:laneSet id="LaneSet_17rankp">
<bpmn:lane id="process_initiator" name="Process Initiator"> <bpmn:lane id="process_initiator" name="Process Initiator">
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef> <bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
<bpmn:flowNodeRef>initator_one</bpmn:flowNodeRef> <bpmn:flowNodeRef>initiator_one</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_06f4e68</bpmn:flowNodeRef> <bpmn:flowNodeRef>Event_06f4e68</bpmn:flowNodeRef>
<bpmn:flowNodeRef>initiator_two</bpmn:flowNodeRef> <bpmn:flowNodeRef>initiator_two</bpmn:flowNodeRef>
</bpmn:lane> </bpmn:lane>
@ -18,18 +18,18 @@
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1tbyols</bpmn:outgoing> <bpmn:outgoing>Flow_1tbyols</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1tbyols" sourceRef="StartEvent_1" targetRef="initator_one" /> <bpmn:sequenceFlow id="Flow_1tbyols" sourceRef="StartEvent_1" targetRef="initiator_one" />
<bpmn:sequenceFlow id="Flow_16ppta1" sourceRef="initator_one" targetRef="finance_approval" /> <bpmn:sequenceFlow id="Flow_16ppta1" sourceRef="initiator_one" targetRef="finance_approval" />
<bpmn:manualTask id="initator_one" name="Initiator One"> <bpmn:manualTask id="initiator_one" name="Initiator One">
<bpmn:extensionElements> <bpmn:extensionElements>
<spiffworkflow:instructionsForEndUser>This is initiator user?</spiffworkflow:instructionsForEndUser> <spiffworkflow:instructionsForEndUser>This is for the initiator user</spiffworkflow:instructionsForEndUser>
</bpmn:extensionElements> </bpmn:extensionElements>
<bpmn:incoming>Flow_1tbyols</bpmn:incoming> <bpmn:incoming>Flow_1tbyols</bpmn:incoming>
<bpmn:outgoing>Flow_16ppta1</bpmn:outgoing> <bpmn:outgoing>Flow_16ppta1</bpmn:outgoing>
</bpmn:manualTask> </bpmn:manualTask>
<bpmn:manualTask id="finance_approval" name="Finance Approval"> <bpmn:manualTask id="finance_approval" name="Finance Approval">
<bpmn:extensionElements> <bpmn:extensionElements>
<spiffworkflow:instructionsForEndUser>This is finance user?</spiffworkflow:instructionsForEndUser> <spiffworkflow:instructionsForEndUser>This is for a Finance Team user</spiffworkflow:instructionsForEndUser>
</bpmn:extensionElements> </bpmn:extensionElements>
<bpmn:incoming>Flow_16ppta1</bpmn:incoming> <bpmn:incoming>Flow_16ppta1</bpmn:incoming>
<bpmn:outgoing>Flow_1cfcauf</bpmn:outgoing> <bpmn:outgoing>Flow_1cfcauf</bpmn:outgoing>
@ -41,7 +41,8 @@
<bpmn:sequenceFlow id="Flow_0x92f7d" sourceRef="initiator_two" targetRef="Event_06f4e68" /> <bpmn:sequenceFlow id="Flow_0x92f7d" sourceRef="initiator_two" targetRef="Event_06f4e68" />
<bpmn:manualTask id="initiator_two" name="Initiator Two"> <bpmn:manualTask id="initiator_two" name="Initiator Two">
<bpmn:extensionElements> <bpmn:extensionElements>
<spiffworkflow:instructionsForEndUser>This is initiator again?</spiffworkflow:instructionsForEndUser> <spiffworkflow:instructionsForEndUser>This is initiator again</spiffworkflow:instructionsForEndUser>
<spiffworkflow:postScript />
</bpmn:extensionElements> </bpmn:extensionElements>
<bpmn:incoming>Flow_1cfcauf</bpmn:incoming> <bpmn:incoming>Flow_1cfcauf</bpmn:incoming>
<bpmn:outgoing>Flow_0x92f7d</bpmn:outgoing> <bpmn:outgoing>Flow_0x92f7d</bpmn:outgoing>
@ -63,7 +64,7 @@
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1lm1ald_di" bpmnElement="initator_one"> <bpmndi:BPMNShape id="Activity_1lm1ald_di" bpmnElement="initiator_one">
<dc:Bounds x="270" y="137" width="100" height="80" /> <dc:Bounds x="270" y="137" width="100" height="80" />
<bpmndi:BPMNLabel /> <bpmndi:BPMNLabel />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:collaboration id="Collaboration_0iyw0q7"> <bpmn:collaboration id="Collaboration_0iyw0q7">
<bpmn:participant id="Participant_17eqap4" processRef="Proccess_yhito9d" /> <bpmn:participant id="Participant_17eqap4" processRef="Process_yhito9d" />
</bpmn:collaboration> </bpmn:collaboration>
<bpmn:process id="Proccess_yhito9d" isExecutable="true"> <bpmn:process id="Process_yhito9d" isExecutable="true">
<bpmn:laneSet id="LaneSet_17rankp"> <bpmn:laneSet id="LaneSet_17rankp">
<bpmn:lane id="process_initiator" name="Process Initiator"> <bpmn:lane id="process_initiator" name="Process Initiator">
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef> <bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_WithForm" name="Process With Form" isExecutable="true"> <bpmn:process id="Process_WithForm" name="Process With Form" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0smvjir</bpmn:outgoing> <bpmn:outgoing>Flow_0smvjir</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -14,6 +14,7 @@
<spiffworkflow:instructionsForEndUser>Hello {{ name }} <spiffworkflow:instructionsForEndUser>Hello {{ name }}
Department: {{ department }} Department: {{ department }}
</spiffworkflow:instructionsForEndUser> </spiffworkflow:instructionsForEndUser>
<spiffworkflow:postScript>user_completing_task = get_last_user_completing_task("Process_WithForm", "Activity_SimpleForm")</spiffworkflow:postScript>
</bpmn:extensionElements> </bpmn:extensionElements>
<bpmn:incoming>Flow_1ly1khd</bpmn:incoming> <bpmn:incoming>Flow_1ly1khd</bpmn:incoming>
<bpmn:outgoing>Flow_1boyhcj</bpmn:outgoing> <bpmn:outgoing>Flow_1boyhcj</bpmn:outgoing>
@ -25,13 +26,14 @@ Department: {{ department }}
<spiffworkflow:property name="formJsonSchemaFilename" value="simple_form.json" /> <spiffworkflow:property name="formJsonSchemaFilename" value="simple_form.json" />
<spiffworkflow:property name="formUiSchemaFilename" value="simple_form_ui.json" /> <spiffworkflow:property name="formUiSchemaFilename" value="simple_form_ui.json" />
</spiffworkflow:properties> </spiffworkflow:properties>
<spiffworkflow:postScript>process_initiator_user = get_process_initiator_user()</spiffworkflow:postScript>
</bpmn:extensionElements> </bpmn:extensionElements>
<bpmn:incoming>Flow_0smvjir</bpmn:incoming> <bpmn:incoming>Flow_0smvjir</bpmn:incoming>
<bpmn:outgoing>Flow_1ly1khd</bpmn:outgoing> <bpmn:outgoing>Flow_1ly1khd</bpmn:outgoing>
</bpmn:userTask> </bpmn:userTask>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_WithForm"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_WithForm">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_With_Bad_Form" name="Process With Form" isExecutable="true"> <bpmn:process id="Process_With_Bad_Form" name="Process With Form" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0smvjir</bpmn:outgoing> <bpmn:outgoing>Flow_0smvjir</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -31,7 +31,7 @@ Department: {{ department }}
</bpmn:userTask> </bpmn:userTask>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_WithForm"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_WithForm">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Proccess_SimpleScript" name="Simple Script" isExecutable="true"> <bpmn:process id="Process_SimpleScript" name="Simple Script" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0r3ua0i</bpmn:outgoing> <bpmn:outgoing>Flow_0r3ua0i</bpmn:outgoing>
</bpmn:startEvent> </bpmn:startEvent>
@ -48,7 +48,7 @@ b = 2</bpmn:script>
<bpmn:sequenceFlow id="Flow_1vqk60p" sourceRef="Activity_DisplayData" targetRef="Event_19fiqu4" /> <bpmn:sequenceFlow id="Flow_1vqk60p" sourceRef="Activity_DisplayData" targetRef="Event_19fiqu4" />
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Proccess_SimpleScript"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_SimpleScript">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" /> <dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>

View File

@ -583,7 +583,7 @@ class TestProcessApi(BaseTest):
# We should get 5 back, as one of the items in the cache is a decision. # We should get 5 back, as one of the items in the cache is a decision.
assert len(response.json) == 5 assert len(response.json) == 5
simple_form = next( 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["display_name"] == "Process With Form"
assert simple_form["process_model_id"] == "test_group_one/simple_form" assert simple_form["process_model_id"] == "test_group_one/simple_form"

View File

@ -0,0 +1,69 @@
"""Test_get_localtime."""
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,
)
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"]
)

View File

@ -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"]
)