added api to get process instances w/ burnettk

This commit is contained in:
jasquat 2022-06-07 17:28:48 -04:00
parent 053571500f
commit 8e246e46b5
6 changed files with 166 additions and 7 deletions

View File

@ -160,6 +160,40 @@ paths:
# responses:
# '204':
# description: The workflow specification has been removed.
/process-models/{process_model_id}/process-instances:
parameters:
- name: process_model_id
in: path
required: true
description: The unique id of an existing workflow specification.
schema:
type: string
- name: page
in: query
required: false
description: The page number to return. Defaults to page 1.
schema:
type: integer
- name: per_page
in: query
required: false
description: The page number to return. Defaults to page 1.
schema:
type: integer
get:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_list
summary: Returns a list of process instances for a given process model
tags:
- Workflow Specification
responses:
'200':
description: Workflow.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Workflow"
/process-models/{process_model_id}/file/{file_name}:
parameters:
- name: process_model_id

View File

@ -1,5 +1,6 @@
"""Process_instance."""
import enum
import json
import marshmallow
from flask_bpmn.models.db import db
@ -85,6 +86,19 @@ class ProcessInstanceModel(db.Model): # type: ignore
process_initiator = relationship("UserModel")
status = db.Column(db.Enum(ProcessInstanceStatus))
@property
def serialized(self):
"""Return object data in serializeable format"""
return {
'id': self.id,
'process_model_identifier': self.process_model_identifier,
'status': self.status.value,
'bpmn_json': self.bpmn_json,
'start_in_seconds': self.start_in_seconds,
'end_in_seconds': self.end_in_seconds,
'process_initiator_id': self.process_initiator_id
}
class ProcessInstanceApi:
"""ProcessInstanceApi."""

View File

@ -8,7 +8,7 @@ from flask_bpmn.api.api_error import ApiError
from spiffworkflow_backend.models.file import FileSchema
from spiffworkflow_backend.models.file import FileType
from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSchema
from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSchema, ProcessInstanceModel
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
from spiffworkflow_backend.models.process_group import ProcessGroupSchema
from spiffworkflow_backend.models.file import File
@ -81,7 +81,6 @@ def add_file(process_model_id):
def process_instance_create(process_model_id):
"""Create_process_instance."""
# import pdb; pdb.set_trace()
process_instance = ProcessInstanceService.create_process_instance(process_model_id, g.user)
processor = ProcessInstanceProcessor(process_instance)
@ -100,6 +99,31 @@ def process_instance_create(process_model_id):
)
def process_instance_list(process_model_id, page=1, per_page=100):
process_model = ProcessModelService().get_spec(process_model_id)
if process_model is None:
raise (
ApiError(
code="process_mode_cannot_be_found",
message=f"Process model cannot be found: {process_model_id}",
status_code=400,
)
)
process_instances = ProcessInstanceModel.query.filter_by(process_model_identifier=process_model.id).order_by(ProcessInstanceModel.start_in_seconds.desc()).paginate(page, per_page, False)
serialized_results = []
for process_instance in process_instances.items:
process_instance_serialized = process_instance.serialized
process_instance_serialized["process_group_id"] = process_model.process_group_id
serialized_results.append(process_instance_serialized)
response_json = {"results": serialized_results, "pagination": {"count": len(process_instances.items), "total": process_instances.total, "pages": process_instances.pages}}
return Response(
json.dumps(response_json), status=200, mimetype="application/json"
)
def process_groups_list():
"""Process_groups_list."""
process_groups = ProcessModelService().get_process_groups()

View File

