diff --git a/bin/run_pyl b/bin/run_pyl
index af82c6a6..d3abd7fc 100755
--- a/bin/run_pyl
+++ b/bin/run_pyl
@@ -20,6 +20,12 @@ function get_python_dirs() {
(git ls-tree -r HEAD --name-only | grep -E '\.py$' | awk -F '/' '{print $1}' | sort | uniq | grep -v '\.' | grep -Ev '^(bin|migrations)$') || echo ''
}
+function run_fix_docstrings() {
+ if command -v fix_python_docstrings >/dev/null ; then
+ fix_python_docstrings $(get_top_level_directories_containing_python_files)
+ fi
+}
+
function run_autoflake() {
if ! command -v autoflake8 >/dev/null ; then
pip install autoflake8
@@ -51,6 +57,7 @@ done
for python_project in "${python_projects[@]}" ; do
pushd "$python_project"
+ run_fix_docstrings || run_fix_docstrings
run_autoflake || run_autoflake
popd
done
diff --git a/spiffworkflow-backend/migrations/versions/568f5fe2c9f8_.py b/spiffworkflow-backend/migrations/versions/ff1c1628337c_.py
similarity index 95%
rename from spiffworkflow-backend/migrations/versions/568f5fe2c9f8_.py
rename to spiffworkflow-backend/migrations/versions/ff1c1628337c_.py
index bfd7fc2b..d8da6d3c 100644
--- a/spiffworkflow-backend/migrations/versions/568f5fe2c9f8_.py
+++ b/spiffworkflow-backend/migrations/versions/ff1c1628337c_.py
@@ -1,8 +1,8 @@
"""empty message
-Revision ID: 568f5fe2c9f8
+Revision ID: ff1c1628337c
Revises:
-Create Date: 2022-11-24 12:11:46.669020
+Create Date: 2022-11-28 15:08:52.014254
"""
from alembic import op
@@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
-revision = '568f5fe2c9f8'
+revision = 'ff1c1628337c'
down_revision = None
branch_labels = None
depends_on = None
@@ -166,17 +166,6 @@ def upgrade():
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('key')
)
- op.create_table('spiff_step_details',
- sa.Column('id', sa.Integer(), nullable=False),
- sa.Column('process_instance_id', sa.Integer(), nullable=False),
- sa.Column('spiff_step', sa.Integer(), nullable=False),
- sa.Column('task_json', sa.JSON(), nullable=False),
- sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False),
- sa.Column('completed_by_user_id', sa.Integer(), nullable=True),
- sa.Column('lane_assignment_id', sa.Integer(), nullable=True),
- sa.ForeignKeyConstraint(['lane_assignment_id'], ['group.id'], ),
- sa.PrimaryKeyConstraint('id')
- )
op.create_table('user_group_assignment',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
@@ -249,6 +238,29 @@ def upgrade():
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('principal_id', 'permission_target_id', 'permission', name='permission_assignment_uniq')
)
+ op.create_table('process_instance_metadata',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('process_instance_id', sa.Integer(), nullable=False),
+ sa.Column('key', sa.String(length=255), nullable=False),
+ sa.Column('value', sa.String(length=255), nullable=False),
+ sa.Column('updated_at_in_seconds', sa.Integer(), nullable=False),
+ sa.Column('created_at_in_seconds', sa.Integer(), nullable=False),
+ sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
+ sa.PrimaryKeyConstraint('id'),
+ sa.UniqueConstraint('process_instance_id', 'key', name='process_instance_metadata_unique')
+ )
+ op.create_table('spiff_step_details',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('process_instance_id', sa.Integer(), nullable=False),
+ sa.Column('spiff_step', sa.Integer(), nullable=False),
+ sa.Column('task_json', sa.JSON(), nullable=False),
+ sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False),
+ sa.Column('completed_by_user_id', sa.Integer(), nullable=True),
+ sa.Column('lane_assignment_id', sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(['lane_assignment_id'], ['group.id'], ),
+ sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
op.create_table('active_task_user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('active_task_id', sa.Integer(), nullable=False),
@@ -282,6 +294,8 @@ def downgrade():
op.drop_index(op.f('ix_active_task_user_user_id'), table_name='active_task_user')
op.drop_index(op.f('ix_active_task_user_active_task_id'), table_name='active_task_user')
op.drop_table('active_task_user')
+ op.drop_table('spiff_step_details')
+ op.drop_table('process_instance_metadata')
op.drop_table('permission_assignment')
op.drop_table('message_instance')
op.drop_index(op.f('ix_message_correlation_value'), table_name='message_correlation')
@@ -291,7 +305,6 @@ def downgrade():
op.drop_table('message_correlation')
op.drop_table('active_task')
op.drop_table('user_group_assignment')
- op.drop_table('spiff_step_details')
op.drop_table('secret')
op.drop_table('refresh_token')
op.drop_index(op.f('ix_process_instance_report_identifier'), table_name='process_instance_report')
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml
index 91207f86..e17e3f11 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml
@@ -136,47 +136,38 @@ permissions:
allowed_permissions: [create, read, update, delete]
uri: /v1.0/process-groups/manage-procurement:procurement:*
- demo-models-instantiate-vendor-block:
- groups: ["demo"]
+ manage-revenue-streams-instantiate:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:vendor-md-maintenance:vendor-md-block/process-instances
- demo-models-instantiate-vendor-change:
- groups: ["demo"]
+ uri: /v1.0/process-models/manage-revenue-streams:product-revenue-streams:customer-contracts-trade-terms/*
+ manage-revenue-streams-instances:
+ groups: ["core-contributor", "demo"]
users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:vendor-md-maintenance:vendor-md-change/process-instances
- demo-models-instantiate-vendor-creation:
- groups: ["demo"]
- users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:vendor-md-maintenance:vendor-md-creation/process-instances
- demo-models-instantiate-vendor-core-invoice_appoval:
- groups: ["demo"]
- users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:procurement:core-contributor-invoice-management:cc-invoice-approval/process-instances
- demo-models-customer-contracts:
- groups: ["demo"]
- users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-revenue-streams:product-revenue-streams:customer-contracts-trade-terms/process-instances
+ allowed_permissions: [create, read]
+ uri: /v1.0/process-instances/manage-revenue-streams:product-revenue-streams:customer-contracts-trade-terms/*
- core-admin-models-instantiate:
- groups: ["core-contributor"]
+ manage-procurement-invoice-instantiate:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:procurement:core-contributor-invoice-management:cc-invoice-approval/process-instances
- core-admin-instances:
- groups: ["core-contributor"]
+ uri: /v1.0/process-models/manage-procurement:procurement:core-contributor-invoice-management:*
+ manage-procurement-invoice-instances:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create, read]
uri: /v1.0/process-instances/manage-procurement:procurement:core-contributor-invoice-management:*
- core-admin-instances-slash:
- groups: ["core-contributor"]
+
+ manage-procurement-instantiate:
+ groups: ["core-contributor", "demo"]
+ users: []
+ allowed_permissions: [create]
+ uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:*
+ manage-procurement-instances:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create, read]
- uri: /v1.0/process-instances/manage-procurement:procurement:core-contributor-invoice-management/*
+ uri: /v1.0/process-instances/manage-procurement:vendor-lifecycle-management:*
core1-admin-models-instantiate:
groups: ["core-contributor"]
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml
index c1a0579c..e60946b3 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml
@@ -136,44 +136,35 @@ permissions:
allowed_permissions: [create, read, update, delete]
uri: /v1.0/process-groups/manage-procurement:procurement:*
- demo-models-instantiate-vendor-block:
- groups: ["demo"]
+ manage-revenue-streams-instantiate:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:vendor-md-maintenance:vendor-md-block/process-instances
- demo-models-instantiate-vendor-change:
- groups: ["demo"]
+ uri: /v1.0/process-models/manage-revenue-streams:product-revenue-streams:customer-contracts-trade-terms/*
+ manage-revenue-streams-instances:
+ groups: ["core-contributor", "demo"]
users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:vendor-md-maintenance:vendor-md-change/process-instances
- demo-models-instantiate-vendor-creation:
- groups: ["demo"]
- users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:vendor-md-maintenance:vendor-md-creation/process-instances
- demo-models-instantiate-vendor-core-invoice_appoval:
- groups: ["demo"]
- users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:procurement:core-contributor-invoice-management:cc-invoice-approval/process-instances
- demo-models-customer-contracts:
- groups: ["demo"]
- users: []
- allowed_permissions: [create]
- uri: /v1.0/process-models/manage-revenue-streams:product-revenue-streams:customer-contracts-trade-terms/process-instances
+ allowed_permissions: [create, read]
+ uri: /v1.0/process-instances/manage-revenue-streams:product-revenue-streams:customer-contracts-trade-terms/*
- core-admin-models-instantiate:
- groups: ["core-contributor"]
+ manage-procurement-invoice-instantiate:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create]
- uri: /v1.0/process-models/manage-procurement:procurement:core-contributor-invoice-management:cc-invoice-approval/process-instances
- core-admin-instances:
- groups: ["core-contributor"]
+ uri: /v1.0/process-models/manage-procurement:procurement:core-contributor-invoice-management:*
+ manage-procurement-invoice-instances:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create, read]
uri: /v1.0/process-instances/manage-procurement:procurement:core-contributor-invoice-management:*
- core-admin-instances-slash:
- groups: ["core-contributor"]
+
+ manage-procurement-instantiate:
+ groups: ["core-contributor", "demo"]
+ users: []
+ allowed_permissions: [create]
+ uri: /v1.0/process-models/manage-procurement:vendor-lifecycle-management:*
+ manage-procurement-instances:
+ groups: ["core-contributor", "demo"]
users: []
allowed_permissions: [create, read]
- uri: /v1.0/process-instances/manage-procurement:procurement:core-contributor-invoice-management/*
+ uri: /v1.0/process-instances/manage-procurement:vendor-lifecycle-management:*
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py b/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py
index 97c99000..71adb57c 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py
@@ -51,5 +51,8 @@ from spiffworkflow_backend.models.spiff_step_details import (
) # noqa: F401
from spiffworkflow_backend.models.user import UserModel # noqa: F401
from spiffworkflow_backend.models.group import GroupModel # noqa: F401
+from spiffworkflow_backend.models.process_instance_metadata import (
+ ProcessInstanceMetadataModel,
+) # noqa: F401
add_listeners()
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py
index f06eb953..e6a5f684 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py
@@ -22,6 +22,10 @@ from spiffworkflow_backend.models.task import TaskSchema
from spiffworkflow_backend.models.user import UserModel
+class ProcessInstanceNotFoundError(Exception):
+ """ProcessInstanceNotFoundError."""
+
+
class NavigationItemSchema(Schema):
"""NavigationItemSchema."""
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py
new file mode 100644
index 00000000..5a4d4ca5
--- /dev/null
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py
@@ -0,0 +1,30 @@
+"""Spiff_step_details."""
+from dataclasses import dataclass
+
+from flask_bpmn.models.db import db
+from flask_bpmn.models.db import SpiffworkflowBaseDBModel
+from sqlalchemy import ForeignKey
+
+from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
+
+
+@dataclass
+class ProcessInstanceMetadataModel(SpiffworkflowBaseDBModel):
+ """ProcessInstanceMetadataModel."""
+
+ __tablename__ = "process_instance_metadata"
+ __table_args__ = (
+ db.UniqueConstraint(
+ "process_instance_id", "key", name="process_instance_metadata_unique"
+ ),
+ )
+
+ id: int = db.Column(db.Integer, primary_key=True)
+ process_instance_id: int = db.Column(
+ ForeignKey(ProcessInstanceModel.id), nullable=False # type: ignore
+ )
+ key: str = db.Column(db.String(255), nullable=False)
+ value: str = db.Column(db.String(255), nullable=False)
+
+ updated_at_in_seconds: int = db.Column(db.Integer, nullable=False)
+ created_at_in_seconds: int = db.Column(db.Integer, nullable=False)
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py
index e00e7cac..91d70116 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py
@@ -8,6 +8,7 @@ from sqlalchemy import ForeignKey
from sqlalchemy.orm import deferred
from spiffworkflow_backend.models.group import GroupModel
+from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
@dataclass
@@ -16,7 +17,9 @@ class SpiffStepDetailsModel(SpiffworkflowBaseDBModel):
__tablename__ = "spiff_step_details"
id: int = db.Column(db.Integer, primary_key=True)
- process_instance_id: int = db.Column(db.Integer, nullable=False)
+ process_instance_id: int = db.Column(
+ ForeignKey(ProcessInstanceModel.id), nullable=False # type: ignore
+ )
spiff_step: int = db.Column(db.Integer, nullable=False)
task_json: str = deferred(db.Column(db.JSON, nullable=False)) # type: ignore
timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False)
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/save_process_instance_metadata.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/save_process_instance_metadata.py
new file mode 100644
index 00000000..ae5fe00e
--- /dev/null
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/save_process_instance_metadata.py
@@ -0,0 +1,42 @@
+"""Get_env."""
+from typing import Any
+
+from flask_bpmn.models.db import db
+
+from spiffworkflow_backend.models.process_instance_metadata import (
+ ProcessInstanceMetadataModel,
+)
+from spiffworkflow_backend.models.script_attributes_context import (
+ ScriptAttributesContext,
+)
+from spiffworkflow_backend.scripts.script import Script
+
+
+class SaveProcessInstanceMetadata(Script):
+ """SaveProcessInstanceMetadata."""
+
+ def get_description(self) -> str:
+ """Get_description."""
+ return """Save a given dict as process instance metadata (useful for creating reports)."""
+
+ def run(
+ self,
+ script_attributes_context: ScriptAttributesContext,
+ *args: Any,
+ **kwargs: Any,
+ ) -> Any:
+ """Run."""
+ metadata_dict = args[0]
+ for key, value in metadata_dict.items():
+ pim = ProcessInstanceMetadataModel.query.filter_by(
+ process_instance_id=script_attributes_context.process_instance_id,
+ key=key,
+ ).first()
+ if pim is None:
+ pim = ProcessInstanceMetadataModel(
+ process_instance_id=script_attributes_context.process_instance_id,
+ key=key,
+ )
+ pim.value = value
+ db.session.add(pim)
+ db.session.commit()
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 111d01ec..9b6ed01b 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py
@@ -590,16 +590,12 @@ class ProcessInstanceProcessor:
if self.bpmn_process_instance.is_completed():
self.process_instance_model.end_in_seconds = round(time.time())
- active_tasks = ActiveTaskModel.query.filter_by(
- process_instance_id=self.process_instance_model.id
- ).all()
- if len(active_tasks) > 0:
- for at in active_tasks:
- db.session.delete(at)
-
db.session.add(self.process_instance_model)
db.session.commit()
+ active_tasks = ActiveTaskModel.query.filter_by(
+ process_instance_id=self.process_instance_model.id
+ ).all()
ready_or_waiting_tasks = self.get_all_ready_or_waiting_tasks()
for ready_or_waiting_task in ready_or_waiting_tasks:
# filter out non-usertasks
@@ -626,27 +622,41 @@ class ProcessInstanceProcessor:
if process_model_info is not None:
process_model_display_name = process_model_info.display_name
- active_task = ActiveTaskModel(
- process_instance_id=self.process_instance_model.id,
- process_model_display_name=process_model_display_name,
- form_file_name=form_file_name,
- ui_form_file_name=ui_form_file_name,
- task_id=str(ready_or_waiting_task.id),
- task_name=ready_or_waiting_task.task_spec.name,
- task_title=ready_or_waiting_task.task_spec.description,
- task_type=ready_or_waiting_task.task_spec.__class__.__name__,
- task_status=ready_or_waiting_task.get_state_name(),
- lane_assignment_id=potential_owner_hash["lane_assignment_id"],
- )
- db.session.add(active_task)
- db.session.commit()
+ active_task = None
+ for at in active_tasks:
+ if at.task_id == str(ready_or_waiting_task.id):
+ active_task = at
+ active_tasks.remove(at)
- for potential_owner_id in potential_owner_hash["potential_owner_ids"]:
- active_task_user = ActiveTaskUserModel(
- user_id=potential_owner_id, active_task_id=active_task.id
+ if active_task is None:
+ active_task = ActiveTaskModel(
+ process_instance_id=self.process_instance_model.id,
+ process_model_display_name=process_model_display_name,
+ form_file_name=form_file_name,
+ ui_form_file_name=ui_form_file_name,
+ task_id=str(ready_or_waiting_task.id),
+ task_name=ready_or_waiting_task.task_spec.name,
+ task_title=ready_or_waiting_task.task_spec.description,
+ task_type=ready_or_waiting_task.task_spec.__class__.__name__,
+ task_status=ready_or_waiting_task.get_state_name(),
+ lane_assignment_id=potential_owner_hash["lane_assignment_id"],
)
- db.session.add(active_task_user)
- db.session.commit()
+ db.session.add(active_task)
+ db.session.commit()
+
+ for potential_owner_id in potential_owner_hash[
+ "potential_owner_ids"
+ ]:
+ active_task_user = ActiveTaskUserModel(
+ user_id=potential_owner_id, active_task_id=active_task.id
+ )
+ db.session.add(active_task_user)
+ db.session.commit()
+
+ if len(active_tasks) > 0:
+ for at in active_tasks:
+ db.session.delete(at)
+ db.session.commit()
@staticmethod
def get_parser() -> MyCustomParser:
diff --git a/spiffworkflow-backend/tests/data/save_process_instance_metadata/save_process_instance_metadata.bpmn b/spiffworkflow-backend/tests/data/save_process_instance_metadata/save_process_instance_metadata.bpmn
new file mode 100644
index 00000000..2c72b08d
--- /dev/null
+++ b/spiffworkflow-backend/tests/data/save_process_instance_metadata/save_process_instance_metadata.bpmn
@@ -0,0 +1,52 @@
+
+