mirror of
https://github.com/sartography/spiffworkflow-backend.git
synced 2025-02-23 21:08:18 +00:00
added some additional apis for the frontend
This commit is contained in:
parent
f00dff8450
commit
49524e6fcd
@ -38,6 +38,19 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkflowSpecCategory"
|
||||
/process-models/{process_model_id}:
|
||||
get:
|
||||
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_model_show
|
||||
summary: Returns a single process model
|
||||
tags:
|
||||
- Workflow Specification
|
||||
responses:
|
||||
'200':
|
||||
description: Workflow spec.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkflowSpec"
|
||||
/workflow-specification:
|
||||
# get:
|
||||
# operationId: crc.api.workflow.all_specifications
|
||||
@ -77,7 +90,7 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkflowSpec"
|
||||
responses:
|
||||
"200":
|
||||
"201":
|
||||
description: Workflow specification created successfully.
|
||||
content:
|
||||
application/json:
|
||||
@ -120,7 +133,7 @@ paths:
|
||||
type: string
|
||||
format: binary
|
||||
responses:
|
||||
"200":
|
||||
"201":
|
||||
description: Metadata about the uploaded file, but not the file content.
|
||||
content:
|
||||
application/json:
|
||||
@ -152,7 +165,7 @@ paths:
|
||||
tags:
|
||||
- Workflow Specifications
|
||||
responses:
|
||||
"200":
|
||||
"201":
|
||||
description: Workflow generated successfully
|
||||
content:
|
||||
application/json:
|
||||
@ -187,7 +200,7 @@ paths:
|
||||
# responses:
|
||||
# '204':
|
||||
# description: The workflow specification has been removed.
|
||||
/workflow-specification/{spec_id}/file/{file_name}:
|
||||
/process-models/{spec_id}/file/{file_name}:
|
||||
parameters:
|
||||
- name: spec_id
|
||||
in: path
|
||||
|
@ -1,9 +1,11 @@
|
||||
"""File."""
|
||||
import enum
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from flask_bpmn.models.db import db
|
||||
from marshmallow import INCLUDE
|
||||
from marshmallow import Schema
|
||||
from typing import Optional
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import deferred # type: ignore
|
||||
from sqlalchemy.orm import relationship
|
||||
@ -85,38 +87,28 @@ CONTENT_TYPES = {
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class File:
|
||||
"""File."""
|
||||
|
||||
def __init__(self):
|
||||
"""__init__."""
|
||||
self.content_type = None
|
||||
self.name = None
|
||||
self.content_type = None
|
||||
self.process_instance_id = None
|
||||
self.irb_doc_code = None
|
||||
self.type = None
|
||||
self.document = {}
|
||||
self.last_modified = None
|
||||
self.size = None
|
||||
self.data_store = {}
|
||||
self.user_uid = None
|
||||
self.archived = None
|
||||
content_type: str
|
||||
name: str
|
||||
type: str
|
||||
document: dict
|
||||
last_modified: str
|
||||
size: int
|
||||
process_instance_id: Optional[int] = None
|
||||
irb_doc_code: Optional[str] = None
|
||||
data_store: Optional[dict] = field(default_factory=dict)
|
||||
user_uid: Optional[str] = None
|
||||
file_contents: Optional[str] = None
|
||||
archived: bool = False
|
||||
|
||||
@classmethod
|
||||
def from_file_system(
|
||||
cls, file_name, file_type, content_type, last_modified, file_size
|
||||
):
|
||||
"""From_file_system."""
|
||||
instance = cls()
|
||||
instance.name = file_name
|
||||
instance.content_type = content_type
|
||||
instance.type = file_type.value
|
||||
instance.document = {}
|
||||
instance.last_modified = last_modified
|
||||
instance.size = file_size
|
||||
# fixme: How to track the user id?
|
||||
instance.data_store = {}
|
||||
instance = cls(name=file_name, content_type=content_type, type=file_type.value, document={}, last_modified=last_modified, size=file_size)
|
||||
return instance
|
||||
|
||||
|
||||
@ -141,6 +133,7 @@ class FileSchema(Schema):
|
||||
"document",
|
||||
"user_uid",
|
||||
"url",
|
||||
"file_contents",
|
||||
]
|
||||
unknown = INCLUDE
|
||||
|
||||
|
@ -2,6 +2,11 @@
|
||||
import marshmallow
|
||||
from marshmallow import post_load
|
||||
from marshmallow import Schema
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
import json
|
||||
|
||||
from spiffworkflow_backend.models.file import File
|
||||
|
||||
|
||||
class ProcessModelInfo:
|
||||
@ -21,6 +26,7 @@ class ProcessModelInfo:
|
||||
process_group_id="",
|
||||
display_order=0,
|
||||
is_review=False,
|
||||
files=None,
|
||||
):
|
||||
"""__init__."""
|
||||
self.id = id # Sting unique id
|
||||
@ -37,9 +43,12 @@ class ProcessModelInfo:
|
||||
|
||||
if libraries is None:
|
||||
libraries = []
|
||||
|
||||
self.libraries = libraries
|
||||
|
||||
if files is None:
|
||||
files = []
|
||||
self.files = files
|
||||
|
||||
def __eq__(self, other):
|
||||
"""__eq__."""
|
||||
if not isinstance(other, ProcessModelInfo):
|
||||
@ -69,6 +78,9 @@ class ProcessModelInfoSchema(Schema):
|
||||
is_review = marshmallow.fields.Boolean(allow_none=True)
|
||||
process_group_id = marshmallow.fields.String(allow_none=True)
|
||||
libraries = marshmallow.fields.List(marshmallow.fields.String(), allow_none=True)
|
||||
files = marshmallow.fields.List(
|
||||
marshmallow.fields.Nested("FileSchema")
|
||||
)
|
||||
|
||||
@post_load
|
||||
def make_spec(self, data, **kwargs):
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""APIs for dealing with process groups, process models, and process instances."""
|
||||
import connexion
|
||||
import json
|
||||
from flask import Blueprint
|
||||
from flask import Response
|
||||
from flask import g
|
||||
from flask_bpmn.api.api_error import ApiError
|
||||
|
||||
@ -9,6 +11,7 @@ from spiffworkflow_backend.models.file import FileType
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSchema
|
||||
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
|
||||
from spiffworkflow_backend.models.process_group import ProcessGroupSchema
|
||||
from spiffworkflow_backend.models.file import File
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
ProcessInstanceProcessor,
|
||||
)
|
||||
@ -35,14 +38,15 @@ def add_process_model(body):
|
||||
size = len(workflows)
|
||||
spec.display_order = size
|
||||
process_model_service.add_spec(spec)
|
||||
return ProcessModelInfoSchema().dump(spec)
|
||||
return Response(
|
||||
json.dumps(ProcessModelInfoSchema().dump(spec)), status=201, mimetype="application/json"
|
||||
)
|
||||
|
||||
|
||||
def get_file(spec_id, file_name):
|
||||
"""Get_file."""
|
||||
workflow_spec_service = ProcessModelService()
|
||||
workflow_spec = workflow_spec_service.get_spec(spec_id)
|
||||
files = SpecFileService.get_files(workflow_spec, file_name)
|
||||
process_model = ProcessModelService().get_spec(spec_id)
|
||||
files = SpecFileService.get_files(process_model, file_name)
|
||||
if len(files) == 0:
|
||||
raise ApiError(
|
||||
code="unknown file",
|
||||
@ -50,21 +54,27 @@ def get_file(spec_id, file_name):
|
||||
f" it does not exist in workflow {spec_id}.",
|
||||
status_code=404,
|
||||
)
|
||||
return FileSchema().dump(files[0])
|
||||
|
||||
file = files[0]
|
||||
file_contents = SpecFileService.get_data(process_model, file.name)
|
||||
file.file_contents = file_contents
|
||||
return FileSchema().dump(file)
|
||||
|
||||
|
||||
def add_file(spec_id):
|
||||
"""Add_file."""
|
||||
workflow_spec_service = ProcessModelService()
|
||||
workflow_spec = workflow_spec_service.get_spec(spec_id)
|
||||
process_model = workflow_spec_service.get_spec(spec_id)
|
||||
request_file = connexion.request.files["file"]
|
||||
file = SpecFileService.add_file(
|
||||
workflow_spec, request_file.filename, request_file.stream.read()
|
||||
process_model, request_file.filename, request_file.stream.read()
|
||||
)
|
||||
if not process_model.primary_process_id and file.type == FileType.bpmn.value:
|
||||
SpecFileService.set_primary_bpmn(process_model, file.name)
|
||||
workflow_spec_service.update_spec(process_model)
|
||||
return Response(
|
||||
json.dumps(FileSchema().dump(file)), status=201, mimetype="application/json"
|
||||
)
|
||||
if not workflow_spec.primary_process_id and file.type == FileType.bpmn.value:
|
||||
SpecFileService.set_primary_bpmn(workflow_spec, file.name)
|
||||
workflow_spec_service.update_spec(workflow_spec)
|
||||
return FileSchema().dump(file)
|
||||
|
||||
|
||||
def create_process_instance(spec_id):
|
||||
@ -79,13 +89,14 @@ def create_process_instance(spec_id):
|
||||
workflow_api_model = ProcessInstanceService.processor_to_process_instance_api(
|
||||
processor
|
||||
)
|
||||
return ProcessInstanceApiSchema().dump(workflow_api_model)
|
||||
return Response(
|
||||
json.dumps(ProcessInstanceApiSchema().dump(workflow_api_model)), status=201, mimetype="application/json"
|
||||
)
|
||||
|
||||
|
||||
def process_groups_list():
|
||||
"""Process_groups_list."""
|
||||
process_model_service = ProcessModelService()
|
||||
process_groups = process_model_service.get_process_groups()
|
||||
process_groups = ProcessModelService().get_process_groups()
|
||||
return ProcessGroupSchema(many=True).dump(process_groups)
|
||||
|
||||
|
||||
@ -93,3 +104,21 @@ def process_group_show(process_group_id):
|
||||
"""Process_group_show."""
|
||||
process_group = ProcessModelService().get_process_group(process_group_id)
|
||||
return ProcessGroupSchema().dump(process_group)
|
||||
|
||||
|
||||
def process_model_show(process_model_id):
|
||||
"""Process_model_show."""
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
files = SpecFileService.get_files(process_model, extension_filter="bpmn")
|
||||
process_model.files = files
|
||||
process_model_json = ProcessModelInfoSchema().dump(process_model)
|
||||
return process_model_json
|
||||
|
@ -37,7 +37,7 @@ class SpecFileService(FileSystemService):
|
||||
files.extend(SpecFileService._get_files(lib_path, file_name))
|
||||
|
||||
if extension_filter != "":
|
||||
files = filter(lambda file: file.name.endswith(extension_filter), files)
|
||||
files = list(filter(lambda file: file.name.endswith(extension_filter), files))
|
||||
|
||||
return files
|
||||
|
||||
|
@ -38,9 +38,9 @@ def test_add_new_process_model(app, client: FlaskClient, with_bpmn_file_cleanup)
|
||||
# def test_get_process_model(self):
|
||||
#
|
||||
# load_test_spec('random_fact')
|
||||
# rv = client.get('/v1.0/workflow-specification/random_fact', headers=logged_in_headers())
|
||||
# assert_success(rv)
|
||||
# json_data = json.loads(rv.get_data(as_text=True))
|
||||
# response = client.get('/v1.0/workflow-specification/random_fact', headers=logged_in_headers())
|
||||
# assert_success(response)
|
||||
# json_data = json.loads(response.get_data(as_text=True))
|
||||
# api_spec = WorkflowSpecInfoSchema().load(json_data)
|
||||
#
|
||||
# fs_spec = process_model_service.get_spec('random_fact')
|
||||
@ -54,31 +54,31 @@ def test_get_workflow_from_workflow_spec(
|
||||
"""Test_get_workflow_from_workflow_spec."""
|
||||
user = find_or_create_user()
|
||||
spec = load_test_spec(app, "hello_world")
|
||||
rv = client.post(
|
||||
response = client.post(
|
||||
f"/v1.0/workflow-specification/{spec.id}", headers=logged_in_headers(user)
|
||||
)
|
||||
assert rv.status_code == 200
|
||||
assert "hello_world" == rv.json["process_model_identifier"]
|
||||
# assert('Task_GetName' == rv.json['next_task']['name'])
|
||||
assert response.status_code == 201
|
||||
assert "hello_world" == response.json["process_model_identifier"]
|
||||
# assert('Task_GetName' == response.json['next_task']['name'])
|
||||
|
||||
|
||||
def test_get_process_groups_when_none(app, client: FlaskClient, with_bpmn_file_cleanup):
|
||||
user = find_or_create_user()
|
||||
rv = client.get(
|
||||
response = client.get(
|
||||
"/v1.0/process-groups", headers=logged_in_headers(user)
|
||||
)
|
||||
assert rv.status_code == 200
|
||||
assert rv.json == []
|
||||
assert response.status_code == 200
|
||||
assert response.json == []
|
||||
|
||||
|
||||
def test_get_process_groups_when_there_are_some(app, client: FlaskClient, with_bpmn_file_cleanup):
|
||||
user = find_or_create_user()
|
||||
load_test_spec(app, "hello_world")
|
||||
rv = client.get(
|
||||
response = client.get(
|
||||
"/v1.0/process-groups", headers=logged_in_headers(user)
|
||||
)
|
||||
assert rv.status_code == 200
|
||||
assert len(rv.json) == 1
|
||||
assert response.status_code == 200
|
||||
assert len(response.json) == 1
|
||||
|
||||
|
||||
def test_get_process_group_when_found(app, client: FlaskClient, with_bpmn_file_cleanup):
|
||||
@ -86,12 +86,36 @@ def test_get_process_group_when_found(app, client: FlaskClient, with_bpmn_file_c
|
||||
test_process_group_id = "group_id1"
|
||||
process_model_dir_name = "hello_world"
|
||||
load_test_spec(app, process_model_dir_name, process_group_id=test_process_group_id)
|
||||
rv = client.get(
|
||||
f"/v1.0/process-group/{test_process_group_id}", headers=logged_in_headers(user)
|
||||
response = client.get(
|
||||
f"/v1.0/process-groups/{test_process_group_id}", headers=logged_in_headers(user)
|
||||
)
|
||||
assert rv.status_code == 200
|
||||
assert rv.json["id"] == test_process_group_id
|
||||
assert rv.json["process_models"][0]["id"] == process_model_dir_name
|
||||
assert response.status_code == 200
|
||||
assert response.json["id"] == test_process_group_id
|
||||
assert response.json["process_models"][0]["id"] == process_model_dir_name
|
||||
|
||||
|
||||
def test_get_process_model_when_found(app, client: FlaskClient, with_bpmn_file_cleanup):
|
||||
user = find_or_create_user()
|
||||
test_process_group_id = "group_id1"
|
||||
process_model_dir_name = "hello_world"
|
||||
load_test_spec(app, process_model_dir_name, process_group_id=test_process_group_id)
|
||||
response = client.get(
|
||||
f"/v1.0/process-models/{process_model_dir_name}", headers=logged_in_headers(user)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json["id"] == process_model_dir_name
|
||||
assert len(response.json["files"]) == 1
|
||||
assert response.json["files"][0]["name"] == "hello_world.bpmn"
|
||||
|
||||
|
||||
def test_get_process_model_when_not_found(app, client: FlaskClient, with_bpmn_file_cleanup):
|
||||
user = find_or_create_user()
|
||||
process_model_dir_name = "THIS_NO_EXISTS"
|
||||
response = client.get(
|
||||
f"/v1.0/process-models/{process_model_dir_name}", headers=logged_in_headers(user)
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert response.json["code"] == "process_mode_cannot_be_found"
|
||||
|
||||
|
||||
def create_process_model(app, client: FlaskClient):
|
||||
@ -117,13 +141,13 @@ def create_process_model(app, client: FlaskClient):
|
||||
primary_file_name="",
|
||||
)
|
||||
user = find_or_create_user()
|
||||
rv = client.post(
|
||||
response = client.post(
|
||||
"/v1.0/workflow-specification",
|
||||
content_type="application/json",
|
||||
data=json.dumps(ProcessModelInfoSchema().dump(spec)),
|
||||
headers=logged_in_headers(user),
|
||||
)
|
||||
assert rv.status_code == 200
|
||||
assert response.status_code == 201
|
||||
|
||||
fs_spec = process_model_service.get_spec("make_cookies")
|
||||
assert spec.display_name == fs_spec.display_name
|
||||
@ -136,7 +160,7 @@ def create_spec_file(app, client: FlaskClient):
|
||||
spec = load_test_spec(app, "random_fact")
|
||||
data = {"file": (io.BytesIO(b"abcdef"), "random_fact.svg")}
|
||||
user = find_or_create_user()
|
||||
rv = client.post(
|
||||
response = client.post(
|
||||
"/v1.0/workflow-specification/%s/file" % spec.id,
|
||||
data=data,
|
||||
follow_redirects=True,
|
||||
@ -144,16 +168,16 @@ def create_spec_file(app, client: FlaskClient):
|
||||
headers=logged_in_headers(user),
|
||||
)
|
||||
|
||||
assert rv.status_code == 200
|
||||
assert rv.get_data() is not None
|
||||
file = json.loads(rv.get_data(as_text=True))
|
||||
assert response.status_code == 201
|
||||
assert response.get_data() is not None
|
||||
file = json.loads(response.get_data(as_text=True))
|
||||
assert FileType.svg.value == file["type"]
|
||||
assert "image/svg+xml" == file["content_type"]
|
||||
|
||||
rv = client.get(
|
||||
response = client.get(
|
||||
f"/v1.0/workflow-specification/{spec.id}/file/random_fact.svg",
|
||||
headers=logged_in_headers(user),
|
||||
)
|
||||
assert rv.status_code == 200
|
||||
file2 = json.loads(rv.get_data(as_text=True))
|
||||
assert response.status_code == 200
|
||||
file2 = json.loads(response.get_data(as_text=True))
|
||||
assert file == file2
|
||||
|
Loading…
x
Reference in New Issue
Block a user