File download from workflow data (#122)

This commit is contained in:
jbirddog 2023-02-02 14:44:37 -05:00 committed by GitHub
parent f4ff86f9b0
commit 18a23a729a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 1 deletions

View File

@ -1605,6 +1605,45 @@ paths:
schema:
$ref: "#/components/schemas/Workflow"
/process-data-file-download/{modified_process_model_identifier}/{process_instance_id}/{process_data_identifier}:
parameters:
- name: modified_process_model_identifier
in: path
required: true
description: The modified id of an existing process model
schema:
type: string
- name: process_instance_id
in: path
required: true
description: The unique id of an existing process instance.
schema:
type: integer
- name: process_data_identifier
in: path
required: true
description: The identifier of the process data.
schema:
type: string
- name: index
in: query
required: false
description: The optional index of the value if key's value is an array
schema:
type: integer
get:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_data_file_download
summary: Download the file referneced in the process data value.
tags:
- Data Objects
responses:
"200":
description: Fetch succeeded.
content:
application/json:
schema:
$ref: "#/components/schemas/Workflow"
/send-event/{modified_process_model_identifier}/{process_instance_id}:
parameters:
- name: modified_process_model_identifier

View File

@ -1,7 +1,9 @@
"""APIs for dealing with process groups, process models, and process instances."""
import base64
import json
from typing import Any
from typing import Dict
from typing import Optional
import flask.wrappers
from flask import Blueprint
@ -81,10 +83,12 @@ def process_list() -> Any:
return SpecReferenceSchema(many=True).dump(references)
def process_data_show(
def _process_data_fetcher(
process_instance_id: int,
process_data_identifier: str,
modified_process_model_identifier: str,
download_file_data: bool,
index: Optional[int] = None,
) -> flask.wrappers.Response:
"""Process_data_show."""
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
@ -94,6 +98,26 @@ def process_data_show(
if process_data_identifier in all_process_data:
process_data_value = all_process_data[process_data_identifier]
if process_data_value is not None and index is not None:
process_data_value = process_data_value[index]
if (
download_file_data
and isinstance(process_data_value, str)
and process_data_value.startswith("data:")
):
parts = process_data_value.split(";")
mimetype = parts[0][4:]
filename = parts[1]
base64_value = parts[2].split(",")[1]
file_contents = base64.b64decode(base64_value)
return Response(
file_contents,
mimetype=mimetype,
headers={"Content-disposition": f"attachment; filename={filename}"},
)
return make_response(
jsonify(
{
@ -105,6 +129,37 @@ def process_data_show(
)
def process_data_show(
process_instance_id: int,
process_data_identifier: str,
modified_process_model_identifier: str,
) -> flask.wrappers.Response:
"""Process_data_show."""
return _process_data_fetcher(
process_instance_id,
process_data_identifier,
modified_process_model_identifier,
False,
None,
)
def process_data_file_download(
process_instance_id: int,
process_data_identifier: str,
modified_process_model_identifier: str,
index: Optional[int] = None,
) -> flask.wrappers.Response:
"""Process_data_file_download."""
return _process_data_fetcher(
process_instance_id,
process_data_identifier,
modified_process_model_identifier,
True,
index,
)
# sample body:
# {"ref": "refs/heads/main", "repository": {"name": "sample-process-models",
# "full_name": "sartography/sample-process-models", "private": False .... }}

View File

@ -17,6 +17,7 @@ from flask import request
from werkzeug.wrappers import Response
from spiffworkflow_backend.exceptions.api_error import ApiError
from spiffworkflow_backend.helpers.api_version import V1_API_PATH_PREFIX
from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.services.authentication_service import AuthenticationService
from spiffworkflow_backend.services.authentication_service import (
@ -58,6 +59,10 @@ def verify_token(
if not token and "Authorization" in request.headers:
token = request.headers["Authorization"].removeprefix("Bearer ")
if not token and "access_token" in request.cookies:
if request.path.startswith(f"{V1_API_PATH_PREFIX}/process-data-file-download/"):
token = request.cookies["access_token"]
# This should never be set here but just in case
_clear_auth_tokens_from_thread_local_data()

View File

@ -0,0 +1,51 @@
"""Markdown_file_download_link."""
from typing import Any
from urllib.parse import unquote
from flask import current_app
from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.script_attributes_context import (
ScriptAttributesContext,
)
from spiffworkflow_backend.scripts.script import Script
class GetMarkdownFileDownloadLink(Script):
"""GetMarkdownFileDownloadLink."""
@staticmethod
def requires_privileged_permissions() -> bool:
"""We have deemed this function safe to run without elevated permissions."""
return False
def get_description(self) -> str:
"""Get_description."""
return """Returns a string which is a string in markdown format."""
def run(
self,
script_attributes_context: ScriptAttributesContext,
*_args: Any,
**kwargs: Any,
) -> Any:
"""Run."""
# example input:
# "data:application/pdf;name=Harmeet_1234.pdf;base64,JV...."
process_data_identifier = kwargs["key"]
parts = kwargs["file_data"].split(";")
file_index = kwargs["file_index"]
label = unquote(parts[1].split("=")[1])
process_model_identifier = script_attributes_context.process_model_identifier
modified_process_model_identifier = (
ProcessModelInfo.modify_process_identifier_for_path_param(
process_model_identifier
)
)
process_instance_id = script_attributes_context.process_instance_id
url = current_app.config["SPIFFWORKFLOW_BACKEND_URL"]
url += f"/v1.0/process-data-file-download/{modified_process_model_identifier}/"
f"{process_instance_id}/{process_data_identifier}?index={file_index}"
link = f"[{label}]({url})"
return link