Merge commit '95d9dbf036f09b62054c04a64d5c7a9e3002173c'
This commit is contained in:
commit
dbb011c911
|
@ -1,8 +1,8 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 3bd6b0b1b8ae
|
||||
Revision ID: bdd1d64689db
|
||||
Revises:
|
||||
Create Date: 2022-10-25 12:31:50.177599
|
||||
Create Date: 2022-11-02 11:31:50.606843
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
|
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '3bd6b0b1b8ae'
|
||||
revision = 'bdd1d64689db'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
@ -18,13 +18,6 @@ depends_on = None
|
|||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('admin_session',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('token', sa.String(length=50), nullable=True),
|
||||
sa.Column('admin_impersonate_uid', sa.String(length=50), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('token')
|
||||
)
|
||||
op.create_table('bpmn_process_id_lookup',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('bpmn_process_identifier', sa.String(length=255), nullable=True),
|
||||
|
@ -183,25 +176,6 @@ def upgrade():
|
|||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('task_id', 'process_instance_id', name='active_task_unique')
|
||||
)
|
||||
op.create_table('file',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=50), nullable=False),
|
||||
sa.Column('type', sa.String(length=50), nullable=False),
|
||||
sa.Column('content_type', sa.String(length=50), nullable=False),
|
||||
sa.Column('process_instance_id', sa.Integer(), nullable=True),
|
||||
sa.Column('task_spec', sa.String(length=50), nullable=True),
|
||||
sa.Column('irb_doc_code', sa.String(length=50), nullable=False),
|
||||
sa.Column('md5_hash', sa.String(length=50), nullable=False),
|
||||
sa.Column('data', sa.LargeBinary(), nullable=True),
|
||||
sa.Column('size', sa.Integer(), nullable=True),
|
||||
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at_in_seconds', sa.Integer(), nullable=True),
|
||||
sa.Column('user_uid', sa.String(length=50), nullable=True),
|
||||
sa.Column('archived', sa.Boolean(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_uid'], ['user.uid'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('message_correlation',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('process_instance_id', sa.Integer(), nullable=False),
|
||||
|
@ -259,28 +233,6 @@ def upgrade():
|
|||
sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('task_event',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('process_instance_id', sa.Integer(), nullable=False),
|
||||
sa.Column('spec_version', sa.String(length=50), nullable=True),
|
||||
sa.Column('action', sa.String(length=50), nullable=True),
|
||||
sa.Column('task_id', sa.String(length=50), nullable=True),
|
||||
sa.Column('task_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('task_title', sa.String(length=50), nullable=True),
|
||||
sa.Column('task_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('task_state', sa.String(length=50), nullable=True),
|
||||
sa.Column('task_lane', sa.String(length=50), nullable=True),
|
||||
sa.Column('form_data', sa.JSON(), nullable=True),
|
||||
sa.Column('mi_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('mi_count', sa.Integer(), nullable=True),
|
||||
sa.Column('mi_index', sa.Integer(), nullable=True),
|
||||
sa.Column('process_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('date', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.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),
|
||||
|
@ -292,19 +244,6 @@ def upgrade():
|
|||
)
|
||||
op.create_index(op.f('ix_active_task_user_active_task_id'), 'active_task_user', ['active_task_id'], unique=False)
|
||||
op.create_index(op.f('ix_active_task_user_user_id'), 'active_task_user', ['user_id'], unique=False)
|
||||
op.create_table('data_store',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=True),
|
||||
sa.Column('key', sa.String(length=50), nullable=False),
|
||||
sa.Column('process_instance_id', sa.Integer(), nullable=True),
|
||||
sa.Column('task_spec', sa.String(length=50), nullable=True),
|
||||
sa.Column('spec_id', sa.String(length=50), nullable=True),
|
||||
sa.Column('user_id', sa.String(length=50), nullable=True),
|
||||
sa.Column('file_id', sa.Integer(), nullable=True),
|
||||
sa.Column('value', sa.String(length=50), nullable=True),
|
||||
sa.ForeignKeyConstraint(['file_id'], ['file.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('message_correlation_message_instance',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('message_instance_id', sa.Integer(), nullable=False),
|
||||
|
@ -324,11 +263,9 @@ def downgrade():
|
|||
op.drop_index(op.f('ix_message_correlation_message_instance_message_instance_id'), table_name='message_correlation_message_instance')
|
||||
op.drop_index(op.f('ix_message_correlation_message_instance_message_correlation_id'), table_name='message_correlation_message_instance')
|
||||
op.drop_table('message_correlation_message_instance')
|
||||
op.drop_table('data_store')
|
||||
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('task_event')
|
||||
op.drop_table('spiff_logging')
|
||||
op.drop_table('permission_assignment')
|
||||
op.drop_table('message_instance')
|
||||
|
@ -337,7 +274,6 @@ def downgrade():
|
|||
op.drop_index(op.f('ix_message_correlation_name'), table_name='message_correlation')
|
||||
op.drop_index(op.f('ix_message_correlation_message_correlation_property_id'), table_name='message_correlation')
|
||||
op.drop_table('message_correlation')
|
||||
op.drop_table('file')
|
||||
op.drop_table('active_task')
|
||||
op.drop_table('user_group_assignment')
|
||||
op.drop_table('secret')
|
||||
|
@ -363,5 +299,4 @@ def downgrade():
|
|||
op.drop_table('group')
|
||||
op.drop_index(op.f('ix_bpmn_process_id_lookup_bpmn_process_identifier'), table_name='bpmn_process_id_lookup')
|
||||
op.drop_table('bpmn_process_id_lookup')
|
||||
op.drop_table('admin_session')
|
||||
# ### end Alembic commands ###
|
|
@ -1873,7 +1873,7 @@ pytz = "*"
|
|||
type = "git"
|
||||
url = "https://github.com/sartography/SpiffWorkflow"
|
||||
reference = "main"
|
||||
resolved_reference = "5cdb881edc4621502bfd61ce67565cf1148199f0"
|
||||
resolved_reference = "a6392d19061f623394f5705fb78af23673d3940d"
|
||||
|
||||
[[package]]
|
||||
name = "SQLAlchemy"
|
||||
|
@ -2621,6 +2621,7 @@ greenlet = [
|
|||
{file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"},
|
||||
{file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"},
|
||||
{file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"},
|
||||
{file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"},
|
||||
]
|
||||
gunicorn = [
|
||||
{file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"},
|
||||
|
@ -2945,7 +2946,10 @@ orjson = [
|
|||
{file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"},
|
||||
{file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"},
|
||||
{file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"},
|
||||
{file = "orjson-3.8.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:200eae21c33f1f8b02a11f5d88d76950cd6fd986d88f1afe497a8ae2627c49aa"},
|
||||
{file = "orjson-3.8.0-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9529990f3eab54b976d327360aa1ff244a4b12cb5e4c5b3712fcdd96e8fe56d4"},
|
||||
{file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"},
|
||||
{file = "orjson-3.8.0-cp311-none-win_amd64.whl", hash = "sha256:b21c7af0ff6228ca7105f54f0800636eb49201133e15ddb80ac20c1ce973ef07"},
|
||||
{file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"},
|
||||
{file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"},
|
||||
{file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"},
|
||||
|
@ -3058,18 +3062,7 @@ py = [
|
|||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
pyasn1 = [
|
||||
{file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
|
||||
{file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"},
|
||||
{file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"},
|
||||
{file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"},
|
||||
{file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"},
|
||||
{file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"},
|
||||
{file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"},
|
||||
{file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"},
|
||||
{file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"},
|
||||
{file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"},
|
||||
{file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"},
|
||||
{file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"},
|
||||
{file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"},
|
||||
]
|
||||
pycodestyle = [
|
||||
|
|
|
@ -21,8 +21,6 @@ from spiffworkflow_backend.models.active_task import ActiveTaskModel # noqa: F4
|
|||
from spiffworkflow_backend.models.bpmn_process_id_lookup import (
|
||||
BpmnProcessIdLookup,
|
||||
) # noqa: F401
|
||||
from spiffworkflow_backend.models.data_store import DataStoreModel # noqa: F401
|
||||
from spiffworkflow_backend.models.file import FileModel # noqa: F401
|
||||
from spiffworkflow_backend.models.message_correlation_property import (
|
||||
MessageCorrelationPropertyModel,
|
||||
) # noqa: F401
|
||||
|
@ -48,7 +46,6 @@ from spiffworkflow_backend.models.process_instance_report import (
|
|||
from spiffworkflow_backend.models.refresh_token import RefreshTokenModel # noqa: F401
|
||||
from spiffworkflow_backend.models.secret_model import SecretModel # noqa: F401
|
||||
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel # noqa: F401
|
||||
from spiffworkflow_backend.models.task_event import TaskEventModel # noqa: F401
|
||||
from spiffworkflow_backend.models.user import UserModel # noqa: F401
|
||||
from spiffworkflow_backend.models.group import GroupModel # noqa: F401
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
"""Data_store."""
|
||||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.db import SpiffworkflowBaseDBModel
|
||||
from flask_marshmallow.sqla import SQLAlchemyAutoSchema # type: ignore
|
||||
|
||||
|
||||
class DataStoreModel(SpiffworkflowBaseDBModel):
|
||||
"""DataStoreModel."""
|
||||
|
||||
__tablename__ = "data_store"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
updated_at_in_seconds = db.Column(db.Integer)
|
||||
key = db.Column(db.String(50), nullable=False)
|
||||
process_instance_id = db.Column(db.Integer)
|
||||
task_spec = db.Column(db.String(50))
|
||||
spec_id = db.Column(db.String(50))
|
||||
user_id = db.Column(db.String(50), nullable=True)
|
||||
file_id = db.Column(db.Integer, db.ForeignKey("file.id"), nullable=True)
|
||||
value = db.Column(db.String(50))
|
||||
|
||||
|
||||
class DataStoreSchema(SQLAlchemyAutoSchema): # type: ignore
|
||||
"""DataStoreSchema."""
|
||||
|
||||
class Meta:
|
||||
"""Meta."""
|
||||
|
||||
model = DataStoreModel
|
||||
load_instance = True
|
||||
include_fk = True
|
||||
sqla_session = db.session
|
|
@ -4,40 +4,10 @@ from dataclasses import field
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.db import SpiffworkflowBaseDBModel
|
||||
from marshmallow import INCLUDE
|
||||
from marshmallow import Schema
|
||||
from sqlalchemy.orm import deferred
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from spiffworkflow_backend.helpers.spiff_enum import SpiffEnum
|
||||
from spiffworkflow_backend.models.data_store import DataStoreModel
|
||||
|
||||
|
||||
class FileModel(SpiffworkflowBaseDBModel):
|
||||
"""FileModel."""
|
||||
|
||||
__tablename__ = "file"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(50), nullable=False)
|
||||
type = db.Column(db.String(50), nullable=False)
|
||||
content_type = db.Column(db.String(50), nullable=False)
|
||||
process_instance_id = db.Column(
|
||||
db.Integer, db.ForeignKey("process_instance.id"), nullable=True
|
||||
)
|
||||
task_spec = db.Column(db.String(50), nullable=True)
|
||||
irb_doc_code = db.Column(
|
||||
db.String(50), nullable=False
|
||||
) # Code reference to the documents.xlsx reference file.
|
||||
data_stores = relationship(DataStoreModel, cascade="all,delete", backref="file")
|
||||
md5_hash = db.Column(db.String(50), unique=False, nullable=False)
|
||||
data = deferred(db.Column(db.LargeBinary)) # type: ignore
|
||||
size = db.Column(db.Integer, default=0)
|
||||
updated_at_in_seconds = db.Column(db.Integer)
|
||||
created_at_in_seconds = db.Column(db.Integer)
|
||||
user_uid = db.Column(db.String(50), db.ForeignKey("user.uid"), nullable=True)
|
||||
archived = db.Column(db.Boolean, default=False)
|
||||
|
||||
|
||||
class FileType(SpiffEnum):
|
||||
|
|
|
@ -78,7 +78,6 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
|
|||
process_initiator = relationship("UserModel")
|
||||
|
||||
active_tasks = relationship("ActiveTaskModel", cascade="delete") # type: ignore
|
||||
task_events = relationship("TaskEventModel", cascade="delete") # type: ignore
|
||||
spiff_logs = relationship("SpiffLoggingModel", cascade="delete") # type: ignore
|
||||
message_instances = relationship("MessageInstanceModel", cascade="delete") # type: ignore
|
||||
message_correlations = relationship("MessageCorrelationModel", cascade="delete") # type: ignore
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
"""Task_event."""
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.db import SpiffworkflowBaseDBModel
|
||||
from marshmallow import fields
|
||||
from marshmallow import INCLUDE
|
||||
from marshmallow import Schema
|
||||
from sqlalchemy import func
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from spiffworkflow_backend.models.process_instance import (
|
||||
ProcessInstanceModel,
|
||||
) # noqa: F401
|
||||
|
||||
|
||||
class TaskAction(enum.Enum):
|
||||
"""TaskAction."""
|
||||
|
||||
COMPLETE = "COMPLETE"
|
||||
TOKEN_RESET = "TOKEN_RESET" # noqa: S105
|
||||
HARD_RESET = "HARD_RESET"
|
||||
SOFT_RESET = "SOFT_RESET"
|
||||
ASSIGNMENT = "ASSIGNMENT" # Whenever the lane changes between tasks we assign the task to specific user.
|
||||
|
||||
|
||||
class TaskEventModel(SpiffworkflowBaseDBModel):
|
||||
"""TaskEventModel."""
|
||||
|
||||
__tablename__ = "task_event"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(
|
||||
db.Integer, db.ForeignKey("user.id"), nullable=False
|
||||
) # In some cases the unique user id may not exist in the db yet.
|
||||
process_instance_id = db.Column(
|
||||
db.Integer, db.ForeignKey("process_instance.id"), nullable=False
|
||||
)
|
||||
spec_version = db.Column(db.String(50))
|
||||
action = db.Column(db.String(50))
|
||||
task_id = db.Column(db.String(50))
|
||||
task_name = db.Column(db.String(50))
|
||||
task_title = db.Column(db.String(50))
|
||||
task_type = db.Column(db.String(50))
|
||||
task_state = db.Column(db.String(50))
|
||||
task_lane = db.Column(db.String(50))
|
||||
form_data = db.Column(
|
||||
db.JSON
|
||||
) # And form data submitted when the task was completed.
|
||||
mi_type = db.Column(db.String(50))
|
||||
mi_count = db.Column(db.Integer)
|
||||
mi_index = db.Column(db.Integer)
|
||||
process_name = db.Column(db.String(50))
|
||||
date = db.Column(db.DateTime(timezone=True), default=func.now())
|
||||
|
||||
|
||||
class TaskEvent:
|
||||
"""TaskEvent."""
|
||||
|
||||
def __init__(self, model: TaskEventModel, process_instance: ProcessInstanceModel):
|
||||
"""__init__."""
|
||||
self.id = model.id
|
||||
self.process_instance = process_instance
|
||||
self.user_id = model.user_id
|
||||
self.action = model.action
|
||||
self.task_id = model.task_id
|
||||
self.task_title = model.task_title
|
||||
self.task_name = model.task_name
|
||||
self.task_type = model.task_type
|
||||
self.task_state = model.task_state
|
||||
self.task_lane = model.task_lane
|
||||
self.date = model.date
|
||||
|
||||
|
||||
class TaskEventSchema(Schema):
|
||||
"""TaskEventSchema."""
|
||||
|
||||
process_instance = fields.Nested("ProcessInstanceMetadataSchema", dump_only=True)
|
||||
task_lane = fields.String(allow_none=True, required=False)
|
||||
|
||||
class Meta:
|
||||
"""Meta."""
|
||||
|
||||
model = TaskEvent
|
||||
additional = [
|
||||
"id",
|
||||
"user_id",
|
||||
"action",
|
||||
"task_id",
|
||||
"task_title",
|
||||
"task_name",
|
||||
"task_type",
|
||||
"task_state",
|
||||
"task_lane",
|
||||
"date",
|
||||
]
|
||||
unknown = INCLUDE
|
|
@ -112,12 +112,3 @@ class UserModelSchema(Schema):
|
|||
|
||||
id = marshmallow.fields.String(required=True)
|
||||
username = marshmallow.fields.String(required=True)
|
||||
|
||||
|
||||
class AdminSessionModel(SpiffworkflowBaseDBModel):
|
||||
"""AdminSessionModel."""
|
||||
|
||||
__tablename__ = "admin_session"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
token = db.Column(db.String(50), unique=True)
|
||||
admin_impersonate_uid = db.Column(db.String(50))
|
||||
|
|
|
@ -424,7 +424,6 @@ def process_instance_run(
|
|||
task=task,
|
||||
) from e
|
||||
processor.save()
|
||||
ProcessInstanceService.update_task_assignments(processor)
|
||||
|
||||
if not current_app.config["RUN_BACKGROUND_SCHEDULER"]:
|
||||
MessageService.process_message_instances()
|
||||
|
@ -1123,8 +1122,6 @@ def task_submit(
|
|||
# last_index = next_task.task_info()["mi_index"]
|
||||
# next_task = processor.next_task()
|
||||
|
||||
ProcessInstanceService.update_task_assignments(processor)
|
||||
|
||||
next_active_task_assigned_to_me = (
|
||||
ActiveTaskModel.query.filter_by(process_instance_id=process_instance_id)
|
||||
.order_by(asc(ActiveTaskModel.id)) # type: ignore
|
||||
|
|
|
@ -79,8 +79,6 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
|||
from spiffworkflow_backend.models.script_attributes_context import (
|
||||
ScriptAttributesContext,
|
||||
)
|
||||
from spiffworkflow_backend.models.task_event import TaskAction
|
||||
from spiffworkflow_backend.models.task_event import TaskEventModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.models.user import UserModelSchema
|
||||
from spiffworkflow_backend.scripts.script import Script
|
||||
|
@ -419,7 +417,7 @@ class ProcessInstanceProcessor:
|
|||
"""Add_user_info_to_process_instance."""
|
||||
current_user = None
|
||||
if UserService.has_user():
|
||||
current_user = UserService.current_user(allow_admin_impersonate=True)
|
||||
current_user = UserService.current_user()
|
||||
|
||||
# fall back to initiator if g.user is not set
|
||||
# this is for background processes when there will not be a user
|
||||
|
@ -433,59 +431,6 @@ class ProcessInstanceProcessor:
|
|||
for task in tasks:
|
||||
task.data["current_user"] = current_user_data
|
||||
|
||||
@staticmethod
|
||||
def reset(
|
||||
process_instance_model: ProcessInstanceModel, clear_data: bool = False
|
||||
) -> None:
|
||||
"""Resets the process_instance back to an unstarted state - where nothing has happened yet.
|
||||
|
||||
If clear_data is set to false, then the information
|
||||
previously used in forms will be re-populated when the form is re-
|
||||
displayed, and any files that were updated will remain in place, otherwise
|
||||
files will also be cleared out.
|
||||
"""
|
||||
# Try to execute a cancel notify
|
||||
try:
|
||||
bpmn_process_instance = (
|
||||
ProcessInstanceProcessor.__get_bpmn_process_instance(
|
||||
process_instance_model
|
||||
)
|
||||
)
|
||||
ProcessInstanceProcessor.__cancel_notify(bpmn_process_instance)
|
||||
except Exception as e:
|
||||
db.session.rollback() # in case the above left the database with a bad transaction
|
||||
current_app.logger.error(
|
||||
"Unable to send a cancel notify for process_instance %s during a reset."
|
||||
" Continuing with the reset anyway so we don't get in an unresolvable"
|
||||
" state. An %s error occured with the following information: %s"
|
||||
% (process_instance_model.id, e.__class__.__name__, str(e))
|
||||
)
|
||||
process_instance_model.bpmn_json = None
|
||||
process_instance_model.status = ProcessInstanceStatus.not_started.value
|
||||
|
||||
# clear out any task assignments
|
||||
db.session.query(TaskEventModel).filter(
|
||||
TaskEventModel.process_instance_id == process_instance_model.id
|
||||
).filter(TaskEventModel.action == TaskAction.ASSIGNMENT.value).delete()
|
||||
|
||||
if clear_data:
|
||||
# Clear out data in previous task events
|
||||
task_events = (
|
||||
db.session.query(TaskEventModel)
|
||||
.filter(TaskEventModel.process_instance_id == process_instance_model.id)
|
||||
.all()
|
||||
)
|
||||
for task_event in task_events:
|
||||
task_event.form_data = {}
|
||||
db.session.add(task_event)
|
||||
# Remove any uploaded files.
|
||||
|
||||
# TODO: grab UserFileService
|
||||
# files = FileModel.query.filter(FileModel.process_instance_id == process_instance_model.id).all()
|
||||
# for file in files:
|
||||
# UserFileService().delete_file(file.id)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def get_bpmn_process_instance_from_workflow_spec(
|
||||
spec: BpmnProcessSpec,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""Process_instance_service."""
|
||||
import time
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
|
@ -9,15 +8,12 @@ from flask import current_app
|
|||
from flask_bpmn.api.api_error import ApiError
|
||||
from flask_bpmn.models.db import db
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
|
||||
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceApi
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
|
||||
from spiffworkflow_backend.models.task import MultiInstanceType
|
||||
from spiffworkflow_backend.models.task import Task
|
||||
from spiffworkflow_backend.models.task_event import TaskAction
|
||||
from spiffworkflow_backend.models.task_event import TaskEventModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.services.git_service import GitService
|
||||
|
@ -108,70 +104,9 @@ class ProcessInstanceService:
|
|||
is_review=is_review_value,
|
||||
title=title_value,
|
||||
)
|
||||
next_task_trying_again = next_task
|
||||
if (
|
||||
not next_task
|
||||
): # The Next Task can be requested to be a certain task, useful for parallel tasks.
|
||||
# This may or may not work, sometimes there is no next task to complete.
|
||||
next_task_trying_again = processor.next_task()
|
||||
|
||||
if next_task_trying_again is not None:
|
||||
previous_form_data = ProcessInstanceService.get_previously_submitted_data(
|
||||
processor.process_instance_model.id, next_task_trying_again
|
||||
)
|
||||
# DeepMerge.merge(next_task_trying_again.data, previous_form_data)
|
||||
next_task_trying_again.data = DeepMerge.merge(
|
||||
previous_form_data, next_task_trying_again.data
|
||||
)
|
||||
|
||||
process_instance_api.next_task = (
|
||||
ProcessInstanceService.spiff_task_to_api_task(
|
||||
next_task_trying_again, add_docs_and_forms=True
|
||||
)
|
||||
)
|
||||
# TODO: Hack for now, until we decide how to implment forms
|
||||
process_instance_api.next_task.form = None
|
||||
|
||||
# Update the state of the task to locked if the current user does not own the task.
|
||||
# user_uids = WorkflowService.get_users_assigned_to_task(processor, next_task)
|
||||
# if not UserService.in_list(user_uids, allow_admin_impersonate=True):
|
||||
# workflow_api.next_task.state = WorkflowService.TASK_STATE_LOCKED
|
||||
|
||||
return process_instance_api
|
||||
|
||||
@staticmethod
|
||||
def get_previously_submitted_data(
|
||||
process_instance_id: int, spiff_task: SpiffTask
|
||||
) -> Dict[Any, Any]:
|
||||
"""If the user has completed this task previously, find the form data for the last submission."""
|
||||
query = (
|
||||
db.session.query(TaskEventModel)
|
||||
.filter_by(process_instance_id=process_instance_id)
|
||||
.filter_by(task_name=spiff_task.task_spec.name)
|
||||
.filter_by(action=TaskAction.COMPLETE.value)
|
||||
)
|
||||
|
||||
if (
|
||||
hasattr(spiff_task, "internal_data")
|
||||
and "runtimes" in spiff_task.internal_data
|
||||
):
|
||||
query = query.filter_by(mi_index=spiff_task.internal_data["runtimes"])
|
||||
|
||||
latest_event = query.order_by(TaskEventModel.date.desc()).first()
|
||||
if latest_event:
|
||||
if latest_event.form_data is not None:
|
||||
return latest_event.form_data # type: ignore
|
||||
else:
|
||||
missing_form_error = (
|
||||
f"We have lost data for workflow {process_instance_id}, "
|
||||
f"task {spiff_task.task_spec.name}, it is not in the task event model, "
|
||||
f"and it should be."
|
||||
)
|
||||
current_app.logger.exception("missing_form_data", missing_form_error)
|
||||
return {}
|
||||
else:
|
||||
return {}
|
||||
|
||||
def get_process_instance(self, process_instance_id: int) -> Any:
|
||||
"""Get_process_instance."""
|
||||
result = (
|
||||
|
@ -181,30 +116,6 @@ class ProcessInstanceService:
|
|||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def update_task_assignments(processor: ProcessInstanceProcessor) -> None:
|
||||
"""For every upcoming user task, log a task action that connects the assigned user(s) to that task.
|
||||
|
||||
All existing assignment actions for this workflow are removed from the database,
|
||||
so that only the current valid actions are available. update_task_assignments
|
||||
should be called whenever progress is made on a workflow.
|
||||
"""
|
||||
db.session.query(TaskEventModel).filter(
|
||||
TaskEventModel.process_instance_id == processor.process_instance_model.id
|
||||
).filter(TaskEventModel.action == TaskAction.ASSIGNMENT.value).delete()
|
||||
db.session.commit()
|
||||
|
||||
tasks = processor.get_current_user_tasks()
|
||||
for task in tasks:
|
||||
user_ids = ProcessInstanceService.get_users_assigned_to_task(
|
||||
processor, task
|
||||
)
|
||||
|
||||
for user_id in user_ids:
|
||||
ProcessInstanceService().log_task_action(
|
||||
user_id, processor, task, TaskAction.ASSIGNMENT.value
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_users_assigned_to_task(
|
||||
processor: ProcessInstanceProcessor, spiff_task: SpiffTask
|
||||
|
@ -279,52 +190,8 @@ class ProcessInstanceService:
|
|||
spiff_task.update_data(dot_dct)
|
||||
# ProcessInstanceService.post_process_form(spiff_task) # some properties may update the data store.
|
||||
processor.complete_task(spiff_task)
|
||||
# Log the action before doing the engine steps, as doing so could effect the state of the task
|
||||
# the workflow could wrap around in the ngine steps, and the task could jump from being completed to
|
||||
# another state. What we are logging here is the completion.
|
||||
ProcessInstanceService.log_task_action(
|
||||
user.id, processor, spiff_task, TaskAction.COMPLETE.value
|
||||
)
|
||||
processor.do_engine_steps(save=True)
|
||||
|
||||
@staticmethod
|
||||
def log_task_action(
|
||||
user_id: int,
|
||||
processor: ProcessInstanceProcessor,
|
||||
spiff_task: SpiffTask,
|
||||
action: str,
|
||||
) -> None:
|
||||
"""Log_task_action."""
|
||||
task = ProcessInstanceService.spiff_task_to_api_task(spiff_task)
|
||||
form_data = ProcessInstanceService.extract_form_data(
|
||||
spiff_task.data, spiff_task
|
||||
)
|
||||
multi_instance_type_value = ""
|
||||
if task.multi_instance_type:
|
||||
multi_instance_type_value = task.multi_instance_type.value
|
||||
|
||||
task_event = TaskEventModel(
|
||||
# study_id=processor.workflow_model.study_id,
|
||||
user_id=user_id,
|
||||
process_instance_id=processor.process_instance_model.id,
|
||||
# workflow_spec_id=processor.workflow_model.workflow_spec_id,
|
||||
action=action,
|
||||
task_id=str(task.id),
|
||||
task_name=task.name,
|
||||
task_title=task.title,
|
||||
task_type=str(task.type),
|
||||
task_state=task.state,
|
||||
task_lane=task.lane,
|
||||
form_data=form_data,
|
||||
mi_type=multi_instance_type_value, # Some tasks have a repeat behavior.
|
||||
mi_count=task.multi_instance_count, # This is the number of times the task could repeat.
|
||||
mi_index=task.multi_instance_index, # And the index of the currently repeating task.
|
||||
process_name=task.process_name,
|
||||
# date=datetime.utcnow(), <=== For future reference, NEVER do this. Let the database set the time.
|
||||
)
|
||||
db.session.add(task_event)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def extract_form_data(latest_data: dict, task: SpiffTask) -> dict:
|
||||
"""Extracts data from the latest_data that is directly related to the form that is being submitted."""
|
||||
|
|
|
@ -11,7 +11,6 @@ from spiffworkflow_backend.models.active_task import ActiveTaskModel
|
|||
from spiffworkflow_backend.models.active_task_user import ActiveTaskUserModel
|
||||
from spiffworkflow_backend.models.group import GroupModel
|
||||
from spiffworkflow_backend.models.principal import PrincipalModel
|
||||
from spiffworkflow_backend.models.user import AdminSessionModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.models.user_group_assignment import UserGroupAssignmentModel
|
||||
|
||||
|
@ -103,27 +102,6 @@ class UserService:
|
|||
"""Has_user."""
|
||||
return "token" in g and bool(g.token) and "user" in g and bool(g.user)
|
||||
|
||||
# Returns true if the current user is an admin.
|
||||
@staticmethod
|
||||
def user_is_admin() -> bool:
|
||||
"""User_is_admin."""
|
||||
return UserService.has_user() and g.user.is_admin()
|
||||
|
||||
# Returns true if the current admin user is impersonating another user.
|
||||
@staticmethod
|
||||
def admin_is_impersonating() -> bool:
|
||||
"""Admin_is_impersonating."""
|
||||
if UserService.user_is_admin():
|
||||
admin_session = UserService.get_admin_session()
|
||||
return admin_session is not None
|
||||
|
||||
else:
|
||||
raise ApiError(
|
||||
"unauthorized",
|
||||
"You do not have permissions to do this.",
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
# Returns true if the given user uid is different from the current user's uid.
|
||||
@staticmethod
|
||||
def is_different_user(uid: str) -> bool:
|
||||
|
@ -131,84 +109,16 @@ class UserService:
|
|||
return UserService.has_user() and uid is not None and uid is not g.user.uid
|
||||
|
||||
@staticmethod
|
||||
def current_user(allow_admin_impersonate: bool = False) -> Any:
|
||||
def current_user() -> Any:
|
||||
"""Current_user."""
|
||||
if not UserService.has_user():
|
||||
raise ApiError(
|
||||
"logged_out", "You are no longer logged in.", status_code=401
|
||||
)
|
||||
|
||||
# Admins can pretend to be different users and act on a user's behalf in
|
||||
# some circumstances.
|
||||
if (
|
||||
UserService.user_is_admin()
|
||||
and allow_admin_impersonate
|
||||
and UserService.admin_is_impersonating()
|
||||
):
|
||||
return UserService.get_admin_session_user()
|
||||
else:
|
||||
return g.user
|
||||
|
||||
# Admins can pretend to be different users and act on a user's behalf in some circumstances.
|
||||
# This method allows an admin user to start impersonating another user with the given uid.
|
||||
# Stops impersonating if the uid is None or invalid.
|
||||
@staticmethod
|
||||
def start_impersonating(uid: Optional[str] = None) -> None:
|
||||
"""Start_impersonating."""
|
||||
if not UserService.has_user():
|
||||
raise ApiError(
|
||||
"logged_out", "You are no longer logged in.", status_code=401
|
||||
)
|
||||
|
||||
if not UserService.user_is_admin():
|
||||
raise ApiError(
|
||||
"unauthorized",
|
||||
"You do not have permissions to do this.",
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
if uid is None:
|
||||
raise ApiError("invalid_uid", "Please provide a valid user uid.")
|
||||
|
||||
if UserService.is_different_user(uid):
|
||||
# Impersonate the user if the given uid is valid.
|
||||
impersonate_user = (
|
||||
db.session.query(UserModel).filter(UserModel.uid == uid).first()
|
||||
)
|
||||
|
||||
if impersonate_user is not None:
|
||||
g.impersonate_user = impersonate_user
|
||||
|
||||
# Store the uid and user session token.
|
||||
db.session.query(AdminSessionModel).filter(
|
||||
AdminSessionModel.token == g.token
|
||||
).delete()
|
||||
db.session.add(
|
||||
AdminSessionModel(token=g.token, admin_impersonate_uid=uid)
|
||||
)
|
||||
db.session.commit()
|
||||
else:
|
||||
raise ApiError("invalid_uid", "The uid provided is not valid.")
|
||||
return g.user
|
||||
|
||||
@staticmethod
|
||||
def stop_impersonating() -> None:
|
||||
"""Stop_impersonating."""
|
||||
if not UserService.has_user():
|
||||
raise ApiError(
|
||||
"logged_out", "You are no longer logged in.", status_code=401
|
||||
)
|
||||
|
||||
# Clear out the current impersonating user.
|
||||
if "impersonate_user" in g:
|
||||
del g.impersonate_user
|
||||
|
||||
admin_session = UserService.get_admin_session()
|
||||
if admin_session:
|
||||
db.session.delete(admin_session)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def in_list(uids: list[str], allow_admin_impersonate: bool = False) -> bool:
|
||||
def in_list(uids: list[str]) -> bool:
|
||||
"""Returns true if the current user's id is in the given list of ids.
|
||||
|
||||
False if there is no user, or the user is not in the list.
|
||||
|
@ -216,46 +126,11 @@ class UserService:
|
|||
if (
|
||||
UserService.has_user()
|
||||
): # If someone is logged in, lock tasks that don't belong to them.
|
||||
user = UserService.current_user(allow_admin_impersonate)
|
||||
user = UserService.current_user()
|
||||
if user.uid in uids:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_admin_session() -> Any:
|
||||
"""Get_admin_session."""
|
||||
if UserService.user_is_admin():
|
||||
return (
|
||||
db.session.query(AdminSessionModel)
|
||||
.filter(AdminSessionModel.token == g.token)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
raise ApiError(
|
||||
"unauthorized",
|
||||
"You do not have permissions to do this.",
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_admin_session_user() -> Any:
|
||||
"""Get_admin_session_user."""
|
||||
if UserService.user_is_admin():
|
||||
admin_session = UserService.get_admin_session()
|
||||
|
||||
if admin_session is not None:
|
||||
return (
|
||||
db.session.query(UserModel)
|
||||
.filter(UserModel.uid == admin_session.admin_impersonate_uid)
|
||||
.first()
|
||||
)
|
||||
else:
|
||||
raise ApiError(
|
||||
"unauthorized",
|
||||
"You do not have permissions to do this.",
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_principal_by_user_id(user_id: int) -> PrincipalModel:
|
||||
"""Get_principal_by_user_id."""
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
<bpmn:scriptTask id="get_group_a">
|
||||
<bpmn:incoming>Flow_1j4jzft</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_10xyk22</bpmn:outgoing>
|
||||
<bpmn:script>members_a = get_group_members("GroupA")</bpmn:script>
|
||||
<bpmn:script>members_a = get_group_members("groupA")</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_10xyk22" sourceRef="get_group_a" targetRef="get_group_b" />
|
||||
<bpmn:scriptTask id="get_group_b">
|
||||
<bpmn:incoming>Flow_10xyk22</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_01xr2ac</bpmn:outgoing>
|
||||
<bpmn:script>members_b = get_group_members("GroupB")</bpmn:script>
|
||||
<bpmn:script>members_b = get_group_members("groupB")</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_01xr2ac" sourceRef="get_group_b" targetRef="Event_1s123jg" />
|
||||
</bpmn:process>
|
||||
|
|
|
@ -275,25 +275,6 @@ class BaseTest:
|
|||
user: UserModel, _redirect_url: str = "http://some/frontend/url"
|
||||
) -> Dict[str, str]:
|
||||
"""Logged_in_headers."""
|
||||
# if user is None:
|
||||
# uid = 'test_user'
|
||||
# user_info = {'uid': 'test_user'}
|
||||
# else:
|
||||
# uid = user.uid
|
||||
# user_info = {'uid': user.uid}
|
||||
|
||||
# query_string = user_info_to_query_string(user_info, redirect_url)
|
||||
# rv = self.app.get("/v1.0/login%s" % query_string, follow_redirects=False)
|
||||
# self.assertTrue(rv.status_code == 302)
|
||||
# self.assertTrue(str.startswith(rv.location, redirect_url))
|
||||
#
|
||||
# user_model = session.query(UserModel).filter_by(uid=uid).first()
|
||||
# self.assertIsNotNone(user_model.ldap_info.display_name)
|
||||
# self.assertEqual(user_model.uid, uid)
|
||||
# self.assertTrue('user' in g, 'User should be in Flask globals')
|
||||
# user = UserService.current_user(allow_admin_impersonate=True)
|
||||
# self.assertEqual(uid, user.uid, 'Logged in user should match given user uid')
|
||||
|
||||
return dict(Authorization="Bearer " + user.encode_auth_token())
|
||||
|
||||
def get_test_data_file_contents(
|
||||
|
|
|
@ -25,7 +25,6 @@ from spiffworkflow_backend.models.process_instance_report import (
|
|||
)
|
||||
from spiffworkflow_backend.models.process_model import NotificationType
|
||||
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
|
||||
from spiffworkflow_backend.models.task_event import TaskEventModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
|
@ -1088,16 +1087,7 @@ class TestProcessApi(BaseTest):
|
|||
f"/v1.0/process-models/{process_group_id}/{process_model_id}/process-instances/{process_instance_id}/run",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
|
||||
assert response.json is not None
|
||||
task_events = (
|
||||
db.session.query(TaskEventModel)
|
||||
.filter(TaskEventModel.process_instance_id == process_instance_id)
|
||||
.all()
|
||||
)
|
||||
assert len(task_events) == 1
|
||||
task_event = task_events[0]
|
||||
assert task_event.user_id == with_super_admin_user.id
|
||||
|
||||
delete_response = client.delete(
|
||||
f"/v1.0/process-models/{process_group_id}/{process_model_id}/process-instances/{process_instance_id}",
|
||||
|
@ -1105,40 +1095,6 @@ class TestProcessApi(BaseTest):
|
|||
)
|
||||
assert delete_response.status_code == 200
|
||||
|
||||
def test_process_instance_run_user_task_creates_task_event(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_process_instance_run_user_task."""
|
||||
process_group_id = "my_process_group"
|
||||
process_model_id = "user_task"
|
||||
|
||||
headers = self.logged_in_headers(with_super_admin_user)
|
||||
response = self.create_process_instance(
|
||||
client, process_group_id, process_model_id, headers
|
||||
)
|
||||
assert response.json is not None
|
||||
process_instance_id = response.json["id"]
|
||||
|
||||
response = client.post(
|
||||
f"/v1.0/process-models/{process_group_id}/{process_model_id}/process-instances/{process_instance_id}/run",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
|
||||
assert response.json is not None
|
||||
task_events = (
|
||||
db.session.query(TaskEventModel)
|
||||
.filter(TaskEventModel.process_instance_id == process_instance_id)
|
||||
.all()
|
||||
)
|
||||
assert len(task_events) == 1
|
||||
task_event = task_events[0]
|
||||
assert task_event.user_id == with_super_admin_user.id
|
||||
# TODO: When user tasks work, we need to add some more assertions for action, task_state, etc.
|
||||
|
||||
def test_task_show(
|
||||
self,
|
||||
app: Flask,
|
||||
|
|
Loading…
Reference in New Issue