@ -1,5 +1,6 @@
"""Process_instance_processor."""
import json
import time
from datetime import datetime
from typing import List
@ -180,6 +181,8 @@ class ProcessInstanceProcessor:
self.bpmn_process_instance.data[
ProcessInstanceProcessor.PROCESS_INSTANCE_ID_KEY
] = process_instance_model.id
# FIXME: This also seems to happen in the save method below
process_instance_model.bpmn_json = (
ProcessInstanceProcessor._serializer.serialize_json(
self.bpmn_process_instance
@ -328,13 +331,21 @@ class ProcessInstanceProcessor:
"""Saves the current state of this processor to the database."""
self.process_instance_model.bpmn_json = self.serialize()
complete_states = [TaskState.CANCELLED, TaskState.COMPLETED]
tasks = list(self.get_all_user_tasks())
user_tasks = list(self.get_all_user_tasks())
self.process_instance_model.status = self.get_status()
self.process_instance_model.total_tasks = len(tasks)
self.process_instance_model.total_tasks = len(user_tasks)
self.process_instance_model.completed_tasks = sum(
1 for t in tasks if t.state in complete_states
1 for t in user_tasks if t.state in complete_states
)
self.process_instance_model.last_updated = datetime.utcnow()
if self.process_instance_model.start_in_seconds is None:
self.process_instance_model.start_in_seconds = time.time()
if self.process_instance_model.end_in_seconds is None:
if self.bpmn_process_instance.is_completed():
self.process_instance_model.end_in_seconds = time.time()
db.session.add(self.process_instance_model)
db.session.commit()

View File

@ -1,6 +1,7 @@
"""Process_instance_service."""
from datetime import datetime
from typing import List
import time
from flask import current_app
from flask_bpmn.models.db import db
@ -34,6 +35,7 @@ class ProcessInstanceService:
process_initiator=user,
process_model_identifier=process_model_identifier,
last_updated=datetime.now(),
start_in_seconds=time.time(),
)
db.session.add(process_instance_model)
db.session.commit()

View File

@ -10,10 +10,12 @@ from tests.spiffworkflow_backend.helpers.test_data import find_or_create_user
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from tests.spiffworkflow_backend.helpers.test_data import logged_in_headers
from flask_bpmn.models.db import db
from spiffworkflow_backend.models.file import FileType
from spiffworkflow_backend.models.process_group import ProcessGroup
from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
from spiffworkflow_backend.services.process_model_service import ProcessModelService
@ -133,12 +135,84 @@ def test_get_process_model_when_not_found(app, client: FlaskClient, with_bpmn_fi
def test_process_instance_create(app, client: FlaskClient, with_bpmn_file_cleanup):
user = find_or_create_user()
test_process_group_id = "runs_without_input"
process_model_dir_name = "sample"
user = find_or_create_user()
headers = logged_in_headers(user)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
def test_process_instance_list_with_default_list(app, client: FlaskClient, with_bpmn_file_cleanup):
db.session.query(ProcessInstanceModel).delete()
db.session.commit()
test_process_group_id = "runs_without_input"
process_model_dir_name = "sample"
user = find_or_create_user()
headers = logged_in_headers(user)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
response = client.get(
f"/v1.0/process-models/{process_model_dir_name}/process-instances", headers=logged_in_headers(user)
)
assert response.status_code == 200
assert len(response.json["results"]) == 1
assert response.json["pagination"]["count"] == 1
assert response.json["pagination"]["pages"] == 1
assert response.json["pagination"]["total"] == 1
process_instance_dict = response.json["results"][0]
f = open("bpmn.json", "w")
f.write(process_instance_dict["bpmn_json"])
f.close()
assert type(process_instance_dict["id"]) is int
assert process_instance_dict["process_model_identifier"] == process_model_dir_name
assert process_instance_dict["process_group_id"] == test_process_group_id
assert type(process_instance_dict["start_in_seconds"]) is int
assert process_instance_dict["start_in_seconds"] > 0
assert type(process_instance_dict["end_in_seconds"]) is int
assert process_instance_dict["end_in_seconds"] > 0
assert process_instance_dict["start_in_seconds"] <= process_instance_dict["end_in_seconds"]
assert process_instance_dict["status"] == "complete"
def test_process_instance_list_with_paginated_items(app, client: FlaskClient, with_bpmn_file_cleanup):
db.session.query(ProcessInstanceModel).delete()
db.session.commit()
test_process_group_id = "runs_without_input"
process_model_dir_name = "sample"
user = find_or_create_user()
headers = logged_in_headers(user)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
create_process_instance(app, client, test_process_group_id, process_model_dir_name, headers)
response = client.get(
f"/v1.0/process-models/{process_model_dir_name}/process-instances?per_page=2&page=3", headers=logged_in_headers(user)
)
assert response.status_code == 200
assert len(response.json["results"]) == 1
assert response.json["pagination"]["count"] == 1
assert response.json["pagination"]["pages"] == 3
assert response.json["pagination"]["total"] == 5
response = client.get(
f"/v1.0/process-models/{process_model_dir_name}/process-instances?per_page=2&page=1", headers=logged_in_headers(user)
)
assert response.status_code == 200
assert len(response.json["results"]) == 2
assert response.json["pagination"]["count"] == 2
assert response.json["pagination"]["pages"] == 3
assert response.json["pagination"]["total"] == 5
def create_process_instance(app, client: FlaskClient, test_process_group_id, process_model_dir_name, headers):
load_test_spec(app, process_model_dir_name, process_group_id=test_process_group_id)
response = client.post(
f"/v1.0/process-models/{process_model_dir_name}", headers=logged_in_headers(user)
f"/v1.0/process-models/{process_model_dir_name}", headers=headers
)
assert response.status_code == 201
assert response.json["status"] == "complete"