mirror of
https://github.com/sartography/spiffworkflow-backend.git
synced 2025-02-23 21:08:18 +00:00
added api to get process instances w/ burnettk
This commit is contained in:
parent
053571500f
commit
8e246e46b5
@ -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
|
||||
|
@ -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."""
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user